【Cocos Creator 3.x】篇——第三章 脚本编程

目录

[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 中创建脚本非常简单:

  1. 在资源管理器中右键点击

  2. 选择"新建" -> "TypeScript"

  3. 输入脚本名称

创建的脚本模板如下:

复制代码
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 执行顺序

生命周期回调的执行顺序:

  1. onLoad() - 组件加载

  2. onEnable() - 组件启用

  3. start() - 组件开始

  4. update() - 每帧更新

  5. lateUpdate() - 每帧更新后

  6. onDisable() - 组件禁用

  7. 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 的资源分为两类:

  1. 内置资源:引擎自带的资源

  2. 用户资源:开发者导入的资源

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 总结

通过本章的学习,你应该掌握了:

  1. 脚本的基本结构和装饰器使用

  2. 生命周期回调函数

  3. 节点的创建、获取和操作

  4. 组件的获取、添加和通信

  5. 资源的静态和动态加载

  6. 动作系统的使用

  7. 定时器的使用

在下一章中,我们将学习UI系统。

相关推荐
雨翼轻尘1 小时前
01_HTML基本结构
前端·html·基本结构
右耳朵猫AI2 小时前
前端周刊2026W22 | React 13周年、TanStack Router、Deno 2.8、Node.js 26、npm 分阶段发布
前端·react.js·node.js
scan7242 小时前
从runtime获取信息
java·服务器·前端
木头羊oll2 小时前
Uniapp 与 H5 在 App 端的交互
前端·javascript·html
可别3902 小时前
Vue 极简实现语音实时转写(录音转文字,低网络依赖、开箱即用)
前端·javascript·vue.js
小雨下雨的雨2 小时前
数独算法与求解器鸿蒙PC Electron框架完成深度解析
javascript·人工智能·算法·游戏·华为·electron·鸿蒙系统
阿猫的故乡2 小时前
Vue插槽从入门到项目实战:默认插槽、具名插槽、作用域插槽,一次讲明白
前端·javascript·vue.js
SEO-狼术2 小时前
Build Interactive Maps Crack
前端
小则又沐风a2 小时前
进程最终篇---进程控制(模拟实现xshell)
java·linux·服务器·前端