检查点
目前游戏是不管在哪个位置角色死亡,都需要复活到起点重新开始闯关,这会大大增加游戏难度。所以我们需要利用检查点将整个关卡拆分成多个小关卡,然后按关卡号保存游戏进度。
1.布置检查点
检查点也是通过触发器来实现功能的,所以我们需要在场景上布置触发器。并且由于触发器是透明的,在游戏中玩家是看不见的,所以需要用一个特效或者模型来标记出触发器的位置。
①拖动一个触发器到场景中,并将网络状态修改为客户端
②在美术对象中选择“粒子特效”分类
③将特效挂载到触发器下(方便同时移动)
④调整相对位置,让特效位置与触发器位置相吻合
2.CheckPointTrigger脚本
接下来我们需要编写检查点脚本来进行关卡进度存储的逻辑。
2.1.创建并挂载脚本
①点击“新建脚本”
②将脚本命名为CheckPointTrigger
③将脚本挂载到触发器上
2.2.自定义属性
在CheckPointTrigger脚本中编写逻辑如下:
装饰器:@Property()
@Property()是一个属性装饰器,它能够让脚本里的属性字段具备一些特殊功能,例如进行属性同步、在属性面板上进行显示等。
ts
@Component
export default class CheckPointTrigger extends Script {
@Property({displayName:"序号"})
public pointNumber:number = 0
}
@Component
export default class CheckPointTrigger extends Script {
@Property({displayName:"序号"})
public pointNumber:number = 0
}
在上述逻辑中,我们给pointNumber属性添加了装饰器,并且将装饰器里的displayName参数赋值为“序号”,那么脚本就能在属性面板上展示出这个序号。我们就可以直接在属性面板上对pointNumber进行赋值。具体效果如下:
①在对象管理器中选中CheckPointTrigger脚本
②在属性面板上将“序号”修改为1(这个检查点放在起点作为第一关)
2.3.编写检查点逻辑
在CheckPointTrigger脚本中添加逻辑如下:
① 通过this.gameObject获取到脚本挂载的物体(这就是脚本需要挂载到触发器上的原因)
② 给触发器添加进入逻辑,通过instanceof判断进入的物体是否为角色类型
③ 通过Player.localPlayer.character获取到当前客户端的角色,实现只有当进入的角色是当前客户端角色,才进行检查点事件的派发。
④ 通过Event.dispatchToLocal这个API,向本地派发"CheckPoint"事件。
ts
@Component
export default class CheckPointTrigger extends Script {
@Property({ displayName: "序号" })
public pointNumber: number = 0
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected onStart(): void {
let trigger = this.gameObject as Trigger
trigger.onEnter.add((other: GameObject) => {
// 进入的物体是否是角色
if (other instanceof Character) {
// 进入的角色 是否是 当前客户端角色
if (other == Player.localPlayer.character) {
// 本地事件通信(派发)
Event.dispatchToLocal("CheckPoint", this)
}
}
})
}
}
@Component
export default class CheckPointTrigger extends Script {
@Property({ displayName: "序号" })
public pointNumber: number = 0
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected onStart(): void {
let trigger = this.gameObject as Trigger
trigger.onEnter.add((other: GameObject) => {
// 进入的物体是否是角色
if (other instanceof Character) {
// 进入的角色 是否是 当前客户端角色
if (other == Player.localPlayer.character) {
// 本地事件通信(派发)
Event.dispatchToLocal("CheckPoint", this)
}
}
})
}
}
3.改写复活逻辑
目前角色都是复活在一个固定位置,我们需要在关卡管理器脚本中添加监听事件,并且配合检查点派发的事件来动态的修改角色下一次的复活位置。这样就能实现局内的进度保存。
这次修改只涉及到关卡管理器脚本。
修改后的LevelManager脚本:
此次修改有如下几个要点:
①在init函数中添加对"CheckPoint"事件的监听
②当监听到CheckPoint事件时,将检查点的位置赋值给重生位置
③角色复活时,将角色的位置修改为重生位置
ts
import CheckPointTrigger from "./CheckPointTrigger"
/**
* 关卡管理器
*/
export class LevelManager {
// 单例模式
private static _instacne: LevelManager
public static get instance(): LevelManager {
if (LevelManager._instacne == null) {
LevelManager._instacne = new LevelManager()
}
return LevelManager._instacne
}
/**死亡触发器 */
private _deathTrigger: Trigger
/**复活位置 */
private _rebornPosition: Vector = new Vector(10, 0, 420)
public async init() {
this._deathTrigger = await GameObject.asyncFindGameObjectById("299CDDA6") as Trigger
this._deathTrigger.onEnter.add((other: GameObject) => {
// 当进入的物体是角色类型
if (other instanceof Character) {
// 让角色死亡
this.charDeath(other)
}
})
Event.addLocalListener("CheckPoint", (checkPointTrigger: CheckPointTrigger) => {
this._rebornPosition = checkPointTrigger.gameObject.worldTransform.position.clone()
})
}
/**让角色死亡 */
public charDeath(char: Character) {
// 开启布娃娃属性
char.ragdollEnabled = true
setTimeout(() => {
// 让角色复活
this.charReborn(char)
}, 3000);
}
/**让角色复活 */
public charReborn(char: Character) {
if (char == Player.localPlayer.character) {
// 将角色的位置改变到复活点
char.worldTransform.position = this._rebornPosition.clone()
}
// 关闭布娃娃属性
char.ragdollEnabled = false
}
}
import CheckPointTrigger from "./CheckPointTrigger"
/**
* 关卡管理器
*/
export class LevelManager {
// 单例模式
private static _instacne: LevelManager
public static get instance(): LevelManager {
if (LevelManager._instacne == null) {
LevelManager._instacne = new LevelManager()
}
return LevelManager._instacne
}
/**死亡触发器 */
private _deathTrigger: Trigger
/**复活位置 */
private _rebornPosition: Vector = new Vector(10, 0, 420)
public async init() {
this._deathTrigger = await GameObject.asyncFindGameObjectById("299CDDA6") as Trigger
this._deathTrigger.onEnter.add((other: GameObject) => {
// 当进入的物体是角色类型
if (other instanceof Character) {
// 让角色死亡
this.charDeath(other)
}
})
Event.addLocalListener("CheckPoint", (checkPointTrigger: CheckPointTrigger) => {
this._rebornPosition = checkPointTrigger.gameObject.worldTransform.position.clone()
})
}
/**让角色死亡 */
public charDeath(char: Character) {
// 开启布娃娃属性
char.ragdollEnabled = true
setTimeout(() => {
// 让角色复活
this.charReborn(char)
}, 3000);
}
/**让角色复活 */
public charReborn(char: Character) {
if (char == Player.localPlayer.character) {
// 将角色的位置改变到复活点
char.worldTransform.position = this._rebornPosition.clone()
}
// 关闭布娃娃属性
char.ragdollEnabled = false
}
}
小提示
大家不要盲目进行复制粘贴哦,这里还是不要忘了将代码中的"299CDDA6"替换为自己触发器的对象ID
4.完善检查点
这一步我们需要在场景中按照自己的需求给关卡布置上检查点,并给检查点脚本的序号进行正确的赋值。其中终点的序号需要填入-1,下一节将会使用到它。
①在场景中布置检查点触发器,并给检查点脚本的序号进行正确的赋值
②给终点检查点脚本的序号赋值为-1