当前位置: 首页 > news >正文

cocos:从@ccclass装饰器到组件化开发

前言:我只负责提问题,答案是由AI(GPT-4o)生成的,感觉很可以,于是便记录下来。在问题导引这里,这些问题大家心中都能回答吗?


问题起因

  • cocos使用@ccclass装饰器实现组件化开发

  • 通过@property实现编辑器可视化配置


问题导引:

  1. @ccclass装饰器是什么?有什么用?

  2. 什么是组件化开发?组件化开发的核心思想是什么?

  3. 为什么@ccclass装饰器能实现组件化开发?

  4. @ccclass 装饰器实现组件化开发设计思想与底层原理是什么?

  5. @ccclass 装饰器实现组件化开发具体实现

  6. 实现自定义的简易组件化开发框架

问题详解:

  1. @ccclass装饰器是什么?有什么用?

  • @ccclass 装饰器是 Cocos Creator 框架中基于 TypeScript 的一种语法特性,它用于定义和注册组件类,使其能够被 Cocos Creator 编辑器识别和使用。

  • 在组件化开发中,@ccclass 装饰器的作用是将一个普通的 TypeScript 类声明为 Cocos Creator 的组件类,从而实现组件化开发。

  1. 什么是组件化开发?组件化开发的核心思想是什么?

组件化开发的核心思想是将功能拆分成独立的、可复用的模块(组件),并通过组合这些模块来构建复杂的系统。这种开发模式的核心包括以下几点:

  1. 功能单一

    1. 每个组件只负责一个明确的功能,例如控制玩家移动、管理敌人行为、播放音效等。

    2. 这种设计遵循了软件开发中的单一职责原则(SRP),使组件易于维护和扩展。

  2. 高内聚、低耦合

    1. 组件内部实现自己的逻辑,与其他组件之间的依赖关系尽量减少。

    2. 组件之间通过公共接口或事件进行通信,而不是直接依赖彼此的实现。

  3. 复用性

    1. 组件可以被多个节点复用,减少重复代码。

    2. 例如,一个 MoveComponent 可以被玩家、敌人、道具等多个对象使用,只需要在编辑器中调整参数即可。

  4. 组合优于继承

    1. 组件化开发强调通过组合多个组件来实现复杂功能,而不是通过继承来扩展类的功能。

    2. 例如,一个游戏角色可以由多个组件组成:MoveComponentHealthComponentAttackComponent 等。

  5. 数据驱动

    1. 组件的行为由数据决定,数据可以通过编辑器配置或动态修改。

    2. 数据驱动的设计使得开发者可以快速调整组件的行为,而无需修改代码。

  6. 生命周期管理

    1. 组件化开发通常依赖框架提供的生命周期方法来管理组件的状态。

    2. 在 Cocos Creator 中,组件的生命周期方法(如 onLoadstartupdate)帮助开发者在合适的时机执行逻辑。


