目录
[1 脚本基础](#1 脚本基础)
[1.1 创建脚本](#1.1 创建脚本)
[1.2 脚本结构](#1.2 脚本结构)
[ccclass 装饰器](#ccclass 装饰器)
[property 装饰器](#property 装饰器)
[2 生命周期](#2 生命周期)
[2.1 生命周期回调](#2.1 生命周期回调)
[2.2 执行顺序](#2.2 执行顺序)
[3 节点操作](#3 节点操作)
[3.1 获取节点](#3.1 获取节点)
[3.2 创建和销毁节点](#3.2 创建和销毁节点)
[3.3 节点变换](#3.3 节点变换)
[4 组件操作](#4 组件操作)
[4.1 获取和添加组件](#4.1 获取和添加组件)
[4.2 组件通信](#4.2 组件通信)
[5 资源加载](#5 资源加载)
[5.1 资源分类](#5.1 资源分类)
[5.2 静态加载](#5.2 静态加载)
[5.3 动态加载](#5.3 动态加载)
[使用 Promise](#使用 Promise)
[5.4 资源释放](#5.4 资源释放)
[6 动作系统](#6 动作系统)
[6.1 基本动作](#6.1 基本动作)
[6.2 组合动作](#6.2 组合动作)
[6.3 回调动作](#6.3 回调动作)
[7 定时器](#7 定时器)
[7.1 setTimeout 和 setInterval](#7.1 setTimeout 和 setInterval)
[7.2 使用 schedule](#7.2 使用 schedule)
[8 总结](#8 总结)
本文摘要:
Cocos Creator 3.x脚本开发指南详细介绍了游戏脚本的核心功能。主要内容包括:
1)脚本创建与结构,使用@ccclass和@property装饰器定义组件类及可序列化属性;
2)完整的生命周期回调函数及其执行顺序;
3)节点操作(获取、创建、变换、销毁);
4)组件管理(获取、添加、通信)及事件系统使用;
5)资源加载方式(静态拖拽和动态加载)及资源释放;
6)动作系统(基础动作、组合动作及回调);
7)定时器实现方案(setTimeout/setInterval和schedule)。
该指南为开发者提供了从脚本基础到高级功能的全面参考,是掌握Cocos Creator脚本开发的实用手册。
1 脚本基础
1.1 创建脚本
在 Cocos Creator 3.x 中创建脚本非常简单:
-
在资源管理器中右键点击
-
选择"新建" -> "TypeScript"
-
输入脚本名称
创建的脚本模板如下:
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('NewScript')
export class NewScript extends Component {
// 在这里声明属性
start() {
// 组件激活时执行
}
update(deltaTime: number) {
// 每帧执行
}
}
1.2 脚本结构
ccclass 装饰器
@ccclass 装饰器用于定义一个组件类,参数是类的名称。
property 装饰器
@property 装饰器用于声明可以在属性检查器中显示的属性。
import { _decorator, Component, Node, SpriteFrame } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('Player')
export class Player extends Component {
// 基本类型属性
@property({ type: Node })
public target: Node = null!;
@property
public speed: number = 5;
@property
public isAlive: boolean = true;
@property
public playerName: string = 'Player';
// 数组类型属性
@property({ type: [SpriteFrame] })
public frames: SpriteFrame[] = [];
}
属性参数
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('PropertyExample')
export class PropertyExample extends Component {
// 完整的属性声明
@property({
type: Node,
visible: true, // 是否在属性检查器中显示
serializable: true, // 是否序列化
displayName: '目标节点', // 在属性检查器中显示的名称
tooltip: '设置目标节点', // 鼠标悬停时显示的提示
})
public target: Node = null!;
// 范围限制
@property({
type: Number,
min: 0,
max: 100,
step: 1
})
public health: number = 100;
}
2 生命周期
2.1 生命周期回调
Cocos Creator 3.x 提供了丰富的生命周期回调函数:
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('LifeCycleExample')
export class LifeCycleExample extends Component {
// 组件被创建时调用(只调用一次)
onLoad() {
console.log('onLoad: 组件被创建');
}
// 组件激活时调用(每次激活都会调用)
onEnable() {
console.log('onEnable: 组件被激活');
}
// 第一次执行 update 之前调用
start() {
console.log('start: 组件开始');
}
// 每帧执行
update(deltaTime: number) {
console.log(`update: 帧时间 ${deltaTime}`);
}
// 所有组件的 update 执行完后执行
lateUpdate(deltaTime: number) {
console.log(`lateUpdate: 帧时间 ${deltaTime}`);
}
// 组件禁用时调用
onDisable() {
console.log('onDisable: 组件被禁用');
}
// 组件被销毁时调用
onDestroy() {
console.log('onDestroy: 组件被销毁');
}
}
2.2 执行顺序
生命周期回调的执行顺序:
-
onLoad()- 组件加载 -
onEnable()- 组件启用 -
start()- 组件开始 -
update()- 每帧更新 -
lateUpdate()- 每帧更新后 -
onDisable()- 组件禁用 -
onDestroy()- 组件销毁
3 节点操作
3.1 获取节点
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('NodeOperations')
export class NodeOperations extends Component {
start() {
// 获取自身节点
const self = this.node;
console.log(`自身节点: ${self.name}`);
// 通过属性面板获取节点
@property({ type: Node })
public targetNode: Node = null!;
// 获取父节点
const parent = this.node.parent;
if (parent) {
console.log(`父节点: ${parent.name}`);
}
// 获取子节点
const child = this.node.getChildByName('ChildNode');
if (child) {
console.log(`子节点: ${child.name}`);
}
// 获取所有子节点
const children = this.node.children;
console.log(`子节点数量: ${children.length}`);
// 通过路径查找节点
const foundNode = this.node.getChildByPath('UI/Button/Text');
if (foundNode) {
console.log(`找到节点: ${foundNode.name}`);
}
}
}
3.2 创建和销毁节点
import { _decorator, Component, Node, Sprite, SpriteFrame } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('NodeCreation')
export class NodeCreation extends Component {
@property({ type: SpriteFrame })
public spriteFrame: SpriteFrame = null!;
start() {
// 创建新节点
const newNode = new Node('NewSprite');
// 添加Sprite组件
const sprite = newNode.addComponent(Sprite);
sprite.spriteFrame = this.spriteFrame;
// 设置父节点
newNode.parent = this.node;
// 设置位置
newNode.setPosition(100, 100, 0);
// 设置缩放
newNode.setScale(2, 2, 1);
// 5秒后销毁节点
setTimeout(() => {
newNode.destroy();
console.log('节点已销毁');
}, 5000);
}
}
3.3 节点变换
import { _decorator, Component, Node, Vec3, Quat } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('NodeTransform')
export class NodeTransform extends Component {
start() {
// 位置操作
const pos = this.node.position;
this.node.setPosition(pos.x + 10, pos.y, pos.z);
// 相对位置
this.node.translate(new Vec3(5, 0, 0));
// 旋转操作(欧拉角)
this.node.setRotationFromEuler(0, 90, 0);
// 旋转操作(四元数)
const quat = new Quat();
Quat.fromEuler(quat, 0, 90, 0);
this.node.rotation = quat;
// 相对旋转
this.node.rotate(new Vec3(0, 10, 0));
// 缩放操作
this.node.setScale(2, 2, 1);
// 相对缩放
this.node.scale(new Vec3(1.1, 1.1, 1));
// 获取世界坐标
const worldPos = this.node.worldPosition;
console.log(`世界坐标: ${worldPos}`);
}
}
4 组件操作
4.1 获取和添加组件
import { _decorator, Component, Node, Sprite, RigidBody2D } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ComponentOperations')
export class ComponentOperations extends Component {
start() {
// 获取组件
const sprite = this.node.getComponent(Sprite);
if (sprite) {
console.log('Sprite组件存在');
}
// 获取多个同类型组件
const sprites = this.node.getComponents(Sprite);
console.log(`Sprite组件数量: ${sprites.length}`);
// 获取子节点的组件
const childSprite = this.node.getChildByName('Child')?.getComponent(Sprite);
// 添加组件
const rigidBody = this.node.addComponent(RigidBody2D);
// 检查组件是否存在
const hasCollider = this.node.hasComponent(Collider2D);
console.log(`是否有Collider2D: ${hasCollider}`);
}
}
4.2 组件通信
通过属性面板
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('Player')
export class Player extends Component {
public health: number = 100;
takeDamage(damage: number) {
this.health -= damage;
console.log(`玩家受到 ${damage} 点伤害,剩余血量: ${this.health}`);
}
}
@ccclass('GameManager')
export class GameManager extends Component {
@property({ type: Node })
public playerNode: Node = null!;
start() {
const player = this.playerNode.getComponent(Player);
if (player) {
player.takeDamage(20);
}
}
}
通过事件系统
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('EventSender')
export class EventSender extends Component {
start() {
// 发送事件
this.node.emit('playerDamaged', { damage: 20 });
}
}
@ccclass('EventReceiver')
export class EventReceiver extends Component {
onLoad() {
// 监听事件
this.node.on('playerDamaged', this.onPlayerDamaged, this);
}
onPlayerDamaged(event: any) {
const data = event.detail;
console.log(`接收到伤害事件: ${data.damage}`);
}
onDestroy() {
// 取消监听
this.node.off('playerDamaged', this.onPlayerDamaged, this);
}
}
5 资源加载
5.1 资源分类
Cocos Creator 3.x 的资源分为两类:
-
内置资源:引擎自带的资源
-
用户资源:开发者导入的资源
5.2 静态加载
通过属性面板拖拽资源:
import { _decorator, Component, SpriteFrame, AudioClip } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('StaticResource')
export class StaticResource extends Component {
// 通过属性面板设置
@property({ type: SpriteFrame })
public playerSprite: SpriteFrame = null!;
@property({ type: AudioClip })
public bgm: AudioClip = null!;
start() {
// 直接使用资源
const sprite = this.node.getComponent(Sprite);
sprite.spriteFrame = this.playerSprite;
}
}
5.3 动态加载
加载单个资源
import { _decorator, Component, Sprite, SpriteFrame, resources } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('DynamicResource')
export class DynamicResource extends Component {
start() {
// 加载SpriteFrame
resources.load('textures/player', SpriteFrame, (err, spriteFrame) => {
if (err) {
console.error('加载失败:', err);
return;
}
const sprite = this.node.getComponent(Sprite);
sprite.spriteFrame = spriteFrame;
});
}
}
加载资源目录
import { _decorator, Component, SpriteFrame, resources } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('LoadDirectory')
export class LoadDirectory extends Component {
start() {
// 加载整个目录的资源
resources.loadDir('textures/enemies', SpriteFrame, (err, spriteFrames) => {
if (err) {
console.error('加载失败:', err);
return;
}
console.log(`加载了 ${spriteFrames.length} 个精灵帧`);
});
}
}
使用 Promise
import { _decorator, Component, SpriteFrame, resources } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('PromiseResource')
export class PromiseResource extends Component {
async start() {
try {
// 使用Promise方式加载
const spriteFrame = await resources.loadAsync('textures/player', SpriteFrame);
const sprite = this.node.getComponent(Sprite);
sprite.spriteFrame = spriteFrame;
} catch (error) {
console.error('加载失败:', error);
}
}
}
5.4 资源释放
import { _decorator, Component, SpriteFrame, resources } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ResourceRelease')
export class ResourceRelease extends Component {
private spriteFrame: SpriteFrame | null = null;
async loadResource() {
this.spriteFrame = await resources.loadAsync('textures/player', SpriteFrame);
}
releaseResource() {
if (this.spriteFrame) {
// 释放资源
resources.release('textures/player', SpriteFrame);
this.spriteFrame = null;
}
}
}
6 动作系统
6.1 基本动作
import { _decorator, Component, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ActionExample')
export class ActionExample extends Component {
start() {
// 移动动作
const moveTo = this.node.moveTo(1, new Vec3(100, 100, 0));
this.node.runAction(moveTo);
// 缩放动作
const scaleTo = this.node.scaleTo(0.5, 2, 2, 1);
// 旋转动作
const rotateTo = this.node.rotateTo(1, 0, 180, 0);
// 淡入淡出
const fadeOut = this.node.fadeOut(1);
// 延迟动作
const delay = this.node.delayTime(2);
}
}
6.2 组合动作
import { _decorator, Component, Node, Vec3, tween } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ActionSequence')
export class ActionSequence extends Component {
start() {
// 顺序动作
tween(this.node)
.to(1, { position: new Vec3(100, 100, 0) })
.to(0.5, { scale: new Vec3(2, 2, 1) })
.delay(1)
.to(1, { position: new Vec3(0, 0, 0) })
.start();
// 并行动作
tween(this.node)
.parallel(
tween().to(1, { position: new Vec3(100, 0, 0) }),
tween().to(1, { rotation: new Vec3(0, 360, 0) })
)
.start();
// 重复动作
tween(this.node)
.to(1, { position: new Vec3(100, 0, 0) })
.to(1, { position: new Vec3(0, 0, 0) })
.repeat(3)
.start();
// 永久重复
tween(this.node)
.to(1, { scale: new Vec3(1.2, 1.2, 1) })
.to(1, { scale: new Vec3(1, 1, 1) })
.repeatForever()
.start();
}
}
6.3 回调动作
import { _decorator, Component, Node, Vec3, tween } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ActionCallback')
export class ActionCallback extends Component {
start() {
tween(this.node)
.to(1, { position: new Vec3(100, 100, 0) })
.call(() => {
console.log('移动完成!');
})
.to(1, { position: new Vec3(0, 0, 0) })
.call(this.onComplete, this)
.start();
}
onComplete() {
console.log('所有动作完成!');
}
}
7 定时器
7.1 setTimeout 和 setInterval
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('TimerExample')
export class TimerExample extends Component {
private timerId: number | null = null;
start() {
// 延迟执行
setTimeout(() => {
console.log('3秒后执行');
}, 3000);
// 定时重复执行
this.timerId = setInterval(() => {
console.log('每秒执行一次');
}, 1000);
}
onDestroy() {
// 清理定时器
if (this.timerId) {
clearInterval(this.timerId);
}
}
}
7.2 使用 schedule
import { _decorator, Component, Node } from 'cc';
const { ccclass, property } = _decorator;
@ccclass('ScheduleExample')
export class ScheduleExample extends Component {
start() {
// 延迟执行
this.scheduleOnce(() => {
console.log('2秒后执行');
}, 2);
// 定时执行(每1秒执行一次)
this.schedule(() => {
console.log('定时执行');
}, 1);
// 带延迟的定时执行
this.schedule(() => {
console.log('延迟1秒后开始,每2秒执行一次');
}, 2, 5, 1); // 间隔2秒,执行5次,延迟1秒开始
}
onDisable() {
// 取消所有调度
this.unscheduleAllCallbacks();
}
}
8 总结
通过本章的学习,你应该掌握了:
-
脚本的基本结构和装饰器使用
-
生命周期回调函数
-
节点的创建、获取和操作
-
组件的获取、添加和通信
-
资源的静态和动态加载
-
动作系统的使用
-
定时器的使用
在下一章中,我们将学习UI系统。