Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/yuwanli/phaser-collection
phaser h5小游戏项目集锦
https://github.com/yuwanli/phaser-collection
cocos-creator hammerjs phaser
Last synced: about 1 month ago
JSON representation
phaser h5小游戏项目集锦
- Host: GitHub
- URL: https://github.com/yuwanli/phaser-collection
- Owner: yuwanli
- Created: 2017-07-16T11:56:14.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2017-07-17T11:55:32.000Z (over 7 years ago)
- Last Synced: 2024-09-29T23:38:58.486Z (about 2 months ago)
- Topics: cocos-creator, hammerjs, phaser
- Language: JavaScript
- Homepage:
- Size: 24.9 MB
- Stars: 191
- Watchers: 5
- Forks: 59
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- Changelog: news_yearPlan/demo.html
Awesome Lists containing this project
README
phaser h5小游戏项目集锦
===========================之前写了一篇[我做过的h5](https://github.com/yuwanli/collection-mobile-page/blob/master/README.md),就是按照使用的库做了一个分类,有一类就是phaser类,这个是我有一段时间里常用也非常爱用的一个游戏框架。
简单说下[phaser](https://github.com/photonstorm/phaser)吧,这个框架是我老大推荐我使用的,是他先开始使用的,他让我有时间就看看这个框架。对于一个前端菜鸟来说,我选择框架的基本原则就是,先入为主,能用,方便用,好用即可。简单的说就是有丰富的示例及代码,然后有完善的文档和社区供解决具体问题。phaser就有我说的这些,但是刚开始使用的时候,存在的问题是,示例是在线示例,查看的时候加载需要很长时间,等待时间略长。后来找到了这个[phaser-examples](https://github.com/photonstorm/phaser-examples/),可以在本地配一个简单的服务器,本地运行demo,这样可以快速查看示例和源码。
![phaser-examples](readme-images/1.png "phaser-examples")
那这里解释下,为啥最近我开始疯狂的写readme文档,是我开始发现这个东西的重要性,今年离职了几个前端,好多他们的代码交接到了我这里,在阅读和修改他们的代码的时候遇到了重重困难,不是说他们代码写的不好(确实有些写的不好/捂脸),而是每个前端的代码风格会有差异,特别是没有注释习惯的情况下(我就不太会给很详细的注释),代码的维护性和可读性就会变的很差。
还有一个很重要的原因是,自从参加了腾讯的2017年的前端大会以后,我就立志要成为一个有情怀的前端老大哥(目前还只是前端小菜鸟),所以希望readme的形式去和后来的前端去分享我做这个时候的想法、我的项目结构,我使用了哪些插件及使用的原因,当然还有遇到的一些问题,通过这样的一个方式把项目交接给下一个人。其实吧,个人觉得readme是使你写的项目变得有价值一个重要手段,如果没有好的readme,后期就不会有人愿意去查阅和维护你的项目代码,最终只会因为你的代码可读性和复用性太差导致弃用然后重写。由于公司的项目有保密协议,所以github上只能推readme和部分demo代码,当然我也会推一份到公司内部gitlab上,附有完整的源码(本人是本着分享和学习的态度,其实是希望能po上项目源码的,若有对源码有兴趣的可以私聊我)。
---------------------
下面就是对具体的项目进行解析了,如果你已经是一个前端大神,请以查阅和检查错误的姿势来看下面的内容(/捂脸)。
### [2016年终策划-重走2016](http://mat1.gtimg.com/zj/yuwanli/dzw1612/news_yearPlan/index.html)
![2016年终策划-重走2016](readme-images/2.png "2016年终策划-重走2016")
![2016年终策划-重走2016](readme-images/3.jpg "2016年终策划-重走2016")
* h5的需求:
* 投骰子的方式决定行走多少步
* 会有前进、后退和暂停
* 有些隐藏的点,用于统计得出最后的结果(称号)这里之所以把这个项目放在第一个讲,是因为我觉得这个项目达到了我预期的效果-可复用性,所以下面会说的比较详细。我做的h5中,这种互动类型的h5大多都是一次性的,不仅是代码还是互动形式的可复用性都较差,不适合复用,仅限一次使用。当时拿到这个需求的时候,我觉得这个互动形式上可以很好的进行复用,把能抽象出来的东西全部抽象到一个`data.js`文件中,所以项目结构上和代码实现上尽量保证复用性。
大家也可以想下,如果这样的一个需求的h5让你做,你会用什么样的方式去做这个h5,用什么样的框架和方式,如何去实现人物走到每个随机位置、及特殊位置的处理(前进后退)、结果的统计、人物的转向等等问题。
拿到这个的时候,我第一个想到的其实是用cocos creater(由于之前有了解过cosos的相关产品),让我想到用这个的原因主要是因为,棋盘和地图形式的h5,觉得可以用这种可视化的方式开发,直接选点或者画框去确定一个区域,具体位置不用人为的去量。然后动画的编辑上,也能通过可视化的方式,而且可以在动画中,具体某一帧加入js代码,然后就是希望能尝试新的开发框架和开发形式。
差不多通过了一天的简单学习,开始尝试去做。但最终还是用了phaser,这不是对cocos creater的否定,只是因为自己功力不够,这种可视化的游戏开发,其实对开发者的要求很高,一个要有代码基础,然后就是游戏制作的基础,动画可视化编辑的基础。总之,我要是用这个做的话,肯定得花很多时间,而且一旦遇到问题,可能很难以下就能解决。在这种情况下,果断放弃。这里也是自己的一个原则,新的东西可以尝试,但一旦发现这个可能会严重影响到工作进度,且不是一下能吃下的东西,浅尝即止,了解下即可。
![cocos creater](readme-images/4.png "cocos creater")
然后具体的phaser的使用上就是为了实现人物的运动(移动及转向),和骰子的投掷,具体的可以查看[demo.html](news_yearPlan/demo.html),这里人物做了先向右,然后向下的运动(人物的转向也会变)。然后骰子有个降落和反弹的物理效果,点击骰子有个向上抛掷的效果,再次点击有随机出现点数的效果。以上的这些效果也就本项目抽象出来的几个基本效果。
人物的动画及转向的变化主要通过播放帧的变化来实现,每个方向切成两帧,即左右左。
![player](readme-images/player.png "player")
```javascript
//添加人物4个方向的动画
_this.player.animations.add("player_back",[0,1],5,true);
_this.player.animations.add("player_left",[2,3],5,true);
_this.player.animations.add("player_down",[4,5],5,true);
_this.player.animations.add("player_right",[6,7],5,true);//先向右运动然后向左运动
var tween1 = _this.game.add.tween(_this.player).to({ x: this.circle2.x }, 4000, Phaser.Easing.Linear.None, true, 0, 0);
var tween2 = _this.game.add.tween(_this.player).to({ y: this.circle3.y }, 4000, Phaser.Easing.Linear.None, false, 0, 0);
tween1.onComplete.add(function(){_this.player.animations.play("player_down");},this)
tween1.chain(tween2);
```然后人物的移动,通过phaser内置的tween函数来实现,demo中时间是固定的,具体实现的时候,可以从某一点运到到另一点的时间通过距离和速度来计算,这样就可以实现一个匀速运动的效果。但是最终使用了物理引擎,利用碰撞的效果来实现,人物的中线为一个碰撞线,另一个点为一个碰撞点,人物给一个固定方向的速度,运动这个点的时候即可停止再进行判断。前面说的通过距离来算的方式,存在的问题是,每次计算都会有误差,当运动次数多的时候,误差会被放大,最终会导致的效果就是人物,运动到的点不是预计中到达的位置。
![collisionPlayer](readme-images/5.png "collisionPlayer")
那之前说的把棋盘上的点抽象出来是怎么做的呢,可以查看项目源码直接查看data.js文件,就能大概知道了。
```javascript
{//
"x":"378",//xy为改点距离棋盘左上角定点的距离
"y":"77",
"dir":"player_right",//正向行走的时候,人物的转向
"_dir":"player_left",//反向行走的时候,人物的转向
"speak":'2',//气泡的类型(最右端,最顶端,最左端等特殊情况下,气泡出现的位置不一样)
"text":"施主,\n馒头泡稀饭——\n粥润发",//气泡中的文字
"result":"r8",//用于统计结果,该情况下会导致r8+1
"alertInfo":{//隐藏点
"h1":"灵隐寺",
"p":"恭喜,前进2步。你喝了一碗灵隐寺的腊八粥,身心温暖。",
"status":"2"//正数则前进对应步数,负数则后退对应步数,stop则暂停三秒
}
}
```
这里把棋盘上的点抽象成一个对象,其中包含一个点的所有信息,渲染的时候并不是去把所有的点都渲染出来,渲染出来的永远只有一个点`collisionPlayer`,意思就是player要去碰撞的点,其实想象成踢皮球,人物行进4格,其实是一个前进函数运行了4次,皮球永远在下一个点,当人物到达这个点的时候,皮球就到下一个点了。需要后退的时候,会把方向变掉,这里要注意的是,在一些转折点的地方,正向和反向经过时播放人物动画的转向需要人为的去判断。所以,投骰得到一个数字以后,会把这个数值赋给一个变量num,然后去执行`godes()`函数,也就是行走到`collisionPlayer`所在的位置,然后`num--`,不为0的话继续执行,为0的话表示行走完毕,这个时候就去判断是否为隐藏点。需要前进的话,重新赋值`num`,然后执行`godes()`,若是后退的话,先改变方向值,然后执行`godes()`。```javascript
_this.goDes = function(){
_this.diceCan = false;//锁机制,行走过程中,不可投骰
if(_this.num==0){//行走至目的地,
var p = jsonData[_this.index];
_this.diceCan = true;
_this.initSpeak(p.speak,p);
_this.walking = false;
_this.collisionPlayer.x = 0;//important
_this.collisionPlayer.y = 0;//important
return
}
var p = jsonData[_this.index]
if(_this.direction){//判断当前的运动方向
_this.player.play(p.dir)
}else{
_this.player.play(p._dir)
}
if(_this.num>0){//前进
_this.direction = true;
_this.walking = true;_this.index++;
_this.collisionPlayer.x = jsonData[_this.index].x/100*ratio+_this.left
_this.collisionPlayer.y = jsonData[_this.index].y/100*ratio+_this.top
var i = _this.index-1
if(Math.abs(parseInt(jsonData[_this.index].x)-parseInt(jsonData[i].x))>0){
if(parseInt(jsonData[_this.index].x)-parseInt(jsonData[i].x)>0){
_this.player.body.velocity.x=_this.player_v;
}else{
_this.player.body.velocity.x=-_this.player_v;
}
_this.player.body.setSize(1,_this.player.height,-0.1*_this.player.width,0)//这里设置的是人物的碰撞线
}else{
_this.player.body.setSize(_this.player.width,1,0,0.1*_this.player.height)
_this.player.body.velocity.y=_this.player_v
}
// _this.num-=1;
// _this.goDes(callback)
}
if(_this.num<0){//前进
_this.direction = false;
_this.walking = true;
_this.index--;
_this.collisionPlayer.x = jsonData[_this.index].x/100*ratio+_this.left
_this.collisionPlayer.y = jsonData[_this.index].y/100*ratio+_this.top
var i = _this.index+1
if(Math.abs(parseInt(jsonData[_this.index].x)-parseInt(jsonData[i].x))>0){
if(parseInt(jsonData[_this.index].x)-parseInt(jsonData[i].x)>0){
_this.player.body.velocity.x=_this.player_v
}else{
_this.player.body.velocity.x=-_this.player_v
}
_this.player.body.setSize(1,_this.player.height,-0.1*_this.player.width,0)}else{
_this.player.body.setSize(_this.player.width,1,0,0.1*_this.player.height)
_this.player.body.velocity.y=-_this.player_v
}
// _this.num+=1;
}}
```结果的统计:通过隐藏点的result字段,给对应结果的num做加1的操作,游戏结束的时候,根据各种结果的num得出结果即可。
'再玩一次',这个简单的做法是刷新页面,但是体验不好,这里我才用的做法是把一些相关的参数重置掉,然后再去执行`init`函数。
可以扫码体验下制作出来的效果,前面说的可复用性体现在,再次复用的时候,设计师只需重新画棋盘,编辑只需替换棋盘,然后去量每个点的位置(距离左上角定点的距离),然后设置改点的相关属性即可。后来这个确实是复用过几次。
![2016年终策划-重走2016](readme-images/6.png "2016年终策划-重走2016")
### [必胜客万圣节策划](http://zj.qq.com/money/ywl_game_halloween.htm)
可扫码体验
![必胜客万圣节策划](readme-images/8.png "必胜客万圣节策划")
这个项目的灵感也是来自之前有个很火的h5-[里约大冒险](http://d.news.163.com/active/2232636/olympic.html),手动画一个小人,然后这个小人贯穿整个设定好的故事,然后故事中引导用户去画或者滑动屏幕,促使故事的行进。
![里约大冒险](readme-images/7.png "里约大冒险")
* h5需求:
* 实现画图的功能
* 根据画的图,生成一张图片
* 动画节奏的把握前面两个的话,查看[demo](draw_game/demo.html)
```javascript
//maxX,minX,maxY,minY用于生成图片 确定边界线
function paint(pointer,x,y) {
if(!ifDone){
ifDone = true;
}
if(flag){
beforeX=x;
beforeY=y;
flag = false;
}
if(init){
maxX = x;
minX = x;
maxY = y;
minY = y;
init = false;
}
if(
x<(winWidth-$(".drawCon").width())/2||
x>winWidth-((winWidth-$(".drawCon").width())/2)||
ywinHeight*0.2+$(".drawCon").height()
){
beforeX=x;
beforeY=y;
return;
}
bmd.line(beforeX, beforeY, x, y, '#5C5C5C',2);
beforeX=x;
beforeY=y;
if(game.input.activePointer.position.x>maxX){
maxX = x;
}
if(game.input.activePointer.position.xmaxY){
maxY = y;
}
if(game.input.activePointer.position.y