CocosCreater 教程(下)

news2025/1/20 13:28:26

1.物理系统

1.1 2D刚体

刚体是组成物理世界的基本对象。

1.2 2D 碰撞组件

目前引擎支持三种不同的碰撞组件: 盒碰撞组件(BoxCollider2D)圆形碰撞组件(CircleCollider2D) 和 多边形碰撞组件(PolygonCollider2D)。在 属性检查器 上点击 添加组件 按钮,输入碰撞组件的名称即可添加。

在 属性检查器 上点击 添加组件,输入 PolygonCollider2D 可添加多边形碰撞组件。

1.3 3D 物理

物理系统是将游戏世界赋予现实世界的物理属性(重力、推力等),并抽象为刚体模型,使得游戏物体在力的作用下,仿真现实世界的运动及其之间的碰撞过程。即在牛顿经典力学模型基础之上,通过 API 计算游戏物体的运动、旋转和碰撞

Cocos Creator 支持以下几种物理引擎:

  • ammo.js:默认物理引擎,Bullet 物理引擎 的 asm.js/wasm 版本。具备碰撞检测和物理模拟的物理引擎。
  • builtin:内置物理引擎,仅用于碰撞检测的轻量引擎。
  • cannon.js:具有碰撞检测和物理模拟的物理引擎。
  • PhysX: 由 NVIDIA 公司开发的游戏物理引擎。具备碰撞检测和物理模拟的物理引擎。

开发者根据开发对物理特性需求或应用场景选择不同的物理引擎,详情请参考:设置物理引擎。

1.碰撞组件

碰撞组件可用于定义需要进行物理碰撞的物体形状,不同的几何形状拥有不同的属性。碰撞体通常分为以下几种:

  1. 基础碰撞体。常见的包含 盒、球、圆柱、圆锥、胶囊 碰撞体。
  2. 复合碰撞体。可以通过在一个节点身上添加一个或多个基础碰撞体,简易模拟游戏对象形状,同时保持较低的性能开销。
  3. 网格碰撞体。根据物体网格信息生成碰撞体,完全的贴合网格。
  4. 单纯形碰撞体。提供点、线、三角面、四面体碰撞。
  5. 平面碰撞体。可以代表无限平面或半空间。这个形状只能用于静态的、非移动的物体。
  6. 地形碰撞体。一种用于凹地形的特殊支持。

2.刚体组件

刚体是组成物理世界的基本对象,它可以使游戏对象的运动方式受物理控制。例如:刚体可以使游戏对象受重力影响做自由下落,也可以在力和扭矩的作用下,让游戏对象模拟真实世界的物理现象。

让刚体运动起来

针对不同的类型,让刚体运动的方式不同:

  • 对于静态刚体(STATIC),应当尽可能保持物体静止,但仍然可以通过变换(位置、旋转等)来改变物体的位置。
  • 对于运动学刚体(KINEMATIC),应当通过改变变换(位置、旋转等)使其运动。

对于动力学(DYNAMIC)刚体,需要改变其速度,有以下几种方式:

通过重力

刚体组件提供了 UseGravity 属性,需要使用重力时候,需将 UseGravity 属性设置为 true

通过施加力

刚体组件提供了 applyForce 接口,根据牛顿第二定律,可对刚体某点上施加力来改变物体的原有状态。

import { math } from 'cc'

rigidBody.applyForce(new math.Vec3(200, 0, 0));

通过扭矩

力与冲量也可以只对旋转轴产生影响,使刚体发生转动,这样的力叫做扭矩。

刚体组件提供了 applyTorque 接口,通过此接口可以施加扭矩到刚体上,因为只影响旋转,所以不需要指定作用点。

rigidBody.applyTorque(new math.Vec3(200, 0, 0));

通过施加冲量

