2d html5 canvas碰撞,howto [英] 2d html5 canvas collision, howto
问题描述
正如标题所示,我有麻烦对象碰撞...
我目前正在使用JavaScript的2d Html5画布游戏。我知道如何保持播放器对象不在游戏画布的宽度/高度之外,我知道如何做的东西,当玩家碰到一个对象(例如上电或敌人或任何),但我只是不知道如何创建一个固体对象的意义,当玩家击中固体对象,玩家只是停止,不能通过实体对象。
是我现在的(不是所有的代码只是我觉得是相关的,对不起,如果太多/太少:
var canvasPlayer = document.getElementById('canvasPlayer');
var ctxPlayer = canvasPlayer.getContext('2d');
var canvasWalls = document.getElementById('canvasWalls');
var ctxWalls = canvasWalls.getContext('2d');
function checkKeyDown(e){
var keyID =(e.keyCode)|| e.which;
if === 38 || keyID === 87){//向上箭头或W键
if(!player1.isDownKey&&!player1.isLeftKey&&!player1.isRightKey){
player1.isUpKey = true;
e.preventDefault();
}}
if(keyID === 39 || keyID === 68){// right arrow或D key
if(!player1.isDownKey&&!player1。 isLeftKey&&!player1.isUpKey){
player1.isRightKey = true;
e.preventDefault();
}}
if(keyID === 40 || keyID === 83){//下箭头或S键
if(!player1.isUpKey&&!player1。 isLeftKey&&!player1.isRightKey){
player1.isDownKey = true;
e.preventDefault();
}}
if(keyID === 37 || keyID === 65){// left arrow OR A key
if(!player1.isDownKey&&!player1。 isUpKey&&!player1.isRightKey){
player1.isLeftKey = true;
e.preventDefault();
}
}
}
Walls.prototype.draw = function(){
ctxWalls.drawImage(imgSprite,this.srcX,this.srcY ,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
this.checkHitPlayer();
};
Walls.prototype.checkHitPlayer = function(){
if(this.drawX> player1.drawX&&
this.drawX< = player1.drawX + player1.width& ;&
this.drawY> = player1.drawY&&
this.drawY< player1.drawY + player1.height){
player1.isUpKey = false;
player1.isDownKey = false;
player1.isRightKey = false;
player1.isLeftKey = false;
}
};
这个可以工作...除非试图向上或向左移动, 3像素,所以它需要3左或上箭头向左或向上。同样,玩家可以直接穿过墙壁,这不是我想要的。任何帮助是非常感谢对不起,如果我包括太多或没有足够的代码。哦,我也忘了提到游戏是一个益智游戏,我有它的设置,所以一个球员只能移动一个方向,直到撞墙。
如果你只是想让你的播放器停在墙上,你可以应用一些数学:
假设您的播放器是一个10px x 10px的矩形,右侧墙的X位置为200.
矩形右侧的X位置如下计算:
var playerRightSide = player.x + player.width;
您可以测试播放器是否已经到达这个墙:
if(playerRightSide> = 200)
如果用户尝试将他们的玩家推到墙外,您可以使用玩家X位置将玩家保持在墙的左侧。
if(playerRightSide> = 200){player.x = 190; }
190是墙的X位置(200)减去玩家的宽度p>
如果您有兴趣进行更高级的碰撞测试,请进一步阅读。
可分为3种类型:
- 圆与圆碰撞
- 矩形与矩形碰撞
- 矩形与圆形碰撞
下面是如何检测这些常见碰撞。
假设你定义一个这样的圆:
var circle1 = {
x:30,
y:30,
r:10
};
假设你像这样定义一个矩形:
var rect1 = {
x:20,
y:100,
w:20,
h:20
}
您可以检测这样的Circle与Circle碰撞...
>
...使用此圆与圆碰撞测试代码:
//如果两个圆碰撞,返回true
// c1和c2是如上定义的圆形
函数CirclesColliding(c1,c2){
var dx = c2.x-c1.x;
var dy = c2.y-c1.y;
var rSum = c1.r + c2.r;
return(dx * dx + dy * dy <= rSum * rSum);
}
你可以像这样检测Rectangle和Rectangle碰撞...
...使用此Rectangle与Rectangle碰撞测试代码:
矩形正在碰撞
// r1和r2是如上定义的矩形
函数RectsColliding(r1,r2){
return!(r1.x> r2.x + r2。 w || r1.x + r1.w r2.y + r2.h || r1.y + r1.h }
您可以像这样检测矩形与圆形碰撞...
...使用此Rectangle与Circle碰撞测试代码:
和圆是碰撞
// rect和circle是上面定义的矩形和圆形
函数RectCircleColliding(rect,circle){
var dx = Math.abs(circle .x-(rect.x + rect.w / 2));
var dy = Math.abs(circle.y-(rect.y + rect.y / 2));
if(dx> circle.r + rect.w2){return(false); }
if(dy> circle.r + rect.h2){return(false); }
if(dx <= rect.w){return(true); }
if(dy< = rect.h){return(true); }
var dx = dx-rect.w;
var dy = dy-rect.h
return(dx * dx + dy * dy <= circle.r * circle.r);
}
例如,您可以使用这些碰撞测试来响应玩家触摸power-up cube:
//创建一个循环播放器对象
//位于[30,30]半径为10px
var player = {x:30,y:30,r:10};
//在位置[200,30]创建矩形上电
var powerup = {x:200,y:30,w:20 ,h:20};
//让我们说用户键盘的播放器来协调[200,35]
//(接通电源)
播放器.x = 220;
player.y = 35;
//你可以测试圆形播放器是否接触矩形开机
if(RectCircleColliding(powerup,player)){
//玩家已经与上电冲突,给予奖励力量!
player.power + = 100;
}
这里是代码和小提琴: http://jsfiddle.net/m1erickson/u6t48/
<!doctype html>
< html>
< head>
< link rel =stylesheettype =text / cssmedia =allhref =css / reset.css/> <! - reset css - >
< script type =text / javascriptsrc =http://code.jquery.com/jquery.min.js>< / script>
< style>
body {background-color:ivory; padding:20px; }
canvas {border:1px solid red;}
< / style>
< script>
$(function(){
var canvas = document.getElementById(canvas);
var ctx = canvas.getContext(2d);
window.requestAnimFrame =(function(callback){
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function callback){
window.setTimeout(callback,1000/60);
};
})();
ctx.fillStyle =lightgray;
ctx.strokeStyle =skyblue;
//顶碰撞圈vs圈
var circle1 = {x:30,y:30,r:10};
var circle2 = {x:70,y:40,r:10};
var circle3 = {x:100,y:30,r:10};
var direction1 = 1;
//中间碰撞rect vs rect
var rect1 = {x:20,y:100,w:20,h:20};
var rect2 = {x: y:110,w:20,h:20};
var rect3 = {x:90,y:100,w:20,h:20}
var direction2 = 1;
// bottom collision rect vs circle
var circle4 = {x:30,y:200,r:10};
var rect4 = {x:50,y:205,w:20,h:20};
var circle5 = {x:100,y:200,r:10};
var direction3 = 1;
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawCircle(circle1);
drawCircle(circle2);
drawCircle(circle3);
drawCircle(circle4);
drawCircle(circle5);
drawRect(rect1);
drawRect(rect2);
drawRect(rect3);
drawRect(rect4);
}
function drawCircle(c){
ctx.beginPath();
ctx.arc(c.x,c.y,c.r,0,Math.PI * 2,false);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function drawRect(r){
ctx.beginPath();
ctx.rect(r.x,r.y,r.w,r.h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
//如果两个圆圈碰撞则返回true
function CirclesColliding(c1,c2){
var dx = c2.x-c1.x;
var dy = c2.y-c1.y;
var rSum = c1.r + c2.r;
return(dx * dx + dy * dy <= rSum * rSum);
}
//如果2个矩形正在碰撞返回true
function RectsColliding(r1,r2){
return!(r1.x> r2.x + r2.w || r1.x + r1.w r2.y + r2.h || r1.y + r1.h }
//如果矩形和圆形碰撞返回true
function RectCircleColliding(rect,circle){
var dx = Math.abs(circle.x - (rect.x + rect.w / 2));
var dy = Math.abs(circle.y-(rect.y + rect.h / 2));
if(dx> circle.r + rect.w / 2){return(false); }
if(dy> circle.r + rect.h / 2){return(false); }
if(dx <= rect.w){return(true); }
if(dy< = rect.h){return(true); }
var dx = dx-rect.w;
var dy = dy-rect.h
return(dx * dx + dy * dy <= circle.r * circle.r);
}
var fps = 15;
function animate(){
setTimeout(function(){
requestAnimFrame(animate);
// circle vs circle
circle2.x = circle2 .x + direction1;
if(CirclesColliding(circle2,circle1)|| CirclesColliding(circle2,circle3)){
direction1 = -direction1;
}
/ / rect vs rect
rect2.x = rect2.x + direction2;
if(RectsColliding(rect2,rect1)|| RectsColliding(rect2,rect3)){
direction2 = -direction2;
}
// rect vs circle
rect4.x = rect4.x + direction3;
if(RectCircleColliding(rect4,circle4)|| RectCircleColliding(rect4,circle5 )){
direction3 = -direction3;
}
drawAll();
},1000 / fps);
}
animate();
}); // end $(function(){});
< / script>
< / head>
< body>
< canvas id =canvaswidth = 300 height = 300>< / canvas>
< / body>
< / html>
As the title suggests, I am having trouble with object collision... I am currently working on a 2d Html5 canvas game using JavaScript. I know how to keep the "player" object from going outside the width/height of the game canvas, and i know how to do something when the player collides with an object (such as a power up or enemy or whatever) but i just don't know how to make a "solid" object meaning when the player hits the solid object, the player just stops, and cannot go through the solid object.
This is what I have now (not all the code just what I feel is relevant, sorry if it's too much/too little.:
var canvasPlayer = document.getElementById('canvasPlayer');
var ctxPlayer = canvasPlayer.getContext('2d');
var canvasWalls = document.getElementById('canvasWalls');
var ctxWalls = canvasWalls.getContext('2d');
function checkKeyDown(e) {
var keyID = (e.keyCode) || e.which;
if (keyID === 38 || keyID === 87) { // up arrow OR W key
if (!player1.isDownKey && !player1.isLeftKey && !player1.isRightKey) {
player1.isUpKey = true;
e.preventDefault();
} }
if (keyID === 39 || keyID === 68) { //right arrow OR D key
if (!player1.isDownKey && !player1.isLeftKey && !player1.isUpKey) {
player1.isRightKey = true;
e.preventDefault();
} }
if (keyID === 40 || keyID === 83) {//down arrow OR S key
if (!player1.isUpKey && !player1.isLeftKey && !player1.isRightKey) {
player1.isDownKey = true;
e.preventDefault();
} }
if (keyID === 37 || keyID === 65) {//left arrow OR A key
if (!player1.isDownKey && !player1.isUpKey && !player1.isRightKey) {
player1.isLeftKey = true;
e.preventDefault();
}
}
}
Walls.prototype.draw = function (){
ctxWalls.drawImage(imgSprite,this.srcX,this.srcY,this.width,this.height,this.drawX,this.drawY,this.width,this.height);
this.checkHitPlayer();
};
Walls.prototype.checkHitPlayer = function() {
if (this.drawX > player1.drawX &&
this.drawX <= player1.drawX + player1.width &&
this.drawY >= player1.drawY &&
this.drawY < player1.drawY + player1.height) {
player1.isUpKey = false;
player1.isDownKey = false;
player1.isRightKey = false;
player1.isLeftKey = false;
}
};
This works... except when trying to go up or left, the player only moves maybe 2-3 pixels, so it takes 3 left or up arrows to go left or up. As well the player can move straight through the wall which is not what i want. Any help is much appreciated sorry if i included too much or not enough code. Oh, i also forgot to mention the game is a puzzle game, and I have it set-up so a player can only move one direction at a time until hitting a wall.
If you just want your player to stop when the reach a wall, you can apply some math:
For example: assume your player is a 10px by 10px rectangle and the right wall's X position is 200.
The X position of the right side of the rectangle is calculated like this:
var playerRightSide = player.x + player.width;
You can test if the player has reached the wall like this:
if( playerRightSide >= 200 )
If the user tries to push their player beyond the wall, you would hold the player to the left of the wall using the players X position.
if( playerRightSide >= 200 ) { player.x = 190; }
The 190 is the wall's X position (200) minus the player's width (10).
Read further if you're interested in doing more advanced collision testing.
Many basic game collisions can be classified into 3 types:
- Circle versus Circle collision
- Rectangle versus Rectangle collision
- Rectangle versus Circle collision
Here’s an illustration of how to detect each of these common collisions.
Assume you define a circle like this:
var circle1={
x:30,
y:30,
r:10
};
Assume you define a rectangle like this:
var rect1={
x:20,
y:100,
w:20,
h:20
};
You can detect Circle vs Circle collisions like this...
...Using this Circle vs Circle collision-test code:
// return true if the 2 circles are colliding
// c1 and c2 are circles as defined above
function CirclesColliding(c1,c2){
var dx=c2.x-c1.x;
var dy=c2.y-c1.y;
var rSum=c1.r+c2.r;
return(dx*dx+dy*dy<=rSum*rSum);
}
You can detect Rectangle vs Rectangle collisions like this...
...Using this Rectangle vs Rectangle collision-test code:
// return true if the 2 rectangles are colliding
// r1 and r2 are rectangles as defined above
function RectsColliding(r1,r2){
return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y);
}
You can detect Rectangle vs Circle collisions like this...
...Using this Rectangle vs Circle collision-test code:
// return true if the rectangle and circle are colliding
// rect and circle are a rectangle and a circle as defined above
function RectCircleColliding(rect,circle){
var dx=Math.abs(circle.x-(rect.x+rect.w/2));
var dy=Math.abs(circle.y-(rect.y+rect.y/2));
if( dx > circle.r+rect.w2 ){ return(false); }
if( dy > circle.r+rect.h2 ){ return(false); }
if( dx <= rect.w ){ return(true); }
if( dy <= rect.h ){ return(true); }
var dx=dx-rect.w;
var dy=dy-rect.h
return(dx*dx+dy*dy<=circle.r*circle.r);
}
For example, you can use these collision tests to respond to a player touching a power-up cube:
// create a circular player object
// that's located at [30,30] and has a radius of 10px
var player={x:30,y:30,r:10};
// create a rectangular power-up at position [200,30]
var powerup={x:200, y:30, w:20, h:20};
// Let's say the user keys the player to coordinate [200,35]
// (touching the power-up)
player.x = 220;
player.y = 35;
// you can test if the circular player is touching the rectangular power-up
if( RectCircleColliding(powerup,player) ) {
// the player has collided with the power-up, give bonus power!
player.power += 100;
}
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/u6t48/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; padding:20px; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
function(callback) {
window.setTimeout(callback, 1000 / 60);
};
})();
ctx.fillStyle="lightgray";
ctx.strokeStyle="skyblue";
// top collision circle vs circle
var circle1={x:30,y:30,r:10};
var circle2={x:70,y:40,r:10};
var circle3={x:100,y:30,r:10};
var direction1=1;
// middle collision rect vs rect
var rect1={x:20,y:100,w:20,h:20};
var rect2={x:50,y:110,w:20,h:20};
var rect3={x:90,y:100,w:20,h:20};
var direction2=1;
// bottom collision rect vs circle
var circle4={x:30,y:200,r:10};
var rect4={x:50,y:205,w:20,h:20};
var circle5={x:100,y:200,r:10};
var direction3=1;
function drawAll(){
ctx.clearRect(0,0,canvas.width,canvas.height);
drawCircle(circle1);
drawCircle(circle2);
drawCircle(circle3);
drawCircle(circle4);
drawCircle(circle5);
drawRect(rect1);
drawRect(rect2);
drawRect(rect3);
drawRect(rect4);
}
function drawCircle(c){
ctx.beginPath();
ctx.arc(c.x,c.y,c.r,0,Math.PI*2,false);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
function drawRect(r){
ctx.beginPath();
ctx.rect(r.x,r.y,r.w,r.h);
ctx.closePath();
ctx.fill();
ctx.stroke();
}
// return true if the 2 circles are colliding
function CirclesColliding(c1,c2){
var dx=c2.x-c1.x;
var dy=c2.y-c1.y;
var rSum=c1.r+c2.r;
return(dx*dx+dy*dy<=rSum*rSum);
}
// return true if the 2 rectangles are colliding
function RectsColliding(r1,r2){
return !(r1.x>r2.x+r2.w || r1.x+r1.w<r2.x || r1.y>r2.y+r2.h || r1.y+r1.h<r2.y);
}
// return true if the rectangle and circle are colliding
function RectCircleColliding(rect,circle){
var dx=Math.abs(circle.x-(rect.x+rect.w/2));
var dy=Math.abs(circle.y-(rect.y+rect.h/2));
if( dx > circle.r+rect.w/2 ){ return(false); }
if( dy > circle.r+rect.h/2 ){ return(false); }
if( dx <= rect.w ){ return(true); }
if( dy <= rect.h ){ return(true); }
var dx=dx-rect.w;
var dy=dy-rect.h
return(dx*dx+dy*dy<=circle.r*circle.r);
}
var fps = 15;
function animate() {
setTimeout(function() {
requestAnimFrame(animate);
// circle vs circle
circle2.x = circle2.x+direction1;
if( CirclesColliding(circle2,circle1) || CirclesColliding(circle2,circle3) ){
direction1=-direction1;
}
// rect vs rect
rect2.x = rect2.x+direction2;
if( RectsColliding(rect2,rect1) || RectsColliding(rect2,rect3) ){
direction2=-direction2;
}
// rect vs circle
rect4.x = rect4.x+direction3;
if( RectCircleColliding(rect4,circle4) || RectCircleColliding(rect4,circle5) ){
direction3=-direction3;
}
drawAll();
}, 1000 / fps);
}
animate();
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
这篇关于2d html5 canvas碰撞,howto的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!