总结

  • @ccclass 装饰器通过将普通类注册为 Cocos Creator 的组件,使其能够被编辑器识别和使用,成为组件化开发的基石。

  • 组件化开发的核心思想是将功能拆分为独立的模块,通过组合这些模块来构建复杂系统,同时保持模块的高内聚和低耦合。

  • 使用组件化开发可以提高代码的复用性、可维护性和扩展性,是现代游戏开发的重要设计模式。

  1. 为什么@ccclass装饰器能实现组件化开发?

  1. 绑定类与 Cocos Creator 编辑器

    import { _decorator, Component } from 'cc';
    const { ccclass, property } = _decorator;
    
    @ccclass('Player')
    export class Player extends Component {
        @propertyspeed: number = 10;
    
        update(deltaTime: number) {
            // 组件的逻辑
        }
    }
    1. @ccclass 装饰器将一个类注册到 Cocos Creator 系统中,使其成为一个组件类。

    2. 通过这个装饰器,Cocos Creator 编辑器能够识别该类,并允许用户将其作为组件附加到场景中的节点上。

    3. 例如:

    4. 在这个例子中,@ccclass('Player')Player 注册为一个组件,用户可以在编辑器中将 Player 组件添加到某个节点上。

  2. 支持组件化的生命周期管理

    1. 使用 @ccclass 注册的组件会自动继承 Cocos Creator 的 Component 基类,具备 Cocos Creator 框架的生命周期方法(如 startupdateonLoad 等)。

    2. 这些生命周期方法是组件化开发的核心,用于管理组件的初始化、更新和销毁等逻辑。

  3. 属性暴露与数据驱动

    @ccclass('Enemy')
    export class Enemy extends Component {
        @property({ type: Number })
        health: number = 100;
    
        @property({ type: Number })
        speed: number = 5;
    
        update(deltaTime: number) {
            // 根据属性值控制敌人的行为
        }
    }

    1. @ccclass 配合 @property 装饰器,可以将类中的属性暴露到编辑器中,使开发者能够在编辑器中设置组件的参数。

    2. 这种设计实现了数据驱动的开发模式,组件的行为可以通过配置数据而改变。

    3. 例如:

  4. 模块化与复用性

    1. 使用 @ccclass 定义的组件是独立的模块,可以被多个节点复用。

    2. 每个组件只负责自己的功能,与其他组件解耦,从而实现模块化开发。

  1. @ccclass 装饰器实现组件化开发设计思想与底层原理是什么?

@ccclass 装饰器是 Cocos Creator 中的核心功能之一,它的设计思想与底层原理直接服务于组件化开发的理念。以下将从 设计思想底层原理 两个角度进行详细分析。


设计思想

@ccclass 装饰器的设计思想是围绕组件化开发的核心理念展开的,其主要思想包括以下几点:

  1. 组件化开发的核心思想

  • 功能单一:通过 @ccclass 定义的组件类,专注于实现一个独立的功能(例如玩家移动、敌人行为、计时器等)。这种设计遵循单一职责原则,使组件易于维护和扩展。

  • 高内聚低耦合:组件之间的逻辑独立,组件只关注自身的功能,通过事件或接口进行通信,避免直接依赖其他组件。

  • 组合优于继承:组件化开发强调通过组合多个功能组件来构建复杂系统,而不是通过深层次的类继承。这种方式避免了继承层级过深带来的复杂性。

  • 数据驱动:组件的行为和状态通过数据配置(例如 @property 装饰器暴露到编辑器)驱动,使开发者能够通过调整参数快速改变组件逻辑,而无需修改代码。

  1. 面向编辑器的设计

  • 组件注册@ccclass 的主要作用是将一个类注册到 Cocos Creator 的运行时系统,使其能够被编辑器识别,允许开发者将该组件添加到场景中的节点。

  • 属性暴露:配合 @property 装饰器,组件的属性能够暴露到编辑器中,以便开发者在编辑器中进行直观的配置。这样实现了数据驱动的开发模式。

  • 生命周期管理:通过继承 Component 基类,组件自动获得生命周期方法(如 onLoadstartupdate 等),使开发者能够在特定的时机执行组件逻辑。

  1. 模块化与复用性

  • 模块化:每个组件是一个独立的模块,可以被单独开发、测试和调试。

  • 复用性:组件可以在多个节点上复用,减少重复代码,提高开发效率。例如,一个 MoveComponent 可以被玩家、敌人和道具节点同时使用。


底层原理
  1. @ccclass 的装饰器机制

  • @ccclass 是 TypeScript 的装饰器语法的一种应用,它在类定义时执行一些额外的逻辑。

  • 在 Cocos Creator 中,@ccclass 的主要作用是将类注册到 Cocos Creator 的运行时系统,使其成为一个合法的组件。

  • 装饰器的实现类似于以下伪代码:

