egret p2物理引擎学习记录


p2(physics)下载地址:https://download.csdn.net/download/qq_31189489/79552684


  • 引入物理引擎

  1. 下载p2 物理引擎包

  2. \physics\libsrc\bin\physics目录下所有文件拷贝到根目录/../p2Physics目录下

  3. 修改项目根目录配置文件egretProperties.json

  4. 修改项如下

    {
          "name":"physics",
          "path":"../physics"
       
        }
    
  5. 编译 打开egret编辑器wing 找到 插件 egret项目工具 编译引擎

    egret p2 物理引擎 (1) 小球坠落 demo
    egret p2 物理引擎 (1) 小球坠落 demo

  6. 查看是否编译成功

    egret p2 物理引擎 (1) 小球坠落 demo
    egret p2 物理引擎 (1) 小球坠落 demo

  7. 如果libs/modules/目录下出现了physics文件夹则表示编译成功


  • 使用物理引擎

  1. 基本概念

    egret p2 物理引擎 (1) 小球坠落 demo
    egret p2 物理引擎 (1) 小球坠落 demo

    • 世界: 设置世界内部的重力加速度 添加元素 添加世界相关设定 等功能,比如设置材质之间的摩擦和相关系数
    • 形状:绘制物体的基本形状,每一个刚体都需要添加形状,设置形状相关属性 比如:
    • 刚体:设置刚体,物理相关属性 ,比如刚体类型 重量 位置,角速度,位置 等等
    • 贴图:displays,通过贴图展示egret相关显示元素,绑定显示
  2. 基本步骤

    1. 创建世界

      // 实例化一个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')
      

      egret p2 物理引擎 (1) 小球坠落 demo
      egret p2 物理引擎 (1) 小球坠落 demo

    2. 创建一个地板

       // 绘制地面,也是通过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)
      

      egret p2 物理引擎 (1) 小球坠落 demo
      egret p2 物理引擎 (1) 小球坠落 demo

    3. 创建一个可视小球

      egret p2 物理引擎 (1) 小球坠落 demo
      egret p2 物理引擎 (1) 小球坠落 demo

      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')
        }
      
    4. 更新视图world创建出来,并不会自动执行运动逻辑,需要通过world.step()进行步进运动

      egret p2 物理引擎 (1) 小球坠落 demo
      egret p2 物理引擎 (1) 小球坠落 demo

      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;
                  }
              }
          }
      
    5. 在主程序中执行所有方法,并且通过时钟函数不断调用update函数,最终代码如下main.ts

      egret p2 物理引擎 (1) 小球坠落 demo
      egret p2 物理引擎 (1) 小球坠落 demo

        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

相关文章: