見出し画像

Rikurikuはゲームを作りたい①


僕、GEOMETRY DASHに最近ハマってて、それを作ろうと思ったんですね。(??)


なので、AIにコードを書かせて、それっぽいのを作りました。

<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>OG Circle Movement</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            overflow: hidden;
            background-color: #87CEEB;
            /* スカイブルー */
            user-select: none;
        }

        #player {
            width: 50px;
            height: 50px;
            position: absolute;
            left: 100px;
            perspective: 600px;
            /* 3D効果 */
        }

        /* 尾 (雫形 90度反時計回り -> 左向き) */
        #player::before {
            content: '';
            position: absolute;
            top: 50%;
            left: -20px;
            width: 40px;
            height: 40px;
            background: linear-gradient(135deg, #e040fb, transparent);
            /* Purple */
            border-radius: 0 50% 50% 50%;
            /* 左上が尖る */
            transform: translateY(-50%) rotate(-45deg);
            /* 左向きに */
            z-index: -1;
            opacity: 0.8;
            filter: blur(2px);
        }

        .tetra {
            position: absolute;
            top: 50%;
            left: 50%;
            width: 0;
            height: 0;
            transform-style: preserve-3d;
            animation: spin 3s linear infinite;
            /* オーラ: drop-shadowで発光表現 */
            filter: drop-shadow(0 0 8px #d500f9) drop-shadow(0 0 15px #aa00ff);
        }

        @keyframes spin {
            0% {
                transform: rotateX(0deg) rotateY(0deg) rotateZ(0deg);
            }

            100% {
                transform: rotateX(360deg) rotateY(360deg) rotateZ(360deg);
            }
        }

        .face {
            position: absolute;
            width: 50px;
            height: 43.3px;
            /* 50 * sqrt(3) / 2 */
            background-color: #aa00ff;
            /* Purple Base */
            opacity: 0.9;
            clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
            /* 重心基準で回転 */
            transform-origin: 50% 66.67%;
            top: -28.87px;
            /* 43.3 * 2/3 = 28.86... */
            left: -25px;
        }

        .face::after {
            content: '';
            position: absolute;
            inset: 0;
            background: linear-gradient(to bottom, rgba(255, 255, 255, 0.4), transparent);
        }

        /* 
           正四面体ジオメトリ: 
           r = 10.2px
           rotateX(19.47deg) (Positive for gapless)
        */
        .face:nth-child(1) {
            transform: rotateY(0deg) rotateX(19.47deg) translateZ(10.2px);
            background-color: #d500f9;
            /* Purple Accent 1 */
        }

        .face:nth-child(2) {
            transform: rotateY(120deg) rotateX(19.47deg) translateZ(10.2px);
            background-color: #e040fb;
            /* Purple Accent 2 */
        }

        .face:nth-child(3) {
            transform: rotateY(240deg) rotateX(19.47deg) translateZ(10.2px);
            background-color: #ea80fc;
            /* Purple Accent 3 */
        }

        .face:nth-child(4) {
            transform: rotateX(90deg) translateZ(10.2px);
            background-color: #4a148c;
            /* Dark Purple */
        }
    </style>
</head>

<body>

    <div id="player">
        <div class="tetra">
            <div class="face"></div>
            <div class="face"></div>
            <div class="face"></div>
            <div class="face"></div>
        </div>
    </div>

    <script>
        const player = document.getElementById('player');

        // 設定
        const speed = 8; // 移動速度
        const radius = 25; // 半径
        const obstacleWidth = 30;
        let obstacleSpeed = 5; // 時間とともに速くする

        // 状態
        let isMovingUp = false;
        let y = window.innerHeight - (radius * 2);
        let frameCount = 0;
        let isGameOver = false;
        const obstacles = [];

        // マウス・タッチイベント
        const startMovingUp = () => { isMovingUp = true; };
        const stopMovingUp = () => { isMovingUp = false; };

        window.addEventListener('mousedown', startMovingUp);
        window.addEventListener('mouseup', stopMovingUp);
        window.addEventListener('touchstart', (e) => { e.preventDefault(); startMovingUp(); }, { passive: false });
        window.addEventListener('touchend', stopMovingUp);

        function createObstacle() {
            // タイプ決定 (0: 通常壁, 1: 浮遊ブロック, 2: 動く壁)
            const type = Math.floor(Math.random() * 3);

            const obstacle = document.createElement('div');
            obstacle.style.position = 'absolute';
            obstacle.style.backgroundColor = '#ff5722';
            obstacle.style.width = obstacleWidth + 'px';
            obstacle.style.left = window.innerWidth + 'px';

            let height, isTop, yPos;
            const moveData = { type: type, dir: 1, speed: 2 }; // 移動用

            if (type === 0) {
                // 通常壁
                height = Math.random() * (window.innerHeight - 250) + 50;
                isTop = Math.random() > 0.5;
                yPos = isTop ? 0 : window.innerHeight - height;
                obstacle.style.height = height + 'px';
                obstacle.style.top = yPos + 'px';
            } else if (type === 1) {
                // 浮遊ブロック
                height = Math.random() * 100 + 50;
                yPos = Math.random() * (window.innerHeight - 100 - height) + 50;
                obstacle.style.height = height + 'px';
                obstacle.style.top = yPos + 'px';
            } else if (type === 2) {
                // 動く壁
                height = Math.random() * 150 + 100;
                yPos = Math.random() * (window.innerHeight - height);
                obstacle.style.height = height + 'px';
                obstacle.style.top = yPos + 'px';
                obstacle.style.backgroundColor = '#ff1744';
            }

            document.body.appendChild(obstacle);

            obstacles.push({
                element: obstacle,
                x: window.innerWidth,
                width: obstacleWidth,
                height: height,
                y: yPos,
                moveData: moveData
            });
        }

        function update() {
            if (isGameOver) return;

            // プレイヤー移動
            if (isMovingUp) {
                y -= speed;
            } else {
                y += speed;
            }

            // 境界チェック
            const maxTop = 0;
            const maxBottom = window.innerHeight - (radius * 2);

            if (y < maxTop) {
                y = maxTop;
            } else if (y > maxBottom) {
                y = maxBottom;
            }

            player.style.top = y + 'px';

            // 障害物管理
            frameCount++;
            // 時間経過で加速 (300フレーム=約5秒ごとに+0.2)
            if (frameCount % 300 === 0) {
                obstacleSpeed += 0.2;
            }

            if (frameCount % 100 === 0) {
                createObstacle();
            }

            // 障害物移動と衝突判定
            for (let i = obstacles.length - 1; i >= 0; i--) {
                const obs = obstacles[i];
                obs.x -= obstacleSpeed;

                // 動く壁の処理
                if (obs.moveData && obs.moveData.type === 2) {
                    obs.y += obs.moveData.speed * obs.moveData.dir;
                    if (obs.y <= 0 || obs.y + obs.height >= window.innerHeight) {
                        obs.moveData.dir *= -1;
                    }
                    obs.element.style.top = obs.y + 'px';
                }

                obs.element.style.left = obs.x + 'px';

                // 出たら削除
                if (obs.x + obs.width < 0) {
                    obs.element.remove();
                    obstacles.splice(i, 1);
                    continue;
                }

                // 衝突判定 (簡易矩形)
                // プレイヤーの当たり判定を少し小さくして遊びやすくする
                // 正四面体は50x50だが、見た目は中心寄りなので、40x40くらいで判定
                const playerRect = {
                    x: 100 + 5,
                    y: y + 5,
                    width: 40,
                    height: 40
                };

                if (
                    playerRect.x < obs.x + obs.width &&
                    playerRect.x + playerRect.width > obs.x &&
                    playerRect.y < obs.y + obs.height &&
                    playerRect.y + playerRect.height > obs.y
                ) {
                    gameOver();
                }
            }

            requestAnimationFrame(update);
        }

        function gameOver() {
            isGameOver = true;
            alert('GAME OVER');
            location.reload();
        }

        // 初期化
        update();

        window.addEventListener('resize', () => {
            // リサイズ対応(今回は省略)
        });

    </script>
</body>

</html>

ただ、ちゃんと機能するか分からないんですけどね。

とりあえず今回は、障害物をランダムに設定しました。




いいなと思ったら応援しよう!

Rikuriku|フォロバ100 ⚠️警告⚠️ もしあなたがチップをくれたら、その分あなたのお金が減ります(?)。お金は大切に。