function ccclass(className: string) {return function (target: Function) {// 将类注册到 Cocos Creator 的组件系统ComponentRegistry.register(className, target);
    };
}
  1. 组件注册机制

  • 使用 @ccclass 装饰器的类会被注册到 Cocos Creator 的组件系统中。这个系统负责管理所有组件的生命周期、属性和行为。

  • 注册后的组件可以被编辑器识别,并允许开发者将该组件添加到场景中的节点。

  • 例如:

@ccclass('Player')
export class Player extends Component {// 这个类会被注册到组件系统中,编辑器可以识别它
}
  1. 继承 Component 基类

  • 使用 @ccclass 装饰器的类通常继承自 Cocos Creator 的 Component 基类。

  • Component 基类提供了以下功能:

    • 生命周期管理:包括 onLoadstartupdate 等方法,用于管理组件的行为。

    • 节点绑定:组件自动绑定到节点,允许组件操作节点的属性(如位置、旋转、缩放等)。

    • 事件系统:组件可以监听节点事件(如点击、碰撞等)。

  1. 属性暴露与数据驱动

  • 配合 @property 装饰器,组件的属性能够暴露到编辑器中。

  • @property 的底层实现是通过元数据(metadata)机制,将属性信息存储到类的定义中。

  • 例如:

@property({ type: Number })
health: number = 100;

  • 底层会记录属性的元信息:

ComponentRegistry.registerProperty('Player', 'health', { type: Number, default: 100 });

  • 编辑器读取这些元信息后,会在属性检查器中显示该属性。

  1. 生命周期方法的运行时绑定

  • 组件的生命周期方法(如 onLoadstartupdate)在运行时通过 Cocos Creator 的组件系统自动调用。

  • 组件系统会检测节点上的所有组件,并在特定的时机调用这些方法。例如:

    • 在节点加载时调用 onLoad 方法。

    • 在游戏逻辑开始时调用 start 方法。

    • 每帧调用 update 方法。

  1. 组件与节点的关联

  • 每个组件都绑定到一个节点,组件可以通过 this.node 操作节点的属性。

  • 这种绑定关系是通过 Component 基类实现的,底层会在组件实例化时自动将组件与节点关联。


总结

设计思想
  • @ccclass 装饰器的设计思想是服务于组件化开发的核心理念,包括功能单一、高内聚低耦合、组合优于继承、数据驱动和模块化复用。

  • 它使得开发者可以通过简单的语法将逻辑模块化,并通过组合这些模块构建复杂系统。

底层原理
  • @ccclass 装饰器通过 TypeScript 的装饰器机制,将类注册到 Cocos Creator 的组件系统中。

  • 配合 Component 基类和 @property 装饰器,组件可以实现生命周期管理、属性暴露和节点绑定。

  • 组件系统负责管理组件的运行时行为,包括生命周期方法的调用、属性的管理以及与节点的关联。

这种设计思想和底层原理共同构建了 Cocos Creator 的组件化开发框架,使得开发者能够以模块化、数据驱动的方式高效地开发游戏功能。

  1. @ccclass 装饰器实现组件化开发具体实现

@ccclass 是 Cocos Creator 使用 TypeScript 装饰器语法定义组件的核心工具,它通过底层的装饰器机制,将一个普通的类转化为 Cocos Creator 的组件,并与编辑器和运行时系统集成。以下将详细分析其具体实现,包括装饰器的工作原理、组件注册机制、属性暴露、生命周期管理等。

1. @ccclass 的基本实现

@ccclass 是一个装饰器,它的作用是在类定义时执行额外的逻辑,将该类注册为 Cocos Creator 的组件。

实现原理

在 TypeScript 中,装饰器是一种运行时语法,它可以在类、方法、属性或参数定义时执行额外的逻辑。对于 @ccclass,其底层实现的核心逻辑如下:

