HTML5 Canvas 游戏无法按预期工作

Posted

技术标签:

【中文标题】HTML5 Canvas 游戏无法按预期工作【英文标题】:HTML5 Canvas game not working as expected 【发布时间】:2022-01-13 17:22:30 【问题描述】:

下午好。

我目前正在使用 html5 开发一个简单的 2D 游戏。游戏的目标如下:玩家(一个大小为“n”的绿球)必须在地图上移动(使用右、左、上、下箭头)并收集较小的球。每次用户收集一个球,它的大小就会增加 25%。当球变得如此之大以至于在地图上几乎看不到任何球时游戏结束,在这种情况下,“游戏结束”文本会加载到画布上。

我遇到的问题是,为了知道玩家是否收集了某个球,我计算了用户与所述球之间的距离。如果小于 3,则视为已收集。为了计算这个距离,我使用了一个数学公式。问题是,它不能正常工作。有时,当用户肯定超过 3 的距离时,球会消失。我想修改代码,以便只有当用户触摸球时球才会消失。我尝试将距离 === 0,但这仍然会产生意想不到的结果。

这里是源代码:

const canvas = document.getElementById("gameArea");
const ctx = canvas.getContext("2d");

let x = 100;
let y = 100;
let radius = 50;
let speed = 10;

let upPressed = false;
let downPressed = false;
let leftPressed = false;
let rightPressed = false;
let gameOver = false;
let points = [ [300, 500], [400, 700], [100, 600], [469, 586], [578, 234], [587, 489] ];
var gAccess = 0;
var multiplier = 1;
let counter = 0;

function drawGame() 
  requestAnimationFrame(drawGame);
  clearScreen();
  inputs();
  boundryCheck();
  drawGreenBlob();
  drawNextTarget();
  checkCollision();


function checkCollision() 
  let b = points[gAccess][0] - x;
  let a = points[gAccess][1] - y;

  var c = Math.sqrt(a * a + b * b);

  if (c < 220) 
    gAccess = (gAccess + 1) % points.length;
    multiplier += 0.25;
    counter++;
    console.log(counter);
  

  if (counter >= 25) 
    gameover = true;
    const context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawgameOver();
  


function drawNextTarget() 
  if (gameOver === true) return;
  ctx.beginPath();
  ctx.arc(points[gAccess][0], points[gAccess][0], radius / 3, 0, Math.PI * 2);
  ctx.fill();


function drawgameOver() 
  var ctx = canvas.getContext("2d");

  var grd = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
  grd.addColorStop(0, "black");
  grd.addColorStop(1, "gray");

  // Fill with gradient
  ctx.fillStyle = grd;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  var ctx = canvas.getContext("2d");
  ctx.fillStyle = "red";
  ctx.font = "36px Arial";
  ctx.fillText("Game Over!", 50, 50);



function boundryCheck() 
  //up
  if (y < radius) 
    y = radius;
  
  //down
  if (y > canvas.height - radius) 
    y = canvas.height - radius;
  
  //left
  if (x < radius) 
    x = radius;
  
  //right
  if (x > canvas.width - radius) 
    x = canvas.width - radius;
  


function inputs() 
  if (upPressed) 
    y = y - speed;
  
  if (downPressed) 
    y = y + speed;
  
  if (leftPressed) 
    x = x - speed;
  
  if (rightPressed) 
    x = x + speed;
  


function drawGreenBlob() 
  ctx.fillStyle = "green";
  if (upPressed) 
    ctx.fillStyle = "red";
  
  if (downPressed) 
    ctx.fillStyle = "blue";
  
  if (leftPressed) 
    ctx.fillStyle = "yellow";
  
  if (rightPressed) 
    ctx.fillStyle = "purple";
  

  ctx.beginPath();
  ctx.arc(x, y, radius * multiplier, 0, Math.PI * 2);
  ctx.fill();


function clearScreen() 
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);


document.body.addEventListener("keydown", keyDown);
document.body.addEventListener("keyup", keyUp);

function keyDown(event) 
  //up
  if (event.keyCode == 38) 
    upPressed = true;
  

  //down
  if (event.keyCode == 40) 
    downPressed = true;
  
  //left
  if (event.keyCode == 37) 
    leftPressed = true;
  

  //right
  if (event.keyCode == 39) 
    rightPressed = true;
  


function keyUp(event) 
  //up
  if (event.keyCode == 38) 
    upPressed = false;
  

  //down
  if (event.keyCode == 40) 
    downPressed = false;
  
  //left
  if (event.keyCode == 37) 
    leftPressed = false;
  

  //right
  if (event.keyCode == 39) 
    rightPressed = false;
  


drawGame();
&lt;canvas id="gameArea" width=800 height=800&gt;&lt;/canvas&gt;

非常感谢您的帮助和关注。

【问题讨论】:

根据您的代码,您将坐标距离与220 进行比较。 “小于3”是什么意思?反正实际碰撞距离好像是radius * multiplier + radius / 3 嗨,克里斯,非常感谢您抽出宝贵的时间。不要介意少于 3 的事情,那是出于测试目的。我想要的是当用户触摸球(距离 0)时,它会消失。您告诉我的那一行,是否会用以下内容替换该行:“var c = Math.sqrt(a * a + b * b);”?我不明白为什么源代码不起作用。再次感谢所有帮助 该行可以计算距离(c),但是在下一行中,您将需要if (c &lt; 220) 而不是if (c &lt; radius * multiplier + radius / 3) ,原因是如果距离两个圆圈会重叠它们的中心数小于它们的半径之和。 【参考方案1】:

就像@ChrisG 提到的,您需要在 checkCollision if 语句中包含半径:if (c &lt; radius * multiplier + radius / 3)

radius * multiplier 是我们播放器的半径 radius / 3 是球的半径

这在技术上是在两个周界接触时产生碰撞如果你想做出不同的事情你可以改变这个数学,例如,如果不是加号,我们将它改为减号,我们会在玩家吞下球时产生错觉.


function drawNextTarget() 上还有一个错误,您没有选择正确的坐标:ctx.arc(points[gAccess][0], points[gAccess][0], VSctx.arc(points[gAccess][0], points[gAccess][1],

现在一切都很好:

const canvas = document.getElementById("gameArea");
const ctx = canvas.getContext("2d");

let x = 100;
let y = 100;
let radius = 50;
let speed = 10;

let upPressed = false;
let downPressed = false;
let leftPressed = false;
let rightPressed = false;
let gameOver = false;
let points = [ [300, 500], [400, 700], [100, 600], [469, 586], [578, 234], [587, 489] ];
var gAccess = 0;
var multiplier = 1;
let counter = 0;

function drawGame() 
  requestAnimationFrame(drawGame);
  clearScreen();
  inputs();
  boundryCheck();
  drawGreenBlob();
  drawNextTarget();
  checkCollision();


function checkCollision() 
  let b = points[gAccess][0] - x;
  let a = points[gAccess][1] - y;

  var c = Math.sqrt(a * a + b * b);

  if (c < radius * multiplier + radius / 3) 
    gAccess = (gAccess + 1) % points.length;
    multiplier += 0.25;
    counter++;
    console.log(counter);
  

  if (counter >= 25) 
    gameover = true;
    const context = canvas.getContext('2d');
    context.clearRect(0, 0, canvas.width, canvas.height);
    drawgameOver();
  


function drawNextTarget() 
  if (gameOver === true) return;
  ctx.beginPath();
  ctx.arc(points[gAccess][0], points[gAccess][1], radius / 3, 0, Math.PI * 2);
  ctx.fill();


function drawgameOver() 
  var ctx = canvas.getContext("2d");

  var grd = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
  grd.addColorStop(0, "black");
  grd.addColorStop(1, "gray");

  // Fill with gradient
  ctx.fillStyle = grd;
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  var ctx = canvas.getContext("2d");
  ctx.fillStyle = "red";
  ctx.font = "36px Arial";
  ctx.fillText("Game Over!", 50, 50);



function boundryCheck() 
  //up
  if (y < radius) 
    y = radius;
  
  //down
  if (y > canvas.height - radius) 
    y = canvas.height - radius;
  
  //left
  if (x < radius) 
    x = radius;
  
  //right
  if (x > canvas.width - radius) 
    x = canvas.width - radius;
  


function inputs() 
  if (upPressed) 
    y = y - speed;
  
  if (downPressed) 
    y = y + speed;
  
  if (leftPressed) 
    x = x - speed;
  
  if (rightPressed) 
    x = x + speed;
  


function drawGreenBlob() 
  ctx.fillStyle = "green";
  if (upPressed) 
    ctx.fillStyle = "red";
  
  if (downPressed) 
    ctx.fillStyle = "blue";
  
  if (leftPressed) 
    ctx.fillStyle = "yellow";
  
  if (rightPressed) 
    ctx.fillStyle = "purple";
  

  ctx.beginPath();
  ctx.arc(x, y, radius * multiplier, 0, Math.PI * 2);
  ctx.fill();


function clearScreen() 
  ctx.fillStyle = "black";
  ctx.fillRect(0, 0, canvas.width, canvas.height);


document.body.addEventListener("keydown", keyDown);
document.body.addEventListener("keyup", keyUp);

function keyDown(event) 
  //up
  if (event.keyCode == 38) 
    upPressed = true;
  

  //down
  if (event.keyCode == 40) 
    downPressed = true;
  
  //left
  if (event.keyCode == 37) 
    leftPressed = true;
  

  //right
  if (event.keyCode == 39) 
    rightPressed = true;
  


function keyUp(event) 
  //up
  if (event.keyCode == 38) 
    upPressed = false;
  

  //down
  if (event.keyCode == 40) 
    downPressed = false;
  
  //left
  if (event.keyCode == 37) 
    leftPressed = false;
  

  //right
  if (event.keyCode == 39) 
    rightPressed = false;
  


drawGame();
&lt;canvas id="gameArea" width=800 height=800&gt;&lt;/canvas&gt;

【讨论】:

以上是关于HTML5 Canvas 游戏无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章

HTML5 Canvas 鼠标滚轮事件

无法在我的 Flash / HTML5 / Canvas 项目中播放音频

播放 HTML5 音频标签,但控件未按预期工作

DOM.style.display 没有按预期工作。无法隐藏 div

设置 HTML5 Canvas 的背景填充、描边和不透明度

HTML5 DnD - 为啥在拖放元素后重影图像只能按预期工作?