欢迎光临散文网 会员登陆 & 注册

《切水果》核心技术:抛物线物理仿真

2021-12-27 18:31 作者:unity小能手  | 我要投稿

在切水果游戏中,我们需要从下方向上斜抛出水果。这时候就需要使用抛物线物理仿真。

  1. 创建项目、导入资源、编辑游戏场景

具体场景在此不过过多阐述,需要源码的可以联系我们。

2.组件化开发流程

【1】创建一个类,自定义脚本js。

【2】实例化这个类,得到这个类的实例。【添加组件】、addComponent。

【3】执行原理:加载游戏场景 → 遍历节点树 → 加载节点上所有组件 → 游戏引擎调用组件中的onLoad方法、start方法 → 每次更新都会调用update(dt)方法。

新建game_mgr,代码如下:

// 定义了一个class, new 构造函数() cc.Class({    // 组件类    extends: cc.Component,    // 属性列表,可以通过编辑器修改设置,注意点:在properties中改无效    properties: {        is_debug: false,        speed: 100,        pos: cc.v2(0, 0),    },    // 第一次运行之前调用  组件实例.start    start () {        // this--> 当前组件实例,  this.node --> 当前组件实例所在的节点;        // 调用引擎的API,来做游戏控制;        console.log("start:", this, this.node);    },    // 每次刷新的时候调用; 组件实例.update;    // dt : 与帧频有关、平均时间(不是每次都相同)    // 保证不同手机显示效果一致,保证是匀速平滑进行    update (dt) {        console.log(dt);    }, });

在Canvas节点上,【添加组件】-【用户脚本组件】-game_mgr。

在properties中添加属性,且通过编辑器绑定:

apple : { type : cc.Node, default : null, },

在update方法中添加如下代码:

// 为什么非得用dt,不用会导致什么问题? // 【1】因为不同手机帧频不一样,保证不同手机显示效果一致! // 60FPS的手机会比30FPS的手机运动距离多一倍 // 【2】因为dt每次都不一样,保证同一手机是匀速运动 //this.apple.x += this.speed; this.apple.x += this.speed * dt;

3.抛物线物理仿真实现

重力加速g:

Vy = v0 + g * t;

h = v0 * t + 0.5 * g * t * t;

斜抛运动:

分解到水平上: 匀速直线运动;

分解到竖直方向: 匀变速直线运动 (加速度)。

4. 自定义用户脚本类throw_action.js

properties: {    G: -160,  // 重力加速度    speed: 200, // 初速度大小    degree: 45, // 抛射角度    play_onload: false, },

在start方法中根据是否需要在加载的时候就执行,调用相应方法:

start () {    this.is_moving = false; // 标记这个物体是否移动;    if (this.play_onload) { // 执行抛物线这个运动        this.throw_aciton();    } }, throw_aciton() {    var r = this.degree * Math.PI / 180;    this.vx = this.speed * Math.cos(r);    this.vy = this.speed * Math.sin(r);    this.is_moving = true; },

在throw_action中实质只是修改设置相关的关键参数(速度分量、移动状态),具体动态效果在update(dt)方法中执行,因为每隔一段时间会刷新一次。

update (dt) {    if (this.is_moving === false) {        return;    }    // 水平方向运动(匀速直线运动)    var sx = this.vx * dt;    this.node.x += sx;    // 竖直方向运动(匀变速直线运动)    var sy = this.vy * dt + 0.5 + this.G * dt * dt;    this.vy = this.vy + this.G * dt;    this.node.y += sy;    // 当前节点(苹果)的坐标转换为世界坐标(参考原点为左下角)    var w_pos = this.node.convertToWorldSpaceAR(cc.v2(0, 0));    if (this.out_of_screen(w_pos)) {        this.node.removeFromParent();        console.log("removed");    } }, out_of_screen(w_pos){    return w_pos.x < 0 || w_pos.x > cc.winSize.width ||        w_pos.y < 0 || w_pos.y > cc.winSize.height; },

如果苹果超出屏幕显示区域,应该移出。

5. 添加组件到apple节点上

运行结果如下:

发现苹果速度小了,改properties中的值200为400,编译发现运行无变化!!为什么?

要么在编辑器中修改,要么在onLoad方法或start方法中修改。而且优先级start>onLoad>编辑器。

6. 随机不断抛出苹果

修改update(dt)方法中的代码如下:

if (this.out_of_screen(w_pos)) {    //this.node.removeFromParent();    //console.log("removed"); this.is_moving = false;    this.re_show(); }

重新显示苹果的代码如下:

re_show(){    if(this.is_moving){        return;    }    // [负屏幕宽度一半,屏幕高度一半) 例如[-200,200)    var x = Math.random() * cc.winSize.width - cc.winSize.width / 2;    var y = -cc.winSize.height * 0.5 + 50;    this.node.setPosition(x, y);    this.speed = Math.random()*300 + 200;   // [200,500)    this.degree = Math.random()*45 + 45;    // [45,90)    this.throw_aciton(); },

如果是在运动中,不要重新出现新苹果。

当苹果超出屏幕区域后,移动状态切换为false。然后,进入到re_show方法中,条件才不会被拦截,所以会设置苹果到新的位置(从屏幕下方抛出,锚点在屏幕中心)。设置抛出速度、角度,然后调用throw_action()方法即可。方法throw_action中会重新计算速度分量,切回将运动移动状态修改为true,如此update方法中又能根据运动状态进行相关刷新,动态显示了。

7.细节优化

发现苹果没有完全离开屏幕就消失了,还有一半遗留在屏幕就消失了。

out_of_screen(w_pos){    /*return w_pos.x < 0 || w_pos.x > cc.winSize.width ||        w_pos.y < 0 || w_pos.y > cc.winSize.height;*/    var apple_width = this.node.width/2;    var apple_height = this.node.height/2;    return w_pos.x < -apple_width  

|| w_pos.x > cc.winSize.width + apple_width

|| w_pos.y < -apple_height

|| w_pos.y > cc.winSize.height + apple_height; },

如上修改即可,因为苹果的锚点也在中心,要完全离开,还需要考虑苹果的宽和高!

8.微信小游戏打包发布

不做具体描述。

更多资源和课程下载请点击:

https://bycwedu.vipwan.cn/promotion_channels/630597732


《切水果》核心技术:抛物线物理仿真的评论 (共 条)

分享到微博请遵守国家法律