function ccclass(className?: string) {
    return function (target: Function) {
        // 将类注册到 Cocos Creator 的组件系统
        const componentName = className || target.name; // 如果未指定名称,则使用类名
        ComponentRegistry.register(componentName, target);

        // 标记为 Cocos Creator 组件
        target.__ccclass__ = true;
    };
}
关键点
  • 注册类到组件系统:通过 ComponentRegistry.register 将类与组件名称绑定,使 Cocos Creator 编辑器能够识别这个类并允许用户在节点上添加该组件。

  • 标记为组件:通过 target.__ccclass__ 标记类为 Cocos Creator 的合法组件,供运行时和编辑器使用。

使用示例

开发者使用 @ccclass 装饰器定义组件类:

@ccclass('Player')
export class Player extends Component {
    update(deltaTime: number) {
        // 玩家组件的逻辑
    }
}

2. 组件注册机制

在 Cocos Creator 中,组件必须被注册到组件系统才能被编辑器和运行时识别。@ccclass 装饰器的核心功能就是完成组件注册。

底层实现

组件注册的底层逻辑通常涉及以下步骤:

  1. 记录组件的元信息:通过装饰器,将类的相关信息(如名称、属性)存储到组件系统。

  2. 与编辑器集成:编辑器通过组件系统读取组件元信息,将组件暴露到用户界面中。

  3. 运行时管理:运行时通过组件系统管理组件的生命周期和行为。

伪代码实现如下:

class ComponentRegistry {
    private static components: Map<string, Function> = new Map();

    static register(name: string, component: Function) {
        this.components.set(name, component);
    }

    static getComponent(name: string): Function | undefined {
        return this.components.get(name);
    }
}

3. 属性暴露机制

@ccclass 配合 @property 装饰器,可以将组件的属性暴露到编辑器中,使开发者能够在编辑器中配置组件的参数。

@property 的实现

@property 装饰器的核心功能是将类的属性元信息存储到组件系统中,并使其能够被编辑器读取和展示。

底层实现伪代码如下:

function property(options: any) {
    return function (target: any, propertyKey: string) {
        // 获取或初始化元信息存储
        const meta = target.constructor.__properties__ || (target.constructor.__properties__ = {});
        meta[propertyKey] = options;

        // 设置默认值
        if (options.default !== undefined) {
            target[propertyKey] = options.default;
        }
    };
}
使用示例

开发者可以通过 @property 装饰器定义组件的属性,并指定类型或默认值:

@ccclass('Enemy')
export class Enemy extends Component {
    @property({ type: Number, default: 100 })
    health: number = 100;

    @property({ type: Number, default: 5 })
    speed: number = 5;

    update(deltaTime: number) {
        // 根据属性值控制敌人的行为
    }
}

在编辑器中,healthspeed 属性会显示在属性检查器中,允许开发者直接修改这些值。

4. 生命周期管理

使用 @ccclass 装饰器定义的组件会自动继承 Cocos Creator 的 Component 基类,从而获得生命周期管理功能。

生命周期方法

Component 基类提供以下常见生命周期方法:

  • onLoad:组件加载时调用,用于初始化逻辑。

  • start:组件首次激活时调用。

  • update:每帧调用,用于更新组件逻辑。

  • onDestroy:组件销毁时调用,用于清理资源。

运行时调用

组件系统会在运行时自动检测节点上的所有组件,并在合适的时机调用这些生命周期方法。例如:

  1. 节点加载时调用 onLoad

  2. 游戏逻辑开始时调用 start

  3. 每帧调用 update

使用示例

开发者可以通过覆盖这些方法定义组件的行为:

@ccclass('Player')
export class Player extends Component {
    @property({ type: Number })
    speed: number = 10;

    onLoad() {
        console.log('Player loaded');
    }

    start() {
        console.log('Player started');
    }

    update(deltaTime: number) {
        this.node.position.x += this.speed * deltaTime;
    }

    onDestroy() {
        console.log('Player destroyed');
    }
}

5. 组件与节点的关联

每个组件都绑定到一个节点,组件通过 this.node 操作节点的属性(如位置、旋转、缩放等)。

底层实现

组件与节点的绑定是通过 Component 基类实现的。组件实例化时,Cocos Creator 会自动将组件与所属节点关联。

伪代码如下:

class Component {
    node: Node;

    constructor(node: Node) {
        this.node = node;
    }
}

使用示例

开发者可以在组件中操作节点:

@ccclass('Mover')
export class Mover extends Component {
    @property({ type: Number })
    speed: number = 10;

    update(deltaTime: number) {
        this.node.position.x += this.speed * deltaTime;
    }
}

6. 与编辑器的集成

通过 @ccclass@property 装饰器定义的组件和属性会自动集成到编辑器中,允许开发者在编辑器中直观地配置组件。

编辑器读取元信息
  • @ccclass 注册的组件会显示在编辑器的组件列表中。

  • @property 定义的属性会显示在属性检查器中,允许开发者修改属性值。

总结

具体实现流程
  1. 组件注册:使用 @ccclass 装饰器将类注册到组件系统。

  2. 属性暴露:使用 @property 装饰器定义组件的属性,并暴露到编辑器中。

  3. 生命周期管理:通过继承 Component 基类,组件自动获得生命周期方法。

  4. 节点绑定:组件与节点关联,允许操作节点的属性。

  5. 编辑器集成:组件和属性通过元信息与编辑器集成。

最终效果

开发者通过 @ccclass 和相关装饰器,可以轻松定义组件,将功能模块化,并通过编辑器配置和运行时管理实现组件化开发。这种设计极大地提高了开发效率和代码复用性,同时保持系统的灵活性和可维护性。

  1. 实现自定义的简易组件化开发框架

⚠️这个实战案例的运行环境并不依赖 Cocos Creator,它是一个简化版的组件化开发框架,可以运行在任何支持 TypeScript 或 JavaScript 的环境中,比如 Node.js 或浏览器。它的目的主要是帮助你理解组件化开发的底层原理,而不是直接使用 Cocos Creator 的框架和编辑器。

为了帮助你彻底领会并运用组件化开发,我们将从底层实现一个简化版的组件化框架,并基于这个框架开发一个简单的游戏场景。这个案例包括:

  1. 组件化开发框架的底层实现

  2. 基于框架实现一个游戏场景:一个玩家可以移动,敌人会追踪玩家

目标
  • 自己实现一个组件化开发框架,包括组件注册、属性暴露、生命周期管理等。

  • 使用这个框架开发一个简单的游戏场景。

1. 自己实现组件化开发框架

核心功能

我们需要实现以下功能:

  1. 组件注册:通过装饰器将组件类注册到框架。

  2. 属性暴露:通过装饰器将组件的属性暴露到框架。

  3. 生命周期管理:提供 onLoadstartupdate 等生命周期方法。

  4. 节点绑定:组件绑定到节点,并可以操作节点的属性。

框架实现

1. 节点类

节点是组件的载体,每个节点可以拥有多个组件,并能管理自己的属性(如位置)。

class Node {
    name: string;
    position: { x: number; y: number } = { x: 0, y: 0 };
    components: Component[] = [];

    constructor(name: string) {
        this.name = name;
    }

    addComponent(componentClass: typeof Component): Component {
        const component = new componentClass();
        component.node = this; // 绑定组件到节点
        this.components.push(component);
        return component;
    }

    update(deltaTime: number) {
        this.components.forEach((component) => {
            if (component.update) {
                component.update(deltaTime);
            }
        });
    }
}

2. 基础组件类

所有组件都继承自 Component 类,提供生命周期管理和节点绑定功能。

class Component {
    node!: Node; // 组件绑定的节点

    onLoad?(): void;
    start?(): void;
    update?(deltaTime: number): void;
}

3. @ccclass 装饰器

