HTML5 Canvas开发迷宫游戏例子

本文介绍如何使用Canvas画布制作一个简单的迷宫游戏:用户按下方向键时,笑脸图标会沿相应的方向移动(移动时有动画效果),遇到墙壁时(碰撞检测)就会停下来。

1,在线样例
加载困难迷宫 加载简单迷宫

开发迷宫游戏例子-html5 canvas绘图例子">

2,实现原理
(1)迷宫的生成:我们这里是使用一幅迷宫图片,然后把整幅图绘制到画布上。
(2)通过设置 window.onkeydown 的响应函数 processKey(),当用户按下方向键的时候,根据键码调整笑脸各方向上的速度。
(3)drawFrame() 函数每10毫秒刷新画布,如果笑脸有速度则移动并绘制轨迹,同时作碰撞检测。最后还会检测笑脸是否到底部,到了话弹出成功消息框。

3,碰撞检测
这里使用的是基于像素颜色碰撞检测,我们取笑脸所在区域的像素块(在笑脸四周再稍微扩展一点),判断其中是否有黑色像素,有的话则说明撞墙了。

4,完整代码

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>hangge.com</title>
  <style>
    canvas {
      border: 6px double black;
      background: white;
    }
 
    img {
      display: none;
    }
 
    button {
      padding: 3px;
    }
  </style>
  <script>
    var canvas;
    var context;
 
    // 记录笑脸图标的当前位置
    var x = 0;
    var y = 0;
 
    // 记录笑脸在x轴和y轴方向上每一帧要移动多少像素
    var dx = 0;
    var dy = 0;
 
    window.onload = function() {
      // 设置画布
      canvas = document.getElementById("canvas");
      context = canvas.getContext("2d");
 
      // 绘制迷宫背景
      drawMaze('http://www.hangge.com/blog_uploads/201602/2016022313460193716.png', 5, 5);
 
      // 当用户按下键盘上的键时,运行processKey()函数
      window.onkeydown = processKey;
    };
 
 
    // timer引用,这样重新加载迷宫的时候可以很方便地停止绘制
    var timer;
 
    function drawMaze(mazeFile, startingX, startingY) {
      // 先停止绘制
      clearTimeout(timer);
 
      // 停止笑脸
      dx = 0;
      dy = 0;
 
      // 加载迷宫图片
      var imgMaze = new Image();
      imgMaze.onload = function() {
        // 调整画布大小以适应迷宫图片
        canvas.width = imgMaze.width;
        canvas.height = imgMaze.height;
 
        // 绘制迷宫
        context.drawImage(imgMaze, 0,0);
 
        // 绘制笑脸
        x = startingX;
        y = startingY;
 
        var imgFace = document.getElementById("face");
        context.drawImage(imgFace, x, y);
        context.stroke();
 
        // 10毫秒后绘制下一帧
        timer = setTimeout(drawFrame, 10);
      };
      imgMaze.src = mazeFile;
    }
 
 
    function processKey(e) {
      // 如果笑脸在移动,停止
      dx = 0;
      dy = 0;
 
      // 按下了向上键,向上移动
      if (e.keyCode == 38) {
        dy = -1;
      }
 
      // 按下了向下键,向下移动
      if (e.keyCode == 40) {
        dy = 1;
      }
 
      // 按下了向左键,向左移动
      if (e.keyCode == 37) {
        dx = -1;
      }
 
      // 按下了向右键,向右移动
      if (e.keyCode == 39) {
        dx = 1;
      }
    }
 
    function checkForCollision() {
      // 取得笑脸所在的像素块,再稍微扩展一点
      var imgData = context.getImageData(x-1, y-1, 15+2, 15+2);
      var pixels = imgData.data;
 
      // 检测其中的像素
      for (var i = 0; n = pixels.length, i < n; i += 4) {
        var red = pixels[i];
        var green = pixels[i+1];
        var blue = pixels[i+2];
        var alpha = pixels[i+3];
 
        // 检测黑色的墙(如果检测到,说明撞墙了)
        if (red == 0 && green == 0 && blue == 0) {
          return true;
        }
        // 检测灰色的边(如果检测到,说明撞墙了)
        if (red == 169 && green == 169 && blue == 169) {
          return true;
        }
      }
      // 没有撞墙
      return false;
    }
 
 
    function drawFrame() {
      // 检测笑脸是否正在哪个方向上移动,如果不是,则什么也不做。
      if (dx != 0 || dy != 0) {
        // 在笑脸当前位置绘制一块黄色背景(表示移动痕迹),然后把笑脸移到下一个位置
        context.beginPath();
        context.fillStyle = "rgb(254,244,207)";
        context.rect(x, y, 15, 15);
        context.fill()
 
        // 增大位置值
        x += dx;
        y += dy;
 
        // 碰撞检测(撞墙的话笑脸需要放回上一个位置并停止移动)
        if (checkForCollision()) {
          x -= dx;
          y -= dy;
          dx = 0;
          dy = 0;
        }
 
        // 这里可以绘制笑脸
        var imgFace = document.getElementById("face");
        context.drawImage(imgFace, x, y);
 
        // 检测笑脸是否已经到达迷宫底部,是的话提示成功
        if (y > (canvas.height - 17)) {
          alert("You win!");
          return;
        }
      }
 
      // 10毫秒后绘制下一正
      timer = setTimeout(drawFrame, 10);
    }
 
    function loadEasy() {
      drawMaze('http://www.hangge.com/blog_uploads/201602/2016022313460193716.png', 5, 5);
    }
 
    function loadHard() {
      drawMaze('http://www.hangge.com/blog_uploads/201602/2016022313455480577.png', 268, 5);
    }
  
  </script>
</head>
 
<body>  
  <canvas id="canvas">
  </canvas>
  <div>
    <button onclick="loadHard()">加载困难迷宫</button>
    <button onclick="loadEasy()">加载简单迷宫</button>
  </div>
 
  <img id="face" src="2016022313454739977.png">
</body>
</html>

HTML5 canvas 小游戏练手

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>无标题文档</title>
<style type="text/css">
*{padding:0;margin:0;color:#fff;}
a {text-decoration:none;}
html,body{background-color:#000;}
#canvas{background-color:#001022;position:absolute;z-index:-1000;top:0}
#game{margin:auto;width:40%;background-color:#001022;}
#lay{width:100%;height:100%;position:relative}
#game p,h2{text-align:center;width:100%}
#gameInfo{position:relative;margin-top:150px;}

#gameState{margin-top:20px;margin-left:-400px;}
#reset{position:absolute;top:20px;text-decoration:none;margin-left:150px;}
#reset:hover{color:blue}
#play{width:80px;height:40px; font-weight:bold;font-size:25px;margin:10px}
h2{font-size:40px}
#footer{margin-top:120px;display:none}
#play {background: #CCC;color: #333;border-radius: 5px;}
</style>
</head>

<body>
<div id="game">
<p><a href="#" id="reset">Reset</a></p>
<a >太空保龄球</a>
<div id="lay">
<div id="gameUI">
<div id="gameInfo">
<p><h2>Space bowling</h2></p>
<p>This is an awesome game.</p>
<p><button id="play">Play</buttom>
</div>
<div id="gameState">
<p>Asteroids:<label id="bowlNum"></label></p>
<p>&nbsp;&nbsp; Clicks:<label id="ClickNum"></label></p>

</div>
<div id="footer">
<h2>You Win!</h2>
<p>Congratulations,you completed</p>
<p>the game in clicks</p>
<p>Play again</p>

</div>
</div>
</div>
<canvas id="canvas"></canvas>
</div>
</body>
</html>
<script type="text/javascript">

var bowlNum=0;
var clickNum=0;
var viewWidth = 0;
var viewHeight = 0;
try{
viewWidth=document.documentElement.clientWidth;
viewHeight = document.documentElement.clientHeight;
}catch(e){
viewWidth = document.body.clientWidth;
viewHeight = document.body.clientHeight;
}
var canvas = document.getElementById("canvas");
//canvas.width=546
canvas.height=viewHeight;
canvas.width=viewWidth/2.5;

var context = canvas.getContext("2d");
var play = document.getElementById("play");

play.onclick=function(){//开始游戏
document.getElementById("gameInfo").style.display="none";
document.getElementById("footer").style.display="none";
drawBegin();
}

//创建小球类
function bowling(x,y,radius,mass,firction){
this.x = x;
this.y=y;
this.radius = radius;
this.mass = mass;
this.firction=firction;
this.vX=0;
this.vY=0;
this.player=true;
this.R=10;
}
var bowlingArr = new Array();

function drawBegin(){
context.fillStyle="#646464";
context.beginPath();
context.arc(canvas.width/2,160,80,0,2*Math.PI,true);
context.closePath();
context.fill();

context.fillStyle="#fff";
context.beginPath();
context.arc(canvas.width/2,canvas.height-60,10,0,2*Math.PI,true);
var playBowling = new bowling(canvas.width/2,canvas.height-60,0,100,10);
bowlingArr.push(playBowling);
context.closePath();
context.fill();

var radius = 0;
//画若干小球在圆台上
for(var i=0;i<8;i++){
var x=canvas.width/2;
var y=100;
radius=Math.PI/4*(i);
x = Math.floor(x+Math.sin(radius)*60);
y = Math.floor(y+60-Math.cos(radius)*60);
var tempalBowling = new bowling(x,y,10,100,0.95);
tempalBowling.vX=0;
tempalBowling.vY=0;
bowlingArr.push(tempalBowling);
context.beginPath();
context.arc(x,y,10,0,Math.PI*2,true);
context.closePath();
context.fill();
}

var tempalBowling = new bowling(canvas.width/2,160,10,100,0.95);
tempalBowling.vX=0;
tempalBowling.vY=0;
bowlingArr.push(tempalBowling);
context.beginPath();
context.arc(canvas.width/2,160,10,0,Math.PI*2,true);
context.closePath();
context.fill();

radius = 0;
for(var i=0;i<5;i++){
var x=canvas.width/2;
var y=130;
radius=Math.PI*0.4*(i+1);
x = Math.floor(x+Math.sin(radius)*30);
y = Math.floor(y+30-Math.cos(radius)*30);
var tempalBowling = new bowling(x,y,10,100,0.95);
tempalBowling.vX=0;
tempalBowling.vY=0;
bowlingArr.push(tempalBowling);
context.beginPath();
context.arc(x,y,10,0,Math.PI*2,true);
context.closePath();
context.fill();
}

//画一个拖动圆台 描述允许拖动的范围

}

//刷新
function UpdateUI(){
context.clearRect(0,0,canvas.width,canvas.height);

 

context.fillStyle="#646464";
context.beginPath();
context.arc(canvas.width/2,canvas.height-60,10,0,Math.PI*2,false);
context.closePath();
context.fill();
//圆台
context.fillStyle="#646464";
context.beginPath();
context.arc(canvas.width/2,160,80,0,2*Math.PI,true);
context.closePath();
context.fill();
//15个小球
for(var i=0;i<bowlingArr.length;i++){
if(bowlingArr.player==false)
continue;
context.fillStyle="#ffffff";
context.beginPath();
context.arc(bowlingArr[i].x,bowlingArr[i].y,bowlingArr[i].R,0,Math.PI*2,false);
context.closePath();
context.fill();
if(bowlingArr[i].player==true)
bowlNum++;
}
//更新圆台上小球的数量
document.getElementById("bowlNum").innerHTML=bowlNum;
//更新点击释放小球的次数
document.getElementById("ClickNum").innerHTML = clickNum;
deleteBowling();

}
//删除小球 重置小球
function deleteBowling(){
for(var i=1;i<bowlingArr.length;i++){
if(bowlingArr[i].vX!=0||bowlingArr[i].vY!=0){
var dx=Math.abs(bowlingArr[i].x-canvas.width/2);
var dy=Math.abs(bowlingArr[i].y-160);
var distance = Math.floor(Math.sqrt(dx*dx+dy*dy));
if(distance>80){
bowlingArr[i].R-=0.5;
if(bowlingArr[i].R<=0)
bowlingArr[i].R=0;
bowlingArr[i].player=false;//不将其计入游戏了
}
}
}
//重置拖拽的小球
if(bowlingArr[0].x>canvas.width||bowlingArr[0].y<0||bowlingArr[0].y>canvas.height||bowlingArr[0].y<0){
bowlingArr[0].R=10;
bowlingArr[0].x=canvas.width/2;
bowlingArr[0].y=canvas.height-60;
bowlingArr[0].vX=0;
bowlingArr[0].vY=0;
}
}

//重置游戏
document.getElementById("reset").onclick = function(e){
var evt = e||window.event;
if(!!evt.preventDefualt){
evt.preventDefualt();
}
else{
evt.returnValue=false;
}
document.getElementById("gameInfo").style.display="block";
context.clearRect(0,0,canvas.width,canvas.height);
bowlingArr.length=0;
}

 

//小球动画
function animate(){
//bowlingArr[0].y-=bowlingArr[0].vy;
for(var i=0;i<bowlingArr.length;i++){
//碰撞检测 方法是两两比较,如果碰撞,能量转化
var tempalA = bowlingArr[i];
for(var j=i+1;j<bowlingArr.length;j++){
var tempalB=bowlingArr[j];
var dx = Math.abs(tempalB.x-tempalA.x);
var dy = Math.abs(tempalB.y-tempalA.y);
var distanceAB = Math.sqrt(dx*dx+dy*dy); //勾股定理

//检测碰撞
if(distanceAB<=tempalA.R+tempalB.R){
//碰了
var angle =Math.atan2(dy,dx);

var sine = Math.sin(angle);
var cosin = Math.cos(angle);

var x=0;
var y=0;

var xB=dx*cosin+dy*sine;
var yB=dy*cosin+dx*sine;

var vy=tempalA.vX*cosin+tempalA.vY*sine;
var vx=tempalA.vY*cosin+tempalA.vX*sine;

var vBX = tempalB.vX*cosin+tempalB.vY*sine;
var vBY = tempalB.vY*cosin+tempalB.vX*sine;

var xTotal = vx-vBX;
vX = ((tempalA.mass-tempalB.mass)*vx+2*tempalB.mass*vBX)/(tempalA.mass+tempalB.mass);
vBX = xTotal+vx;
vY = ((tempalA.mass-tempalB.mass)*vy+2*tempalB.mass*vBY)/(tempalA.mass+tempalB.mass);
vBY = xTotal+vy;

xB = x+(tempalA.radius+tempalB.radius);

tempalA.x = tempalA.x+(x*cosin-y*sine);
tempalA.y = tempalA.y+(y*cosin+x*sine);

tempalB.x = tempalB.x+(xB*cosin-yB*sine);
tempalB.y = tempalB.y+(yB*cosin+yB*sine);

 

tempalA.vX = vx*cosin - vy*sine;
tempalA.vY = vy*cosin + vx*sine;

tempalB.vX = vBX*cosin - vBY*sine;
tempalB.vY = vBY*cosin + vBY*sine;

}
}
bowlingArr[i].x+=bowlingArr[i].vX;
bowlingArr[i].y+=bowlingArr[i].vY;

}
UpdateUI();
setTimeout(arguments.callee,40);
}

//监听鼠标拖拽,释放小球
var moveAble=false;
var dragable=false;
var clickYN = false;
canvas.onmousedown = function(){
if(bowlingArr[0].y>=canvas.height-60)//必须在这个范围才能拖拽小球
clickYN=true;
}
canvas.onmousemove = function(e){
if(clickYN==true){
dragable=true;
}
if(dragable==true){

//计算拖动角度
bowlingArr[0].x = e.clientX-canvas.offsetLeft;
bowlingArr[0].y = e.clientY-canvas.offsetTop;
bowlingArr[0].vX = -(bowlingArr[0].x-canvas.width/2);
bowlingArr[0].vY = -(bowlingArr[0].y-canvas.height+60);
UpdateUI();
}
}
canvas.onmouseup = function(){
clickYN=false;
if(dragable==true){
clickNum++;//点击次数增加
dragable=false;
moveAble=true;

//开始游戏
if(moveAble)
animate();
}
}
</script>

时间: 2024-11-05 12:25:51

HTML5 Canvas开发迷宫游戏例子的相关文章

分享29款基于 HTML5 Canvas 开发的网页游戏

现在,越来越多的人尝试用 HTML5 来制作网页游戏等丰富的 Web 应用.上次向大家推荐了21款最佳 HTML5 网页游戏,今天要与大家分享的是另外25款基于 HTML5 Canvas 开发的网页游戏,相信体验了这些游戏之后,大家都会觉得 HTML5 很好很强大. 1. 3Bored 2. 3D Tetris – Cubeout 3. A first person shooter 4. A torus style game 5. Agent 008 Ball 6. Asteroids 7. B

HTML5 Canvas捕获用于游戏开发的键盘、鼠标和触摸事件

学习如何处理键盘和鼠标事件,如何阻止 Web 浏览器的默认事件行为,以及如何向游戏对象的某种逻辑表示传播事件.此外,还将学习如何处理 iPhone 和 iPad 等移动设备上与设备无关的(device-agnostic)输入. 令拥有 Flash 或 Silverlight 背景的开发人员感到惊讶的是,为 HTML5 Canvas 编写的应用程序在处理用户输入方面并没有什么特立独行之处.实质上,从启用了 JavaScript 的 Web 浏览器诞生之初开始,HTML 用户输入就涉及到使用内置于浏

《HTML5 canvas开发详解(第2版)》——导读

前言第2版介绍自从本书第1版发行之后,在过去的两年里,HTML5 Canvas的使用有了突飞猛进的增长.本书的第1版可以称得上是第一批介绍Canvas的专著之一.在我们为自己的快速而感到自豪同时也意味着我们曾经独自进行了大量的研究和探索.早在2011年,只有极少数HTML5 Canvas应用的例子和教程.但在2013年情形发生了改变.现在有许多关于HTML5 Canvas的资源可供选择,从框架到API,有许多网站和书籍进行专门的阐述.为了编写第2版,我们进行了大量艰辛的工作来检查在第1版中哪些部

《HTML5 canvas开发详解(第2版)》——第1章 HTML5 Canvas简介1.1 什么是HTML5

第1章 HTML5 Canvas简介 HTML5是新一代的HTML,即超文本标记语言.HTML从1993年第一次标准化后,便奠定了万维网的基础.HTML通过使用将标签用尖括号(< >)括起来的方式定义Web页面内容. HTML5 Canvas是屏幕上的一个由JavaScript控制的即时模式位图区域.即时模式是指在画布上呈现像素的方式,HTML Canvas通过JavaScript调用Canvas API,在每一帧中完全重绘屏幕上的位图.作为一名程序员,所要做的就是在每一帧渲染之前设置屏幕的显

《HTML5 Canvas开发详解》——第1章 HTML5 Canvas简介1.1 基础的HTML页面

第1章 HTML5 Canvas简介 HTML5是新一代的HTML,即超文本标记语言.HTML从1993年第一次标准化后,便奠定了万维网的基础.HTML通过使用将标签用尖括号(< >)括起来的方式定义Web页面内容. HTML5 Canvas是屏幕上的一个由JavaScript控制的即时模式位图区域.即时模式是指在画布上呈现像素的方式,HTML Canvas通过JavaScript调用Canvas API,在每一帧完全重绘屏幕上的位图.作为一个程序员,所要做的就是在每一帧渲染之前设置屏幕显示,

《HTML5 Canvas开发详解》——导读

https://yqfile.alicdn.com/bc81e95aba389209ecb7176965c56b0ba2d9c780.png" > 前言HTML5 Canvas为开发者提供了一个新的机会,利用它仅使用普通的HTML和JavaScript语言就可以在常见的浏览器中创建动画图形.Canvas是HTML5中使用率最高的一部分,它被用于许多演示与游戏.它提供了视觉效果很棒的交互特性,而且它还提供了非常大的自由度,几乎允许开发者在浏览器窗口中做任何事情.然而它与JavaScript的

《HTML5 canvas开发详解(第2版)》——1.11 动画版本的Hello World

1.11 动画版本的Hello World "Hello World"和"猜字母"本身都是不错的示例,但是它们都没能回答出"为什么"--究竟为什么要使用HTML5 Canvas?自创立以来,静态的图像和文字就是HTML的领域,那么画布的不同之处在哪里呢?要回答这个问题,需要创建第二个"Hello World"示例.这个示例将介绍画布与HTML上的其他显示方式的最大不同之处:动画.在这个示例中,将为"Hello Wor

《HTML5 canvas开发详解(第2版)》——1.6 HTML5 Canvas版“Hello World!”

1.6 HTML5 Canvas版"Hello World!" 如前所述,将Canvas放入HTML5页面时第一件要做的事就是,看看整个页面是否已经加载,并且开始操作前是否所有HTML元素都已展现.在用Canvas处理图像和声音的时候,这点会非常重要. 为此,这里要使用JavaScript的事件.当定义的事件发生时,事件从对象发出.其他对象监听事件,这样就可以基于事件进行处理.用JavaScript可以监听对象的一些常见事件,包括键盘输入.鼠标移动以及加载结束. 第一个需要监听的事件是

《HTML5 Canvas开发详解》——1.5 HTML5 Canvas版“Hello World!”

1.5 HTML5 Canvas版"Hello World!" 如前所述,将Canvas放入HTML5页面时第一件要做的事,就是看看整个页面是否已经加载,并且开始操作前是否所有HTML元素都已展现.用Canvas处理图像和声音的时候这点会非常重要. 为此,这里要使用JavaScript的事件.当定义的事件发生时,事件从对象发出.其他对象监听事件,这样就可以基于事件进行处理.用JavaScript可以监听对象的一些常见事件,包括键盘输入.鼠标移动以及加载结束. 第一个需要监听的事件是wi