随机城市生成器2.0edit icon

作者:
邓朝元
Fork(复制)
下载
嵌入
BUG反馈
index.html
现在支持上传本地图片了!
index.html
            
            <!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
  <title>🌌 随机城市生成器</title>
  <link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet"/>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/>
  <style>
    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }
    body {
      font-family: 'Roboto', sans-serif;
      background: linear-gradient(135deg, #1e3c72, #2a5298);
      color: #fff;
      min-height: 100vh;
      padding: 20px;
    }
    .container {
      max-width: 1200px;
      margin: 0 auto;
    }
    header {
      text-align: center;
      margin-bottom: 30px;
    }
    h1 {
      font-size: 2.8em;
      margin-bottom: 10px;
      text-shadow: 0 2px 10px rgba(0,0,0,0.3);
    }
    .subtitle {
      font-size: 1.2em;
      opacity: 0.9;
    }
    .generate-btn {
      display: block;
      margin: 20px auto;
      padding: 15px 40px;
      font-size: 1.3em;
      background: #ff6b6b;
      color: white;
      border: none;
      border-radius: 50px;
      cursor: pointer;
      box-shadow: 0 4px 15px rgba(255,107,107,0.4);
      transition: all 0.3s;
    }
    .generate-btn:hover {
      background: #ff5252;
      transform: translateY(-2px);
    }
    .city-container {
      display: grid;
      grid-template-columns: 1fr 1fr;
      gap: 30px;
      margin-top: 20px;
    }
    @media (max-width: 900px) {
      .city-container {
        grid-template-columns: 1fr;
      }
    }
    .info-panel {
      background: rgba(255, 255, 255, 0.1);
      backdrop-filter: blur(10px);
      border-radius: 15px;
      padding: 20px;
      box-shadow: 0 8px 32px rgba(0,0,0,0.2);
    }
    .info-panel h2 {
      font-size: 1.6em;
      margin-bottom: 15px;
      color: #ffd166;
      border-bottom: 2px solid #ffd166;
      padding-bottom: 5px;
    }
    .info-item {
      margin: 12px 0;
      line-height: 1.6;
    }
    .info-item i {
      width: 25px;
      color: #a29bfe;
    }
    .map-container {
      text-align: center;
    }
    .map-container h2 {
      margin-bottom: 15px;
      color: #06d6a0;
    }
    #city-map {
      display: inline-grid;
      grid-template-columns: repeat(8, 40px);
      grid-template-rows: repeat(8, 40px);
      gap: 1px;
      margin: 10px;
    }
    .map-cell {
      width: 40px;
      height: 40px;
      border: 1px solid #333;
      position: relative;
      transition: transform 0.2s;
    }
    .map-cell:hover {
      transform: scale(1.2);
      z-index: 10;
    }
    .residential { background: #6c5ce7; }
    .commercial { background: #00cec9; }
    .industrial { background: #d63031; }
    .government { background: #0984e3; }
    .medical { background: #fdcb6e; }
    .education { background: #e17055; }
    .park { background: #00b894; }
    .entertainment { background: #fd79a8; }
    .transport { background: #74b9ff; }
    .tooltip {
      position: absolute;
      bottom: 100%;
      left: 50%;
      transform: translateX(-50%);
      background: rgba(0,0,0,0.85);
      color: white;
      padding: 8px 12px;
      border-radius: 8px;
      white-space: nowrap;
      font-size: 0.85em;
      z-index: 100;
      opacity: 0;
      transition: opacity 0.3s;
    }
    .map-cell:hover .tooltip {
      opacity: 1;
    }
    footer {
      text-align: center;
      margin-top: 50px;
      opacity: 0.7;
      font-size: 0.9em;
    }
    .loading {
      text-align: center;
      font-size: 1.2em;
      margin: 20px 0;
      display: none;
    }
  </style>
</head>
<body>
  <div class="container">
    <header>
      <h1>🌌 随机城市生成器</h1>
      <p class="subtitle">点击下方按钮,生成一个完全虚构但极度逼真的城市</p>
      <button class="generate-btn" id="generateBtn">
        <i class="fas fa-magic"></i> 生成新城市
      </button>
      <div class="loading" id="loading">🌍 正在生成城市数据...</div>
    </header>

    <div id="output" style="display: none;">
      <div class="city-container">
        <!-- 左侧:城市信息 -->
        <div class="info-panel">
          <h2><i class="fas fa-city"></i> 城市概况</h2>
          <div class="info-item"><i class="fas fa-tag"></i> <strong>城市名称:</strong> <span id="cityName"></span></div>
          <div class="info-item"><i class="fas fa-globe-americas"></i> <strong>国家:</strong> <span id="country"></span></div>
          <div class="info-item"><i class="fas fa-map-marker-alt"></i> <strong>地理位置:</strong> <span id="location"></span></div>
          <div class="info-item"><i class="fas fa-mountain"></i> <strong>地形:</strong> <span id="terrain"></span></div>
          <div class="info-item"><i class="fas fa-thermometer-half"></i> <strong>气候类型:</strong> <span id="climate"></span></div>
          <div class="info-item"><i class="fas fa-sun"></i> <strong>年均温:</strong> <span id="avgTemp"></span></div>
          <div class="info-item"><i class="fas fa-cloud"></i> <strong>当前天气:</strong> <span id="weather"></span></div>
          <div class="info-item"><i class="fas fa-users"></i> <strong>人口:</strong> <span id="population"></span></div>
          <div class="info-item"><i class="fas fa-ruler-combined"></i> <strong>面积:</strong> <span id="area"></span> km²</div>
          <div class="info-item"><i class="fas fa-weight-hanging"></i> <strong>人口密度:</strong> <span id="density"></span> 人/km²</div>
          <div class="info-item"><i class="fas fa-calendar-alt"></i> <strong>建市年份:</strong> <span id="founded"></span></div>
          <div class="info-item"><i class="fas fa-quote-left"></i> <strong>城市口号:</strong> <span id="motto"></span></div>
          <div class="info-item"><i class="fas fa-star"></i> <strong>昵称:</strong> <span id="nickname"></span></div>
        </div>

        <!-- 右侧:经济与政府 -->
        <div class="info-panel">
          <h2><i class="fas fa-chart-line"></i> 经济与政府</h2>
          <div class="info-item"><i class="fas fa-industry"></i> <strong>支柱产业:</strong> <span id="industry"></span></div>
          <div class="info-item"><i class="fas fa-dollar-sign"></i> <strong>GDP(总量):</strong> <span id="gdp"></span> 亿美元</div>
          <div class="info-item"><i class="fas fa-hand-holding-usd"></i> <strong>人均GDP:</strong> <span id="perCapitaGDP"></span> 美元</div>
          <div class="info-item"><i class="fas fa-percentage"></i> <strong>失业率:</strong> <span id="unemployment"></span></div>
          <div class="info-item"><i class="fas fa-balance-scale"></i> <strong>税收率:</strong> <span id="taxRate"></span></div>
          <div class="info-item"><i class="fas fa-skull-crossbones"></i> <strong>犯罪率:</strong> <span id="crimeRate"></span></div>

          <h2 style="margin-top: 20px;"><i class="fas fa-user-tie"></i> 政府高层</h2>
          <div class="info-item"><i class="fas fa-user"></i> <strong>市长:</strong> <span id="mayor"></span></div>
          <div class="info-item"><i class="fas fa-users-cog"></i> <strong>党派:</strong> <span id="party"></span></div>
          <div class="info-item"><i class="fas fa-calendar-check"></i> <strong>任期:</strong> <span id="term"></span></div>
          <div class="info-item"><i class="fas fa-shield-alt"></i> <strong>警察局长:</strong> <span id="policeChief"></span></div>
          <div class="info-item"><i class="fas fa-money-bill-wave"></i> <strong>财政局长:</strong> <span id="financeChief"></span></div>
        </div>
      </div>

      <!-- 中下:历史与人口 -->
      <div class="city-container">
        <div class="info-panel">
          <h2><i class="fas fa-book"></i> 历史大事记</h2>
          <div id="history"></div>
        </div>
        <div class="info-panel">
          <h2><i class="fas fa-democrat"></i> 人口结构</h2>
          <div class="info-item"><i class="fas fa-venus-mars"></i> <strong>性别比:</strong> <span id="genderRatio"></span></div>
          <div class="info-item"><i class="fas fa-baby"></i> <strong>出生率:</strong> <span id="birthRate"></span></div>
          <div class="info-item"><i class="fas fa-skull"></i> <strong>死亡率:</strong> <span id="deathRate"></span></div>
          <div class="info-item"><i class="fas fa-heartbeat"></i> <strong>平均寿命:</strong> <span id="lifeExpectancy"></span></div>
          <div class="info-item"><i class="fas fa-plane-arrival"></i> <strong>移民率:</strong> <span id="migration"></span></div>
          <div class="info-item"><i class="fas fa-user-graduate"></i> <strong>教育水平:</strong> <span id="education"></span></div>
          <div class="info-item"><i class="fas fa-layer-group"></i> <strong>年龄分布:</strong> <span id="ageDist"></span></div>
        </div>
      </div>

      <!-- 地图 -->
      <div class="info-panel map-container">
        <h2><i class="fas fa-th-large"></i> 城市地图(8x8)</h2>
        <div id="city-map"></div>
        <p><small>📌 悬停区块查看详细建筑</small></p>
      </div>
    </div>

    <footer>
      随机城市生成器 v2.0 | 数据完全虚构 | 使用 HTML/CSS/JS 构建
    </footer>
  </div>

  <script>
    // ======================
    // 数据词库
    // ======================
    const CITY_PREFIXES = ["New", "Port", "Lake", "North", "South", "East", "West", "Fort", "Grand", "Spring", "Mill", "Rock", "Hill", "Sun", "Bay", "Old", "Central", "Upper", "Lower"];
    const CITY_SUFFIXES = ["ville", "ton", "burg", "field", "wood", "port", "shire", "land", "view", "crest", "haven", "dale", "ford", "stone", "beach", "town", "mouth", "cross", "grove"];
    const COUNTRIES = ["United States", "Canada", "United Kingdom", "Germany", "France", "Australia", "New Zealand", "Sweden", "Norway", "Austria"];
    const TERRAINS = ["Coastal", "Plains", "Hilly", "Mountainous", "River Valley", "Island", "Desert Edge", "Forest"];
    const CLIMATES = [
      { name: "Temperate", temp: "8-15°C", desc: "四季分明" },
      { name: "Mediterranean", temp: "12-20°C", desc: "冬雨夏干" },
      { name: "Continental", temp: "1-25°C", desc: "冬冷夏热" },
      { name: "Arid", temp: "18-35°C", desc: "干燥少雨" },
      { name: "Subtropical", temp: "15-28°C", desc: "湿热多雨" },
      { name: "Oceanic", temp: "10-18°C", desc: "温和多云" }
    ];
    const WEATHERS = ["Sunny", "Cloudy", "Rainy", "Snowy", "Foggy", "Stormy"];
    const INDUSTRIES = ["Technology", "Manufacturing", "Tourism", "Education", "Healthcare", "Agriculture", "Finance", "Renewable Energy", "Entertainment", "Logistics"];
    const MOTTOES = [
      "Progress Through Unity",
      "Innovation & Tradition",
      "Where Nature Meets City",
      "Built for Tomorrow",
      "Strong, Safe, Sustainable",
      "Freedom to Grow"
    ];
    const NICKNAMES = ["The Emerald City", "Riverfront Gem", "Silicon Valley North", "Heart of the Valley", "The Twin Lakes", "Capital of Innovation"];
    const NAMES_MALE = ["James", "John", "Robert", "Michael", "William", "David", "Richard", "Joseph", "Thomas", "Charles"];
    const NAMES_FEMALE = ["Mary", "Patricia", "Jennifer", "Linda", "Elizabeth", "Barbara", "Susan", "Jessica", "Sarah", "Karen"];
    const SURNAMES = ["Smith", "Johnson", "Williams", "Brown", "Jones", "Garcia", "Miller", "Davis", "Rodriguez", "Martinez"];
    const PARTIES = ["Progressive", "Conservative", "Liberal", "Green", "Independent", "Unity"];
    const HISTORICAL_EVENTS = [
      "Great Fire of {year} destroyed downtown, rebuilt in Art Deco style.",
      "Founded as a trading post in {year} by European settlers.",
      "Hosted the National Games in {year}, boosting tourism.",
      "Tech boom in {year}s transformed the economy.",
      "Major flood in {year} led to new levee system.",
      "Renowned author {name} was born here in {year}.",
      "City declared carbon neutral in {year}.",
      "University established in {year}, becoming regional education hub."
    ];

    const ZONES = ['residential', 'commercial', 'industrial', 'government', 'medical', 'education', 'park', 'entertainment', 'transport'];
    const BUILDINGS = {
      'residential': ['Apartment', 'House', 'Condo', 'Townhouse'],
      'commercial': ['Shopping Mall', 'Restaurant', 'Cafe', 'Office Building', 'Bank', 'Hotel'],
      'industrial': ['Factory', 'Warehouse', 'Power Plant', 'Recycling Center'],
      'government': ['City Hall', 'Police Station', 'Fire Station', 'Courthouse', 'Post Office'],
      'medical': ['Hospital', 'Clinic', 'Pharmacy'],
      'education': ['Elementary School', 'High School', 'University', 'Library'],
      'park': ['Park', 'Botanical Garden', 'Zoo', 'Playground'],
      'entertainment': ['Cinema', 'Theater', 'Museum', 'Stadium', 'Arcade'],
      'transport': ['Bus Station', 'Train Station', 'Airport', 'Subway Entrance', 'Parking Garage']
    };

    // ======================
    // 工具函数
    // ======================
    function rand(arr) {
      return arr[Math.floor(Math.random() * arr.length)];
    }

    function randName() {
      const first = Math.random() > 0.5 ? rand(NAMES_MALE) : rand(NAMES_FEMALE);
      return first + " " + rand(SURNAMES);
    }

    function randFloat(min, max) {
      return parseFloat((Math.random() * (max - min) + min).toFixed(2));
    }

    function randInt(min, max) {
      return Math.floor(Math.random() * (max - min + 1)) + min;
    }

    // ======================
    // 城市生成主函数
    // ======================
    function generateCity() {
      const city = {};

      // 基础信息
      city.name = rand(CITY_PREFIXES) + " " + rand(CITY_SUFFIXES);
      city.country = rand(COUNTRIES);
      city.latitude = randFloat(-70, 70).toFixed(4);
      city.longitude = randFloat(-180, 180).toFixed(4);
      city.location = `${city.latitude}°N, ${city.longitude}°E`;
      city.terrain = rand(TERRAINS);
      city.climateObj = rand(CLIMATES);
      city.climate = city.climateObj.name;
      city.avgTemp = city.climateObj.temp;
      city.weather = rand(WEATHERS);
      city.population = randInt(20000, 2000000);
      city.area = randFloat(50, 1000);
      city.density = (city.population / city.area).toFixed(1);
      city.founded = randInt(1700, 1950);
      city.motto = rand(MOTTOES);
      city.nickname = rand(NICKNAMES);

      // 经济
      city.industry = rand(INDUSTRIES);
      city.gdpTotal = (city.population * randFloat(30000, 80000) / 1e8).toFixed(1); // 亿
      city.perCapitaGDP = randInt(35000, 90000);
      city.unemployment = (randFloat(3, 12)).toFixed(1) + "%";
      city.taxRate = (randFloat(8, 25)).toFixed(1) + "%";
      city.crimeRate = ["Low", "Moderate", "High"][randInt(0, 2)];

      // 政府
      city.mayor = randName();
      city.party = rand(PARTIES);
      city.term = `${randInt(2020, 2024)} - ${randInt(2024, 2028)}`;
      city.policeChief = randName();
      city.financeChief = randName();

      // 人口
      city.genderRatio = randInt(95, 105) + ":100";
      city.birthRate = randFloat(8, 16).toFixed(1) + "‰";
      city.deathRate = randFloat(6, 12).toFixed(1) + "‰";
      city.lifeExpectancy = randInt(75, 85) + " 岁";
      city.migration = ["Net Inflow", "Net Outflow", "Balanced"][randInt(0, 2)];
      city.education = ["High", "Medium", "Growing"][randInt(0, 2)];
      city.ageDist = `0-14: ${randInt(15, 20)}%, 15-24: ${randInt(10, 15)}%, 25-54: ${randInt(35, 45)}%, 55-64: ${randInt(8, 12)}%, 65+: ${randInt(12, 20)}%`;

      // 历史
      city.history = [];
      const usedYears = new Set();
      for (let i = 0; i < 3; i++) {
        let event = rand(HISTORICAL_EVENTS);
        let year = randInt(1800, 2023);
        while (usedYears.has(year)) year = randInt(1800, 2023);
        usedYears.add(year);
        event = event.replace("{year}", year);
        event = event.replace("{name}", randName());
        city.history.push(event);
      }

      // 地图生成
      city.map = [];
      const n = 8;
      const center = Math.floor(n / 2);
      for (let i = 0; i < n; i++) {
        city.map[i] = [];
        for (let j = 0; j < n; j++) {
          let zone;
          const dist = Math.abs(i - center) + Math.abs(j - center);
          if (dist <= 1) zone = 'commercial';
          else if (dist <= 3) zone = rand(['residential', 'residential', 'government']);
          else if (i === 0 || j === 0 || i === n-1 || j === n-1) zone = 'industrial';
          else zone = rand(ZONES);
          const buildings = BUILDINGS[zone] ? rand(BUILDINGS[zone]) : "None";
          city.map[i][j] = { zone, buildings };
        }
      }

      return city;
    }

    // ======================
    // 渲染函数
    // ======================
    function renderCity(city) {
      document.getElementById('cityName').textContent = city.name;
      document.getElementById('country').textContent = city.country;
      document.getElementById('location').textContent = city.location;
      document.getElementById('terrain').textContent = city.terrain;
      document.getElementById('climate').textContent = city.climate;
      document.getElementById('avgTemp').textContent = city.avgTemp;
      document.getElementById('weather').textContent = city.weather;
      document.getElementById('population').textContent = city.population.toLocaleString();
      document.getElementById('area').textContent = city.area.toFixed(1);
      document.getElementById('density').textContent = city.density;
      document.getElementById('founded').textContent = city.founded;
      document.getElementById('motto').textContent = `"${city.motto}"`;
      document.getElementById('nickname').textContent = city.nickname;

      document.getElementById('industry').textContent = city.industry;
      document.getElementById('gdp').textContent = city.gdpTotal;
      document.getElementById('perCapitaGDP').textContent = city.perCapitaGDP.toLocaleString();
      document.getElementById('unemployment').textContent = city.unemployment;
      document.getElementById('taxRate').textContent = city.taxRate;
      document.getElementById('crimeRate').textContent = city.crimeRate;

      document.getElementById('mayor').textContent = city.mayor;
      document.getElementById('party').textContent = city.party;
      document.getElementById('term').textContent = city.term;
      document.getElementById('policeChief').textContent = city.policeChief;
      document.getElementById('financeChief').textContent = city.financeChief;

      document.getElementById('genderRatio').textContent = city.genderRatio;
      document.getElementById('birthRate').textContent = city.birthRate;
      document.getElementById('deathRate').textContent = city.deathRate;
      document.getElementById('lifeExpectancy').textContent = city.lifeExpectancy;
      document.getElementById('migration').textContent = city.migration;
      document.getElementById('education').textContent = city.education;
      document.getElementById('ageDist').textContent = city.ageDist;

      const historyEl = document.getElementById('history');
      historyEl.innerHTML = '';
      city.history.forEach(h => {
        const p = document.createElement('p');
        p.textContent = "• " + h;
        p.style.margin = '6px 0';
        historyEl.appendChild(p);
      });

      // 渲染地图
      const mapEl = document.getElementById('city-map');
      mapEl.innerHTML = '';
      city.map.forEach((row, i) => {
        row.forEach((cell, j) => {
          const div = document.createElement('div');
          div.className = `map-cell ${cell.zone}`;
          const tooltip = document.createElement('div');
          tooltip.className = 'tooltip';
          tooltip.textContent = `${cell.buildings} (${cell.zone})`;
          div.appendChild(tooltip);
          mapEl.appendChild(div);
        });
      });
    }

    // ======================
    // 事件监听
    // ======================
    document.getElementById('generateBtn').addEventListener('click', function() {
      const loading = document.getElementById('loading');
      const output = document.getElementById('output');
      loading.style.display = 'block';
      output.style.display = 'none';

      // 模拟生成延迟(更真实)
      setTimeout(() => {
        const city = generateCity();
        renderCity(city);
        loading.style.display = 'none';
        output.style.display = 'block';
      }, 800);
    });

    // 初始化:首次生成
    window.onload = function() {
      document.getElementById('generateBtn').click();
    };
  </script>
</body>
</html>
        
编辑器加载中
预览
控制台