DIV CSS 佈局教程網

 DIV+CSS佈局教程網 >> 網頁腳本 >> HTML基礎知識 >> HTML5詳解 >> html5 迷宮游戲(碰撞檢測)實例一
html5 迷宮游戲(碰撞檢測)實例一
編輯:HTML5詳解     
游戲效果圖 
 
通過鼠標拖拽在畫布上添加牆壁,通過方向鍵控制多邊形上下左右移動,遇到牆壁則無法前進。 

需要解決的問題 

鼠標按下,鼠標拖動,鼠標釋放事件的檢測 
多邊形的繪制 
牆壁的繪制 
多邊形和牆壁的碰撞檢測(實質上是圓和線段的相交判斷) 

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> 

難點 

多邊形和線段碰撞檢測的方法 
函數intersect()負責檢測多邊形和線段是否相交 
記線段上一點p(x,y) 
線段2個端點是(sx,sy)和(fx,fy) 

記 

dx=fx-sx 

dy=fy-sy 

x和y可以表示如下 

x=sx+t*dx 

y=sy+t*dy 

要判斷線段和多邊形是否相交,轉化為判斷線段和多邊形的外接圓是否相交 
為此需要找到線段上離圓心o最近的一點p 
如果|op|<圓的半徑,則可以判斷線段和圓相交。 
否則不相交。

怎麼找到線段上離圓心距離最近的點呢? 

p點到o點的距離可以表示為 

distance=sqrt((x-cx)*(x-cx)+(y-cy)*(y-cy)); 

代入 

x=sx+t*dx和y=sy+t*dy 

可以得到distance是一個關於t的函數 

對此函數求導 

求出函數值為0時對應的t值就可以得到距離圓心最近的點
XML學習教程| jQuery入門知識| AJAX入門| Dreamweaver教程| Fireworks入門知識| SEO技巧| SEO優化集錦|
Copyright © DIV+CSS佈局教程網 All Rights Reserved