我正在尝试制作一个像游戏这样的简单平台游戏。我正在使用的代码如下所示
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.fillStyle="orange";
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<obLen;x++){
var obX = obstacles[x].x;
var obY = obstacles[x].y;
if((playerX + playerWidth > 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);
}
<canvas id="game" width="1000" height="600" style="border:1px solid #000;"></canvas>
问题是,有时当“玩家”的速度很高时,它可能会遇到如下图所示的障碍。我该如何阻止这种情况的发生?
所以我想要的是玩家应该在到达障碍物时停下来,不要越过障碍物
碰撞测试快速移动的对象时会出现复杂情况
您必须确定您的播放器和障碍物相交在任何时间在移动过程中-即使玩家已经通过此举结束超越的障碍。因此,您必须说明玩家从移动开始到结束的完整路径。
然后,您可以通过检查玩家的轨迹是否与障碍物相交来检查玩家在移动过程中是否与障碍物相交。
测试涉及快速移动物体的碰撞的相对有效方法
Calculate the "x" & "y" distances of the selected line segment.
var dx = obstacleIntersection.x - start.x;
var dy = obstacleIntersection.y - start.y;
Move the player from their starting position by the distance calculated in #3. This results in the player moving to the spot where it first collided with the obstacle.
player.x += dx;
player.y += dy;
Code and Demo:
Useful functions in the code:
setPlayerVertices
determines the 3 line segments that connect the 3 vertices of the player's starting rectangle that are closest to the player's ending rectangle.
hasCollided
finds the shortest segment connecting a vertex from the player's starting position with the collision point on the obstacle.
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.strokeStyle='blue';
ctx.strokeRect(ob.x,ob.y,ob.w,ob.h);
ctx.globalAlpha=1.00;
ctx.fillStyle='black';
ctx.fillText('obstacle',ob.x+ob.w/2,ob.y+ob.h/2);
//
ctx.globalAlpha=0.250;
ctx.strokeStyle='gold';
ctx.strokeRect(p1.x,p1.y,p1.w,p1.h);
ctx.strokeStyle='purple';
ctx.strokeRect(p2.x,p2.y,p2.w,p2.h);
ctx.fillStyle='black';
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 && mx<p1.x+p1.w && my>p1.y && my<p1.y+p1.h){
isDown=true;
dragging=p1;
}else if(mx>p2.x && mx<p2.x+p2.w && my>p2.y && my<p2.y+p2.h){
isDown=true;
dragging=p2;
}
}
function handleMouseUpOut(e){
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
// Put your mouseup stuff here
isDown=false;
dragging=null;
}
function handleMouseMove(e){
if(!isDown){return;}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
//
dragging.x+=dx;
dragging.y+=dy;
//
draw();
//
setPlayerVertices(p1,p2);
var c=hasCollided(obVertices);
if(c.dx){
ctx.strokeStyle='gold';
ctx.strokeRect(p1.x+c.dx,p1.y+c.dy,p1.w,p1.h);
ctx.fillStyle='black';
ctx.fillText('hit',p1.x+c.dx+p1.w/2,p1.y+c.dy+p1.h/2);
line(c.s,c.i,'red');
}
}
function setPlayerVertices(p1,p2){
var tl1={x:p1.x, y:p1.y};
var tl2={x:p2.x, y:p2.y};
var tr1={x:p1.x+p1.w, y:p1.y};
var tr2={x:p2.x+p2.w, y:p2.y};
var br1={x:p1.x+p1.w, y:p1.y+p1.h};
var br2={x:p2.x+p2.w, y:p2.y+p2.h};
var bl1={x:p1.x, y:p1.y+p1.h};
var bl2={x:p2.x, y:p2.y+p2.h};
//
if(p1.x<=p2.x && p1.y<=p2.y){
s1=tr1; s2=br1; s3=bl1;
e1=tr2; e2=br2; e3=bl2;
o1=0; o2=1; o3=3; o4=0;
}else if(p1.x<=p2.x && p1.y>=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<tracks.length;i++){
var t=tracks[i];
var testdist=t.dx*t.dx+t.dy*t.dy;
if(testdist<minDistSq){
minDistSq=testdist;
halt.dx=t.dx;
halt.dy=t.dy;
halt.s=t.s;
halt.i=t.i;
}
}
return(halt);
}
//
function track(s,e,i){
dot(s);dot(i);line(s,i);line(i,e);
return({ dx:i.x-s.x, dy:i.y-s.y, s:s, i:i });
}
function line2lineIntersection(p0,p1,p2,p3) {
var unknownA = (p3.x-p2.x) * (p0.y-p2.y) - (p3.y-p2.y) * (p0.x-p2.x);
var unknownB = (p1.x-p0.x) * (p0.y-p2.y) - (p1.y-p0.y) * (p0.x-p2.x);
var denominator = (p3.y-p2.y) * (p1.x-p0.x) - (p3.x-p2.x) * (p1.y-p0.y);
// Test if Coincident
// If the denominator and numerator for the ua and ub are 0
// then the two lines are coincident.
if(unknownA==0 && unknownB==0 && denominator==0){return(null);}
// Test if Parallel
// If the denominator for the equations for ua and ub is 0
// then the two lines are parallel.
if (denominator == 0) return null;
// If the intersection of line segments is required
// then it is only necessary to test if ua and ub lie between 0 and 1.
// Whichever one lies within that range then the corresponding
// line segment contains the intersection point.
// If both lie within the range of 0 to 1 then
// the intersection point is within both line segments.
unknownA /= denominator;
unknownB /= denominator;
var isIntersecting=(unknownA>=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.lineWidth=lw || 1;
ctx.strokeStyle=stroke || 'gray';
ctx.stroke();
}
body{ background-color: ivory; }
#canvas{border:1px solid red; }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<h4>Drag start & end player position rects<br>The shortest segment intersecting the obstacle is red.<br>The repositioned player is shown on the obstacle.</h4>
<canvas id="canvas" width=400 height=400></canvas>
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句