事件中心(发布订阅模式)
Runtime/EventManager.ts
发布和订阅模式,发布事件
import Singleton from '../Base/Singleton'
interface IItem {
ctx: unknown // this
func: Function
}
/**
* 单例模式
* 按钮事件
*/
export default class EventManager extends Singleton {
static get Instance() {
return super.GetInstance()
}
// 使用key->Array的结构存储事件
private eventDic: Map = new Map()
// 添加绑定事件
on(eventName: string, func: Function, ctx?: unknown) {
if (this.eventDic.has(eventName)) {
this.eventDic.get(eventName).push({ func, ctx })
} else {
this.eventDic.set(eventName, [{ func, ctx }])
}
}
// 解绑事件
off(eventName: string, func: Function) {
if (this.eventDic.has(eventName)) {
const index = this.eventDic.get(eventName).findIndex(i => i.func === func)
index > -1 && this.eventDic.get(eventName).slice(index, 1)
}
}
// 调用事件
emit(eventName: string, ...params: unknown[]) {
console.log('this.eventDic.has(eventName)', eventName)
if (this.eventDic.has(eventName)) {
this.eventDic.get(eventName).forEach((i: IItem) => {
if (i.ctx) {
i.func.apply(i.ctx, params)
} else {
i.func(...params)
}
})
}
}
// 清除事件
clear() {
this.eventDic.clear()
}
}
export const DataManagerInstance = new EventManager()
切换地图
Scripts/Scene/BattleManager.ts
事件中心的使用-关键代码
onLoad() {
// 绑定事件-关卡切换
EventManager.Instance.on(EVENT_ENUM.NEXT_LEVEL, this.nextLevel, this)
}
// 关卡切换-下一关
nextLevel() {
DataManager.Instance.levelIndex++
this.initLevel()
}
// 关卡清空
clearLevel() {
this.stage.destroyAllChildren()
DataManager.Instance.reset()
}
onDestroy() {
// 解绑事件
EventManager.Instance.off(EVENT_ENUM.NEXT_LEVEL, this.nextLevel)
}
控制台添加动画
新建Sprite—>添加Animation组件→点击动画编辑器→拖入每一帧图片,设置帧率,循环播放
组件勾选PlayOnLoad
文档地址:
程序化编辑动画剪辑
Scripts/Player/PlayerManager.ts
import {
_decorator,
Component,
Node,
Sprite,
UITransform,
Animation,
AnimationClip,
animation,
Vec3,
SpriteFrame,
} from 'cc'
import { TILE_HEIGHT, TILE_WIDTH } from '../Tile/TileManager'
import ResourceManager from '../../Runtime/ResourceManager'
const { ccclass, property } = _decorator
const ANIMATION_SPEED = 1 / 8 // 1秒8帧
@ccclass('PlayerManager')
export class PlayerManager extends Component {
async init() {
const sprite = this.addComponent(Sprite)
sprite.sizeMode = Sprite.SizeMode.CUSTOM
const transform = this.getComponent(UITransform)
transform.setContentSize(TILE_WIDTH * 4, TILE_HEIGHT * 4)
// 加载资源文件夹
const spriteFrames = await ResourceManager.Instance.loadDir('texture/player/idle/top')
// 添加动画
const animationComponent = this.addComponent(Animation)
const animationClip = new AnimationClip()
// 创建一个对象轨道
const track = new animation.ObjectTrack()
// 添加轨道路径为Sprite组件
track.path = new animation.TrackPath().toComponent(Sprite).toProperty('spriteFrame')
const frames: Array = spriteFrames.map((item, index) => [index * ANIMATION_SPEED, item])
// 设置一条通道channel的关键帧
track.channel.curve.assignSorted(
frames,
/* [
// 为 x 通道的曲线添加关键帧
[0.4, { value: 0.4 }], //[时间,属性]
[0.6, { value: 0.6 }],
[0.8, { value: 0.8 }],
]*/
)
// 最后将轨道添加到动画剪辑以应用
animationClip.addTrack(track)
// 整个动画剪辑的周期 帧数*帧率
animationClip.duration = frames.length * ANIMATION_SPEED
// 循环播放
animationClip.wrapMode = AnimationClip.WrapMode.Loop
// 设置动画,defaultClip,并且播放
animationComponent.defaultClip = animationClip
animationComponent.play()
}
}
Scripts/Scene/BattleManager.ts
start() {
this.generatePlayer()
}
// 创建人物
generatePlayer() {
const player = createUINode()
player.setParent(this.stage)
const playerManager = player.addComponent(PlayerManager)
playerManager.init()
}
人物移动
Enum/index.ts
/**
* 人物移动方向枚举
*/
export enum CONTROLLER_ENUM {
TOP = 'TOP',
LEFT = 'LEFT',
RIGHT = 'RIGHT',
BOTTOM = 'BOTTOM',
TURN_LEFT = 'TURN_LEFT',
TURN_RIGHT = 'TURN_RIGHT',
}
Scripts/Player/PlayerManager.ts
import {
_decorator,
Component,
Node,
Sprite,
UITransform,
Animation,
AnimationClip,
animation,
Vec3,
SpriteFrame,
} from 'cc'
import { TILE_HEIGHT, TILE_WIDTH } from '../Tile/TileManager'
import ResourceManager from '../../Runtime/ResourceManager'
import { CONTROLLER_ENUM, EVENT_ENUM } from '../../Enum'
import EventManager from '../../Runtime/EventManager'
const { ccclass, property } = _decorator
const ANIMATION_SPEED = 1 / 8 // 1秒8帧
@ccclass('PlayerManager')
export class PlayerManager extends Component {
// 坐标
x: number = 0
y: number = 0
// 目标坐标
targetX: number = 0
targetY: number = 0
// 速度
private readonly sped = 1 / 10
init() {
this.render()
EventManager.Instance.on(EVENT_ENUM.PLAY_CTRL, this.move, this)
}
update() {
// 更新人物移动坐标数据
this.updateXY()
// 更新移动位置,由于人物占4个格子居中需要偏移
this.node.setPosition(this.x * TILE_WIDTH - TILE_WIDTH * 1.5, -this.y * TILE_HEIGHT + TILE_HEIGHT * 1.5)
}
// 更新xy,让xy无限趋近于targetX targetY(位移过渡)
updateXY() {
if (this.targetX this.x) {
this.x += this.sped
}
if (this.targetY this.y) {
this.y += this.sped
}
if (Math.abs(this.targetY - this.y)
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?