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

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项目工具 编译引擎

    9e3c157f63630e22e7e4397976151e41.png
    image

  6. 查看是否编译成功

    5bbf974a7f99351d79a4eff9391377c4.png
    image

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


  • 使用物理引擎

  1. 基本概念

    截图
    image

    • 世界: 设置世界内部的重力加速度 添加元素 添加世界相关设定 等功能,比如设置材质之间的摩擦和相关系数
    • 形状:绘制物体的基本形状,每一个刚体都需要添加形状,设置形状相关属性 比如:
    • 刚体:设置刚体,物理相关属性 ,比如刚体类型 重量 位置,角速度,位置 等等
    • 贴图: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')
      

      截图
      image

    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)
      

      截图
      image

    3. 创建一个可视小球

      截图
      image

      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()进行步进运动

      截图
      image

      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

      截图
      image

        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

posted @ 2022-02-07 23:02  三十男  阅读(331)  评论(0编辑  收藏  举报