用来注册组件类到框架。

function ccclass(className: string) {
    return function (target: Function) {
        target.prototype.__ccclass__ = className;
        ComponentRegistry.register(className, target);
    };
}

class ComponentRegistry {
    private static components: Map<string, Function> = new Map();

    static register(name: string, component: Function) {
        this.components.set(name, component);
    }

    static getComponent(name: string): Function | undefined {
        return this.components.get(name);
    }
}

4. @property 装饰器

用来暴露组件的属性到框架。

function property(options?: { default?: any }) {
    return function (target: any, propertyKey: string) {
        const meta = target.constructor.__properties__ || (target.constructor.__properties__ = {});
        meta[propertyKey] = options?.default;

        // 设置默认值
        if (options?.default !== undefined) {
            target[propertyKey] = options.default;
        }
    };
}

5. 游戏引擎

模拟一个简单的游戏引擎,负责管理节点和更新逻辑。

class Engine {
    private nodes: Node[] = [];

    addNode(node: Node) {
        this.nodes.push(node);
    }

    start() {
        this.nodes.forEach((node) => {
            node.components.forEach((component) => {
                if (component.onLoad) {
                    component.onLoad();
                }
                if (component.start) {
                    component.start();
                }
            });
        });

        setInterval(() => {
            this.update(0.016); // 假设每帧间隔 16ms
        }, 16);
    }

    update(deltaTime: number) {
        this.nodes.forEach((node) => node.update(deltaTime));
    }
}

2. 使用框架开发一个游戏场景

需求
  • 玩家可以使用键盘控制移动。

  • 敌人会追踪玩家。

实现玩家组件

玩家组件负责处理玩家的输入逻辑,并更新玩家的节点位置。

@ccclass('Player')
class Player extends Component {
    @property({ default: 5 })
    speed: number = 5;

    update(deltaTime: number) {
        // 简单的键盘输入模拟
        const input = getInput(); // 假设有一个函数获取输入
        if (input === 'left') {
            this.node.position.x -= this.speed * deltaTime;
        } else if (input === 'right') {
            this.node.position.x += this.speed * deltaTime;
        } else if (input === 'up') {
            this.node.position.y += this.speed * deltaTime;
        } else if (input === 'down') {
            this.node.position.y -= this.speed * deltaTime;
        }
        console.log(`Player position: (${this.node.position.x}, ${this.node.position.y})`);
    }
}

实现敌人组件

敌人组件负责追踪玩家的位置。

@ccclass('Enemy')
class Enemy extends Component {
    @property({ default: 3 })
    speed: number = 3;

    playerNode!: Node; // 玩家节点

    onLoad() {
        // 假设我们能找到玩家节点
        this.playerNode = findNodeByName('Player'); // 假设有一个函数实现节点查找
    }

    update(deltaTime: number) {
        const dx = this.playerNode.position.x - this.node.position.x;
        const dy = this.playerNode.position.y - this.node.position.y;

        const distance = Math.sqrt(dx * dx + dy * dy);
        if (distance > 0) {
            this.node.position.x += (dx / distance) * this.speed * deltaTime;
            this.node.position.y += (dy / distance) * this.speed * deltaTime;
        }

        console.log(`Enemy position: (${this.node.position.x}, ${this.node.position.y})`);
    }
}
搭建场景

创建玩家和敌人节点,并添加对应的组件。

const engine = new Engine();

const playerNode = new Node('Player');
playerNode.addComponent(Player);

const enemyNode = new Node('Enemy');
enemyNode.addComponent(Enemy);

engine.addNode(playerNode);
engine.addNode(enemyNode);

engine.start();

辅助函数

模拟键盘输入和节点查找:

function getInput(): string {
    // 假设这是一个简单的输入模拟
    const inputs = ['left', 'right', 'up', 'down'];
    return inputs[Math.floor(Math.random() * inputs.length)];
}

