egret p2 物理引擎 (1) 小球坠落 demo
egret p2物理引擎学习记录
p2(physics)下载地址:https://download.csdn.net/download/qq_31189489/79552684
-
引入物理引擎
-
下载p2 物理引擎包
-
\physics\libsrc\bin\physics
目录下所有文件拷贝到根目录/../p2Physics
目录下 -
修改项目根目录配置文件
egretProperties.json
-
修改项如下
{ "name":"physics", "path":"../physics" }
-
编译 打开
egret编辑器wing
找到插件
egret项目工具
编译引擎
-
查看是否编译成功
-
如果
libs/modules/
目录下出现了physics文件夹则表示编译成功
-
使用物理引擎
-
基本概念
- 世界: 设置世界内部的
重力加速度
添加元素
添加世界相关设定
等功能,比如设置材质之间的摩擦和相关系数
- 形状:绘制物体的基本形状,每一个刚体都需要添加形状,设置
形状相关属性
比如: - 刚体:设置刚体,
物理相关属性
,比如刚体类型 重量
位置
,角速度
,位置
等等 - 贴图:displays,通过贴图展示
egret
相关显示元素,绑定显示
- 世界: 设置世界内部的
-
基本步骤
-
创建世界
// 实例化一个world对象 this.world = new p2.World(); //设置world为睡眠状态 this.world.sleepMode = p2.World.BODY_SLEEPING; this.world.gravity = [0,9.8] console.log('create world success')
-
创建一个地板
// 绘制地面,也是通过shape和body 两个基础对象进行合成 let stageHeight = egret.MainContext.instance.stage.stageHeight var groundShape:p2.Plane = new p2.Plane() var groundBody:p2.Body = new p2.Body({ type:p2.Body.STATIC, position:[0,stageHeight -100] }) groundShape.material = this.steelMaterial groundBody.angle = Math.PI groundBody.addShape(groundShape) groundBody.displays = [] this.world.addBody(groundBody) // 由于没有绑定材质,直接绘制一条的线条 let groundLine:egret.Shape = new egret.Shape groundLine.graphics.lineStyle(2,0x00ff00) groundLine.graphics.moveTo(0,stageHeight-90) groundLine.graphics.lineTo(egret.MainContext.instance.stage.stageWidth,stageHeight-90) this.addChild(groundLine)
-
创建一个可视小球
private display:egret.Shape; private createBody():void{ var boxShape:p2.Shape = new p2.Box({width:20,height:20}) var boxBody:p2.Body = new p2.Body({ mass: 2, position: [200, 200],velocity:[30,5]}) boxShape.material = this.iceMaterial this.display = new egret.Shape() this.display.x = 100 this.display.graphics.beginFill(0xff0000,1) this.display.graphics.drawCircle(0,0,(<p2.Box>boxShape).width) this.display.graphics.endFill() // this.display.width = (<p2.Box>bfoxShape).width // this.display.height = (<p2.Box>boxShape).height boxBody.displays = [this.display] boxBody.addShape(boxShape) this.world.addBody(boxBody) this.addChild(this.display) // var boxShape:p2.Shape = new p2.Shape() // var boxBody:p2.Body = new p2.Body({ mass: 1, position: [200, 180],angularVelocity:1 }) // boxBody.addShape(boxShape) // this.world.addBody(boxBody) console.log('create body success') }
-
更新视图
world
创建出来,并不会自动执行运动逻辑,需要通过world.step()
进行步进运动
this.world.step(1); var l = this.world.bodies.length; for (var i:number = 0; i < l; i++) { var boxBody:p2.Body = this.world.bodies[i]; var box:egret.DisplayObject = boxBody.displays[0]; if (box) { //将刚体的坐标和角度赋值给显示对象 box.x = boxBody.position[0]; box.y = boxBody.position[1]; //如果刚体当前状态为睡眠状态,将图片alpha设为0.5,否则为1 if (boxBody.sleepState == p2.Body.SLEEPING) { box.alpha = 0.5; } else { box.alpha = 1; } } }
-
在主程序中执行所有方法,并且通过时钟函数不断调用update函数,最终代码如下
main.ts
class HelloWorld extends eui.UILayer{ // 定义一个world变量 private world:p2.World // 定义一个调试画布 private debugDraw:any // 定义两种材质 private iceMaterial = new p2.Material(1); private steelMaterial = new p2.Material(2); private async runGame(){ console.log('加载资源') // 入口方法 await this.loadResource() // console.log('创建背景') // this.createBg() console.log('创建灰色遮罩') this.createMask() // console.log('绘制movieClips') // this.createClips() this.createWorld() this.createGround() this.createBody() this.addEventListener(egret.Event.ENTER_FRAME,this.update,this); } private createClips(){ let data = RES.getRes("chara_json") let textr = RES.getRes('chara_png') let factorys:egret.MovieClipDataFactory = new egret.MovieClipDataFactory(data,textr) let paimeng:egret.MovieClip = new egret.MovieClip(factorys.generateMovieClipData('paimeng')) this.addChild(paimeng) paimeng.gotoAndPlay("main",-1) } // 入口函数 protected createChildren(): void { super.createChildren() this.runGame() } // 创建背景图片 private createBg(){ let bg = new Util().createBitMap('bg_jpg') console.log(bg) this.addChild(bg) bg.width = this.stage.stageWidth bg.height = this.stage.stageHeight } // 加载资源 private async loadResource() { try { const loadingView = new LoadingUI(); this.stage.addChild(loadingView); // 暂时注释预加载资源 // await RES.loadConfig("resource/default.res.json", "resource/"); // await RES.loadGroup("preload", 0, loadingView); this.stage.removeChild(loadingView); } catch (e) { console.error(e); } } // 创建遮罩 private createMask(){ let mask = new egret.Shape() mask.graphics.beginFill(0xffffff,1) mask.graphics.drawRect(0,0,this.stage.stageWidth,this.stage.stageHeight) mask.graphics.endFill() mask.y = 0 this.addChild(mask) } // 创建刚体 private createWorld():void{ // 实例化一个world对象 this.world = new p2.World(); //设置world为睡眠状态 this.world.sleepMode = p2.World.BODY_SLEEPING; this.world.gravity = [0,9.8] console.log('create world success') } //生成地板Plane private planeBody:p2.Body; private createGround():void{ // 绘制地面,也是通过shape和body 两个基础对象进行合成 let stageHeight = egret.MainContext.instance.stage.stageHeight var groundShape:p2.Plane = new p2.Plane() var groundBody:p2.Body = new p2.Body({ type:p2.Body.STATIC, position:[0,stageHeight -100] }) groundShape.material = this.steelMaterial groundBody.angle = Math.PI groundBody.addShape(groundShape) groundBody.displays = [] this.world.addBody(groundBody) // 由于没有绑定材质,直接绘制一条的线条 let groundLine:egret.Shape = new egret.Shape groundLine.graphics.lineStyle(2,0x00ff00) groundLine.graphics.moveTo(0,stageHeight-90) groundLine.graphics.lineTo(egret.MainContext.instance.stage.stageWidth,stageHeight-90) this.addChild(groundLine) // //建立一个shape形状 // let planeShape:p2.Plane = new p2.Plane(); // //建立body刚体 // this.planeBody= new p2.Body({ // //刚体类型 // type:p2.Body.STATIC, // //刚体的位置 // position:[0,this.stage.stageHeight] // }); // this.planeBody.angle = Math.PI; // this.planeBody.displays = []; // this.planeBody.addShape(planeShape); // this.world.addBody(this.planeBody); console.log(' create ground success') } private display:egret.Shape; private createBody():void{ var boxShape:p2.Shape = new p2.Box({width:20,height:20}) var boxBody:p2.Body = new p2.Body({ mass: 2, position: [200, 200],velocity:[30,5]}) boxShape.material = this.iceMaterial this.display = new egret.Shape() this.display.x = 100 this.display.graphics.beginFill(0xff0000,1) this.display.graphics.drawCircle(0,0,(<p2.Box>boxShape).width) this.display.graphics.endFill() // this.display.width = (<p2.Box>bfoxShape).width // this.display.height = (<p2.Box>boxShape).height boxBody.displays = [this.display] boxBody.addShape(boxShape) this.world.addBody(boxBody) this.addChild(this.display) // var boxShape:p2.Shape = new p2.Shape() // var boxBody:p2.Body = new p2.Body({ mass: 1, position: [200, 180],angularVelocity:1 }) // boxBody.addShape(boxShape) // this.world.addBody(boxBody) console.log('create body success') } //帧事件,步函数 private update() { this.world.step(1); var l = this.world.bodies.length; for (var i:number = 0; i < l; i++) { var boxBody:p2.Body = this.world.bodies[i]; var box:egret.DisplayObject = boxBody.displays[0]; if (box) { //将刚体的坐标和角度赋值给显示对象 box.x = boxBody.position[0]; box.y = boxBody.position[1]; //如果刚体当前状态为睡眠状态,将图片alpha设为0.5,否则为1 if (boxBody.sleepState == p2.Body.SLEEPING) { box.alpha = 0.5; } else { box.alpha = 1; } } } } // private createDebug():void{ // } // private createTestPhysic():void{ // console.log('create begin') // const body = new p2.Body() // //创建宽4单位、高2单位的矩形形状 // const shpRect: p2.Shape = new p2.Shape({angle:1,position: [200, 180]}); // //创建平面形状 // const shpPlane: p2.Plane = new p2.Plane(); // } }
-
遇到的坑:详见这个博客:https://www.cnblogs.com/zm-blogs/p/15869701.html