如何在画布上创建障碍

阿克沙伊

我正在尝试制作一个像游戏这样的简单平台游戏。我正在使用的代码如下所示

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>

问题是,有时当“玩家”的速度很高时,它可能会遇到如下图所示的障碍。我该如何阻止这种情况的发生?

在此处输入图片说明

所以我想要的是玩家应该在到达障碍物时停下来,不要越过障碍物

品牌

碰撞测试快速移动的对象时会出现复杂情况

您必须确定您的播放器和障碍物相交任何时间在移动过程中-即使玩家已经通过此举结束超越的障碍。因此,您必须说明玩家从移动开始到结束的完整路径。

在此处输入图片说明 ... 在此处输入图片说明

然后,您可以通过检查玩家的轨迹是否与障碍物相交来检查玩家在移动过程中是否与障碍物相交。

在此处输入图片说明

测试涉及快速移动物体的碰撞的相对有效方法

  1. 定义3条线段,这些线段连接玩家起始矩形的3个顶点,最接近玩家终止矩形的3个顶点。

在此处输入图片说明

  1. For any of the 3 lines that intersect an obstacle, calculate the distance of the line segment to the obstacle. Select the line that has the shortest distance between starting vertex and the obstacle.

在此处输入图片说明 在此处输入图片说明

  1. Calculate the "x" & "y" distances of the selected line segment.

    var dx = obstacleIntersection.x - start.x;
    var dy = obstacleIntersection.y - start.y;
    
  2. 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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在画布上创建Duval Triangle

来自分类Dev

如何在画布上创建一个悬停按钮?

来自分类Dev

如何在画布上创建不同的文字艺术设计?

来自分类Dev

如何在画布上叠加 div 而不创建更多空间

来自分类Dev

如何在 tkinter 画布上创建文本并更改画布中的文本?

来自分类Dev

如何在 tkinter 上创建后退按钮/或删除画布上的所有小部件?

来自分类Dev

如何在画布上的图像上换行

来自分类Dev

如何在画布上的图像上“绘画”?

来自分类Dev

如何在WPF中移动由画布上的按钮创建的形状?

来自分类Dev

如何在VisualBrush上设置ViewPort和ViewBox以在WPF画布中创建虚线背景?

来自分类Dev

如何在WPF中移动由画布上的按钮创建的形状?

来自分类Dev

在tkinter画布对象的查看区域周围创建“障碍”

来自分类Dev

在tkinter画布对象的查看区域周围创建“障碍”

来自分类Dev

如何在每个画布上添加图像?

来自分类Dev

如何在画布上随机绘制对象

来自分类Dev

[WPF]如何在画布上绘制网格?

来自分类Dev

如何在画布上绘制RelativeLayout?

来自分类Dev

如何在矩形的画布上绘画

来自分类Dev

如何在织物画布上添加图像?

来自分类Dev

如何在画布上绘制读取JSON?

来自分类Dev

如何在画布上停止动画?

来自分类Dev

如何在画布元素上绘制视频?

来自分类Dev

Java:如何在画布上绘制?

来自分类Dev

如何在Tkinter画布上更新情节?

来自分类Dev

如何在背景画布上绘画

来自分类Dev

如何在画布上获取状态项

来自分类Dev

如何在Tkinter画布上更新情节?

来自分类Dev

如何在画布上实现拖放?

来自分类Dev

如何在 HTML 画布上使颜色透明?

Related 相关文章

热门标签

归档