html5 迷宮游戲(碰撞檢測(cè))實(shí)例一
發(fā)布時(shí)間:2013-07-25 17:20:36 作者:佚名
我要評(píng)論

通過鼠標(biāo)拖拽在畫布上添加墻壁,通過方向鍵控制多邊形上下左右移動(dòng),遇到墻壁則無法前進(jìn),下面為大家介紹下需要解決的問題及具體的實(shí)現(xiàn)代碼,感興趣的朋友可以學(xué)習(xí)下
游戲效果圖
通過鼠標(biāo)拖拽在畫布上添加墻壁,通過方向鍵控制多邊形上下左右移動(dòng),遇到墻壁則無法前進(jìn)。
需要解決的問題
鼠標(biāo)按下,鼠標(biāo)拖動(dòng),鼠標(biāo)釋放事件的檢測(cè)
多邊形的繪制
墻壁的繪制
多邊形和墻壁的碰撞檢測(cè)(實(shí)質(zhì)上是圓和線段的相交判斷)
MYCode:
<html>
<head>
<title>迷宮</title>
<script>
var canvas_width = 900;
var canvas_height = 350;
var ctx;
var canvas;
var everything = [];
var cur_wall;
var wall_width;
var wall_style = "rgb(200,0,200)";
var walls = [];
var in_motion = false;
var unit = 10;
function Token(sx, sy, rad, style_string, n)
{
this.sx = sx;
this.sy = sy;
this.rad = rad;
this.draw = draw_token;
this.n = n;
this.angle = (2 * Math.PI) / n;
this.move = move_token;
this.fill_style = style_string;
}
function draw_token()//繪制正n邊形
{
ctx.fill_style = this.fill_style;
ctx.beginPath();
var i;
var rad = this.rad;
ctx.moveTo(this.sx + rad * Math.cos(-0.5 * this.angle), this.sy + rad * Math.sin(-0.5 * this.angle));
for (i = 1; i < this.n; i++)
ctx.lineTo(this.sx + rad * Math.cos((i - 0.5) * this.angle), this.sy + rad * Math.sin((i - 0.5) * this.angle));
ctx.fill();
}
function move_token(dx, dy)
{
this.sx += dx;
this.sy += dy;
var i;
var wall;
for (i = 0; i < walls.length; i++)
{
wall = walls[i];
if (intersect(wall.sx, wall.sy, wall.fx, wall.fy, this.sx, this.sy, this.rad))
{
this.sx -= dx;
this.sy -= dy;
break;
}
}
}
function Wall(sx, sy, fx, fy, width, styleString)
{
this.sx = sx;
this.sy = sy;
this.fx = fx;
this.fy = fy;
this.width = width;
this.draw = draw_line;
this.strokeStyle = styleString;
}
function draw_line()
{
ctx.lineWidth = this.width;
ctx.strokeStye = this.strokeStyle;
ctx.beginPath();
ctx.moveTo(this.sx, this.sy);
ctx.lineTo(this.fx, this.fy);
ctx.stroke();
}
//note
var mypent = new Token(100, 100, 20, "rgb(0,0,250)", 5);
everything.push(mypent);
function init()
{
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
//note
canvas.addEventListener('mousedown', start_wall, false);
canvas.addEventListener('mousemove', stretch_wall, false);
canvas.addEventListener('mouseup', finish_wall, false);
window.addEventListener('keydown', getkey_and_move, false);
draw_all();
}
function start_wall(ev)
{
var mx;
var my;
if (ev.layerX || ev.layerx == 0)
{
mx = ev.layerX;
my = ev.layerY;
}
else if (ev.offsetX || ev.offsetX == 0)
{
mx = ev.offsetX;
my = ev.offsetY;
}
cur_wall = new Wall(mx, my, mx + 1, my + 1, wall_width, wall_style);
in_motion = true;
everything.push(cur_wall);
draw_all();
}
function stretch_wall(ev)
{
if (in_motion)
{
var mx;
var my;
if (ev.layerX || ev.layerX == 0)
{
mx = ev.layerX;
my = ev.layerY;
}
else if (ev.offsetX || ev.offsetX == 0)
{
mx = ev.offsetX;
my = ev.offsetY;
}
cur_wall.fx = mx;
cur_wall.fy = my;
draw_all();
}
}
function finish_wall(ev)
{
in_motion = false;
walls.push(cur_wall);
}
function draw_all()
{
ctx.clearRect(0, 0, canvas_width, canvas_height);
var i;
for (i = 0; i < everything.length; i++)
{
everything[i].draw();
}
}
function getkey_and_move(event)
{
var keyCode;
if (event == null)
{
keyCode = window.event.keyCode;
window.event.preventDefault();
}
else
{
keyCode = event.keyCode;
event.preventDefault();
}
switch (keyCode)
{
case 37://left arrow
mypent.move(-unit, 0);
break;
case 38://up arrow
mypent.move(0, -unit);
break;
case 39://right arrow
mypent.move(unit, 0);
break;
case 40:
mypent.move(0, unit);
break;
default:
//window.removeEventListener('keydown', getkey_and_move, false);
}
draw_all();
}
function intersect(sx, sy, fx, fy, cx, cy, rad)
{
var dx;
var dy;
var t;
var rt;
dx = fx - sx;
dy = fy - sy;
t = 0.0 - (((sx - cx) * dx + (sy - cy) * dy) / (dx * dx + dy * dy));
if (t < 0.0)
{
t = 0.0;
}
else if (t > 1.0)
t = 1.0;
var dx1 = (sx + t * dx) - cx;
var dy1 = (sy + t * dy) - cy;
var rt = dx1 * dx1 + dy1 * dy1;
if (rt < rad * rad)
return true;
else
return false;
}
</script>
<body onLoad="init();">
<canvas id="canvas" width="900" height="350"></canvas>
</body>
</html>
難點(diǎn)
多邊形和線段碰撞檢測(cè)的方法
函數(shù)intersect()負(fù)責(zé)檢測(cè)多邊形和線段是否相交
記線段上一點(diǎn)p(x,y)
線段2個(gè)端點(diǎn)是(sx,sy)和(fx,fy)
記
dx=fx-sx
dy=fy-sy
x和y可以表示如下
x=sx+t*dx
y=sy+t*dy
要判斷線段和多邊形是否相交,轉(zhuǎn)化為判斷線段和多邊形的外接圓是否相交
為此需要找到線段上離圓心o最近的一點(diǎn)p
如果|op|<圓的半徑,則可以判斷線段和圓相交。
否則不相交。
怎么找到線段上離圓心距離最近的點(diǎn)呢?
p點(diǎn)到o點(diǎn)的距離可以表示為
distance=sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
代入
x=sx+t*dx和y=sy+t*dy
可以得到distance是一個(gè)關(guān)于t的函數(shù)
對(duì)此函數(shù)求導(dǎo)
求出函數(shù)值為0時(shí)對(duì)應(yīng)的t值就可以得到距離圓心最近的點(diǎn)