function findNodeByName(name: string): Node {
    // 假设我们能通过名字找到节点
    return engine.nodes.find((node) => node.name === name)!;
}

3. 运行效果

运行场景后:

  1. 玩家可以通过键盘输入移动。

  2. 敌人会持续追踪玩家的位置。

输出日志会显示玩家和敌人的位置变化。

总结

通过这个案例,你实现了一个简化版的组件化开发框架,并基于这个框架开发了一个游戏场景。核心思想包括:

  • 组件注册:通过 @ccclass 实现组件的注册。

  • 属性暴露:通过 @property 将组件属性暴露到框架。

  • 生命周期管理:通过 Component 基类管理组件的 onLoadstartupdate 等生命周期。

  • 节点绑定:组件与节点绑定,操作节点的属性。

这种方式不仅帮助你理解了组件化开发的底层原理,还让你能够自己实现一个框架并应用到实际开发中!

  1. cocos实战案例

案例:点击屏幕生成物体并随机运动

目标
  1. 玩家点击屏幕时生成一个物体(如一个方块)。

  2. 生成的物体会以随机方向和速度移动。

  3. 物体离开屏幕后销毁。

实现步骤

1. 创建场景

在 Cocos Creator 中创建一个新的场景,并添加一个空节点作为脚本挂载点。

2. 编写脚本
主脚本:点击屏幕生成物体

创建一个脚本 GameManager.ts,负责管理屏幕点击事件以及生成物体。

import { _decorator, Component, Prefab, Node, instantiate, Vec3, UITransform, view } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('GameManager')
export class GameManager extends Component {
    @property({ type: Prefab })
    objectPrefab: Prefab = null!; // 用于生成的物体预制件

    onLoad() {
        // 监听屏幕点击事件
        this.node.on(Node.EventType.TOUCH_START, this.spawnObject, this);
    }

    spawnObject(event: any) {
        // 获取点击位置
        const touchPos = event.getLocation();
        const worldPos = new Vec3(touchPos.x, touchPos.y, 0);

        // 转换为节点坐标
        const uiTransform = this.node.getComponent(UITransform)!;
        const localPos = uiTransform.convertToNodeSpaceAR(worldPos);

        // 实例化物体
        const newObject = instantiate(this.objectPrefab);
        newObject.setPosition(localPos); // 设置物体位置
        this.node.addChild(newObject); // 添加到场景中
    }
}
物体脚本:随机运动

创建一个脚本 MovingObject.ts,负责控制物体的随机运动。

import { _decorator, Component, Vec3, view, Node } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('MovingObject')
export class MovingObject extends Component {
    @property({ type: Number })
    speed: number = 100; // 物体移动速度

    private direction: Vec3 = new Vec3(); // 随机方向

    onLoad() {
        // 初始化随机方向
        this.direction.x = Math.random() * 2 - 1; // 随机生成 -1 到 1 的值
        this.direction.y = Math.random() * 2 - 1;
        this.direction.normalize(); // 归一化方向
    }

    update(deltaTime: number) {
        // 移动物体
        const movement = this.direction.multiplyScalar(this.speed * deltaTime);
        this.node.setPosition(this.node.position.add(movement));

        // 检测是否离开屏幕
        const screenSize = view.getVisibleSize();
        const pos = this.node.position;

        if (
            pos.x < -screenSize.width / 2 ||
            pos.x > screenSize.width / 2 ||
            pos.y < -screenSize.height / 2 ||
            pos.y > screenSize.height / 2
        ) {
            // 离开屏幕后销毁
            this.node.destroy();
        }
    }
}
3. 创建预制件
  1. 在 Cocos Creator 中创建一个新的节点(如一个方块),并添加 MovingObject 脚本。

  2. 将节点保存为预制件(Prefab),命名为 ObjectPrefab

  3. GameManager 脚本的 objectPrefab 属性中拖入这个预制件。

