🔒 サンドボックス内で実行中 ⛶ 全画面で遊ぶ
HTML / CSS / JS
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PokeAPI ポケモンバトル & ボール選択</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
    <style>
        @import url('https://fonts.googleapis.com/css2?family=DotGothic16&display=swap');

        body {
            font-family: 'Helvetica Neue', Arial, "Hiragino Kaku Gothic ProN", "Hiragino Sans", Meiryo, sans-serif;
            background-color: #2c3e50;
            color: #333;
            overflow-x: hidden;
        }

        .pixel-font {
            font-family: 'DotGothic16', sans-serif;
        }

        .battle-screen {
            background: linear-gradient(to bottom, #87CEEB 0%, #87CEEB 60%, #90EE90 60%, #90EE90 100%);
            position: relative;
            height: 350px;
            border-radius: 8px;
            overflow: hidden;
            box-shadow: inset 0 0 50px rgba(0,0,0,0.2);
        }

        .pokemon-img {
            image-rendering: pixelated;
            transition: transform 0.3s ease, opacity 0.5s ease, filter 0.5s;
        }

        .evolving {
            animation: evolveEffect 2s infinite;
        }

        @keyframes evolveEffect {
            0% { filter: brightness(1) contrast(1); transform: scale(1); }
            50% { filter: brightness(5) contrast(0); transform: scale(1.1); }
            100% { filter: brightness(1) contrast(1); transform: scale(1); }
        }

        .hp-bar {
            height: 10px;
            transition: width 0.5s ease-in-out;
        }

        .shake {
            animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both;
        }

        @keyframes shake {
            10%, 90% { transform: translate3d(-1px, 0, 0); }
            20%, 80% { transform: translate3d(2px, 0, 0); }
            30%, 50%, 70% { transform: translate3d(-4px, 0, 0); }
            40%, 60% { transform: translate3d(4px, 0, 0); }
        }

        .attack-player {
            animation: attackPlayer 0.5s ease-in-out;
        }

        @keyframes attackPlayer {
            0% { transform: translateX(0); }
            50% { transform: translateX(30px) translateY(-20px); }
            100% { transform: translateX(0); }
        }

        .attack-enemy {
            animation: attackEnemy 0.5s ease-in-out;
        }

        @keyframes attackEnemy {
            0% { transform: translateX(0); }
            50% { transform: translateX(-30px) translateY(20px); }
            100% { transform: translateX(0); }
        }

        .throw-ball {
            position: absolute;
            bottom: 50px;
            left: 50px;
            z-index: 50;
            animation: throw 1s forwards cubic-bezier(0.25, 0.46, 0.45, 0.94);
        }

        @keyframes throw {
            0% { transform: translate(0, 0) rotate(0deg); opacity: 1; }
            50% { transform: translate(150px, -150px) rotate(360deg); }
            100% { transform: translate(250px, -80px) rotate(720deg); opacity: 0; }
        }

        .message-box {
            background-color: rgba(255, 255, 255, 0.9);
            border: 4px solid #333;
            min-height: 85px;
        }

        .controls-grid {
            display: grid;
            grid-template-columns: 1fr 1fr;
            gap: 8px;
        }

        .loader {
            border: 4px solid #f3f3f3;
            border-top: 4px solid #3498db;
            border-radius: 50%;
            width: 30px;
            height: 30px;
            animation: spin 2s linear infinite;
        }

        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }

        .collection-item {
            image-rendering: pixelated;
            background: #f8f9fa;
            border: 2px solid #ddd;
            transition: all 0.2s;
            cursor: pointer;
            position: relative;
        }
        .collection-item:hover {
            transform: scale(1.1);
            border-color: #3498db;
        }
        .collection-item.active {
            border-color: #e74c3c;
            background: #ffebee;
        }
        .evolve-ready::after {
            content: '▲';
            position: absolute;
            top: -5px;
            right: -5px;
            color: #f1c40f;
            font-size: 10px;
            text-shadow: 0 0 2px black;
            animation: bounce 1s infinite;
        }

        @keyframes bounce {
            0%, 100% { transform: translateY(0); }
            50% { transform: translateY(-3px); }
        }

        .starter-card {
            cursor: pointer;
            transition: all 0.2s;
            border: 3px solid transparent;
        }
        .starter-card:hover {
            transform: translateY(-5px);
            border-color: #3498db;
            background-color: #ebf8ff;
        }

        .ball-menu-btn {
            transition: all 0.2s;
        }
        .ball-menu-btn:hover {
            filter: brightness(1.1);
            transform: scale(1.02);
        }
    </style>
