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

Canvas矩形移动时无法触发边界反弹问题求助

Canvas矩形反弹功能失效问题修复

我正在为课程开发一款简单游戏,想通过bounce函数让矩形在Canvas边界内移动时触发反弹,但这个功能无效——移动矩形时它会直接飞出Canvas边界,找不到问题出在哪。以下是我的代码:

var canvas;
var ctx;
var w = 1000;
var h = 700;
 
var o1 = {
    x: 100,
    y: h/2,
    w: 100,
    h: 100,
    c: 0,
    a: 100,
    angle: 0, //changes angle that shape sits at
    distance: 10
}
 
document.onkeydown = function(e){keypress(e, o1)}
 
setUpCanvas();
animationLoop();
 
function animationLoop(){
    clear();
    rect(o1);
    bounce(o1)
    requestAnimationFrame(animationLoop)
}
 
function bounce(o){
    if(o.x+o.w/2 > w || o.x-o.w/2 < 0){ 
        o.changeX *= -1; 
    }
 
    if(o.y+o.h/2 > h || o.y-o.h/2 <0){
        o.changeY *= -1;
    }
}
 
function updateData(o){
o.x += o.changeX;
o.y += o.changeY;
}
 
function keypress(e,o){
    if (e.key == "ArrowUp"){
        o.angle = 270;
        o.distance= 80;
        forward(o);
    }
 
    if (e.key == "ArrowDown"){
        o.angle = 90;
        o.distance= 20;
        forward(o);
    }
}
 
function forward(o){ 
    var cx;
    var cy;
    cx = o.distance*Math.cos(o.angle);
    cy = o.distance*Math.sin(o.angle)
    o.y += cy;
}
 
function rect(o){
    var bufferx = o.x;
    var buffery = o.y
    o.x = o.x - o.w/2;
    o.y = o.y- o.h/2;
    ctx.beginPath();
    ctx.moveTo(o.x,o.y);
    ctx.lineTo(o.x+o.w,o.y);
    ctx.lineTo(o.x+o.w,o.y+o.h);
    ctx.lineTo(o.x, o.y+o.h);
    ctx.lineTo(o.x,o.y);
    ctx.fillStyle = "hsla("+String (o.c)+",100%,50%,"+o.a+")";
    ctx.fill();
    o.x = bufferx;
    o.y = buffery;
}
 
function clear(){
    ctx.clearRect(0, 0, w, h);
}
 
function randn(range){
    var r = Math.random()*range-(range/2);
    return r
}
function rand(range){
    var r = Math.random()*range
    return r
}
 
function setUpCanvas(){
    canvas = document.querySelector("#myCanvas");
    canvas.width = w;
    canvas.height = h;
    canvas.style.border = "10px solid black";
    ctx = canvas.getContext("2d");
}
 
console.log("Final Assignment")

问题原因及修复步骤

1. 缺失核心属性

o1对象中没有定义changeX和changeY属性,bounce函数里对这两个属性的操作完全无效。需要在o1中添加初始值:

var o1 = {
    // ... 原有属性
    changeX: 0,
    changeY: 0
}

2. 未调用位置更新函数

animationLoop里只调用了bounce,但没有执行updateData来根据changeX/changeY更新矩形位置。修改animationLoop:

function animationLoop(){
    clear();
    rect(o1);
    updateData(o1); // 先更新位置
    bounce(o1);     // 再检测反弹
    requestAnimationFrame(animationLoop)
}

3. 角度单位不匹配

JavaScript的Math.cos和Math.sin接收弧度作为参数,但代码里用的是度数,导致移动计算完全错误。修改forward函数,把角度转为弧度:

function forward(o){ 
    var angleInRadians = o.angle * Math.PI / 180;
    o.changeY = o.distance * Math.sin(angleInRadians); // 改为设置changeY,而非直接修改y
}

4. 反弹逻辑不完善

原bounce函数只反转方向,但如果矩形已经超出边界,会持续触发反弹判断。需要在反转方向后将矩形拉回边界:

function bounce(o){
    // 水平边界检测
    if(o.x + o.w/2 > w){
        o.x = w - o.w/2; // 拉回右边界内
        o.changeX *= -1;
    } else if(o.x - o.w/2 < 0){
        o.x = o.w/2; // 拉回左边界内
        o.changeX *= -1;
    }

    // 垂直边界检测
    if(o.y + o.h/2 > h){
        o.y = h - o.h/2; // 拉回下边界内
        o.changeY *= -1;
    } else if(o.y - o.h/2 < 0){
        o.y = o.h/2; // 拉回上边界内
        o.changeY *= -1;
    }
}

修复后的完整代码

var canvas;
var ctx;
var w = 1000;
var h = 700;
 
var o1 = {
    x: 100,
    y: h/2,
    w: 100,
    h: 100,
    c: 0,
    a: 100,
    angle: 0,
    distance: 10,
    changeX: 0,
    changeY: 0
}
 
document.onkeydown = function(e){keypress(e, o1)}
 
setUpCanvas();
animationLoop();
 
function animationLoop(){
    clear();
    rect(o1);
    updateData(o1);
    bounce(o1);
    requestAnimationFrame(animationLoop)
}
 
function bounce(o){
    if(o.x + o.w/2 > w){
        o.x = w - o.w/2;
        o.changeX *= -1;
    } else if(o.x - o.w/2 < 0){
        o.x = o.w/2;
        o.changeX *= -1;
    }
 
    if(o.y + o.h/2 > h){
        o.y = h - o.h/2;
        o.changeY *= -1;
    } else if(o.y - o.h/2 < 0){
        o.y = o.h/2;
        o.changeY *= -1;
    }
}
 
function updateData(o){
    o.x += o.changeX;
    o.y += o.changeY;
}
 
function keypress(e,o){
    if (e.key == "ArrowUp"){
        o.angle = 270;
        o.distance= 80;
        forward(o);
    }
 
    if (e.key == "ArrowDown"){
        o.angle = 90;
        o.distance= 20;
        forward(o);
    }
}
 
function forward(o){ 
    var angleInRadians = o.angle * Math.PI / 180;
    o.changeY = o.distance * Math.sin(angleInRadians);
}
 
function rect(o){
    var bufferx = o.x;
    var buffery = o.y
    o.x = o.x - o.w/2;
    o.y = o.y- o.h/2;
    ctx.beginPath();
    ctx.moveTo(o.x,o.y);
    ctx.lineTo(o.x+o.w,o.y);
    ctx.lineTo(o.x+o.w,o.y+o.h);
    ctx.lineTo(o.x, o.y+o.h);
    ctx.lineTo(o.x,o.y);
    ctx.fillStyle = "hsla("+String (o.c)+",100%,50%,"+o.a+")";
    ctx.fill();
    o.x = bufferx;
    o.y = buffery;
}
 
function clear(){
    ctx.clearRect(0, 0, w, h);
}
 
function randn(range){
    var r = Math.random()*range-(range/2);
    return r
}
function rand(range){
    var r = Math.random()*range
    return r
}
 
function setUpCanvas(){
    canvas = document.querySelector("#myCanvas");
    canvas.width = w;
    canvas.height = h;
    canvas.style.border = "10px solid black";
    ctx = canvas.getContext("2d");
}
 
console.log("Final Assignment")

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 16:15:56