我试图制作一个像游戏一样简单的平台游戏.我使用的代码如下所示
window.onload = function(){
var canvas = document.getElementById('game');
var ctx = canvas.getContext("2d");
var rightKeyPress = false;
var leftKeyPress = false;
var upKeyPress = false;
var downKeyPress = false;
var playerX = canvas.width / 2;
var playerY = -50;
var dx = 3;
var dy = 3;
var dxp = 3;
var dyp = 3;
var dxn = 3;
var dyn = 3;
var prevDxp = dxp;
var prevDyp = dyp;
var prevDxn = dxn;
var prevDyn = dyn;
var playerWidth = 50;
var playerHeight = 50;
var obstacleWidth = 150;
var obstacleHeight = 50;
var obstaclePadding = 10;
var G = .98;
var currentVelocity = 0;
var obstacles = [];
var imageLoaded = false;
document.addEventListener("keyup",keyUp,false);
document.addEventListener("keydown",keyDown,false);
function keyDown(e){
if(e.keyCode == 37){
leftKeyPress = true;
if(currentVelocity > 2){
currentVelocity -= .1;
}
}
if(e.keyCode == 38){
upKeyPress = true;
}
if(e.keyCode == 39){
rightKeyPress = true;
if(currentVelocity < 2){
currentVelocity += .1;
}
}
if(e.keyCode == 40){
downKeyPress = true;
}
}
function keyUp(e){
if(e.keyCode == 37){
leftKeyPress = false;
}
if(e.keyCode == 38){
upKeyPress = false;
}
if(e.keyCode == 39){
rightKeyPress = false;
}
if(e.keyCode == 40){
downKeyPress = false;
}
}
function createObstacles(){
for(x=0;x < 4;x++){
var obX = (200 * x) + Math.round(Math.random() * 150);
var obY = 50 + Math.round(Math.random() * 400);
obstacles.push({"x":obX,"y":obY});
}
}
createObstacles();
function drawObstacles(){
ctx.beginPath();
for(x=0;x < 4;x++){
var obX = obstacles[x].x;
var obY = obstacles[x].y;
ctx.rect(obX,obY,obstacleWidth,obstacleHeight)
}
ctx.fillStyle = "grey";
ctx.fill();
ctx.closePath();
}
function initPlayer(){
ctx.beginPath();
ctx.rect(playerX,playerY,50,50);
ctx.fill;
ctx.fill();
ctx.closePath();
}
function KeyPressAndGravity(){
checkObstacleCollision();
playerX += currentVelocity;
if(rightKeyPress && playerX + 50 < canvas.width){
playerX += dxp;
}
if(leftKeyPress && playerX > 0){
playerX -= dxn;
}
if(upKeyPress && playerY > 0){
playerY -= dyn;
}
if(downKeyPress && playerY + 50 < canvas.height){
playerY += dyp;
}
if(playerY+50 < canvas.height){
playerY += G;
}
if(playerX <= 0){
currentVelocity = 0;
}else if(playerX + 50 >= canvas.width){
currentVelocity = 0;
}
dxp = prevDxp;
dyp = prevDyp;
dxn = prevDxn;
dyn = prevDyn;
G = .98;
if(currentVelocity != 0){
if(currentVelocity > 0){
currentVelocity -= .01;
}else{
currentVelocity += .01;
}
}
}
/*-----------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
---------------------------Check this part-------------------
-------------------------------------------------------------
-------------------------------------------------------------
-------------------------------------------------------------
------------------------------------------------------------*/
function checkObstacleCollision(){
var obLen = obstacles.length;
for(var x=0;x obX && playerX + playerWidth < obX + obstacleWidth || playerX > obX && playerX < obX + obstacleWidth) && playerY + playerHeight > obY - obstaclePadding && playerY + playerHeight < obY){
dyp = 0;
G = 0;
}else if((playerX + playerWidth > obX && playerX + playerWidth < obX + obstacleWidth || playerX > obX && playerX < obX + obstacleWidth) && playerY > obY + obstacleHeight && playerY < obY + obstacleHeight + obstaclePadding){
dyn = 0;
}else if(playerX + playerWidth > obX - obstaclePadding && playerX + playerWidth < obX && ((playerY + playerHeight > obY && playerY + playerHeight < obY + obstacleHeight) || (playerY > obY && playerY < obY + obstacleHeight))){
dxp = 0;
}else if(playerX > obX + obstacleWidth && playerX < obX + obstacleWidth + obstaclePadding && ((playerY + playerHeight > obY && playerY + playerHeight < obY + obstacleHeight) || (playerY > obY && playerY < obY + obstacleHeight))){
dxn = 0;
}
}
}
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
initPlayer();
KeyPressAndGravity();
drawObstacles();
}
setInterval(draw,15);
}
问题是,有时当"玩家"的速度很高时,它可能会遇到如下图所示的障碍.我怎么能阻止这种情况发生?
所以我想要的是玩家应该在他到达障碍物时停下来而不是通过它
碰撞测试快速移动的对象时会出现复杂情况
您必须确定您的播放器和障碍物相交在任何时间在移动过程中 -即使玩家已经通过此举结束超越的障碍.因此,您必须考虑玩家从移动的开始到结束移动的完整路径.
...
然后,您可以通过检查玩家的轨道是否与障碍物相交来检查玩家是否在移动过程中与障碍物相交.
一种测试涉及快速移动物体的碰撞的相对有效的方法
定义连接玩家起始矩形的3个顶点的3个线段,这些顶点最接近玩家的结束矩形.
对于与障碍物相交的3条线中的任何一条,计算线段与障碍物的距离.选择起始顶点和障碍物之间距离最短的线.
计算所选线段的"x"和"y"距离.
var dx = obstacleIntersection.x - start.x; var dy = obstacleIntersection.y - start.y;
将玩家从起始位置移动到#3中计算的距离.这导致玩家移动到它首先与障碍物碰撞的地方.
player.x += dx; player.y += dy;
代码和演示:
代码中的有用功能:
setPlayerVertices
确定连接玩家起始矩形的3个顶点的3个线段,这些顶点最接近玩家的结束矩形.
hasCollided
找到将玩家起始位置的顶点与障碍物上的碰撞点连接起来的最短段.
line2lineIntersection
找到2行之间的交点(如果有的话).这用于测试从开始到结束段(来自#1)和构成障碍矩形的4个线段中的任何一个的交叉点.归因:这个功能改编自Paul Bourke 关于十字路口的有用论述.
下面是示例代码和演示,演示如何在障碍物的碰撞点停止玩家:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw=canvas.width;
var ch=canvas.height;
function reOffset(){
var BB=canvas.getBoundingClientRect();
offsetX=BB.left;
offsetY=BB.top;
}
var offsetX,offsetY;
reOffset();
window.onscroll=function(e){ reOffset(); }
window.onresize=function(e){ reOffset(); }
var isDown=false;
var startX,startY,dragging;
ctx.translate(0.50,0.50);
ctx.textAlign='center';
ctx.textBaseline='middle';
var pts;
var p1={x:50,y:50,w:25,h:25,fill:''};
var p2={x:250,y:250,w:25,h:25,fill:''};
var ob={x:100,y:150,w:125,h:25,fill:''};
var obVertices=[
{x:ob.x,y:ob.y},
{x:ob.x+ob.w,y:ob.y},
{x:ob.x+ob.w,y:ob.y+ob.h},
{x:ob.x,y:ob.y+ob.h}
];
var s1,s2,s3,e1,e2,e3,o1,o2,o3,o4;
draw();
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUpOut(e);});
$("#canvas").mouseout(function(e){handleMouseUpOut(e);});
function draw(){
ctx.clearRect(0,0,cw,ch);
//
ctx.lineWidth=4;
ctx.globalAlpha=0.250;
ctx.stroke;
ctx.strokeRect(ob.x,ob.y,ob.w,ob.h);
ctx.globalAlpha=1.00;
ctx.fill;
ctx.fillText('obstacle',ob.x+ob.w/2,ob.y+ob.h/2);
//
ctx.globalAlpha=0.250;
ctx.stroke;
ctx.strokeRect(p1.x,p1.y,p1.w,p1.h);
ctx.stroke;
ctx.strokeRect(p2.x,p2.y,p2.w,p2.h);
ctx.fill;
ctx.globalAlpha=1.00;
ctx.fillText('start',p1.x+p1.w/2,p1.y+p1.h/2);
ctx.fillText('end',p2.x+p2.w/2,p2.y+p2.h/2);
}
function handleMouseDown(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
var mx=startX;
var my=startY;
if(mx>p1.x && mxp1.y && myp2.x && mxp2.y && my=p2.y){
s1=tl1; s2=tr1; s3=br1;
e1=tl2; e2=tr2; e3=br2;
o1=2; o2=3; o3=3; o4=0;
}else if(p1.x>=p2.x && p1.y<=p2.y){
s1=tl1; s2=br1; s3=bl1;
e1=tl2; e2=br2; e3=bl2;
o1=0; o2=1; o3=1; o4=2;
}else if(p1.x>=p2.x && p1.y>=p2.y){
s1=tl1; s2=tr1; s3=bl1;
e1=tl2; e2=tr2; e3=bl2;
o1=1; o2=2; o3=2; o4=3;
}
}
function hasCollided(o){
//
var i1=line2lineIntersection(s1,e1,o[o1],o[o2]);
var i2=line2lineIntersection(s2,e2,o[o1],o[o2]);
var i3=line2lineIntersection(s3,e3,o[o1],o[o2]);
var i4=line2lineIntersection(s1,e1,o[o3],o[o4]);
var i5=line2lineIntersection(s2,e2,o[o3],o[o4]);
var i6=line2lineIntersection(s3,e3,o[o3],o[o4]);
//
var tracks=[];
if(i1){tracks.push(track(s1,e1,i1));}
if(i2){tracks.push(track(s2,e2,i2));}
if(i3){tracks.push(track(s3,e3,i3));}
if(i4){tracks.push(track(s1,e1,i4));}
if(i5){tracks.push(track(s2,e2,i5));}
if(i6){tracks.push(track(s3,e3,i6));}
//
var nohitDist=10000000;
var minDistSq=nohitDist;
var halt={dx:null,dy:null,};
for(var i=0;i=0 && unknownA<=1 && unknownB>=0 && unknownB<=1)
if(!isIntersecting){return(null);}
return({
x: p0.x + unknownA * (p1.x-p0.x),
y: p0.y + unknownA * (p1.y-p0.y)
});
}
function dot(pt){
ctx.beginPath();
ctx.arc(pt.x,pt.y,3,0,Math.PI*2);
ctx.closePath();
ctx.fill();
}
function line(p0,p1,stroke,lw){
ctx.beginPath();
ctx.moveTo(p0.x,p0.y);
ctx.lineTo(p1.x,p1.y);
ctx.line| 1;
ctx.stroke| 'gray';
ctx.stroke();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
Drag start & end player position rects
The shortest segment intersecting the obstacle is red.
The repositioned player is shown on the obstacle.