• 重力的方向和地面的问题

    p2中默认的方向是从上到下,如果重力默认是正数的话,物体放到世界中是会从上面往下面飘的

    p2plane地面默认的方向是y轴的方向,而在p2y轴的方向默认是从上往下

    首先来看,重力gravity是正数,并且plane地面在视图中间,小球是怎么运动

    // 创建世界
    this.world = new p2.World()
    this.world.sleepMode = p2.World.BODY_SLEEPING
    this.world.gravity = [0,5]
    // 设置弹性属性
    this.world.defaultContactMaterial.restitution = 1; // 创建地面
    this.planeBody = new p2.Body({
    position:[egret.MainContext.instance.stage.stageWidth/2,egret.MainContext.instance.stage.stageHeight/2]
    })
    let plane = new p2.Plane()



    小球受重力的影响从上往下掉,没有问题,并且即使是在地面下面,地面的方向也是从上往下,小球下到地面之后依旧是从上往下运动

    下面把世界的重力改成从下往上,相当于漂浮的感觉



    可以看到plane下方,也就是在p2引擎中的y轴正方向地面上的小球依照物理定律,自由落地,从下往上落到地面上

    plane上方,也就是p2物理引擎中的地下世界,是会奇怪的往地面上跑

    总体来说:在p2物理世界中,地面上的物体,遵循自由落体和牛顿引力相关运动原理,但是默认方向是从上往下的Y轴方向,所以如果地面在最下面的话,需要将plane地面水平翻转180‘,并且此时重力可以设置为正数,达到从上往下的效果

    正确的效果是这样的:



    实现代码

    // 创建世界
    this.world = new p2.World()
    this.world.sleepMode = p2.World.BODY_SLEEPING
    this.world.gravity = [0,5]
    // 设置弹性属性
    this.world.defaultContactMaterial.restitution = 1; // 创建地面
    this.planeBody = new p2.Body({
    position:[egret.MainContext.instance.stage.stageWidth/2,egret.MainContext.instance.stage.stageHeight/2]
    })
    let plane = new p2.Plane()
    this.planeBody.angle = Math.PI // 地面需要旋转180度,不然是从上往下
  • 生成阻碍方块,并且不允许方块有重叠区域

    实现原理

    纵坐标可以设定在同一水平线上,横坐标位置随机,通过随机数生成位置,并且通过随机数确定方块的大小,生成第二个随机方块的时候判断时候与前面生成的所有方块有重叠部分` 半径 只差的绝对值 < 半径值和`, 如果有重叠部分的话,嵌套调用,如果没有的话,即生成新的方块

    实现代码

    private randomNum(minNum,maxNum):number{  // 生成随机数的方法,借鉴自菜鸟教程
    switch(arguments.length){
    case 1:
    return parseInt(Math.random() * minNum+1 + '',10);
    break;
    case 2:
    return parseInt(Math.random()*(maxNum-minNum+1)+minNum,10);
    break;
    default:
    return 0;
    break;
    }
    } private genereteBox():void{
    /**
    * 生成随机个障碍盒子
    */
    let stageHeight = egret.MainContext.instance.stage.stageHeight // 获取屏幕高度
    let stageWidth = egret.MainContext.instance.stage.stageWidth // 获取屏幕宽度 let count = this.randomNum(1,4) // 生成的障碍个数 let arr = [] let generatePosition = ()=>{ // 保证this指向问题
    let size = this.randomNum(30,70)
    let location = this.randomNum(size,stageWidth-size)
    if(arr.length === 0){
    arr.push({
    size:size,
    location:location
    })
    return [size,location]
    }else{
    for(let index = 0;index<arr.length;index++){
    if((Math.abs(location-arr[index].location)) < (size + arr[index].size)){
    console.log(size,location)
    return generatePosition()
    }
    }
    arr.push({
    size:size,
    location:location
    })
    return [size,location]
    }
    }
    for(let index = 0;index<count;index++){
    let [size,location] = generatePosition()
    let react:egret.Shape = this.createBox(size)
    let reactShape: p2.Shape = new p2.Box({
    width:size,
    height:size
    })
    let reactBody:p2.Body = new p2.Body({
    type:p2.Body.STATIC,
    position:[
    location,stageHeight-size
    ],
    })
    reactBody.addShape(reactShape)
    reactBody.displays = [react]
    this.world.addBody(reactBody)
    }
    }
  • 点击生成小球逻辑

    实现逻辑

    1.生成小球刚体,形状,及绑定贴图
    
    2.生成小球的位置为点击事件的位置
    
    3.绑定到`egret`的点击事件上

    实现代码

    //步骤1,2
    private generateBall(locationX:number,locationY:number):void{
    var ball:egret.Shape
    var ballShape:p2.Shape
    var ballBody:p2.Body ball = this.createBall()
    ballShape = new p2.Circle({
    radius:10
    })
    ballBody = new p2.Body({
    position:[locationX,locationY],
    mass:50,
    overlaps:false
    })
    ball.width = (<p2.Circle>ballShape).radius*2
    ball.height = (<p2.Circle>ballShape).radius*2
    ball.anchorOffsetX = ball.width/2
    ball.anchorOffsetY = ball.height/2
    ballBody.addShape(ballShape)
    ballBody.displays = [ball]
    this.world.addBody(ballBody)
    } // 步骤3 this.addEventListener(egret.TouchEvent.TOUCH_TAP,(e:egret.TouchEvent)=>{
    this.generateBall(e.localX,e.localY) // e.localX和e.localY 可以拿到点击事件的点击X或者y
    },this)
  • 小球碰撞出现锚点问题,即碰撞不是发生在边缘,而是感觉发生在球心或者什么位置

    原因分析

    1.可能是因为贴图的视觉中心和 刚体的中心没有设置在一起
    
    在`egret`贴图的中心,默认是在坐标左上角
    
    但是在`p2`物理引擎中,默认的图形锚点确是在刚体的中心
    
    所以在使用两个合并时需要将贴图的锚点中心设置到和刚体中心一样
    
    ![截图](attachment:8f15efc90e41b0d12e13731386c191a1)

    代码如下


    private createBox(width:number,angle:number):egret.Shape{
    var box = new egret.Shape()
    box.graphics.beginFill(0x0000ff)
    box.graphics.drawRect(0,0,width,width)
    box.graphics.endFill()
    box.anchorOffsetX = box.width/2
    box.anchorOffsetY = box.height/2
    box.rotation = angle * 180 / Math.PI;
    console.log('box rotation : ' + box.rotation)
    this.addChild(box)
    return box
    }
  • 小球和方块出现重叠的现象,而且碰撞中心感觉只是在小球的中心点,并不是小球的边缘碰撞

    问题现象

    ![3.gif](attachment:774c5f928557ca980283141254dba5f8)

    检查原因

    原来是小球贴图`egret.shape`和小球物理引擎中刚体的大小不一样`p2.body`
    
    小球的刚体结构实际上是在贴图内部的一个小区域

    代码如下

    //修改后
    private generateBall(locationX:number,locationY:number):void{
    var ball:egret.Shape
    var ballShape:p2.Shape
    var ballBody:p2.Body
    var size:number = 10
    ball = this.createBall(size*2) // size是刚体半径的大小,生成小球贴图的时候需要两倍大小,因为egret drawCirle是直径
    ballShape = new p2.Circle({
    radius:size
    })
    ballBody = new p2.Body({
    position:[locationX,locationY],
    mass:50
    })
    ball.width = (<p2.Circle>ballShape).radius*2 // 小球宽度也是直径
    ball.height = (<p2.Circle>ballShape).radius*2 // 小球高度页是直径
    ball.anchorOffsetX = ball.width/2 //参考下一个问题
    ball.anchorOffsetY = ball.height/2
    ballBody.addShape(ballShape)
    ballBody.displays = [ball]
    this.world.addBody(ballBody)
    }
  • 贴图的旋转和刚体的旋转数值明明设置的是一样的,但是旋转角度和碰撞反应感觉角度并不正确

    问题原因:

    `egret`中表示旋转的`rotate`属性是弧度制
    
    而 `p2`中表示旋转的`angle`属性是角度制,即在`p2`中写多少度就是旋转多少度,但是在`egret`的贴图中需要将角度转换为弧度
    
    转换公式如下

数学上是用弧度而非角度,因为360的容易整除对数学不重要,而数学使用弧度更方便。角度和弧度关系是:2π弧度=360°。从而1°≈0.0174533弧度,1弧度≈57.29578°。

  1. 角度转换为弧度公式:弧度=角度÷180×π

2)弧度转换为角度公式: 角度=弧度×180÷π


** 代码如下:** ```typescript
protected freshFrame():void{
this.world.step(1)
var len:number = this.world.bodies.length
for(let index = 0;index<len;index++){
var body:p2.Body = this.world.bodies[index]
var display: egret.DisplayObject = body.displays[0]
display.x = body.position[0]
display.y = body.position[1]
display.rotation = body.angle * 180/ Math.PI
}
}
  • 在两侧填上阻止的墙壁,形成密闭的环境

【h5游戏开发】egret引擎p2物理引擎 - 小球碰撞地面搞笑的物理现象的更多相关文章

  1. 最近这两天看了关于H5游戏开发的一个教程,实践很短暂,看了很多理论的东西,现在呢也只是想回忆回忆关于EUI的部分知识吧

    首先我了解了什么是Egret: Egret中文就是白鹭的意思,Egret是一套H5游戏开发的软件.(纯粹属于个人理解) 其次我对以下几款软件的相关知识做了些了解: Egret Engine(引擎),E ...

  2. 今天我看了一个H5游戏EUI的例子,我都快分不清我到底是在用什么语言编译了代码了,作为刚刚学习H5游戏开发的菜鸟只能默默的收集知识

    今天看了一个EUI的demo,也是接触H5游戏开发的第五天了,我想看看我能不能做点什么出来,哎,自己写果然还是有问题的.在看EUI哪一个demo的时候就遇见了一些摇摆不定的问题,我觉得提出来 1.to ...

  3. 关于h5游戏开发,你想了解的一切都在这儿!

    ​2020年,受疫情影响,线下产业红利褪去,线上迎来的新一轮的高峰.众多商家纷纷抓住了转型时机,开启了流量争夺战.H5游戏定制无疑是今年引流的大热门.如何开发一款有趣.有爆点.用户爱买单的好游戏呢? ...

  4. 为什么选择H5游戏开发定制?

    为什么选择H5游戏开发定制? 随着微信H5游戏推广带来的显著效果,越来越多的商家已经加入到游戏营销的队伍中来, 对H5小游戏有了解的商家都知道,[模板游戏]的价格往往低于[定制游戏]的价格,可是为什么 ...

  5. 2、Cocos2dx 3.0游戏开发找小三之引擎简单介绍

    尊重开发人员的劳动成果,转载的时候请务必注明出处:http://blog.csdn.net/haomengzhu/article/details/27094663 引擎简单介绍 Cocos2d-x 的 ...

  6. H5游戏开发之抓住小恐龙

    第一次写技术性博文,以前都只是写一些生活感想,记录一些生活发生的事情. 博主大三学生一枚,目前学习JS一年多,还处于学习阶段,有什么说的不好的希望大牛指点下,由于第一次写博文,排版什么的有待改进,希望 ...

  7. H5游戏开发:贪吃蛇

    贪吃蛇的经典玩法有两种: 积分闯关 一吃到底 第一种是笔者小时候在掌上游戏机最先体验到的(不小心暴露了年龄),具体玩法是蛇吃完一定数量的食物后就通关,通关后速度会加快:第二种是诺基亚在1997年在其自 ...

  8. H5游戏开发之多边形碰撞检测

    2D多边形碰撞检测介绍这是一篇论证如何在2D动作游戏中执行碰撞检测的文章(Mario,宇宙入侵者等),为了保证它的高效性和精确性,碰撞检测是以多边形为基础的,而不是以sprite为基础.这是两种不同的 ...

  9. cocos2d-x ios游戏开发初认识(八) 触摸事件与碰撞检測

    玩过植物大战僵尸都知道,要在草坪里放一朵向日葵或者其他的植物仅仅需触摸那个植物将其拖入到想要摆放的位置,这事实上就是这节要写的触摸事件.还能够发现当我们的僵尸出来的时候,我们的小豌豆会发子弹攻击僵尸, ...

随机推荐

  1. 牛客练习赛39 B:选点(二叉树遍历+LIS)

    链接: https://ac.nowcoder.com/acm/contest/368/B 来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言262 ...

  2. k8s loadbalancer与ingress实践

    k8s可以通过三种方式将集群内服务暴露到外网,分别是NodePort.LoadBalancer.Ingress,其中NodePort作为基础通信形式我们在<k8s网络模型与集群通信>中进行 ...

  3. Ranger-Kylin插件安装

    Ranger-Kylin插件安装, 从Ranger1.1.0版本开始支持Ranger Kylin插件, 从Kylin2.3.0版本开始支持Ranger Kylin插件的权限控制. 1.获取安装包 sc ...

  4. URL中使用IPv4,IPv6和主机名

    在浏览器的Http请求的URL中如何使用IPv4,IPv6和主机名, 因为IPv6的地址需要加[],导致用法有点区别, 下面通过具体的例子总结一下不同情况下的用法. 1.假设有台Linux主机名配置如 ...

  5. 使用.NET 6开发TodoList应用(22)——实现缓存

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 有的时候为了减少客户端请求相同资源的逻辑重复执行,我们会考虑使用一些缓存的方式,在.NET 6中,我们可以借助框架提供的中间件 ...

  6. Jenkins_构建任务提示找不到命令的处理方法

    问题现象 部署pytest环境后,在linux上能执行命令,但是使用jenkins构建就提示找不到命令. 问题分析 可能是...jenkins中执行时,默认使用的是linux中的jenkins用户权限 ...

  7. Linux7系统开通防火墙端口

    一.查看防火墙状态 查看防火墙状态 systemctl status firewalld 开启防火墙 systemctl start firewalld 关闭防火墙 systemctl stop fi ...

  8. django创建促销系统

    创建应用(coupons) 把应用添加到settings.py文件中 创建数据模型 创建优惠码表单forms.py 添加到admin后台,方便控制 运行命令python manage.py makem ...

  9. let var const 区别

    let es6 语法 let是作用域是块级的,即{}内的范围 如果未声明变量就使用的话,报错ReferenceError,而var则会报错undefined(不存在变量提升) 只要块级作用域内存在le ...

  10. Feign的应用

    一.定义 可以把Rest的请求进行隐藏,伪装成类似SpringMVC的Controller一样 它集成了ribbon.hystrix.eureka组件 Feign的日志级别需要自定义,因为日志是单独的 ...