</head>
<body class="flex flex-col items-center justify-center min-h-screen p-4 bg-slate-800">

    <div id="game-container" class="max-w-md w-full bg-white rounded-xl shadow-2xl overflow-hidden border-4 border-gray-800">
        
        <!-- 相棒選択画面 -->
        <div id="starter-selection" class="p-6">
            <h2 class="text-xl font-bold text-center mb-4 pixel-font">さいしょの ポケモンを えらぼう!</h2>
            <div class="grid grid-cols-3 gap-3" id="starter-list"></div>
            <div id="selection-loader" class="mt-8 flex flex-col items-center">
                <div class="loader mb-2"></div>
                <p class="text-sm text-gray-500">博士が準備中...</p>
            </div>
        </div>

        <!-- バトル画面 -->
        <div id="battle-area" class="hidden">
            <div class="battle-screen p-4 flex flex-col justify-between">
                <div id="ball-layer"></div>

                <!-- 相手エリア -->
                <div class="flex justify-start items-start">
                    <div id="enemy-stats" class="bg-white/90 p-2 rounded-lg border-2 border-gray-700 w-52 shadow-md">
                        <div class="flex justify-between items-center mb-1">
                            <span id="enemy-name" class="font-bold text-sm">読み込み中...</span>
                            <span class="text-[10px] font-bold">Lv.50</span>
                        </div>
                        <div class="w-full bg-gray-300 rounded-full border border-gray-400">
                            <div id="enemy-hp-fill" class="hp-bar bg-green-500 rounded-full" style="width: 100%"></div>
                        </div>
                        <div class="text-right text-[10px] mt-1 font-bold" id="enemy-hp-text">0/0</div>
                    </div>
                    <div id="enemy-sprite-container" class="ml-auto">
                        <img id="enemy-img" src="" alt="Enemy" class="w-32 h-32 pokemon-img object-contain">
                    </div>
                </div>

                <!-- プレイヤーエリア -->
                <div class="flex justify-end items-end">
                    <div id="player-sprite-container" class="mr-auto">
                        <img id="player-img" src="" alt="Player" class="w-40 h-40 pokemon-img object-contain">
                    </div>
                    <div id="player-stats" class="bg-white/90 p-2 rounded-lg border-2 border-gray-700 w-52 shadow-md">
                        <div class="flex justify-between items-center mb-1">
                            <span id="player-name" class="font-bold text-sm">読み込み中...</span>
                            <span class="text-[10px] font-bold">Lv.50</span>
                        </div>
                        <div class="w-full bg-gray-300 rounded-full border border-gray-400">
                            <div id="player-hp-fill" class="hp-bar bg-green-500 rounded-full" style="width: 100%"></div>
                        </div>
                        <div class="text-right text-[10px] mt-1 font-bold" id="player-hp-text">0/0</div>
                    </div>
                </div>
            </div>

            <div id="log-container" class="message-box p-3 m-2 rounded-lg border-double border-4 flex flex-col justify-center">
                <p id="message-text" class="text-sm font-bold leading-relaxed pixel-font">ポケモンのデータを取得しています...</p>
                <div id="evolution-btn-container" class="hidden mt-2">
                    <button onclick="evolveActivePokemon()" class="w-full bg-yellow-500 hover:bg-yellow-600 text-white font-bold py-1 px-4 rounded shadow-md text-xs pixel-font animate-pulse">
                        おや!? 様子が おかしいぞ! (進化させる)
                    </button>
                </div>
            </div>

            <div id="controls" class="p-3 bg-gray-200 border-t-4 border-gray-800">
                <div id="action-controls">
                    <div class="controls-grid" id="move-buttons"></div>
                    <div class="mt-2 flex gap-2">
                        <button onclick="healPlayer()" class="flex-1 bg-green-600 hover:bg-green-700 text-white font-bold py-2 rounded shadow-md text-xs transition-colors">
                            きずぐすり
                        </button>
                        <button onclick="toggleBallMenu()" class="flex-1 bg-red-600 hover:bg-red-700 text-white font-bold py-2 rounded shadow-md text-xs transition-colors">
                            モンスターボール
                        </button>
                        <button id="next-battle-btn" onclick="startNewBattle()" class="bg-blue-600 hover:bg-blue-700 text-white font-bold py-2 px-3 rounded shadow-md text-xs transition-colors">
                            つぎのあいて
                        </button>
                    </div>
                </div>
                
                <!-- ボール選択メニュー -->
                <div id="ball-selection-menu" class="hidden">
                    <p class="text-[10px] font-bold text-gray-600 mb-2 px-1">どのボールをなげる?</p>
                    <div class="grid grid-cols-3 gap-2">
                        <button onclick="catchWithBall('common')" class="ball-menu-btn bg-white border-2 border-red-500 p-2 rounded flex flex-col items-center">
                            <span class="text-lg">⚾</span>
                            <span class="text-[9px] font-bold">通常</span>
                        </button>
                        <button onclick="catchWithBall('great')" class="ball-menu-btn bg-white border-2 border-blue-500 p-2 rounded flex flex-col items-center">
                            <span class="text-lg">🔵</span>
                            <span class="text-[9px] font-bold">スーパー</span>
                        </button>
                        <button onclick="catchWithBall('ultra')" class="ball-menu-btn bg-white border-2 border-yellow-500 p-2 rounded flex flex-col items-center">
                            <span class="text-lg">🟡</span>
                            <span class="text-[9px] font-bold">ハイパー</span>
                        </button>
                    </div>
                    <button onclick="toggleBallMenu()" class="w-full mt-2 text-[10px] font-bold text-gray-500 py-1 underline">キャンセル</button>
                </div>
            </div>
        </div>

        <!-- ローディング中 -->
        <div id="main-loader" class="p-8 hidden flex flex-col items-center justify-center">
            <div class="loader mb-4"></div>
            <p class="text-gray-600 font-bold">準備中...</p>
        </div>
    </div>

    <!-- 手持ちポケモン・コレクション -->
    <div class="max-w-md w-full mt-4 p-4 bg-white/10 rounded-xl backdrop-blur-sm border-2 border-white/20">
        <h3 class="text-white font-bold text-sm mb-2 flex items-center justify-between">
            <span><i class="fas fa-briefcase mr-2"></i> 手持ち・コレクション</span>
            <span class="text-[10px] opacity-80">2回勝つと進化できるかも?</span>
        </h3>
        <div id="collection-list" class="flex flex-wrap gap-2 min-h-[50px]"></div>
    </div>

    <script>
        const API_URL = "https://pokeapi.co/api/v2/pokemon/";
        const SPECIES_URL = "https://pokeapi.co/api/v2/pokemon-species/";
        const MAX_POKEMON = 1010;
        const EVOLVE_THRESHOLD = 2;

        let activePartnerId = null; 
        let player = null;
        let enemy = null;
        let isProcessing = false;
        let capturedPokemons = []; 
        
        const ballData = {
            common: { name: "モンスターボール", rate: 1.0, icon: "⚾" },
            great: { name: "スーパーボール", rate: 1.5, icon: "🔵" },
            ultra: { name: "ハイパーボール", rate: 2.0, icon: "🟡" }
        };

        const typeChart = {
            fire: { water: 0.5, grass: 2.0, fire: 0.5, ice: 2.0, bug: 2.0, steel: 2.0, rock: 0.5 },
            water: { fire: 2.0, grass: 0.5, water: 0.5, ground: 2.0, rock: 2.0 },
            grass: { water: 2.0, fire: 0.5, grass: 0.5, ground: 2.0, rock: 2.0, poison: 0.5, flying: 0.5, bug: 0.5, steel: 0.5 },
            electric: { water: 2.0, grass: 0.5, electric: 0.5, flying: 2.0, ground: 0 },
            normal: { rock: 0.5, ghost: 0, steel: 0.5 },
            dark: { psychic: 2.0, ghost: 2.0, dark: 0.5, fairy: 0.5, fighting: 0.5 },
            ghost: { ghost: 2.0, psychic: 2.0, normal: 0, dark: 0.5 }
        };

        function getJapaneseName(names) {
            const ja = names.find(n => n.language.name === 'ja-Hrkt' || n.language.name === 'ja');
            return ja ? ja.name : names[0].name;
        }

        async function fetchPokemon(id) {
            const [pokeRes, speciesRes] = await Promise.all([
                fetch(`${API_URL}${id}`),
                fetch(`${SPECIES_URL}${id}`)
            ]);
            
            const data = await pokeRes.json();
            const speciesData = await speciesRes.json();
            const japaneseName = getJapaneseName(speciesData.names);
            
            const moves = await Promise.all(
                data.moves.slice(0, 4).map(async (m) => {
                    const moveRes = await fetch(m.move.url);
                    const moveData = await moveRes.json();
                    return {
                        name: getJapaneseName(moveData.names),
                        power: moveData.power || 40,
                        type: moveData.type.name
                    };
                })
            );

            const gen5Sprite = data.sprites.versions['generation-v']['black-white']?.animated;
            const frontSprite = gen5Sprite?.front_default || data.sprites.front_default;
            const backSprite = gen5Sprite?.back_default || data.sprites.back_default;

            return {
                id: data.id,
                name: japaneseName,
                hp: data.stats[0].base_stat * 2,
                maxHp: data.stats[0].base_stat * 2,
                attack: data.stats[1].base_stat,
                defense: data.stats[2].base_stat,
                sprite: frontSprite,
                backSprite: backSprite,
                staticSprite: data.sprites.front_default,
                moves: moves,
                types: data.types.map(t => t.type.name),
                speciesUrl: data.species.url,
                wins: 0,
                evolved: false
            };
        }

        async function initStarterSelection() {
            const starters = [1, 4, 7, 810, 813, 816];
            const starterList = document.getElementById('starter-list');
            
            for (const id of starters) {
                try {
                    const pokemon = await fetchPokemon(id);
                    const card = document.createElement('div');
                    card.className = 'starter-card bg-white p-2 rounded-lg text-center shadow-sm border-gray-100 border';
                    card.onclick = () => selectPartner(pokemon);
                    card.innerHTML = `
                        <img src="${pokemon.staticSprite}" class="w-16 h-16 object-contain mx-auto">
                        <p class="text-[10px] font-bold mt-1">${pokemon.name}</p>
                    `;
                    starterList.appendChild(card);
                } catch (e) { console.error(e); }
            }
            document.getElementById('selection-loader').classList.add('hidden');
        }

        async function selectPartner(pokemon) {
            addCollection(pokemon);
            switchActivePokemon(pokemon.id);
            document.getElementById('starter-selection').classList.add('hidden');
            document.getElementById('battle-area').classList.remove('hidden');
            startNewBattle();
        }

        function switchActivePokemon(id) {
            const target = capturedPokemons.find(p => p.id === id);
            if (!target) return;
            
            activePartnerId = id;
            player = JSON.parse(JSON.stringify(target)); 
            
            updateUI();
            renderMoves();
            renderCollection();
            updateMessage(`${player.name} に 入れ替えた!`);
            checkEvolutionAvailability();
        }

        async function startNewBattle() {
            if (isProcessing) return;
            isProcessing = true;
            
            document.getElementById('evolution-btn-container').classList.add('hidden');
            document.getElementById('ball-selection-menu').classList.add('hidden');
            document.getElementById('action-controls').classList.remove('hidden');
            document.getElementById('main-loader').classList.remove('hidden');
            document.getElementById('controls').classList.add('hidden');
            document.getElementById('player-img').style.opacity = '1';
            document.getElementById('enemy-img').style.opacity = '1';

            try {
                const currentPartner = capturedPokemons.find(p => p.id === activePartnerId);
                player = JSON.parse(JSON.stringify(currentPartner));
                
                const enemyID = Math.floor(Math.random() * MAX_POKEMON) + 1;
                enemy = await fetchPokemon(enemyID);

                updateUI();
                renderMoves();

                document.getElementById('main-loader').classList.add('hidden');
                document.getElementById('controls').classList.remove('hidden');
                updateMessage(`あ! 野生の ${enemy.name} が とびだしてきた!`);
                isProcessing = false;
            } catch (error) {
                console.error(error);
                isProcessing = false;
                startNewBattle();
            }
        }

        function updateUI() {
            if (!player || !enemy) return;
            document.getElementById('player-name').innerText = player.name;
            document.getElementById('player-img').src = player.backSprite;
            updateHPBar('player', player.hp, player.maxHp);

            document.getElementById('enemy-name').innerText = enemy.name;
            document.getElementById('enemy-img').src = enemy.sprite;
            updateHPBar('enemy', enemy.hp, enemy.maxHp);
        }

        function updateHPBar(who, current, max) {
            const percent = Math.max(0, (current / max) * 100);
            const bar = document.getElementById(`${who}-hp-fill`);
            const text = document.getElementById(`${who}-hp-text`);
            bar.style.width = `${percent}%`;
            text.innerText = `${Math.ceil(current)} / ${max}`;
            if (percent < 20) bar.className = 'hp-bar bg-red-500 rounded-full';
            else if (percent < 50) bar.className = 'hp-bar bg-yellow-500 rounded-full';
            else bar.className = 'hp-bar bg-green-500 rounded-full';
        }

        function renderMoves() {
            const container = document.getElementById('move-buttons');
            container.innerHTML = '';
            player.moves.forEach(move => {
                const btn = document.createElement('button');
                btn.className = 'bg-white hover:bg-gray-100 text-gray-800 border-2 border-gray-400 font-bold py-2 rounded text-[11px] shadow-sm transition-all active:translate-y-1';
                btn.innerText = move.name;
                btn.onclick = () => handleAttack(move);
                container.appendChild(btn);
            });
        }

        function updateMessage(text) {
            document.getElementById('message-text').innerText = text;
        }

        async function performMove(attacker, defender, move, role) {
            updateMessage(`${attacker.name} の ${move.name}!`);
            const attackerImg = document.getElementById(`${role}-img`);
            const defenderImg = document.getElementById(`${role === 'player' ? 'enemy' : 'player'}-img`);
            
            attackerImg.classList.add(role === 'player' ? 'attack-player' : 'attack-enemy');
            await new Promise(r => setTimeout(r, 500));
            attackerImg.classList.remove(role === 'player' ? 'attack-player' : 'attack-enemy');

            let multiplier = 1;
            defender.types.forEach(defType => {
                if (typeChart[move.type] && typeChart[move.type][defType] !== undefined) multiplier *= typeChart[move.type][defType];
            });

            const isCritical = Math.random() < 0.0625;
            let damage = (((2 * 50 / 5 + 2) * move.power * (attacker.attack / defender.defense)) / 50) + 2;
            damage *= multiplier;
            if (isCritical) damage *= 1.5;
            damage = Math.floor(damage * (Math.random() * 0.15 + 0.85));

            defender.hp = Math.max(0, defender.hp - damage);
            defenderImg.classList.add('shake');
            updateHPBar(role === 'player' ? 'enemy' : 'player', defender.hp, defender.maxHp);
            await new Promise(r => setTimeout(r, 400));
            defenderImg.classList.remove('shake');

            if (isCritical) { updateMessage("急所に あたった!"); await new Promise(r => setTimeout(r, 800)); }
            if (multiplier > 1) { updateMessage("効果は バツグンだ!"); await new Promise(r => setTimeout(r, 800)); }
            else if (multiplier > 0 && multiplier < 1) { updateMessage("効果は いまひとつの ようだ..."); await new Promise(r => setTimeout(r, 800)); }
        }

        async function handleAttack(move) {
            if (isProcessing || player.hp <= 0 || enemy.hp <= 0) return;
            isProcessing = true;
            await performMove(player, enemy, move, 'player');
            if (enemy.hp <= 0) {
                updateMessage(`相手の ${enemy.name} は たおれた!`);
                recordWin();
                triggerVictory();
                return;
            }
            await enemyTurn();
        }

        async function enemyTurn() {
            await new Promise(r => setTimeout(r, 1000));
            if (enemy.hp <= 0) return;
            const enemyMove = enemy.moves[Math.floor(Math.random() * enemy.moves.length)];
            await performMove(enemy, player, enemyMove, 'enemy');
            if (player.hp <= 0) {
                updateMessage(`${player.name} は たおれてしまった...`);
                triggerGameOver();
                return;
            }
            isProcessing = false;
        }

        function toggleBallMenu() {
            if (isProcessing || player.hp <= 0 || enemy.hp <= 0) return;
            const action = document.getElementById('action-controls');
            const menu = document.getElementById('ball-selection-menu');
            if (menu.classList.contains('hidden')) {
                action.classList.add('hidden');
                menu.classList.remove('hidden');
            } else {
                action.classList.remove('hidden');
                menu.classList.add('hidden');
            }
        }

        async function catchWithBall(ballType) {
            toggleBallMenu();
            if (isProcessing) return;
            isProcessing = true;

            const selectedBall = ballData[ballType];
            updateMessage(`${player.name} は ${selectedBall.name} を なげた!`);
            
            const ball = document.createElement('div');
            ball.className = 'throw-ball text-2xl';
            ball.innerHTML = selectedBall.icon;
            document.getElementById('ball-layer').appendChild(ball);
            
            await new Promise(r => setTimeout(r, 1000));
            ball.remove();

            const hpRatio = enemy.hp / enemy.maxHp;
            // ボールの種類によって捕獲率を調整 (通常よりハイパーの方が捕まえやすい)
            const catchProbability = (0.2 + (0.7 * (1 - hpRatio))) * selectedBall.rate;
            const isSuccess = Math.random() < catchProbability;

            if (isSuccess) {
                document.getElementById('enemy-img').style.opacity = '0';
                updateMessage(`やったー! ${enemy.name} を つかまえたぞ!`);
                recordWin(); 
                addCollection(enemy);
                showReset();
            } else {
                updateMessage(`だめだ! ${enemy.name} は ボールから ぬけだした!`);
                await enemyTurn();
            }
        }

        function recordWin() {
            const p = capturedPokemons.find(p => p.id === activePartnerId);
            if (p) {
                p.wins++;
                renderCollection();
                checkEvolutionAvailability();
            }
        }

        async function checkEvolutionAvailability() {
            const p = capturedPokemons.find(p => p.id === activePartnerId);
            if (p && p.wins >= EVOLVE_THRESHOLD) {
                const nextEvoId = await getNextEvolutionId(p.speciesUrl, p.id);
                if (nextEvoId) {
                    p.nextEvoId = nextEvoId;
                    document.getElementById('evolution-btn-container').classList.remove('hidden');
                }
            }
        }

        async function getNextEvolutionId(speciesUrl, currentId) {
            try {
                const speciesRes = await fetch(speciesUrl);
                const speciesData = await speciesRes.json();
                const evoRes = await fetch(speciesData.evolution_chain.url);
                const evoData = await evoRes.json();
                
                let current = evoData.chain;
                
                const findInChain = (node, id) => {
                    const nodeUrlParts = node.species.url.split('/');
                    const nodeId = parseInt(nodeUrlParts[nodeUrlParts.length - 2]);
                    
                    if (nodeId === id) return node;
                    for (let next of node.evolves_to) {
                        const found = findInChain(next, id);
                        if (found) return found;
                    }
                    return null;
                };

                const currentNode = findInChain(current, currentId);
                if (currentNode && currentNode.evolves_to.length > 0) {
                    const nextUrlParts = currentNode.evolves_to[0].species.url.split('/');
                    return parseInt(nextUrlParts[nextUrlParts.length - 2]);
                }
                return null;
            } catch (e) {
                console.error("Evolution check failed:", e);
                return null;
            }
        }

        async function evolveActivePokemon() {
            if (isProcessing) return;
            isProcessing = true;
            
            const p = capturedPokemons.find(p => p.id === activePartnerId);
            if (!p || !p.nextEvoId) return;

            document.getElementById('evolution-btn-container').classList.add('hidden');
            document.getElementById('controls').classList.add('hidden');
            updateMessage(`${p.name} の 様子が......!`);
            
            const playerImg = document.getElementById('player-img');
            playerImg.classList.add('evolving');
            
            await new Promise(r => setTimeout(r, 2500));
            
            const newPokemon = await fetchPokemon(p.nextEvoId);
            newPokemon.wins = 0; 
            
            const index = capturedPokemons.findIndex(x => x.id === p.id);
            capturedPokemons[index] = newPokemon;
            activePartnerId = newPokemon.id;
            player = JSON.parse(JSON.stringify(newPokemon));
            
            playerImg.classList.remove('evolving');
            updateUI();
            renderMoves();
            renderCollection();
            
            updateMessage(`おめでとう! ${p.name} は ${newPokemon.name} に 進化した!`);
            
            await new Promise(r => setTimeout(r, 2000));
            document.getElementById('controls').classList.remove('hidden');
            isProcessing = false;
        }

        function addCollection(pokemon) {
            if (capturedPokemons.some(p => p.id === pokemon.id)) return;
            capturedPokemons.push(pokemon);
            renderCollection();
        }

        function renderCollection() {
            const list = document.getElementById('collection-list');
            list.innerHTML = '';
            capturedPokemons.forEach(p => {
                const item = document.createElement('div');
                const isActive = p.id === activePartnerId;
                const canEvolve = p.wins >= EVOLVE_THRESHOLD;
                item.className = `collection-item w-12 h-12 rounded-lg flex items-center justify-center p-1 border-2 ${isActive ? 'active' : 'border-gray-200'} ${canEvolve ? 'evolve-ready' : ''}`;
                item.onclick = () => {
                    if (isProcessing && player.hp > 0 && enemy.hp > 0) {
                        updateMessage("バトル中は入れ替えられません!");
                        return;
                    }
                    switchActivePokemon(p.id);
                };
                item.innerHTML = `<img src="${p.staticSprite}" class="w-full h-full object-contain" title="${p.name} (勝利数: ${p.wins})">`;
                list.appendChild(item);
            });
        }

        async function healPlayer() {
            if (isProcessing || player.hp <= 0) return;
            isProcessing = true;
            player.hp = Math.min(player.maxHp, player.hp + Math.floor(player.maxHp * 0.4));
            updateMessage(`${player.name} は きずぐすりを つかった!`);
            updateHPBar('player', player.hp, player.maxHp);
            await enemyTurn();
        }

        function triggerVictory() { document.getElementById('enemy-img').style.opacity = '0'; showReset(); }
        function triggerGameOver() { document.getElementById('player-img').style.opacity = '0'; showReset(); }
        
        function showReset() {
            document.getElementById('move-buttons').innerHTML = `
                <button onclick="startNewBattle()" class="col-span-2 bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 rounded text-xs shadow-lg">
                    別のポケモンを探す
                </button>`;
            isProcessing = false;
        }

        window.onload = initStarterSelection;
    </script>
</body>
</html>

バトル

by o-yuto

ポケモンの作品

🤖 使用したAI
Gemini
👁 32 回閲覧
📅 投稿:2026年4月18日 🔄 更新:2026年8月13日
応援スタンプを押してみよう!