4. 添加脚本到场景
  1. 创建一个空节点(命名为 GameManager)。

  2. GameManager 脚本挂载到这个节点上。

运行效果

  1. 点击屏幕时,会在点击位置生成一个物体。

  2. 生成的物体会以随机方向移动。

  3. 当物体离开屏幕时会自动销毁。

扩展功能

1. 添加不同类型的物体

可以在 GameManager 中随机选择不同的预制件来生成不同类型的物体。

@ccclass('GameManager')
export class GameManager extends Component {
    @property({ type: [Prefab] })
    objectPrefabs: Prefab[] = []; // 多个预制件

    spawnObject(event: any) {
        const touchPos = event.getLocation();
        const worldPos = new Vec3(touchPos.x, touchPos.y, 0);
        const uiTransform = this.node.getComponent(UITransform)!;
        const localPos = uiTransform.convertToNodeSpaceAR(worldPos);

        // 随机选择一个预制件
        const randomIndex = Math.floor(Math.random() * this.objectPrefabs.length);
        const newObject = instantiate(this.objectPrefabs[randomIndex]);
        newObject.setPosition(localPos);
        this.node.addChild(newObject);
    }
}

2. 添加碰撞检测

可以为物体添加碰撞组件,检测物体之间的碰撞并触发事件。

3. 添加粒子效果

在物体销毁时,可以播放粒子效果以增强视觉表现。

总结

这个案例展示了如何在 Cocos Creator 中实现一个简单的互动场景,涵盖以下内容:

  • 屏幕点击事件处理

  • 物体的随机运动逻辑

  • 物体的销毁机制

通过这个案例,你可以进一步理解 Cocos Creator 的组件化开发方式,同时为实现更复杂的游戏场景奠定基础。如果你有其他需求或想扩展这个案例,可以随时告诉我!

过程总结

请注意问题的顺序,我的提问主要是由浅入深,从cocos的@ccclass到组件化开发思想,核心思想为了解->掌握->运用->再了解,在浏览完问题详解后,问题导引中的问题大家可以回答了吗?并且建议强行提出5个或以上的问题,看看自己能否解答。

相关文章:

  • 大模型在舌癌预测及治疗方案制定中的应用研究
  • 软考中级网络工程师第六章网互联与互联网
  • VectorBT:Python量化交易策略开发与回测评估详解
  • sklearn基础教程
  • 【AVRCP】蓝牙链路控制器(LC)与AVRCP互操作性要求深度解析
  • 希尔排序中的Hibbard序列
  • AI大白话(四):自然语言处理——AI是如何理解和生成人类语言的?
  • 自动化测试框架详解
  • 车载软件架构 --- AUTOSAR AP/CP中诊断的区别
  • Python functools 模块的 @lru_cache 装饰器介绍
  • wps字符很分散
  • 【STM32】SPI通信协议W25Q64Flash存储器芯片(学习笔记)
  • OSS Browser2.0安装使用(阿里云对象存储OSS 图形化界面工具2.0版本)
  • 集成学习(下):Stacking集成方法
  • iPaaS集成平台安全通信的挑战与保障策略
  • MyBatis之参数传递
  • 网络故障排查指南:分治法与排除法结合的分层诊断手册
  • Diamond软件的使用--(5)查看原语
  • 【HTTP 传输过程中的 cookie】
  • 基于springboot和vue项目使用docker部署项目到服务器
  • 著名植物学家、园艺学家,国际植物园协会原主席贺善安逝世
  • 首个偏头痛急性治疗药物可缓解前期症状
  • 中保协发布《保险机构适老服务规范》,全面规范保险机构面向老年人提供服务的统一标准
  • 在笔墨金石间,看胡问遂与梅舒适的艺术对话
  • 网信部门曝光网络谣言典型案例,“AI预测彩票号码百分百中奖”等在列
  • 波兰关闭俄罗斯驻克拉科夫领事馆