Newer
Older
2025-shino / fog.js
(() => {
  'use strict';

  document.addEventListener("DOMContentLoaded", () => {

    const START_POS = [38.891, 139.824];
    const REVEAL_RADIUS = 40; // メートル
    const GRID_SIZE = 0.0005; // 霧管理用グリッド

    let map;
    let playerMarker;
    let fogLayer;

    // 探索済みグリッド管理
    const revealedCells = new Set();
    const holes = [];

    function initMap() {
      map = L.map("locationmap").setView(START_POS, 16);

      L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", {
        attribution: '© OpenStreetMap contributors'
      }).addTo(map);

      playerMarker = L.marker(START_POS).addTo(map);

      createFog();

      map.on("click", (e) => {
        updateLocation(e.latlng);
      });
    }

    /** ===== 霧を1回だけ作成 ===== */
    function createFog() {
      const world = [
        [-90, -180],
        [-90, 180],
        [90, 180],
        [90, -180]
      ];

      fogLayer = L.polygon([world], {
        color: "#000",
        fillColor: "#000",
        fillOpacity: 0.6,
        stroke: false
      }).addTo(map);
    }

    /** ===== 位置更新 ===== */
    function updateLocation(latlng) {
      playerMarker.setLatLng(latlng);
      revealFog(latlng);
    }

    /** ===== 霧解除(チカチカしない核心部分) ===== */
    function revealFog(latlng) {
      const key = gridKey(latlng);

      // すでに解除済みなら何もしない
      if (revealedCells.has(key)) return;

      revealedCells.add(key);

      const hole = createCircle(latlng, REVEAL_RADIUS);
      holes.push(hole);

      // 🔑 ポリゴンは作り直さず、穴だけ更新
      fogLayer.setLatLngs([
        fogLayer.getLatLngs()[0], // 外枠
        ...holes
      ]);
    }

    /** ===== グリッド判定 ===== */
    function gridKey(latlng) {
      const x = Math.floor(latlng.lat / GRID_SIZE);
      const y = Math.floor(latlng.lng / GRID_SIZE);
      return `${x}_${y}`;
    }

    /** ===== 円形穴生成 ===== */
    function createCircle(center, radius) {
      const points = [];
      const steps = 24;

      for (let i = 0; i < steps; i++) {
        const angle = (i / steps) * Math.PI * 2;
        const dx = (radius * Math.cos(angle)) / 111320;
        const dy = (radius * Math.sin(angle)) /
          (111320 * Math.cos(center.lat * Math.PI / 180));

        points.push([
          center.lat + dy,
          center.lng + dx
        ]);
      }
      return points;
    }

    initMap();
  });
})();