通過鼠標(biāo)拖拽在畫布上添加墻壁,通過方向鍵控制多邊形上下左右移動(dòng),遇到墻壁則無法前進(jìn)。
需要解決的問題
鼠標(biāo)按下,鼠標(biāo)拖動(dòng),鼠標(biāo)釋放事件的檢測(cè)
多邊形的繪制
墻壁的繪制
多邊形和墻壁的碰撞檢測(cè)(實(shí)質(zhì)上是圓和線段的相交判斷)
MYCode:
復(fù)制代碼
代碼如下:<html>
<head>
<title>迷宮</title>
<script>
var canvas_width = 900;
var canvas_height = 350;
var ctx;
var canvas;
var everything = [];
var cur_wall;
var wall_width;
var wall_style = "rgb(200,0,200)";
var walls = [];
var in_motion = false;
var unit = 10;
function Token(sx, sy, rad, style_string, n)
{
this.sx = sx;
this.sy = sy;
this.rad = rad;
this.draw = draw_token;
this.n = n;
this.angle = (2 * Math.PI) / n;
this.move = move_token;
this.fill_style = style_string;
}
function draw_token()//繪制正n邊形
{
ctx.fill_style = this.fill_style;
ctx.beginPath();
var i;
var rad = this.rad;
ctx.moveTo(this.sx + rad * Math.cos(-0.5 * this.angle), this.sy + rad * Math.sin(-0.5 * this.angle));
for (i = 1; i < this.n; i++)
ctx.lineTo(this.sx + rad * Math.cos((i - 0.5) * this.angle), this.sy + rad * Math.sin((i - 0.5) * this.angle));
ctx.fill();
}
function move_token(dx, dy)
{
this.sx += dx;
this.sy += dy;
var i;
var wall;
for (i = 0; i < walls.length; i++)
{
wall = walls[i];
if (intersect(wall.sx, wall.sy, wall.fx, wall.fy, this.sx, this.sy, this.rad))
{
this.sx -= dx;
this.sy -= dy;
break;
}
}
}
function Wall(sx, sy, fx, fy, width, styleString)
{
this.sx = sx;
this.sy = sy;
this.fx = fx;
this.fy = fy;
this.width = width;
this.draw = draw_line;
this.strokeStyle = styleString;
}
function draw_line()
{
ctx.lineWidth = this.width;
ctx.strokeStye = this.strokeStyle;
ctx.beginPath();
ctx.moveTo(this.sx, this.sy);
ctx.lineTo(this.fx, this.fy);
ctx.stroke();
}
//note
var mypent = new Token(100, 100, 20, "rgb(0,0,250)", 5);
everything.push(mypent);
function init()
{
canvas = document.getElementById("canvas");
ctx = canvas.getContext('2d');
//note
canvas.addEventListener('mousedown', start_wall, false);
canvas.addEventListener('mousemove', stretch_wall, false);
canvas.addEventListener('mouseup', finish_wall, false);
window.addEventListener('keydown', getkey_and_move, false);
draw_all();
}
function start_wall(ev)
{
var mx;
var my;
if (ev.layerX || ev.layerx == 0)
{
mx = ev.layerX;
my = ev.layerY;
}
else if (ev.offsetX || ev.offsetX == 0)
{
mx = ev.offsetX;
my = ev.offsetY;
}
cur_wall = new Wall(mx, my, mx + 1, my + 1, wall_width, wall_style);
in_motion = true;
everything.push(cur_wall);
draw_all();
}
function stretch_wall(ev)
{
if (in_motion)
{
var mx;
var my;
if (ev.layerX || ev.layerX == 0)
{
mx = ev.layerX;
my = ev.layerY;
}
else if (ev.offsetX || ev.offsetX == 0)
{
mx = ev.offsetX;
my = ev.offsetY;
}
cur_wall.fx = mx;
cur_wall.fy = my;
draw_all();
}
}
function finish_wall(ev)
{
in_motion = false;
walls.push(cur_wall);
}
function draw_all()
{
ctx.clearRect(0, 0, canvas_width, canvas_height);
var i;
for (i = 0; i < everything.length; i++)
{
everything[i].draw();
}
}
function getkey_and_move(event)
{
var keyCode;
if (event == null)
{
keyCode = window.event.keyCode;
window.event.preventDefault();
}
else
{
keyCode = event.keyCode;
event.preventDefault();
}
switch (keyCode)
{
case 37://left arrow
mypent.move(-unit, 0);
break;
case 38://up arrow
mypent.move(0, -unit);
break;
case 39://right arrow
mypent.move(unit, 0);
break;
case 40:
mypent.move(0, unit);
break;
default:
//window.removeEventListener('keydown', getkey_and_move, false);
}
draw_all();
}
function intersect(sx, sy, fx, fy, cx, cy, rad)
{
var dx;
var dy;
var t;
var rt;
dx = fx - sx;
dy = fy - sy;
t = 0.0 - (((sx - cx) * dx + (sy - cy) * dy) / (dx * dx + dy * dy));
if (t < 0.0)
{
t = 0.0;
}
else if (t > 1.0)
t = 1.0;
var dx1 = (sx + t * dx) - cx;
var dy1 = (sy + t * dy) - cy;
var rt = dx1 * dx1 + dy1 * dy1;
if (rt < rad * rad)
return true;
else
return false;
}
</script>
<body onLoad="init();">
<canvas id="canvas" width="900" height="350"></canvas>
</body>
</html>
難點(diǎn)
多邊形和線段碰撞檢測(cè)的方法
函數(shù)intersect()負(fù)責(zé)檢測(cè)多邊形和線段是否相交
記線段上一點(diǎn)p(x,y)
線段2個(gè)端點(diǎn)是(sx,sy)和(fx,fy)
記
dx=fx-sx
dy=fy-sy
x和y可以表示如下
x=sx+t*dx
y=sy+t*dy
要判斷線段和多邊形是否相交,轉(zhuǎn)化為判斷線段和多邊形的外接圓是否相交
為此需要找到線段上離圓心o最近的一點(diǎn)p
如果|op|<圓的半徑,則可以判斷線段和圓相交。
否則不相交。
怎么找到線段上離圓心距離最近的點(diǎn)呢?
p點(diǎn)到o點(diǎn)的距離可以表示為
distance=sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy));
代入
x=sx+t*dx和y=sy+t*dy
可以得到distance是一個(gè)關(guān)于t的函數(shù)
對(duì)此函數(shù)求導(dǎo)
求出函數(shù)值為0時(shí)對(duì)應(yīng)的t值就可以得到距離圓心最近的點(diǎn)
相關(guān)文章
- 這是一款基于HTML5實(shí)現(xiàn)的熊貓彈跳小游戲源碼。點(diǎn)擊開始按鈕進(jìn)入游戲后,玩家通過長(zhǎng)按鼠標(biāo)按鍵控制彈簧的壓縮強(qiáng)度,松開鼠標(biāo)按鍵后,彈簧彈起熊貓使其跳落到下一個(gè)柱子上。2019-08-23
HTML5實(shí)現(xiàn)的卡牌配對(duì)小游戲源碼
這是一款基于HTML5實(shí)現(xiàn)的卡牌配對(duì)小游戲源碼。點(diǎn)擊開始按鈕進(jìn)入游戲可以看到5行*4列的卡牌排列。玩家點(diǎn)擊卡牌使之翻轉(zhuǎn)過來,兩張卡牌的類型相同則配對(duì)正確,否則配對(duì)錯(cuò)誤,2019-08-09js實(shí)現(xiàn)的魔塔闖關(guān)類小游戲源碼
這是一款基于js實(shí)現(xiàn)的魔塔闖關(guān)類小游戲源碼。玩家通過鍵盤方向鍵控制游戲中人物的上下左右移動(dòng),使游戲中的人物角色打開房間,獲取鑰匙、藥水、寶劍、盾牌等道具。最終跨過2019-08-07使用數(shù)據(jù)結(jié)構(gòu)給女朋友寫個(gè)Html5走迷宮游戲
本文給大家分享使用數(shù)據(jù)結(jié)構(gòu)給女朋友寫個(gè)Html5走迷宮游戲功能,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2019-11-26