刚体组件提供了 applyImpulse 接口,施加冲量到刚体上的一个点,根据动量守恒,将立即改变刚体的线性速度。 如果冲量施加到的点不是刚体的质心,那么将产生一个扭矩并影响刚体的角速度。

rigidBody.applyImpulse(new math.Vec3(5, 0, 0));

通过改变速度

刚体组件提供了 setLinearVelocity 接口,可用于改变线性速度。

rigidBody.setLinearVelocity(new math.Vec3(5, 0, 0));

刚体组件提供了 setAngularVelocity 接口,可用于改变旋转速度。

rigidBody.setAngularVelocity(new math.Vec3(5, 0, 0));

3.恒力组件

恒力组件是一个工具组件,依赖于刚体组件,每帧都会对一个刚体施加给定的力和扭矩。

4.约束

在物理引擎中,约束 用于模拟物体间的连接情况,如连杆、绳子、弹簧或者布娃娃等。

约束依赖 刚体组件,若节点无刚体组件,则添加约束时,引擎会自动添加刚体组件。

1.4 物理材质

物理材质是一种资源,它记录了物体的物理属性,这些信息用来计算碰撞物体受到的摩擦力和弹力等。

1.5 物理事件

触发器与碰撞器

碰撞组件属性 IsTrigger 决定了组件为触发器还是碰撞器。将 IsTrigger 设置为 true 时,组件为触发器。触发器只用于碰撞检测和触发事件,会被物理引擎忽略。默认设置 false,组件为碰撞器,可以结合刚体产生碰撞效果。

1.6 射线检测

射线检测是对一条射线和另一个形状进行 相交性判断,如下图所示。

 1.7 物理应用案例

射击苹果——静态网格、凸包、多步模拟(步长调整)

一般的苹果都带有凹面,处理好凹类或带连续平滑不规则曲面的模型都非常棘手,这是因为目前成熟的理论和技术都建立在离散、凸包的世界之上(微积分中用差分近似表示微分就是最典型的范例)。

运动表现与模拟参数有非常大的关系,穿透是最具有代表性的现象,这可以通过缩减步长和增加步数来实现,调整步长有个小技巧:输入分式,即 1/Frame,其中 Frame 表示帧率。

2.粒子系统

粒子系统是游戏引擎特效表现的基础,它可以用于模拟的火、烟、水、云、雪、落叶等自然现象,也可用于模拟发光轨迹、速度线等抽象视觉效果。

3.缓动系统

缓动系统被广泛的应用于游戏开发中,其主要目的之一是用于解决离线动画无法满足需求时的动态动画的问题。

 4.地形系统

地形系统以一种高效的方式来展示大自然的山川地貌。开发者可以很方便的使用画刷来雕刻出盆地、山脉、峡谷、平原等地貌。

5.资源管理

Asset Manager 概述

在游戏的开发过程中,一般需要使用到大量的图片、音频等资源来丰富整个游戏内容,而大量的资源就会带来管理上的困难。所以 Creator 提供了 Asset Manager 资源管理模块来帮助开发者管理其资源的使用,大大提升开发效率和使用体验。

5.1 加载资源

1.动态加载 resources

通常我们会把项目中需要动态加载的资源放在 resources 目录下,配合 resources.load 等接口动态加载。你只要传入相对 resources 的路径即可,并且路径的结尾处 不能 包含文件扩展名。

// 加载 Prefab
resources.load("test_assets/prefab", Prefab, (err, prefab) => {
    const newNode = instantiate(prefab);
    this.node.addChild(newNode);
});

// 加载 AnimationClip
resources.load("test_assets/anim", AnimationClip, (err, clip) => {s
    this.node.getComponent(Animation).addClip(clip, "anim");
});

2.加载 SpriteFrame 或 Texture2D

图片设置为 sprite-frame 或 texture 或其他图片类型后,将会在 资源管理器 中生成一个对应类型的资源。但如果直接加载 test_assets/image,得到的类型将会是 ImageAsset。你必须指定路径到具体的子资源,才能加载到图片生成的 SpriteFrame

