JS+HTML实现经典游戏吃豆人_第1页
JS+HTML实现经典游戏吃豆人_第2页
JS+HTML实现经典游戏吃豆人_第3页
JS+HTML实现经典游戏吃豆人_第4页
JS+HTML实现经典游戏吃豆人_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第JS+HTML实现经典游戏吃豆人目录前言HTML代码JS代码游戏截图

前言

很早就知道canvas,当时一直没应用到,最近闲来无事就顺便写写看。吃豆游戏可以说是我们80,90后共同的回忆录,小时候常常在学习机上玩,所以也就有了强烈的欲望去写。为了写这个游戏,看了很多吃豆人游戏的相关信息,包括游戏规则,历史,其它相关游戏设计。又去了各个小游戏平台玩了下,找些灵感!!!就连最简单的配色,也是反复斟酌几个小时确定的方案哈哈,不容易啊代码分两部分,游戏引擎和游戏主程序,引擎用来类的定义,管理动画场景,事件定义等等游戏主程序主要组织业务逻辑。算面向对象编程吧,纯手工打造是男人就吃光所有豆子!!!

项目结构

因需要四个文件即可实现,index.html游戏主页,index.js主页控制,game.js游戏控制,favicon.png图标。代码简单,易懂。后续小伙伴们还可以自己加入音乐!可以部署到服务器上,也可用浏览器直接打开index.html玩耍!!!

HTML代码

html

head

metacharset="utf8"

titlePac-Man.吃豆游戏/title

linkrel="shortcuticon"href="favicon.png"rel="externalnofollow"

style

body{background-color:#292929}

*{padding:0;margin:0;}

.wrapper{

width:960px;

margin:0auto;

line-height:36px;

text-align:center;

color:#999;

canvas{display:block;background:#000;}

.mod-botton{

height:32px;

padding:15px0;

text-align:center;

/style

/head

body

div

canvasid="canvas"width="960"height="640"不支持画布/canvas

p按[空格]暂停或继续/p

/div

scriptsrc="game.js"/script

scriptsrc="index.js"/script

/body

/html

JS代码

//主程序,业务逻辑

(function(){

var_DATA=[//地图数据

[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],

[1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1],

[1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1],

[1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1],

[1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1],

[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],

[1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1],

[1,0,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,0,1],

[1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1],

[1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,1,1,1,2,2,1,1,1,0,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,1,2,2,2,2,2,2,1,0,1,1,0,1,1,1,1,1,1],

[0,0,0,0,0,0,0,0,0,0,1,2,2,2,2,2,2,1,0,0,0,0,0,0,0,0,0,0],

[1,1,1,1,1,1,0,1,1,0,1,2,2,2,2,2,2,1,0,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1],

[1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1],

[1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1],

[1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1],

[1,0,1,1,1,1,0,1,1,1,1,1,0,1,1,0,1,1,1,1,1,0,1,1,1,1,0,1],

[1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,1],

[1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1],

[1,1,1,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,0,1,1,0,1,1,0,1,1,1],

[1,0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,1],

[1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1],

[1,0,1,1,1,1,1,1,1,1,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,1],

[1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],

[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]

_GOODS={//能量豆

'1,3':1,

'26,3':1,

'1,23':1,

'26,23':1

_COS=[1,0,-1,0],

_SIN=[0,1,0,-1],

_COLOR=['#F00','#F93','#0CF','#F9C'],//红,橙,

_LIFE=3,

_SCORE=0;//得分

vargame=newGame('canvas');

//启动页

(function(){

varstage=game.createStage();

//logo

stage.createItem({

x:game.width/2,

y:game.height*.45,

width:100,

height:100,

frames:3,

draw:function(context){

vart=Math.abs(5-this.times%10);

context.fillStyle='#FFE600';

context.beginPath();

context.arc(this.x,this.y,this.width/2,t*.04*Math.PI,(2-t*.04)*Math.PI,false);

context.lineTo(this.x,this.y);

context.closePath();

context.fill();

context.fillStyle='#000';

context.beginPath();

context.arc(this.x+5,this.y-27,7,0,2*Math.PI,false);

context.closePath();

context.fill();

//游戏名

stage.createItem({

x:game.width/2,

y:game.height*.6,

draw:function(context){

context.font='bold42pxHelvetica';

context.textAlign='center';

context.textBaseline='middle';

context.fillStyle='#FFF';

context.fillText('Pac-Man',this.x,this.y);

//版权信息

stage.createItem({

x:game.width-12,

y:game.height-5,

draw:function(context){

context.font='14pxHelvetica';

context.textAlign='right';

context.textBaseline='bottom';

context.fillStyle='#AAA';

context.fillText('©',this.x,this.y);

//事件绑定

stage.bind('keydown',function(e){

switch(e.keyCode){

case13:

case32:

game.nextStage();

break;

})();

//游戏主程序

(function(){

varstage,map,beans,player,times;

stage=game.createStage({

update:function(){

varstage=this;

if(stage.status==1){//场景正常运行

items.forEach(function(item){

if(map!map.get(item.coord.x,item.coord.y)!map.get(player.coord.x,player.coord.y)){

vardx=item.x-player.x;

vardy=item.y-player.y;

if(dx*dx+dy*dy750item.status!=4){//物体检测

if(item.status==3){

item.status=4;

_SCORE+=10;

}else{

stage.status=3;

stage.timeout=30;

if(JSON.stringify(beans.data).indexOf(0)0){//当没有物品的时候,进入结束画面

game.nextStage();

}elseif(stage.status==3){//场景临时状态

if(!stage.timeout){

_LIFE--;

if(_LIFE){

stage.resetItems();

}else{

game.nextStage();

returnfalse;

//绘制地图

map=stage.createMap({

x:60,

y:10,

data:_DATA,

cache:true,

draw:function(context){

context.lineWidth=2;

for(varj=0;jthis.y_length;j++){

for(vari=0;ithis.x_length;i++){

varvalue=this.get(i,j);

if(value){

varcode=[0,0,0,0];

if(this.get(i+1,j)!(this.get(i+1,j-1)this.get(i+1,j+1)this.get(i,j-1)this.get(i,j+1))){

code[0]=1;

if(this.get(i,j+1)!(this.get(i-1,j+1)this.get(i+1,j+1)this.get(i-1,j)this.get(i+1,j))){

code[1]=1;

if(this.get(i-1,j)!(this.get(i-1,j-1)this.get(i-1,j+1)this.get(i,j-1)this.get(i,j+1))){

code[2]=1;

if(this.get(i,j-1)!(this.get(i-1,j-1)this.get(i+1,j-1)this.get(i-1,j)this.get(i+1,j))){

code[3]=1;

if(code.indexOf(1)-1){

context.stroke"#FFF":"#09C";

varpos=this.coord2position(i,j);

switch(code.join('')){

case'1100':

context.beginPath();

context.arc(pos.x+this.size/2,pos.y+this.size/2,this.size/2,Math.PI,1.5*Math.PI,false);

context.stroke();

context.closePath();

break;

case'0110':

context.beginPath();

context.arc(pos.x-this.size/2,pos.y+this.size/2,this.size/2,1.5*Math.PI,2*Math.PI,false);

context.stroke();

context.closePath();

break;

case'0011':

context.beginPath();

context.arc(pos.x-this.size/2,pos.y-this.size/2,this.size/2,0,.5*Math.PI,false);

context.stroke();

context.closePath();

break;

case'1001':

context.beginPath();

context.arc(pos.x+this.size/2,pos.y-this.size/2,this.size/2,.5*Math.PI,1*Math.PI,false);

context.stroke();

context.closePath();

break;

default:

vardist=this.size/2;

code.forEach(function(v,index){

if(v){

context.beginPath();

context.moveTo(pos.x,pos.y);

context.lineTo(pos.x-_COS[index]*dist,pos.y-_SIN[index]*dist);

context.stroke();

context.closePath();

//物品地图

beans=stage.createMap({

x:60,

y:10,

data:_DATA,

frames:8,

draw:function(context){

for(varj=0;jthis.y_length;j++){

for(vari=0;ithis.x_length;i++){

if(!this.get(i,j)){

varpos=this.coord2position(i,j);

context.fillStyle="#F5F5DC";

if(_GOODS[i+','+j]){

context.beginPath();

context.arc(pos.x,pos.y,3+this.times%2,0,2*Math.PI,true);

context.fill();

context.closePath();

}else{

context.fillRect(pos.x-2,pos.y-2,4,4);

//得分

stage.createItem({

x:690,

y:100,

draw:function(context){

context.font='bold28pxHelvetica';

context.textAlign='left';

context.textBaseline='bottom';

context.fillStyle='#C33';

context.fillText('SCORE',this.x,this.y);

context.font='28pxHelvetica';

context.textAlign='left';

context.textBaseline='top';

context.fillStyle='#FFF';

context.fillText(_SCORE,this.x+12,this.y);

//状态文字

stage.createItem({

x:690,

y:320,

frames:25,

draw:function(context){

if(stage.status==2this.times%2){

context.font='24pxHelvetica';

context.textAlign='left';

context.textBaseline='center';

context.fillStyle='#09F';

context.fillText('PAUSE',this.x,this.y);

//生命值

stage.createItem({

x:705,

y:540,

width:30,

height:30,

draw:function(context){

for(vari=0;i_LIFE-1;i++){

varx=this.x+40*i,y=this.y;

context.fillStyle='#FFE600';

context.beginPath();

context.arc(x,y,this.width/2,.15*Math.PI,-.15*Math.PI,false);

context.lineTo(x,y);

context.closePath();

context.fill();

//NPC

for(vari=0;ii++){

stage.createItem({

width:30,

height:30,

orientation:3,

color:_COLOR[i],

location:map,

coord:{x:12+i,y:14},

vector:{x:12+i,y:14},

type:2,

frames:10,

speed:1,

timeout:Math.floor(Math.random()*120),

update:function(){

varnew_map;

if(this.status==3!this.timeout){

this.status=1;

if(!this.coord.offset){//到达坐标中心时计算

if(this.status==1){

if(!this.timeout){//定时器

new_map=JSON.parse(JSON.stringify(map.data).replace(/2/g,0));

varid=this._id;

items.forEach(function(item){

if(item._id!=iditem.status==1){//NPC将其它所有还处于正常状态的NPC当成一堵墙

new_map[item.coord.y][item.coord.x]=1;

this.path=map.finder({

map:new_map,

start:this.coord,

end:player.coord

if(this.path.length){

this.vector=this.path[0];

}elseif(this.status==3){

new_map=JSON.parse(JSON.stringify(map.data).replace(/2/g,0));

varid=this._id;

items.forEach(function(item){

if(item._id!=id){

new_map[item.coord.y][item.coord.x]=1;

this.path=map.finder({

map:new_map,

start:player.coord,

end:this.coord,

type:'next'

if(this.path.length){

this.vector=this.path[Math.floor(Math.random()*this.path.length)];

}elseif(this.status==4){

new_map=JSON.parse(JSON.stringify(map.data).replace(/2/g,0));

this.path=map.finder({

map:new_map,

start:this.coord,

end:this._params.coord

if(this.path.length){

this.vector=this.path[0];

}else{

this.status=1;

//是否转变方向

if(this.vector.change){

this.coord.x=this.vector.x;

this.coord.y=this.vector.y;

varpos=map.coord2position(this.coord.x,this.coord.y);

this.x=pos.x;

this.y=pos.y;

//方向判定

if(this.vector.xthis.coord.x){

this.orientation=0;

}elseif(this.vector.xthis.coord.x){

this.orientation=2;

}elseif(this.vector.ythis.coord.y){

this.orientation=1;

}elseif(this.vector.ythis.coord.y){

this.orientation=3;

this.x+=this.speed*_COS[this.orientation];

this.y+=this.speed*_SIN[this.orientation];

draw:function(context){

varisSick=false;

if(this.status==3){

isSick=this.timeout80||this.times%2true:false;

if(this.status!=4){

context.fillStyle=isSick'#BABABA':this.color;

context.beginPath();

context.arc(this.x,this.y,this.width*.5,0,Math.PI,true);

switch(this.times%2){

case0:

context.lineTo(this.x-this.width*.5,this.y+this.height*.4);

context.quadraticCurveTo(this.x-this.width*.4,this.y+this.height*.5,this.x-this.width*.2,this.y+this.height*.3);

context.quadraticCurveTo(this.x,this.y+this.height*.5,this.x+this.width*.2,this.y+this.height*.3);

context.quadraticCurveTo(this.x+this.width*.4,this.y+this.height*.5,this.x+this.width*.5,this.y+this.height*.4);

break;

case1:

context.lineTo(this.x-this.width*.5,this.y+this.height*.3);

context.quadraticCurveTo(this.x-this.width*.25,this.y+this.height*.5,this.x,this.y+this.height*.3);

context.quadraticCurveTo(this.x+this.width*.25,this.y+this.height*.5,this.x+this.width*.5,this.y+this.height*.3);

break;

context.fill();

context.closePath();

context.fillStyle='#FFF';

if(isSick){

context.beginPath();

context.arc(this.x-this.width*.15,this.y-this.height*.21,this.width*.08,0,2*Math.PI,false);

context.arc(this.x+this.width*.15,this.y-this.height*.21,this.width*.08,0,2*Math.PI,false);

context.fill();

context.closePath();

}else{

context.beginPath();

context.arc(this.x-this.width*.15,this.y-this.height*.21,this.width*.12,0,2*Math.PI,false);

context.arc(this.x+this.width*.15,this.y-this.height*.21,this.width*.12,0,2*Math.PI,false);

context.fill();

context.closePath();

context.fillStyle='#000';

context.beginPath();

context.arc(this.x-this.width*(.15-.04*_COS[this.orientation]),this.y-this.height*(.21-.04*_SIN[this.orientation]),this.width*.07,0,2*Math.PI,false);

context.arc(this.x+this.width*(.15+.04*_COS[this.orientation]),this.y-this.height*(.21-.04*_SIN[this.orientation]),this.width*.07,0,2*Math.PI,false);

context.fill();

context.closePath();

items=stage.getItemsByType(2);

//主角

player=stage.createItem({

width:30,

height:30,

type:1,

location:map,

coord:{x:13.5,y:23},

orientation:2,

speed:2,

frames:10,

update:function(){

varcoord=this.coord;

if(!coord.offset){

if(this.control.orientation!='undefined'){

if(!map.get(coord.x+_COS[this.control.orientation],coord.y+_SIN[this.control.orientation])){

this.orientation=this.control.orientation;

this.control={};

varvalue=map.get(coord.x+_COS[this.orientation],coord.y+_SIN[this.orientation]);

if(value==0){

this.x+=this.speed*_COS[this.orientation];

this.y+=this.speed*_SIN[this.orientation];

}elseif(value0){

this.x-=map.size*(map.x_length-1)*_COS[this.orientation];

this.y-=map.size*(map.y_length-1)*_SIN[this.orientation];

}else{

if(!beans.get(this.coord.x,this.coord.y)){//吃豆

_SCORE++;

beans.set(this.coord.x,this.coord.y,1);

if(_GOODS[this.coord.x+','+this.coord.y]){//吃到能量豆

items.forEach(function(item){

if(item.status==1||item.status==3){//如果NPC为正常状态,则置为临时状态

item.timeout=450;

item.status=3;

this.x+=this.speed*_COS[this.orientation];

this.y+=this.speed*_SIN[this.orientation];

draw:function(context){

context.fillStyle='#FFE600';

context.beginPath();

if(stage.status!=3){//玩家正常状态

if(this.times%2){

context.arc(this.x,this.y,this.width/2,(.5*this.orientation+.20)*Math.PI,(.5*this.orientation-.20)*Math.PI,false);

}else{

context.arc(this.x,this.y,this.width/2,(.5*this.orientation+.01)*Math.PI,(.5*this.orientation-.01)*Math.PI,fals

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论