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 @   三十男  阅读(380)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示