// 加载 SpriteFrame,image 是 ImageAsset,spriteFrame 是 image/spriteFrame,texture 是 image/texture
resources.load("test_assets/image/spriteFrame", SpriteFrame, (err, spriteFrame) => {
    this.node.getComponent(Sprite).spriteFrame = spriteFrame;
});
// 加载 texture
resources.load("test_assets/image/texture", Texture2D, (err: any, texture: Texture2D) => {
    const spriteFrame = new SpriteFrame();
    spriteFrame.texture = texture;
    this.node.getComponent(Sprite).spriteFrame = spriteFrame;
});

3.加载图集中的 SpriteFrame

// 加载 SpriteAtlas(图集),并且获取其中的一个 SpriteFrame
// 注意 atlas 资源文件(plist)通常会和一个同名的图片文件(png)放在一个目录下, 所以需要在第二个参数指定资源类型
resources.load("test_assets/sheep", SpriteAtlas, (err, atlas) => {
    const frame = atlas.getSpriteFrame('sheep_down_0');
    sprite.spriteFrame = frame;
});

4.加载 FBX 或 glTF 模型中的资源

在将 FBX 模型或 glTF 模型导入编辑器后,会解析出该模型中包含的相关资源如网格,材质,骨骼,动画等,如下图所示:

// 加载模型中的网格资源
resources.load("Monster/monster", Mesh, (err, mesh) => {
    this.node.getComponent(MeshRenderer).mesh = mesh;
});

// 加载模型中的材质资源
resources.load("Monster/monster-effect", Material, (err, material) => {
    this.node.getComponent(MeshRenderer).material = material;
});

// 加载模型中的骨骼
resources.load("Monster/Armature", Skeleton, (err, skeleton) => {
    this.node.getComponent(SkinnedMeshRenderer).skeleton = skeleton;
});

5.资源批量加载

resources.loadDir 可以加载相同路径下的多个资源:

// 加载 test_assets 目录下所有资源
resources.loadDir("test_assets", function (err, assets) {
    // ...
});

// 加载 test_assets 目录下所有 SpriteFrame,并且获取它们的路径
resources.loadDir("test_assets", SpriteFrame, function (err, assets) {
    // ...
});

6.预加载资源

因为预加载没有去解析资源,所以需要在预加载完成后配合加载接口进行资源的解析和初始化,来完成资源加载。

resources.preload('test_assets/image/spriteFrame', SpriteFrame);

// wait for while
resources.load('test_assets/image/spriteFrame', SpriteFrame, (err, spriteFrame) => {
    this.node.getComponent(Sprite).spriteFrame = spriteFrame;
});

7.加载远程资源和设备资源

// 远程 url 带图片后缀名
let remoteUrl = "http://unknown.org/someres.png";
assetManager.loadRemote<ImageAsset>(remoteUrl, function (err, imageAsset) {
    const spriteFrame = new SpriteFrame();
    const texture = new Texture2D();
    texture.image = imageAsset;
    spriteFrame.texture = texture;
    // ...
});

// 用绝对路径加载设备存储内的资源,比如相册
const absolutePath = "/dara/data/some/path/to/image.png";
assetManager.loadRemote<ImageAsset>(absolutePath, function (err, imageAsset) {
    const spriteFrame = new SpriteFrame();
    const texture = new Texture2D();
    texture.image = imageAsset;
    spriteFrame.texture = texture;
    // ...
});

// 远程音频
remoteUrl = "http://unknown.org/sound.mp3";
assetManager.loadRemote(remoteUrl, function (err, audioClip) {
    // play audio clip
});

// 远程文本
remoteUrl = "http://unknown.org/skill.txt";
assetManager.loadRemote(remoteUrl, function (err, textAsset) {
    // use string to do something
});

5.2 资源释放

1.自动释放

场景的自动释放可以直接在编辑器中设置。在 资源管理器 选中场景后,属性检查器 中会出现 自动释放资源 选项。

 

 勾选后,点击右上方的 应用 按钮,之后在切换该场景时便会自动释放该场景所有的依赖资源。建议场景尽量都勾选自动释放选项,以确保内存占用较低,除了部分高频使用的场景(例如主场景)。

另外,所有 Asset 实例都拥有成员函数 Asset.addRef 和 Asset.decRef,分别用于增加和减少引用计数。一旦引用计数为零,Creator 会对资源进行自动释放(需要先通过释放检查,具体可参考下部分内容的介绍)

start () {
    resources.load('images/background', Texture2D, (err, texture) => {
        this.texture = texture;
        // 当需要使用资源时,增加其引用
        texture.addRef();
        // ...
    });
}

onDestroy () {
    // 当不需要使用资源时,减少引用
    // Creator 会在调用 decRef 后尝试对其进行自动释放
    this.texture.decRef();
}

自动释放的优势在于不用显式地调用释放接口,开发者只需要维护好资源的引用计数,Creator 会根据引用计数自动进行释放。这大大降低了错误释放资源的可能性,并且开发者不需要了解资源之间复杂的引用关系。对于没有特殊需求的项目,建议尽量使用自动释放的方式来释放资源。

2.手动释放

当项目中使用了更复杂的资源释放机制时,可以调用 Asset Manager 的相关接口来手动释放资源。例如:

assetManager.releaseAsset(texture);

3.资源的动态引用

当开发者在编辑器中没有对资源做任何设置,而是通过代码动态加载资源并设置到场景的组件上,则资源的引用关系不会记录在序列化数据中,引擎无法统计到这部分的引用关系,这些引用关系就是动态引用。

如果开发者在项目中使用动态加载资源来进行动态引用,例如:

resources.load('images/background/spriteFrame', SpriteFrame, function (err, spriteFrame) {
    self.getComponent(Sprite).spriteFrame = spriteFrame;
});

此时会将 SpriteFrame 资源设置到 Sprite 组件上,引擎不会做特殊处理,SpriteFrame 的引用计数仍保持 0。如果动态加载出来的资源需要长期引用、持有,或者复用时,建议使用 addRef 接口手动增加引用计数。例如:

resources.load('images/background/spriteFrame', SpriteFrame, function (err, spriteFrame) {
    self.getComponent(Sprite).spriteFrame = spriteFrame;
    spriteFrame.addRef();
});

增加引用计数后,可以保证该资源不会被提前错误释放。而在不需要引用该资源以及相关组件,或者节点销毁时,请 务必记住 使用 decRef 移除引用计数,并将资源引用设为 null,例如:

this.spriteFrame.decRef();
this.spriteFrame = null;

5.3 下载与解析

Asset Manager 底层使用了多条加载管线来加载和解析资源,每条管线中都使用了 downloader 和 parser 模块,也就是下载器和解析器。开发者可以通过 assetManager.downloader 和 assetManager.parser 来访问。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40943.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中的抽象类和接口

java中的抽象类和接口抽象类什么是抽象类&#xff1f;抽象的使用场景抽象类的案例抽象类的特征、注意事项小结抽象类的应用知识&#xff1a;模版方法模式接口接口概述、特点接口的基本使用&#xff1a;被实现接口与接口的关系&#xff1a;多继承JDK8开始接口新增方法接口的注意…

AtCoder Beginner Contest 277 F. Sorting a Matrix(拓扑排序+虚点)

题目 n*m(2<n,m<1e6,n*m<1e6)的矩阵&#xff0c; 第i行第j列元素a[i][j](0<a[i][j]<n*m) 对于值为0的元素&#xff0c;你可以将其赋值为任意正整数&#xff0c; 不同位置的0元素&#xff0c;可以被赋值成不同的正整数 然后&#xff0c;你可以执行以下操作若…

