egret p2 物理引擎 小球坠落 demo

Posted JJesson

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了egret p2 物理引擎 小球坠落 demo相关的知识,希望对你有一定的参考价值。

2022 h5小游戏制作第一天,先做个属于自己的物理引擎世界吧

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


  6. 查看是否编译成功


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


  • 使用物理引擎

  1. 基本概念


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


    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)


    3. 创建一个可视小球


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


      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


        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

以上是关于egret p2 物理引擎 小球坠落 demo的主要内容,如果未能解决你的问题,请参考以下文章

Egret P2 ( 一) 掉落的小球

Egret中使用P2物理引擎

canvas 模拟小球上抛运动的物理效果

egret白鹭引擎入门(第一章)

p2.js物理引擎学习

白鹭Egret Engine 1.5震撼发布 HTML5游戏性能大幅提升