当前位置: 首页 > Web前端 > HTML5

基于nodejs环境,使用Phaser制作一个html5游戏

时间:2023-04-05 22:37:29 HTML5

最近对html5小游戏有点兴趣,于是在网上搜索了一些教程,自己学会了实现一个简单的flappybird。效果如下:今天给大家简单介绍下我的实现。相应的代码已经放在我的github上了。以下步骤涉及的资源资料均在代码中。1.创建节点项目。游戏主要由js控制,依赖服务器运行。这里我选择的是node环境,所以需要先创建一个node项目,这里就不详细介绍了。如果不行可以参考如何创建nodejs项目?.2、添加游戏相关的空架子创建完节点项目后,我们需要在这个框架结构中编写游戏。首先,我们需要搭建一个与游戏编码相关的空架子。目录结构如下:我们需要编辑的是views/index.ejs(相当于index.html,首页入口),public/images(游戏图片),public/Javascripts(游戏相关的js,main.js是主要编辑的js,phaser.min.js是基于游戏的技术实现)3.初始化修改node工程的主文件index.ejs,引入phaser和main.jshead>FlappyBirdClone4.游戏场景实例化接下来,我们需要编辑各种游戏场景来控制整个游戏过程并运行。这里需要在mainjs中实现,依赖于phaser这里就不详细介绍phaser了,不明白的可以查看官方文档,或者看这里。首先,这里设置了四个游戏场景:加载动画(bootState)、预加载(preloadState)、菜单(menuState)、游戏(mainState)。这里使用相位器的状态。首先根据四个场景的设计,搭建main.js的空架子,实例化一个游戏,如下://loadanimationvarbootState={};//preloadvarpreloadState={};//menuvarmenuState={};//游戏varmainState={};//实例化游戏vargame=newPhaser.Game(285,490);//将定义的场景添加到游戏中game.state.add('boot',bootState);game.state.add('preload',preloadState);game.state.add('menu',menuState);game.state.add('main',mainState);//调用开机场景开始游戏game.state.start('boot');5.加载动画我们设置游戏在开始时加载动画。这里有个小问题,就是这里的gif动画无法运行。这部分暂时没有优化,大家也可以跟着看。可选,您可以根据自己的喜好添加它。如果你不想要这块,只需将初始操作更改为预加载模块即可。代码如下:varbootState={preload:function(){game.load.image('loading','/images/flappybird/loading0.gif');//加载进度条图片资源},create:function(){game.state.start('preload');//加载完成后调用预加载场景}};6.调用preload场景游戏需要的所有资源都在这里加载,代码如下:varpreloadState={preload:function(){varpreloadSprite=game.add.sprite(0,0,'loading');//创建显示负载ing进度精灵game.load.setPreloadSprite(preloadSprite);//使用setPreloadSprite方法实现动态进度条的效果//下面是需要加载的资源game.load.image('background','/images/flappybird/bg_day.png');//游戏背景图片game.load.image('ground','/images/flappybird/land.png');//地面game.load.image('title','/images/flappybird/title.png');//游戏标题game.load.image('bird','/images/Flappy-bird.png');//birdgame.load.image('btn','/images/flappybird/button_play.png');//按钮game.load.image('pipe','/images/pipe.png');//管道game.load.audio('jump','/images/jump.wav');game.load.image('ready_text','/images/flappybird/text_ready.png');//准备好图像game.load.image('play_tip','/images/flappybird/tutorial.png');//游戏提示图片game.load.image('game_over','/images/flappybird/text_game_over.png');//游戏结束图像game.load.image('score_board','/images/flappybird/score_panel.png');//得分面板},创建:函数(){game.state.start('菜单');//当以上所有资源加载完成后,即可进入菜单游戏菜单场景}};7、进入菜单场景加载资源后开始进入游戏的菜单页面,从这里开始就是整个游戏的主体。菜单分为背景、楼层、标题组(包括标题和小鸟)和按钮(游戏开始入口)四部分。实现效果如图:实现原理:(1)背景和地面:我们看到这两个东西是可以移动的,地面移动的比较快,背景图片比较慢。Phaser中有一个特殊的东西来处理这个效果,叫做TileSprite,什么是TileSprite?TileSprite本质上还是一个sprite对象,但是这个sprite的贴图是可以移动的,移动后会自动平铺弥补空隙,所以如果我们的素材图平铺后没有出现空隙,就可以现在用作TileSprite的移动纹理。TileSprite的纹理可以水平或垂直移动,或同时移动。我们只需要调用TileSprite对象的autoScroll(x,y)方法就可以让它的纹理动起来,其中x是水平方向的速度,y是垂直方向的速度。varmenuState={create:function(){game.add.tileSprite(0,0,game.width,game.height,'background').autoScroll(-10,0);//背景图game.add.tileSprite(0,game.height-80,game.width,112,'ground').autoScroll(-100,0);//地面}};(2)标题组:我们可以看到标题组有标题文字和小鸟,两者还是动态的,一起上下移动,这里用到的是Phaser.Group,也就是组。一个组相当于一个父容器。我们可以把很多对象放到一个组中,然后使用组提供的方法对这些对象进行批量或整体的操作。我们把标题文字和小鸟放到这个组里,对这个组进行整体操作。varmenuState={create:function(){...vartitleGroup=game.add.group();//创建一个组来存储标题titleGroup.create(0,0,'title');//标题varbird=titleGroup.create(190,10,'bird');//将鸟添加到组中bird.animations.add('fly');//添加动画bird.animations.play('fly',12,true);//播放动画titleGroup.x=35;标题组.y=100;game.add.tween(titleGroup).to({y:120},1000,null,true,0,Number.MAX_VALUE,true);//标题的补间动画,给这个组添加一个补间动画,让它不断上下移动}};(3)按钮:按钮就是给个图片,然后添加点击事件,点击开始游戏的场景varmenuState={create:function(){......varbtn=game.add.button(game.width/2,game.height/2,'btn',function(){//button//点击启动主游戏场景game.state.start('main');});btn.anchor.setTo(0.5,0.5);}};8.游戏场景是整个游戏的亮点,从这里开始操作和玩游戏,整个过程都在mainState中完成。至于每一个游戏的小部分,都是靠里面的各种函数体来控制完成的。首先,游戏准备部分。游戏开始前,会给出简单的游戏教程说明。这里是整体的Static:(1)初始化背景(2)创建一个存放管道的组(3)打开地面物理系统,但保持地面不动(4)开启小鸟的物理系统,但先让小鸟保持不动(5)Titlehead(6)教程图,添加点击事件,点击开始游戏varmainState={create:function(){this.background=game.add.tileSprite(0,0,game.width,game.height,'background');//背景图this.pipeGroup=game.add.group();//用于存储管道的组,this.pipeGroup.enableBody=true;this.ground=game.add.tileSprite(0,game.height-80,game.width,112,'ground');//Floorgame.physics.enable(this.ground,Phaser.Physics.ARCADE);//启用地面的物理系统this.ground.body.immovable=true;//让地面在物理环境中不动this.bird=game.add.sprite(50,150,'bird');//birdgame.physics.enable(this.bird,Phaser.Physics.ARCADE);//启用小鸟的物理系统this.bird.body.gravity.y=0;//小鸟的重力,在开始游戏之前先让重力为0,否则小鸟会掉下来this.readyText=game.add.image(game.width/2,40,'ready_text');//准备文本this.playTip=game.add.image(game.width/2,300,'play_tip');//提示点击屏幕图像this.readyText.anchor.setTo(0.5,0);this.playTip.anchor.setTo(0.5,0);//game.time.events.stop(false);//先不要开始计时game.input.onDown.addOnce(this.startGame,this);//点击屏幕正式开始游戏},}然后,开始玩游戏(1)从startGame函数开始,玩游戏的主题函数让背景和地面开始移动,开启重力系统小鸟的,点击屏幕让小鸟起飞,去掉游戏准备阶段的标题头和提示图,管道开始移动,然后在左上角显示分数。通过update更新游戏状态varmainState={create:function(){...},startGame:function(){this.gameSpeed=200;//游戏速度this.background.autoScroll(-(this.gameSpeed/10),0);//让背景开始移动this.ground.autoScroll(-this.gameSpeed,0);//让地面开始移动//Birdgame.physics.arcade.enable(this.bird);this.bird.body.gravity.y=1000;this.readyText.destroy();//移除'getready'图片this.playTip.destroy();//去掉'playtip'图片varspaceKey=game.input.keyboard.addKey(Phaser.Keyboard.SPACEBAR);spaceKey.onDown.add(this.jump,this);//管道this.pipes=game.add.group();//定时器,每1.5秒调用一次addRowOfPipesthis.timer=game.time.events.loop(1500,this.addRowOfPipes,this);//得分:在左上角显示得分this.score=0;this.labelScore=game.add.text(20,20,"0",{font:"30pxArial",fill:"#ffffff"});//改变小鸟旋转的中心点this.bird.anchor.setTo(-0.2,0.5);//声音this.jumpSound=game.add.audio('jump');},/***最后一个update方法是一个update函数,会在游戏的每一帧执行,创建一个Dynamicgame*/update:function(){//如果小鸟超出范围,游戏会重新开始如果(this.bird.y<0||this.bird.y>490)this.restartGame();//小鸟慢慢向下旋转直到某一点if(this.bird.angle<20)this.bird.angle+=1;//当小鸟死亡时,重新开始游戏//game.physics.arcade.overlap(this.bird,this.pipes,this.restartGame,null,this);//当小鸟死亡时,它会从屏幕上掉下来game.physics.arcade.overlap(this.bird,this.pipes,this.hitPipe,null,this);},(2)跳跃函数:点击屏幕控制小鸟跳跃的飞行状态:function(){//小鸟死后不能跳跃if(this.bird.alive==false)return;//点击屏幕,小鸟重力系数变为负值,可以起飞this.bird.body.velocity.y=-350;//小鸟跳起来的时候向上旋转game.add.tween(this.bird).to({angle:-20},100).start();//小鸟起飞的音效this.jumpSound.play();},(3)管道组:创建管道和管道组,通过startGame设备添加计时控制流水线的时序产生和移动,然后这里有一个分数计算。这里的设置是每生成一个pipeline,就加一个点。addOnePipe:function(x,y){varpipe=game.add.sprite(x,y,'pipe');this.pipes.add(管道);game.physics.arcade.enable(管道);pipe.body.velocity.x=-200;pipe.checkWorldBounds=true;pipe.outOfBoundsKill=true;},addRowOfPipes:function(){//在1到5之间随机选择一个数字//这将是洞的位置varhole=Math.floor(Math.random()*5)+1;//添加6个管道//在位置'hole'和'hole+1'有一个大孔for(vari=0;i<8;i++)if(i!=hole&&i!=hole+1)this.addOnePipe(285,i*60+10);//每创建一个新管道就给分数加1this.score+=1;这个.labelScore。text=this.score;},(3)下一步是判断小鸟在撞到管道时死亡hitPipe:function(){//如果小鸟已经撞到管道,则什么都不做//这意味着小鸟已经从screenif(this.bird.alive==false)返回;//设置小鸟的alive属性为falsethis.bird.alive=false;//防止新管道出现game.time.events.remove(this.timer);//遍历所有管道,并停止它们的移动this.pipes.forEach(function(p){p.body.velocity.x=0;},this);}(4)最后,当小鸟死亡时,游戏结束,这个时候需要启动设置重启游戏,设置跳转菜单页面。//重启游戏restartGame:function(){game.state.start('menu');},就到这里了,有兴趣的可以在github上fork我的代码!如果觉得不错,请给个赞!!