상세 컨텐츠

본문 제목

달토끼 점프 게임 실습교안

Keep Up WIth AI Revolution

by 달의 언어 2024. 6. 25. 17:57

본문

KakaoTalk_20240623_092457198

달토끼 점프 게임 실습교안

소개

이 실습에서는 HTML, CSS, JavaScript를 이용하여 간단한 달토끼 점프 게임을 만들어 보겠습니다. 초등학생들이 직접 따라할 수 있도록 단계별로 안내합니다.

준비물

  • 인터넷이 연결된 컴퓨터
  • 텍스트 에디터 (예: Visual Studio Code, Sublime Text 등)

실습 단계

1단계: HTML 구조 작성

먼저 HTML 파일을 생성하고, 게임에 필요한 기본 구조를 작성합니다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>달토끼 점프 게임</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            font-family: Arial, sans-serif;
        }
        #gameCanvas {
            background-color: #000033; /* 밤하늘을 표현하기 위한 진한 파란색 */
        }
        #gameStats {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-size: 20px;
        }
        #startScreen, #gameOverScreen {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            color: white;
            font-size: 24px;
            background-color: rgba(0, 0, 0, 0.7);
            padding: 20px;
            border-radius: 10px;
        }
        button {
            font-size: 20px;
            padding: 10px 20px;
            margin-top: 20px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div id="gameStats">점수: <span id="score">0</span></div>
    <div id="startScreen">
        <h1>달토끼 점프 게임</h1>
        <p>장애물을 넘고 별을 모으세요!</p>
        <button id="startButton">게임 시작</button>
    </div>
    <div id="gameOverScreen" style="display: none;">
        <h1>게임 오버</h1>
        <p>당신의 점수: <span id="finalScore"></span></p>
        <button id="restartButton">다시 시작</button>
    </div>
</body>
</html>

2단계: 게임 로직 구현

게임의 핵심 로직을 JavaScript로 작성합니다.

<script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const scoreElement = document.getElementById('score');
    const startScreen = document.getElementById('startScreen');
    const gameOverScreen = document.getElementById('gameOverScreen');
    const startButton = document.getElementById('startButton');
    const restartButton = document.getElementById('restartButton');
    const finalScoreElement = document.getElementById('finalScore');

    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    let score = 0;
    let gameState = 'start'; // 'start', 'playing', 'gameOver'

    // SVG 이미지 정의
    const bunnySvg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80">
        <style>rect { stroke: #000; stroke-width: 0.5; }</style>
        <rect x="30" y="30" width="20" height="30" fill="#FFF"/>
        <rect x="30" y="10" width="20" height="20" fill="#FFF"/>
        <rect x="25" y="5" width="10" height="15" fill="#FFF"/>
        <rect x="45" y="5" width="10" height="15" fill="#FFF"/>
        <rect x="35" y="15" width="5" height="5" fill="#000"/>
        <rect x="45" y="15" width="5" height="5" fill="#000"/>
        <rect x="40" y="25" width="5" height="5" fill="#FFC0CB"/>
        <rect x="25" y="55" width="10" height="5" fill="#FFF"/>
        <rect x="45" y="55" width="10" height="5" fill="#FFF"/>
    </svg>`;

    const shellSvg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 40">
        <style>rect { stroke: #000; stroke-width: 0.2; }</style>
        <g transform="translate(0,0)">
            <rect x="2" y="18" width="4" height="4" fill="#FFA07A"/>
            <rect x="6" y="14" width="4" height="8" fill="#FFA07A"/>
            <rect x="10" y="10" width="4" height="12" fill="#FFA07A"/>
            <rect x="14" y="6" width="4" height="16" fill="#FFA07A"/>
            <rect x="18" y="10" width="4" height="12" fill="#FFA07A"/>
            <rect x="22" y="14" width="4" height="8" fill="#FFA07A"/>
            <rect x="26" y="18" width="4" height="4" fill="#FFA07A"/>
            <rect x="18" y="22" width="8" height="4" fill="#FF8C69"/>
        </g>
    </svg>`;

    const cloudSvg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 80">
        <style>rect { stroke: #E6E6FA; stroke-width: 0.2; }</style>
        <g transform="translate(0,0)">
            <rect x="10" y="20" width="10" height="10" fill="#FFFFFF" opacity="0.7"/>
            <rect x="20" y="10" width="20" height="20" fill="#FFFFFF" opacity="0.7"/>
            <rect x="40" y="20" width="10" height="10" fill="#FFFFFF" opacity="0.7"/>
        </g>
    </svg>`;

    const starSvg = `
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
        <polygon points="25,5 30,20 45,20 35,30 40,45 25,35 10,45 15,30 5,20 20,20" fill="#FFD700"/>
    </svg>`;

    // SVG를 이미지로 변환
    function createImageFromSvg(svgString) {
        const svgBlob = new Blob([svgString], {type: 'image/svg+xml'});
        const svgUrl = URL.createObjectURL(svgBlob);
        const img = new Image();
        img.src = svgUrl;
        return img;
    }

    const bunnyImg = createImageFromSvg(bunnySvg);
    const shellImg = createImageFromSvg(shellSvg);
    const cloudImg = createImageFromSvg(cloudSvg);
    const starImg = createImageFromSvg(starSvg);

    // 게임 객체
    const bunny = {
        x: 100,
        y: canvas.height - 150,
        width: 120,
        height: 120,
        speed: 5,
        jumpStrength: 20,
        yVelocity: 0,
        isJumping: false
    };

    const obstacles = [];
    const clouds = [];
    const stars = [];

    // 구름 초기화
    for (let i = 0; i < 5; i++) {
        clouds.push({
            x: Math.random() * canvas.width,
            y: Math.random() * (canvas.height / 2),
            speed: 0.5 + Math.random(),
            size: 80 + Math.random() * 80
        });
    }

    // 게임 루프
    function gameLoop() {
        if (gameState === 'playing') {
            update();
            draw();
        }
        requestAnimationFrame(gameLoop);
    }

    function update() {
        // 달토끼 업데이트
        if (bunny.isJumping) {
            bunny.yVelocity += 0.8; // 중력
            bunny.y += bunny.yVelocity;
            if (bunny.y > canvas.height - 150) {
                bunny.y = canvas.height - 150;
                bunny.isJumping = false;
                bunny.yVelocity = 0;
            }
        }

        // 장애물 업데이트
        if (Math.random() < 0.02) {
            obstacles.push({
                x: canvas.width,
                y: canvas.height - 90,
                width: 60,
                height: 60
            });
        }

        obstacles.forEach((obstacle, index) => {
            obstacle.x -= 5;
            if (obstacle.x + obstacle.width < 0) {
                obstacles.splice(index, 1);
                score++;
                scoreElement.textContent = score;
            }

            // 충돌 감지
            if (
                bunny.x < obstacle.x + obstacle.width &&
                bunny.x + bunny.width > obstacle.x &&
                bunny.y < obstacle.y + obstacle.height &&
                bunny.y + bunny.height > obstacle.y
            ) {
                gameOver();
            }
        });

        // 구름 업데이트
        clouds.forEach(cloud => {
            cloud.x -= cloud.speed;
            if (cloud.x + cloud.size < 0) {
                cloud.x = canvas.width;
                cloud.y = Math.random() * (canvas.height / 2);
                cloud.size = 80 + Math.random() * 80;
            }
        });

        // 별 업데이트
        if (Math.random() < 0.02) {
            stars.push({
                x: canvas.width,
                y: Math.random() * (canvas.height - 100),
                size: 30 + Math.random() * 20
            });
        }

        stars.forEach((star, index) => {
            star.x -= 3;
            if (star.x + star.size < 0) {
                stars.splice(index, 1);
            }

            // 달토끼와의 충돌 감지
            if (
                bunny.x < star.x + star.size &&
                bunny.x + bunny.width > star.x &&
                bunny.y < star.y + star.size &&
                bunny.y + bunny.height > star.y
            ) {
                stars.splice(index, 1);
                score += 5;
                scoreElement.textContent = score;
            }
        });
    }

    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // 별 배경 그리기
        ctx.fillStyle = 'white';
        for (let i = 0; i < 100; i++) {
            ctx.beginPath();
            ctx.arc(Math.random() * canvas.width, Math.random() * canvas.height, 1, 0, Math.PI * 2);
            ctx.fill();
        }

        // 달 그리기
        ctx.fillStyle = '#FFFACD';
        ctx.beginPath();
        ctx.arc(canvas.width - 100, 100, 50, 0, Math.PI * 2);
        ctx.fill();

        // 구름 그리기
        clouds.forEach(cloud => {
            ctx.drawImage(cloudImg, cloud.x, cloud.y, cloud.size, cloud.size / 2);
        });

        // 별 그리기
        stars.forEach(star => {
            ctx.drawImage(starImg, star.x, star.y, star.size, star.size);
        });

        // 달토끼 그리기
        ctx.drawImage(bunnyImg, bunny.x, bunny.y, bunny.width, bunny.height);

        // 장애물 그리기
        obstacles.forEach(obstacle => {
            ctx.drawImage(shellImg, obstacle.x, obstacle.y, obstacle.width, obstacle.height);
        });
    }

    // 이벤트 리스너
    document.addEventListener('keydown', (event) => {
        if (event.code === 'Space' && !bunny.isJumping && gameState === 'playing') {
            bunny.isJumping = true;
            bunny.yVelocity = -bunny.jumpStrength;
        }
    });

    window.addEventListener('resize', () => {
        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;
        bunny.y = canvas.height - 150;
    });

    startButton.addEventListener('click', startGame);
    restartButton.addEventListener('click', startGame);

    function startGame() {
        gameState = 'playing';
        score = 0;
        scoreElement.textContent = '0';
        obstacles.length = 0;
        stars.length = 0;
        bunny.y = canvas.height - 150;
        bunny.isJumping = false;
        bunny.yVelocity = 0;
        startScreen.style.display = 'none';
        gameOverScreen.style.display = 'none';
    }

    function gameOver() {
        gameState = 'gameOver';
        finalScoreElement.textContent = score;
        gameOverScreen.style.display = 'block';
    }

    // 게임 루프 시작
    gameLoop();
</script>

전체 코드

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Enhanced 달토끼 (Moon Rabbit) Jumping Game</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            height: 100%;
            overflow: hidden;
            font-family: Arial, sans-serif;
        }
        #gameCanvas {
            background-color: #000033; /* Dark blue for night sky */
        }
        #gameStats {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-size: 20px;
        }
        #startScreen, #gameOverScreen {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            text-align: center;
            color: white;
            font-size: 24px;
            background-color: rgba(0, 0, 0, 0.7);
            padding: 20px;
            border-radius: 10px;
        }
        button {
            font-size: 20px;
            padding: 10px 20px;
            margin-top: 20px;
            cursor: pointer;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div id="gameStats">Score: <span id="score">0</span></div>
    <div id="startScreen">
        <h1>달토끼 (Moon Rabbit)</h1>
        <p>Jump over obstacles and collect stars!</p>
        <button id="startButton">Start Game</button>
    </div>
    <div id="gameOverScreen" style="display: none;">
        <h1>Game Over</h1>
        <p>Your score: <span id="finalScore"></span></p>
        <button id="restartButton">Play Again</button>
    </div>
    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const scoreElement = document.getElementById('score');
        const startScreen = document.getElementById('startScreen');
        const gameOverScreen = document.getElementById('gameOverScreen');
        const startButton = document.getElementById('startButton');
        const restartButton = document.getElementById('restartButton');
        const finalScoreElement = document.getElementById('finalScore');

        canvas.width = window.innerWidth;
        canvas.height = window.innerHeight;

        let score = 0;
        let gameState = 'start'; // 'start', 'playing', 'gameOver'

        // SVG definitions
        const bunnySvg = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 80 80">
            <style>rect { stroke: #000; stroke-width: 0.5; }</style>
            <rect x="30" y="30" width="20" height="30" fill="#FFF"/>
            <rect x="30" y="10" width="20" height="20" fill="#FFF"/>
            <rect x="25" y="5" width="10" height="15" fill="#FFF"/>
            <rect x="45" y="5" width="10" height="15" fill="#FFF"/>
            <rect x="35" y="15" width="5" height="5" fill="#000"/>
            <rect x="45" y="15" width="5" height="5" fill="#000"/>
            <rect x="40" y="25" width="5" height="5" fill="#FFC0CB"/>
            <rect x="25" y="55" width="10" height="5" fill="#FFF"/>
            <rect x="45" y="55" width="10" height="5" fill="#FFF"/>
        </svg>`;

        const shellsSvg = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 40">
            <style>rect { stroke: #000; stroke-width: 0.2; }</style>
            <g transform="translate(0,0)">
                <rect x="2" y="18" width="4" height="4" fill="#FFA07A"/>
                <rect x="6" y="14" width="4" height="8" fill="#FFA07A"/>
                <rect x="10" y="10" width="4" height="12" fill="#FFA07A"/>
                <rect x="14" y="6" width="4" height="16" fill="#FFA07A"/>
                <rect x="18" y="10" width="4" height="12" fill="#FFA07A"/>
                <rect x="22" y="14" width="4" height="8" fill="#FFA07A"/>
                <rect x="26" y="18" width="4" height="4" fill="#FFA07A"/>
                <rect x="18" y="22" width="8" height="4" fill="#FF8C69"/>
            </g>
        </svg>`;

        const cloudsSvg = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 160 80">
            <style>rect { stroke: #E6E6FA; stroke-width: 0.2; }</style>
            <g transform="translate(0,0)">
                <rect x="10" y="20" width="10" height="10" fill="#FFFFFF" opacity="0.7"/>
                <rect x="20" y="10" width="20" height="20" fill="#FFFFFF" opacity="0.7"/>
                <rect x="40" y="20" width="10" height="10" fill="#FFFFFF" opacity="0.7"/>
            </g>
        </svg>`;

        const starSvg = `
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50">
            <polygon points="25,5 30,20 45,20 35,30 40,45 25,35 10,45 15,30 5,20 20,20" fill="#FFD700"/>
        </svg>`;

        // Create image objects
        function createImageFromSvg(svgString) {
            const svgBlob = new Blob([svgString], {type: 'image/svg+xml'});
            const svgUrl = URL.createObjectURL(svgBlob);
            const img = new Image();
            img.src = svgUrl;
            return img;
        }

        const bunnyImg = createImageFromSvg(bunnySvg);
        const shellImg = createImageFromSvg(shellsSvg);
        const cloudImg = createImageFromSvg(cloudsSvg);
        const starImg = createImageFromSvg(starSvg);

        // Game objects
        const bunny = {
            x: 100,
            y: canvas.height - 150,
            width: 120,
            height: 120,
            speed: 5,
            jumpStrength: 20,
            yVelocity: 0,
            isJumping: false
        };

        const obstacles = [];
        const clouds = [];
        const stars = [];

        // Initialize clouds
        for (let i = 0; i < 5; i++) {
            clouds.push({
                x: Math.random() * canvas.width,
                y: Math.random() * (canvas.height / 2),
                speed: 0.5 + Math.random(),
                size: 80 + Math.random() * 80
            });
        }

        // Game loop
        function gameLoop() {
            if (gameState === 'playing') {
                update();
                draw();
            }
            requestAnimationFrame(gameLoop);
        }

        function update() {
            // Update bunny
            if (bunny.isJumping) {
                bunny.yVelocity += 0.8; // Gravity
                bunny.y += bunny.yVelocity;
                if (bunny.y > canvas.height - 150) {
                    bunny.y = canvas.height - 150;
                    bunny.isJumping = false;
                    bunny.yVelocity = 0;
                }
            }

            // Update obstacles
            if (Math.random() < 0.02) {
                obstacles.push({
                    x: canvas.width,
                    y: canvas.height - 90,
                    width: 60,
                    height: 60
                });
            }

            obstacles.forEach((obstacle, index) => {
                obstacle.x -= 5;
                if (obstacle.x + obstacle.width < 0) {
                    obstacles.splice(index, 1);
                    score++;
                    scoreElement.textContent = score;
                }

                // Collision detection
                if (
                    bunny.x < obstacle.x + obstacle.width &&
                    bunny.x + bunny.width > obstacle.x &&
                    bunny.y < obstacle.y + obstacle.height &&
                    bunny.y + bunny.height > obstacle.y
                ) {
                    gameOver();
                }
            });

            // Update clouds
            clouds.forEach(cloud => {
                cloud.x -= cloud.speed;
                if (cloud.x + cloud.size < 0) {
                    cloud.x = canvas.width;
                    cloud.y = Math.random() * (canvas.height / 2);
                    cloud.size = 80 + Math.random() * 80;
                }
            });

            // Update stars
            if (Math.random() < 0.02) {
                stars.push({
                    x: canvas.width,
                    y: Math.random() * (canvas.height - 100),
                    size: 30 + Math.random() * 20
                });
            }

            stars.forEach((star, index) => {
                star.x -= 3;
                if (star.x + star.size < 0) {
                    stars.splice(index, 1);
                }

                // Collision detection with bunny
                if (
                    bunny.x < star.x + star.size &&
                    bunny.x + bunny.width > star.x &&
                    bunny.y < star.y + star.size &&
                    bunny.y + bunny.height > star.y
                ) {
                    stars.splice(index, 1);
                    score += 5;
                    scoreElement.textContent = score;
                }
            });
        }

        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Draw stars background
            ctx.fillStyle = 'white';
            for (let i = 0; i < 100; i++) {
                ctx.beginPath();
                ctx.arc(Math.random() * canvas.width, Math.random() * canvas.height, 1, 0, Math.PI * 2);
                ctx.fill();
            }

            // Draw moon
            ctx.fillStyle = '#FFFACD';
            ctx.beginPath();
            ctx.arc(canvas.width - 100, 100, 50, 0, Math.PI * 2);
            ctx.fill();

            // Draw clouds
            clouds.forEach(cloud => {
                ctx.drawImage(cloudImg, cloud.x, cloud.y, cloud.size, cloud.size / 2);
            });

            // Draw collectible stars
            stars.forEach(star => {
                ctx.drawImage(starImg, star.x, star.y, star.size, star.size);
            });

            // Draw bunny
            ctx.drawImage(bunnyImg, bunny.x, bunny.y, bunny.width, bunny.height);

            // Draw obstacles
            obstacles.forEach(obstacle => {
                ctx.drawImage(shellImg, obstacle.x, obstacle.y, obstacle.width, obstacle.height);
            });
        }

        // Event listeners
        document.addEventListener('keydown', (event) => {
            if (event.code === 'Space' && !bunny.isJumping && gameState === 'playing') {
                bunny.isJumping = true;
                bunny.yVelocity = -bunny.jumpStrength;
            }
        });

        window.addEventListener('resize', () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            bunny.y = canvas.height - 150;
        });

        startButton.addEventListener('click', startGame);
        restartButton.addEventListener('click', startGame);

        function startGame() {
            gameState = 'playing';
            score = 0;
            scoreElement.textContent = '0';
            obstacles.length = 0;
            stars.length = 0;
            bunny.y = canvas.height - 150;
            bunny.isJumping = false;
            bunny.yVelocity = 0;
            startScreen.style.display = 'none';
            gameOverScreen.style.display = 'none';
        }

        function gameOver() {
            gameState = 'gameOver';
            finalScoreElement.textContent = score;
            gameOverScreen.style.display = 'block';
        }

        // Start the game loop
        gameLoop();
    </script>
</body>
</html>

관련글 더보기

댓글 영역