cocos - 游戏开发。
Cocos 开发游戏
2d 版本
在 2D 游戏中,大部分可见物都是可以使用图像描述的。因而 2D 游戏会比 3D 游戏简单,更容易入门学习。
2D/UI 元素必须要在 Canvas 下才能看到,因此需要确保资源在 Canvas 层级下。
同时,层级决定了显示关系,随意调整会导致显示问题的出现。
预制体
是引擎的一种特殊资源。可以将节点持久化保存在资源管理器中,使得可以复用。
直接将需要保存为预制体的节点拖曳到资源管理器即可。
创建节点
cocos 中,实例被称为节点。比如地图节点,UI节点,摄像机节点等。
首先在层级管理中点击右键,在弹出的菜单中可以根据需要创建不同的节点。
创建角色
通常会使用图片作为角色,cocos 提供了一系列的内置的图片。
此处需要创建的角色,属于 Sprite 节点。
可以在侧边的属性检查器对节点属性进行包括位置,材质等在内的操作。
创建脚本
游戏是由不同的脚本所驱动的。而 cocos 则是使用的 TypeScript
语言。它是 JavaScript
的超集。
在资源管理器窗口右键,选择创建再点击脚本项即可创建一个脚本。
通常会在 assets
下创建一个 Scripts
文件夹用于存放各类脚本。
由引擎模板所创建的脚步则称之为组件。
在 cocos 内创建组件时会同时确定组件内根据模板生成的内容。如果输入了错误名字,可以直接删除重建,否则只是修改名称而不修改内部内容的话,会导致类名与文件名称不一致,使得属性检查器无法找到对应的类。
import { _decorator, Component, Node } from 'cc'
const { ccclass, property } = _decorator
@ccclass('PlayerController')
export class PlayerController extends Component {
// start 会在组件第一次激活的时候调用
start() {}
// 会被引擎以一定的时间间隔调用
// 比如帧率 30 每秒时 则每秒调用三十次
// deltaTime 则是更新的时间间隔
update(deltaTime: number) {}
}
需要注意,组件是必须挂载到节点上才能生效的。
首先点开对应节点的属性检查器,随后拖曳脚本组件过去即可。
也可以通过属性检查器的添加组件按钮进行增加组件,但是因为 Node
类已经有定义在 TypeScript
内置库中,所以导入时需要注意导入的是在 cc
命名空间下的 Node
。
import { _decorator, Component, Node } from 'cc'
保存场景
引擎首先需要一个场景才能正常运行。
在 assets
目录下新建 Scene
文件夹以保存场景。
首次保存需要命名场景并保存到指定位置。
直接 Crtl + S 快捷键即可保存。
编写脚本
监听输入
cocos 支持鼠标、键盘,触摸、手柄等硬件,并封装在了 Input
类中。
监听事件分为两种:
input.on
会监听所有的事件node.on
则只会监听某个范围内的事件
// input 为实例
// Input 为类型
// 这里监听了鼠标弹起的事件 并在触发时调用操作方法
input.on(Input.EventType.MOUSE_UP, 操作方法, 操作对象实例)
矢量存储和计算
Vec3
是三维矢量 Vector3 的缩写。这个类会提供三维矢量的存储和计算。
虽然在编辑器中所见到的都是 2D 的信息,但是引擎都是以 3D 为基础进行运算的。
因此,在计算时都会采用三维矢量用作运算位置的基础。
创建动画
cocos 支持多种动画效果,比如关键帧动画,Spine 和龙骨灯动画格式。
通常制作 2D 动画时,有几种方法:
- 关键帧动画,通过引擎进行制作,常用于 UI 动画,序列帧动画等。
- 骨骼动画,通过第三方工具制作并导出使用。
以关键帧动画为例,首先需要在对应节点上增加一个 Animation
组件。
随后建立 assets/Animation
文件夹以存放相关的动画剪辑。
将新建的动画剪辑拖曳到对应节点的剪辑区域即可。
编辑动画
选择已经绑定动画并需要进行编辑动画的节点,在编辑器的控制台区域切换到动画页面,点击进入编辑模式即可进行编辑操作。
在动画编辑器中,可以添加不同的动画轨道。
添加轨道之后,就可以增加不同的关键帧。
以 position 轨道为例,在编辑模式下,如果修改了物体的位置,只要该帧没有关键帧存在,则会自动创建关键帧。
播放动画
// animation 是节点动画的动画组件的引用
// play 则是播放动画的方法
// 参数为绑定给节点的动画名称
animation.play(AnimationName)
// NodeObject.ts
import { _decorator, Component, Vec3, EventMouse, input, Input, Animation } from "cc"
const { ccclass, property } = _decorator
@ccclass('NodeObject')
export class NodeObject extends Component {
// 使用装饰器助编辑器将 animation 视为 Animation 类型
// 此处命名的动画属性将会在应用的节点的属性检查器区域会示
// 需要注意 不能以 _ 开头
// 否则会导致无法识别
@property(Animation)
animation: Animation = null
}
选择应用脚本的节点,在属性检查器区域会显示定义的动画属性。
将应用动画的节点拖曳过去即可。
游戏管理器
为了将生成的过程和结果保存,一般而言是为了保存游戏的数据。需要建立一些辅助的工具类。也就是管理器类。
虽然可以将管理器类挂载到任意节点上,但一般出于清晰的考虑,会选择建立一个同名节点并挂载。
生成地图
虽然可以通过手动布置节点来生成地图,但过于单一的地图未免有些乏味了。因此,可以通过动态生成的方式创建地图。
首先需要让游戏管理器知道应该使用什么资源创建地图。
这里使用的是预制体。
@property({type: Prefab})
public boxPrefab: Prefab | null = null
// GameManager.ts
import { _decorator, Component, Prefab } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('GameManager')
export class GameManager extends Component {
@property({type: Prefab})
public boxPrefab: Prefab|null = null;
start(){}
update(dt: number): void {}
}
与动画一样,定义的预制体属性也会出现在对应节点的属性检查器上。
然后就可以将对应的预制体拖曳过去了。
之后就可以在代码中编写关于地图生成的代码了。
需要注意的是,如果需要设置节点的位置,要使用 setPosition
方法或 set position
这样的读取器。
相机和卷轴
2D 游戏中,必须考虑处理卷轴问题,也就是相机会随着角色的运动而运动。导致了看到的场景不一样的情况。
为实现卷轴,需要允许相机 (Camera) 可以移动并且不再强制和 Canvas 对齐。同时需要取消 Canvas 节点的 cc.Canvas
组件的 Align Canas With Screen 属性。
菜单制作
对于游戏而言,UI 都是比较重要的部分。
通过 UI 的提示,可以让玩家知道某些游戏内的信息,从而让玩家做出对应的策略。
在 2D 游戏下,虽然本身就拥有一个 Canvas 节点,因为这个节点会移动,只能作为角色,地图,游戏逻辑的父节点。否则会导致 UI 无法渲染。
因此需要重新创建一个同级的 Canvas 节点作为 UI 容器。
随后就可以在该 Canvas 节点下进行各种 UI 布局了。
UI 的布局很简单,cocos 的场景编辑器提供了所见即所得的功能。只需要创建对应的 UI 节点,修改文本,拖曳到对应的位置即可。
游戏状态
此处以初始化、游戏中、游戏重置或结算三种状态为例。
可以使用枚举来描述游戏的状态。
在游戏管理器脚本中可以根据不同的状态来进行不同的操作。
比如初始化时初始地图,角色位置,分数,游戏中更改角色位置,分数,游戏重置或结算时告诉玩家走了多少步,获得了多少分等。
层级
在 2D 中,需要规划好物体的层级以确保显示的内容是正确的。
UICanvas 和 Canvas 如果没有做其他操作,则默认会重叠,因为 UICanvas 的相机也绘制了 Canvas 的内容。
因而需要将 Canvas 相关节点,Canvas 用到的预制体资源的层级修改为 DEFAULT。
然后修改相机的可见属性,Canvas 的更改为 DEFAULT,而 UICanvas 的则改为 UI_2D 即可。
3D 版本
只介绍与 2D 版本所不同的地方。
光照和阴影
光影是描述游戏的重要渲染特性,通过它,可以模拟更真实的游戏世界,提供更好的体验。
首先需要在层级管理器最顶层的 Scene 节点的属性检查器中勾选 shadows 的 Enabled 启用。
随后在需要增加光影的节点的属性检查器打开阴影即可。
调整光照
新建场景时,默认挂载了一个 Main Ligth 组件。
由这个平行光计算阴影,因此,可以调整平行光的方向以使得阴影可以换个方向。