(() => {
'use strict';
document.addEventListener("DOMContentLoaded", () => {
const START_POS = [38.891, 139.824];
const CAPTURE_DISTANCE = 30;
const NEAR_DISTANCE = 100;
const CAPTURE_RATE = 0.7;
const titleEl = document.getElementById("title");
const startBtn = document.getElementById("start");
const stopBtn = document.getElementById("stop");
const captureBtn = document.getElementById("capture");
let map;
let playerMarker;
let monsterMarker = null;
let monsterLatLng = null;
let watchId = null;
let nTrial = 100;
let canCapture = false;
function initMap() {
map = L.map("locationmap", { tap: true })
.setView(START_POS, 16);
L.tileLayer("https://{s}.tile.osm.org/{z}/{x}/{y}.png", {
attribution:
'© <a href="http://osm.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
playerMarker = L.marker(map.getCenter()).addTo(map);
playerMarker.bindPopup("STARTを押して探索開始").openPopup();
map.on("click", (e) => {
updateLocation(e.latlng);
});
}
function spawnMonster(center) {
const offsetLat = (Math.random() - 0.5) * 0.002;
const offsetLng = (Math.random() - 0.5) * 0.002;
monsterLatLng = L.latLng(
center.lat + offsetLat,
center.lng + offsetLng
);
if (monsterMarker) {
map.removeLayer(monsterMarker);
}
monsterMarker = L.marker(monsterLatLng, {
title: "なにかの気配"
}).addTo(map);
}
function updateLocation(latlng) {
map.panTo(latlng);
playerMarker.setLatLng(latlng);
if (!monsterLatLng) {
spawnMonster(latlng);
}
const distance = map.distance(latlng, monsterLatLng);
let message = "探索中…";
if (distance < CAPTURE_DISTANCE) {
message = "🎯 モンスターが近い!捕獲できる!";
canCapture = true;
captureBtn.disabled = false;
} else if (distance < NEAR_DISTANCE) {
message = "👀 気配が近い…";
canCapture = false;
captureBtn.disabled = true;
} else {
canCapture = false;
captureBtn.disabled = true;
}
playerMarker.setPopupContent(message).openPopup();
}
function captureMonster() {
if (!canCapture || !monsterLatLng) return;
const success = Math.random() < CAPTURE_RATE;
playerMarker.setPopupContent(
success ? "🎉 捕獲成功!" : "💨 逃げられた…"
).openPopup();
if (monsterMarker) {
map.removeLayer(monsterMarker);
}
monsterMarker = null;
monsterLatLng = null;
canCapture = false;
captureBtn.disabled = true;
}
function onSuccess(pos) {
updateLocation(
L.latLng(pos.coords.latitude, pos.coords.longitude)
);
}
function onError() {
nTrial--;
playerMarker
.setPopupContent(`捕捉失敗… 残り ${nTrial} 回`)
.openPopup();
if (nTrial <= 0 && watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
titleEl.textContent = "ERROR";
}
}
function startWatch() {
stopWatch();
watchId = navigator.geolocation.watchPosition(
onSuccess,
onError,
{ maximumAge: 0, timeout: 3000, enableHighAccuracy: true }
);
titleEl.textContent = "探索中";
}
function stopWatch() {
if (watchId !== null) {
navigator.geolocation.clearWatch(watchId);
watchId = null;
titleEl.textContent = "STOP";
playerMarker.setPopupContent("探索を停止しました").openPopup();
}
}
startBtn.addEventListener("click", startWatch);
stopBtn.addEventListener("click", stopWatch);
captureBtn.addEventListener("click", captureMonster);
initMap();
});
})();