firefly3399 移植linux5.15.80 - 2022-11-27

需要注意的是&#xff0c;虚拟机需要足够的硬盘空间&#xff0c;不小于15GB&#xff01;&#xff01; 一、内核源码下载 国内镜像地址 git clone https://kernel.source.codeaurora.cn/pub/scm/linux/kernel/git/stable/linux.git/ 基本达到了带宽的最大值。 国外地址&#…

Android使用AudioTrack播放WAV音频文件

目录 1、wav文件格式 2、wav文件解析 3、wav文件播放 QA&#xff1a; 开始播放wav的时候使用了系统的播放器mediaplayer进行播放&#xff0c;但是无奈mediaplayer支持的实在不好。 好些年前自己做过pcm播放使用的是audiotrack&#xff0c;参考&#xff1a;CSDN 其实两者之…

php 进程池设计与实现,phper必学!

php 进程池设计与实现phper 为什么要学习进程池池的概念为什么要有进程池?动态创建进程缺点进程池的优点选择子进程为新任务服务的方式进程池模型服务端客户端结语phper 为什么要学习进程池 在php开发过程中经常使用的 php-fpm 使用的进程模型就是进程池&#xff0c;学习进程…

如何基于FSM有限状态机实现Enemies AI

文章目录&#x1f35f; Preface&#x1f355; 巡逻状态&#x1f37f; 寻路状态&#x1f32d; 攻击状态&#x1f357; 完整代码&#x1f35f; Preface 本文简单介绍如何基于FSM有限状态机实现Enemies AI&#xff0c;首先定义敌人的AI逻辑&#xff1a;默认状态下Enemy为巡逻状态…

刷爆力扣之等价多米诺骨牌对的数量

刷爆力扣之等价多米诺骨牌对的数量 HELLO&#xff0c;各位看官大大好&#xff0c;我是阿呆 &#x1f648;&#x1f648;&#x1f648; 今天阿呆继续记录下力扣刷题过程&#xff0c;收录在专栏算法中 &#x1f61c;&#x1f61c;&#x1f61c; 该专栏按照不同类别标签进行刷题&…

使用 nlohmann 解析 json 文件

使用 nlohmann 解析 json 文件nlohmann/json的配置json基本数据结构json文件的读取、构造与输出C对象与nlohmann::json对象的转换C对象转换成nlohmann::json对象nlohmann::json对象转换成C对象序列化反序列化序列化nlohmann 是德国工程师&#xff0c;以其名字为工程名的 nlohm…

springboot项目的打包发布部署,jar和war的区别

简介&#xff1a; 1.Spring Boot使用了内嵌容器&#xff0c;因此它的部署方式也变得非常简单灵活&#xff0c;可以将Spring Boot项目打包成JAR包来独立运行&#xff0c;也可以打包成WAR包部署到Tomcat容器中运行&#xff0c;如果涉及大规模的部署&#xff0c;Jenkins成为最佳选…

【HCIP-Datacom】 IS-IS基础 ISIS动态路由协议配置(ISIS思维导图在底部)

目录 ISIS配置方法&#xff1a; 路由计算&#xff1a; ATT置位条件&#xff1a; 路由渗透&#xff1a; ISIS的认证&#xff1a; ISIS配置命令&#xff1a; ISIS的开销类型&#xff1a; ISIS配置方法&#xff1a; 进入ISIS进程 isis 1 //创建isis进程 设置实体名 network-entit…

.NET 升级发布后,IIS出现了System.IO.DirectoryNotFoundException

最近计划升级项目到.NET6, 在使用Release发布后发现IIS不能发现wwwroot目录,什么错误? 📢欢迎点赞 :👍 收藏 ⭐留言 📝 如有错误敬请指正,赐人玫瑰,手留余香!📢本文作者:由webmote 原创📢作者格言:无尽的折腾后,终于又回到了起点,工控,我来了 !1 发布的一…

《统计学习方法》 第十六章 主成分分析PCA

主成分分析(PCA) 假设xxx为mmm 维随机变量&#xff0c;其均值为μ\muμ&#xff0c;协方差矩阵为Σ\SigmaΣ 考虑由mmm维随机变量xxx到mmm维随机变量yyy的线性变换 yiαiTx∑k1mαkixk,i1,2,⋯,my _ { i } \alpha _ { i } ^ { T } x \sum _ { k 1 } ^ { m } \alpha _ { k …

计算点在线上的投影坐标

如题 计算点到线上的垂点&#xff0c;首先明确&#xff1a; 该线段必须给出确切的起始点和终点&#xff0c; 而不是一个向量&#xff0c;因为一个向量并不能代表一个线段。 所以参数列表如下&#xff1a; Vector3 VerticalPoint(Vector3 point, Vector3 lStart, Vector3 lEnd…

【论文翻译】增强复制状态机的两阶段提交协议

Enhancing Two Phase-Commit Protocol for Replicated State Machines Halit Uyanık and Tolga Ovatman Department of Computer Engineering Istanbul Technical University 34469 Istanbul, Turkey Email目录1 介绍2 设计和实现2.1 事件类型2.2 在状态机上执行事件2.3 具有优…

8、常用基本命令(重要)

文章目录8、常用基本命令&#xff08;重要&#xff09;8.1 帮助命令8.1.1 man 获得帮助信息8.1.2 help 获得 shell 内置命令的帮助信息8.1.3 常用快捷键8.2 文件目录类8.2.1 pwd 显示当前工作目录的绝对路径8.2.2 ls 列出目录的内容8.2.3 cd 切换目录8.2.4 mkdir 创建一个新的目…

Linux驱动入门

一、驱动简介 Linux的驱动在本质上就是一种软件程序&#xff0c;上层软件可以在不了解硬件特性的情况下&#xff0c;通过驱动提供的接口&#xff0c;和计算机硬件进行通信。 系统调用是内核和应用程序之间的接口&#xff0c;而驱动程序是内核和硬件之间的接口。它为应用程序屏蔽…

缓存穿透、缓存击穿、缓存雪崩及其解决方案

缓存&#xff08;cache&#xff09;&#xff0c;大家都非常熟悉&#xff0c;几乎每个系统乃至整个计算机体系中都会用到。在分布式系统架构中&#xff0c;主要用于减轻数据库的压力&#xff0c;提高系统的响应速度和并发吞吐&#xff0c;即空间(内存)换时间。当大量的读、写请求…

【模型推理加速系列】06: 基于resnet18加速方案评测

简介 花雪随风不厌看&#xff0c;更多还肯失林峦。愁人正在书窗下&#xff0c;一片飞来一片寒。小伙伴们好&#xff0c;我是微信公众号小窗幽记机器学习的首席称重师&#xff1a;卖麻辣烫的小男孩。今天这篇文章以resnet18模型为例&#xff0c;对比Pytorch、ONNX、TorchScript…

cmdline(二):uboot cmdline怎么传?cmdline kernel怎么用?

前面我们知道了cmdline是什么&#xff0c;已经在哪里添加cmdline&#xff1f;现在我们来看看在哪里传输cmdline&#xff0c;以及传输收到后怎么用&#xff1f; 参考内容来自前辈&#xff0c;感激&#xff1a; https://blog.csdn.net/weixin_42031299/article/details/12123950…

Spring Boot JPA EntityManager实体管理器示例

在本教程中&#xff0c;您将了解如何在 Spring Boot 示例中使用 JPA EntityManager&#xff08;使用 CRUD 操作和查询方法&#xff09;。我将向您展示&#xff1a; 在 Spring 引导中访问 JPA 实体管理器的方法如何使用实体管理器方法&#xff1a;执行SQL查询使用和CRUD操作cre…