您的位置:首页 > 其它

基于egret引擎、P2物理库的搭积木游戏

2015-12-03 18:21 387 查看
最近不务正业,参加了一个HTML5游戏设计比赛。速成了一个搭积木游戏。

http://dev.redianbar.com/6fb2e2ef1a/



因为有重力感应,手机玩效果好一些,微信扫一扫!(用的是比赛官方给的服务器,不知道什么时候链接就会失效)。。

好了!我们开始:

egret:

使用的是egret游戏引擎,因为以前没接触过H5游戏制作,这个的新手教程十分简单。
看了看入门: http://edn.egret.com/cn/index.php/docs/page/639
还有视频教程讲的也是十分的细致:
http://edn.egret.com/cn/list/video/
编辑器用的也是egret wing,还是有一些bug的。开发过程中egret也在不断更新,还是蛮好哒。

P2物理库:

不好用啊,虽然是egret官方推荐的,但是教程非常少版本也是非常的旧。给开发带来了好多的麻烦。
竟然在创建三角形刚体上卡住了好久。。。最后请教了@ladeng6666(陈文登),用了神改过的P2库才解决问题。神的egret书要出版了,大家支持支持~
如果能再选择一次,我会去试试BOX2D,起码它教程很多,还跨平台。

创建工程,导入第三方库P2:

egret wing创建工程,在项目文件夹的平级目录加入第三方库文件。例如项目路径
C:\project\demo\src。拷贝
myLibs(http://download.csdn.net/detail/lixintong1992/9386255)第三方库文件夹位置到 C:\project。修改egretProperties.json文件
modules 中增加
之后运行命令行,cd到工程文件目录,执行下egret
build -e

P2物理世界初始化:

我们来创建世界!(中二病。。。)

private world: p2.World = new p2.World();
节省资源模式启动!
this.world.sleepMode = p2.World.BODY_SLEEPING;
我带了重力!
this.world.gravity = [0,-5];


P2物理世界通过

this.world.step(t);
计算t秒后世界中所有刚体的位置。

egret中有心跳函数,我们只要每次心跳调用
this.world.step(t);

就能让世界运转!

我写的不好,不明白的可以参考下 http://edn.egret.com/cn/docs/page/627

重力感应:

var orientation = new egret.DeviceOrientation();//创建 DeviceOrientation 类
orientation.addEventListener(egret.Event.CHANGE,this.onOrientation,this);//添加事件监听器
orientation.start(); //开始监听设备方向变化
private onOrientation(e: egret.OrientationEvent) {
this.beta_gamma = Math.round(e.gamma);
}
没什么好解释的···

游戏胜利失败判断:

过关条件:

1.场景中活动实体达到上限且都是静止

2.场景中活动实体达到上限且经过一段时间没失败

失败条件:

存在实体的y坐标超过屏幕下限(就是掉下去啦)

当然要在心跳函数中实时判断过关还是失败啦:
egret.Ticker.getInstance().register(function(dt) {
this.world.step(dt / 1000);
this.world.gravity[0] = this.beta_gamma / 30;
if(!this._isDebug) {
var stageHeight: number = egret.MainContext.instance.stage.stageHeight;
var l = this.world.bodies.length;
for(var i: number = 0;i < l;i++) {
var boxBody: p2.Body = this.world.bodies[i];
if(boxBody) {
if(boxBody.displays[0]) {
var box: egret.DisplayObject = boxBody.displays[0];
}

if(box) {
box.x = boxBody.position[0] * this.factor;
box.y = stageHeight - boxBody.position[1] * this.factor;
if(box.y > 900) {
count = 0;
this.level(-2);
}
box.rotation = 360 - boxBody.angle * 180 / Math.PI;
if(boxBody.sleepState == p2.Body.SLEEPING) {
box.alpha = 0.8;
count_sleep += 1;
}
else {
box.alpha = 1;
}
if(l == this.success_num[this.level_num]) {
if(count == 4000) {
this.level_num += 1;
Data.score = this.level_num;
this.level(this.level_num);
l = 0;
count = 0;
}
else { count = count + 1; }
}
}
}
}
if(count_sleep == this.sleep_num[this.level_num]) {
this.level_num += 1;
Data.score = this.level_num;
this.level(this.level_num);
l = 0;
count = 0;
count_sleep = 0;
}
else {
count_sleep = 0;
}
}
},this);
相当于一个while(1),其中dt就是两次执行自身的时间间隔,遍历所有刚体,更新实体对应贴图的坐标,休眠的刚体变透明。判断胜利失败条件。

里面还加了一发重力感应:
this.world.gravity[0] = this.beta_gamma / 30;


创建支撑三角、方块、圆刚体:

创建那种不会动的静止刚体函数:

private supportertrect(_width:number,_height:number,_rotation:number,_x:number,_y:number) {
var supporterShape: p2.Shape = new p2.Box({ width: _width,height: _height });
var supporterBody: p2.Body = new p2.Body({ mass: 0,position: [_x/this.factor,_y/this.factor],angle:Math.PI*((_rotation)/180),angularVelocity: 0 });
supporterBody.addShape(supporterShape);
this.world.addBody(supporterBody);
var display: egret.DisplayObject = this.createBitmapByName("rect2");
display.width = (<p2.Box>supporterShape).width * this.factor;
display.height = (<p2.Box>supporterShape).height * this.factor;
display.anchorOffsetX = display.width / 2;
display.anchorOffsetY = display.height / 2;
supporterBody.displays = [display];
this.addChild(display);
}
private supportertriangle(_sidelenght:number,_rotation:number,_x:number,_y:number) {
var center1: number[] = new Array(0, 0);
var mousePos_11: number[] = new Array(0, _sidelenght/this.factor);
var mousePos_21: number[] = new Array(_sidelenght/this.factor, _sidelenght/this.factor);
var mousePos_31: number[] = new Array(0, 0);
var points1: number[][] = new Array();
p2.vec2.centroid(center1,mousePos_11,mousePos_21,mousePos_31);
p2.vec2.subtract(mousePos_11,mousePos_11,center1);
p2.vec2.subtract(mousePos_21,mousePos_21,center1);
p2.vec2.subtract(mousePos_31,mousePos_31,center1);
points1.push(mousePos_11);
points1.push(mousePos_21);
points1.push(mousePos_31);

var supporterBody: p2.Body = new p2.Body({ mass: 0,position: [_x/this.factor,_y/this.factor],angle:Math.PI*((_rotation)/180),angularVelocity: 0 });
supporterBody.fromPolygon(points1,{optimalDecomp:false});
this.world.addBody(supporterBody);

var items1:egret.Bitmap = new egret.Bitmap();
items1.texture = RES.getRes('triangle');
items1.width = _sidelenght;
items1.height = _sidelenght;
items1.rotation = -_rotation;
items1.x = _x;
items1.y = _y;
items1.anchorOffsetX = center1[0] * this.factor;
items1.anchorOffsetY = items1.height-center1[1] * this.factor;
supporterBody.displays = [items1];
this.addChild(items1);
}
private supportercircle(_radius:number,_x:number,_y:number) {
var supporterShape: p2.Shape = new p2.Circle( {radius:((_radius/2)/this.factor) });
var supporterBody: p2.Body = new p2.Body({ mass: 0,position: [_x/this.factor,_y/this.factor],angularVelocity: 0 });
supporterBody.addShape(supporterShape);
this.world.addBody(supporterBody);
var display: egret.DisplayObject = this.createBitmapByName("circle2");
display.width = _radius;
display.height = _radius;
display.x = _x;
display.y = _y;
display.anchorOffsetX = display.width / 2;
display.anchorOffsetY = display.height / 2;
supporterBody.displays = [display];
this.addChild(display);
}


三个函数的流程都一样,创建shape,创建body,通过body的addShape为body绑定shape,之后建立一个显示贴图的DisplayObject,通过body的displays为body绑定贴图。最后addChild。

对于三角形来说有点麻烦,三角形是通过创建多边形fromPolygon来实现的。fromPolygon是body的一个方法,给他坐标,它就能自动给你搞出来一个shape绑到body上
要根据三角形三点坐标算一下重心(centroid)。之后根据重心坐标对三个坐标做减法(subtract)

创建活动的三角、方块、圆刚体:

创建那种手指拖的活动的刚体:

private creatrect(_width:number,_height:number,_rotation:number,_x:number,_y:number){
var display :egret.DisplayObject= this.createBitmapByName('rect')
display.width = _width;
display.height = _height;
display.x = _x;
display.y = _y;
display.rotation = -_rotation;
display.anchorOffsetX = display.width / 2;
display.anchorOffsetY = display.height / 2;
this.addChild(display);
display.touchEnabled = true;
display.addEventListener(egret.TouchEvent.TOUCH_BEGIN,startMove,this);
display.addEventListener(egret.TouchEvent.TOUCH_END,stopMove,this);
var draggedObject:egret.Shape;
var offsetX:number;
var offsetY:number;
function startMove(e:egret.TouchEvent):void{
//把手指按到的对象记录下来
draggedObject = e.currentTarget;
//计算手指和要拖动的对象的距离
offsetX = e.stageX - draggedObject.x;
offsetY = e.stageY - draggedObject.y;
//把触摸的对象放在显示列表的顶层
this.addChild(draggedObject);
//手指在屏幕上移动,会触发 onMove 方法
this.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE,onMove,this);
}
function stopMove(e:egret.TouchEvent) {
//            console.log(22);
//手指离开屏幕,移除手指移动的监听
this.stage.removeEventListener(egret.TouchEvent.TOUCH_MOVE,onMove,this);
draggedObject = e.currentTarget;

var positionX: number = draggedObject.x / this.factor;
var positionY: number = (egret.MainContext.instance.stage.stageHeight - draggedObject.y) / this.factor;
var boxShape: p2.Shape = new p2.Box({width:_width/this.factor,height:_height/this.factor});
var boxBody: p2.Body = new p2.Body({ mass: 1,position: [positionX,positionY],angle:Math.PI*((_rotation)/180),angularVelocity: 0 });
boxBody.addShape(boxShape);
this.world.addBody(boxBody);
boxBody.displays = [e.currentTarget];
e.currentTarget.touchEnabled = false;
//            var sound:egret.Sound = RES.getRes( "bgm_2" );
//            var channel:egret.SoundChannel = sound.play(0,1);
}
function onMove(e:egret.TouchEvent):void{
//通过计算手指在屏幕上的位置,计算当前对象的坐标,达到跟随手指移动的效果
draggedObject.x = e.stageX - offsetX;
draggedObject.y = e.stageY - offsetY;
}
}
private creatrect_candy(_width:number,_height:number,_rotation:number,_x:number,_y:number){
var display :egret.DisplayObject= this.createBitmapByName('candy')
display.width = _width;
display.height = _height;
display.x = _x;
display.y = _y;
display.rotation = -_rotation;
display.anchorOffsetX = display.width / 2;
display.anchorOffsetY = display.height / 2;
this.addChild(display);
display.touchEnabled = true;
display.addEventListener(egret.TouchEvent.TOUCH_BEGIN,startMove,this);
display.addEventListener(egret.TouchEvent.TOUCH_END,stopMove,this);
var draggedObject:egret.Shape;
var offsetX:number;
var offsetY:number;
function startMove(e:egret.TouchEvent):void{
//把手指按到的对象记录下来
draggedObject = e.currentTarget;
//计算手指和要拖动的对象的距离
offsetX = e.stageX - draggedObject.x;
offsetY = e.stageY - draggedObject.y;
//把触摸的对象放在显示列表的顶层
this.addChild(draggedObject);
//手指在屏幕上移动,会触发 onMove 方法
this.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE,onMove,this);
}
function stopMove(e:egret.TouchEvent) {
//            console.log(22);
//手指离开屏幕,移除手指移动的监听
this.stage.removeEventListener(egret.TouchEvent.TOUCH_MOVE,onMove,this);
draggedObject = e.currentTarget;

var positionX: number = draggedObject.x / this.factor;
var positionY: number = (egret.MainContext.instance.stage.stageHeight - draggedObject.y) / this.factor;
var boxShape: p2.Shape = new p2.Box({width:_width/this.factor,height:_height/this.factor});
var boxBody: p2.Body = new p2.Body({ mass: 1,position: [positionX,positionY],angle:Math.PI*((_rotation)/180),angularVelocity: 0 });
boxBody.addShape(boxShape);
this.world.addBody(boxBody);
boxBody.displays = [e.currentTarget];
e.currentTarget.touchEnabled = false;
//            var sound:egret.Sound = RES.getRes( "bgm_2" );
//            var channel:egret.SoundChannel = sound.play(0,1);
}
function onMove(e:egret.TouchEvent):void{
//通过计算手指在屏幕上的位置,计算当前对象的坐标,达到跟随手指移动的效果
draggedObject.x = e.stageX - offsetX;
draggedObject.y = e.stageY - offsetY;
}
}
private creatcircle(_radius:number,_x:number,_y:number){
var display1 :egret.DisplayObject= this.createBitmapByName('circle')
display1.width = _radius;
display1.height = _radius;
display1.x = _x;
display1.y = _y;
display1.anchorOffsetX = display1.width / 2;
display1.anchorOffsetY = display1.height / 2;
this.addChild(display1);
display1.touchEnabled = true;
display1.addEventListener(egret.TouchEvent.TOUCH_BEGIN,startMove2,this);
display1.addEventListener(egret.TouchEvent.TOUCH_END,stopMove2,this);
var draggedObject:egret.Shape;
var offsetX:number;
var offsetY:number;
function startMove2(e:egret.TouchEvent):void{
//把手指按到的对象记录下来
draggedObject = e.currentTarget;
//计算手指和要拖动的对象的距离
offsetX = e.stageX - draggedObject.x;
offsetY = e.stageY - draggedObject.y;
//把触摸的对象放在显示列表的顶层
this.addChild(draggedObject);
//手指在屏幕上移动,会触发 onMove 方法
this.stage.addEventListener(egret.TouchEvent.TOUCH_MOVE,onMove2,this);
}
function stopMove2(e:egret.TouchEvent) {
//            console.log(22);
//手指离开屏幕,移除手指移动的监听
this.stage.removeEventListener(egret.TouchEvent.TOUCH_MOVE,onMove2,this);
draggedObject = e.currentTarget;

var positionX: number = draggedObject.x / this.factor;
var positionY: number = (egret.MainContext.instance.stage.stageHeight - draggedObject.y) / this.factor;
var boxShape: p2.Shape = new p2.Circle({radius:((_radius/2)/this.factor)});
var boxBody: p2.Body = new p2.Body({ mass: 1,position: [positionX,positionY] });
boxBody.addShape(boxShape);
this.world.addBody(boxBody);
boxBody.displays = [e.currentTarget];
e.currentTarget.touchEnabled = false;
//            var sound:egret.Sound = RES.getRes( "bgm_3" );
//            var channel:egret.SoundChannel = sound.play(0,1);
}
function onMove2(e:egret.TouchEvent):void{
//通过计算手指在屏幕上的位置,计算当前对象的坐标,达到跟随手指移动的效果
draggedObject.x = e.stageX - offsetX;
draggedObject.y = e.stageY - offsetY;
}
}


三个函数差不多的。先显示图,为这个图添加事件侦听。具体的图片移动看这个 http://edn.egret.com/cn/docs/page/583 我就不细说了,在最后手离开屏幕的事件中,为这个贴图创建一个刚体body,以及shape。

整个游戏流程:



ps:流程图在线画哒:https://www.processon.com/network

最开始就是为每个关卡赋值对应的所有刚体数,能活动的刚体数。



初始化,大清洗,世界清空,显示清空



关卡函数



每个关卡函数就是这个样子啦



其他的就是基本教程里的东西啦,按钮啊,事件啦

over~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: