You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Canvas游戏中实现顶部下落小球的生成逻辑?

躲避下落小球游戏(完成版)

HTML 代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  <!--  <link rel="stylesheet" href="style.css"> --> 
</head>
<body>
    <canvas id="canvas" width="500" height="500" style="border: 1px solid rgb(0, 0, 0)"></canvas>
    <script src="volcano.js"></script>
   
</body>
</html>

JavaScript 代码

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

const width = canvas.width;
const height = canvas.height;

class Position {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

class Player {
    constructor() {

        this.position = new Position(250, 460)
        this.radius = 20;
        this.speed = 5;
        this.color = "teal";
        this.lives = 1;

        // Belongs to the handleKeyUp and handleKeyDown functions
        this.right = false;
        this.left = false;

    }
}
let player = new Player();

// Creating a class to handle the enemy balls
class Enemy {
    constructor() {
        this.position = { x: Math.random() * width, y: 5 };
        this.radius = 20;
        this.velocity = { x: 0, y: (Math.random() * 8 + 4) }
        this.color = "red";
    }

    move() {
        this.position.x += this.velocity.x / 5;
        this.position.y += this.velocity.y / 4;
    }

    draw() {
        context.beginPath();
        context.arc(this.position.x, this.position.y, this.radius, 0, Math.PI * 2);
        context.fillStyle = this.color;
        context.fill();
    }
}

let enemy = new Enemy();

function isCircleOutside(entity) {
    return (entity.position.x < - entity.radius ||
        entity.position.x > width + entity.radius ||
        entity.position.y < - entity.radius ||
        entity.position.y > height + entity.radius);
}

//Creating our main player
function drawCircle(entity) {
    context.beginPath();
    context.arc(entity.position.x, entity.position.y, entity.radius, 0, Math.PI * 2);
    context.fillStyle = entity.color;
    context.fill();
}

//Handles the A and D keyboard buttons
function handleKeyDown(event) {

    if (event.key === "a") {
        player.left = true;
    }
    else if (event.key === "d") {
        player.right = true;
    }
}

function handleKeyUp(event) {
    if (event.key === "a") {
        player.left = false;
    }
    else if (event.key === "d") {
        player.right = false;
    }
}

//Makes sure that the player ball does not go outside the canvas
function handlePlayerMovement(player) {
    if (player.right && player.position.x < canvas.width - player.radius)
        player.position.x += player.speed;

    if (player.left && player.position.x > player.radius)
        player.position.x -= player.speed;
}

function circleCollision(circle1, circle2) {
    let dx = circle1.position.x - circle2.position.x;
    let dy = circle1.position.y - circle2.position.y;
    let distance = Math.sqrt((dx * dx) + (dy * dy));

    return distance < circle1.radius + circle2.radius;
}

window.addEventListener("keypress", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);



let enemyArr = [];

let frameCount = 120;
function tick() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawCircle(player);
    handlePlayerMovement(player);

    frameCount++;
    if (frameCount >= 120) {
        frameCount = 0;
        enemyArr.push(new Enemy(enemy.position.x, enemy.position.y, enemy.velocity, enemy.radius, enemy.color));

    }

    for (let i = 0; i < enemyArr.length; i++) {
        let enemy = enemyArr[i];

        enemy.move();

        enemy.draw();

        if (isCircleOutside(enemy)) {
            enemyArr.splice(i, 1);
            continue;
        }

        if (circleCollision(enemy, player)) {
            enemyArr.splice(i, 1);
            player.lives -= 1;


            if (player.lives <= 0) {
                alert("GAME OVER");
                document.location.reload();
                clearInterval(interval);
                return;
            }
            continue;

        }
    }

    requestAnimationFrame(tick);
}

tick();

这是我的第二版游戏,在社区帮助下已按预期完成,可能存在未发现的Bug。游戏玩法简单:玩家可通过A/D键控制画布底部的青色主球左右移动,数秒后随机红色小球从顶部下落,玩家需躲避碰撞,触碰则弹出“GAME OVER”提示,刷新页面即可重启。


最初遇到的技术问题

我正在开发一款玩家需躲避Canvas顶部下落小球的游戏,已实现玩家小球的左右移动功能,但卡在生成下落小球的环节。我知晓需用空数组存储所有下落小球,但不清楚如何编写生成小球位置的函数,恳请提供建议或思路,谢谢!

最初版本代码

HTML 代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
  <!--  <link rel="stylesheet" href="style.css"> --> 
</head>
<body>
    <canvas id="canvas" width="500" height="500" style="border: 1px solid rgb(0, 0, 0)"></canvas>
    <script src="volcano.js"></script>
   
</body>
</html>

JavaScript 代码

const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');

const width = canvas.width;
const height = canvas.height;

class Position {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
}

class Player {
    constructor() {

        this.position = new Position(250, 460)
        this.radius = 20;
        this.speed = 5;
        this.color = "teal";

        // Belongs to the handleKeyUp and handleKeyDown functions
        this.right = false;
        this.left = false;

    }
}
let player = new Player();

// Creating a class to handle the enemy balls (stuck!)
class Enemy {
    constructor(position, velocity) {
        this.position = position;
        this.radius = 10;
        this.velocity = velocity;
        this.color = "red";
    }
}

//Creating our main player
function drawCircle(entity) {
    context.beginPath();
    context.arc(entity.position.x, entity.position.y, entity.radius, 0, Math.PI * 2);
    context.fillStyle = entity.color;
    context.fill();
}

//Handles the A and D keyboard buttons
function handleKeyDown(event) {

    if (event.key === "a") {
        player.left = true;
    }
    else if (event.key === "d") {
        player.right = true;
    }
}

function handleKeyUp(event) {
    if (event.key === "a") {
        player.left = false;
    }
    else if (event.key === "d") {
        player.right = false;
    }
}

window.addEventListener("keypress", handleKeyDown);
window.addEventListener("keyup", handleKeyUp);


//Makes sure that the player ball does not go outside the canvas
function handlePlayerMovement(player) {
    if (player.right && player.position.x < canvas.width - player.radius)
        player.position.x += player.speed;

    if (player.left && player.position.x > player.radius)
        player.position.x -= player.speed;
}

function tick() {
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawCircle(player);

    handlePlayerMovement(player);
    requestAnimationFrame(tick);
}

tick();

内容的提问来源于stack exchange,提问作者BusyMind

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 03:20:43