【Cocos Creator 3.x】篇——第四章 子系统

目录

[1 UI系统](#1 UI系统)

[1.1 Canvas](#1.1 Canvas)

[1.2 Sprite组件](#1.2 Sprite组件)

Sprite渲染模式

[1.3 Label组件](#1.3 Label组件)

[1.4 Button组件](#1.4 Button组件)

Button过渡效果

[1.5 ProgressBar组件](#1.5 ProgressBar组件)

[1.6 ScrollView组件](#1.6 ScrollView组件)

[2 动画系统](#2 动画系统)

[2.1 Animation组件](#2.1 Animation组件)

[2.2 创建动画剪辑](#2.2 创建动画剪辑)

[2.3 动画事件](#2.3 动画事件)

[3 音频系统](#3 音频系统)

[3.1 AudioSource组件](#3.1 AudioSource组件)

[4 物理系统](#4 物理系统)

[4.1 物理组件](#4.1 物理组件)

2D物理组件

碰撞检测

[4.2 射线检测](#4.2 射线检测)

[5 网络系统](#5 网络系统)

[5.1 HTTP请求](#5.1 HTTP请求)

[5.2 WebSocket](#5.2 WebSocket)

[6 总结](#6 总结)


本文介绍了Cocos Creator 3.x的核心游戏开发系统,主要包括:UI系统(Canvas、Sprite、Label、Button、ProgressBar和ScrollView组件)、动画系统(Animation组件、动画剪辑创建和事件处理)、音频系统(AudioSource组件控制)、物理系统(2D物理组件、碰撞检测和射线检测)以及网络系统(HTTP请求和WebSocket通信)。

通过代码示例详细展示了各系统的使用方法,为开发者提供了完整的游戏开发基础框架参考。

1 UI系统

1.1 Canvas

Canvas是UI系统的根节点,所有UI元素都应该放在Canvas下。

复制代码
import { _decorator, Component, Node, Canvas } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('CanvasExample')
export class CanvasExample extends Component {
    start() {
        // 获取Canvas组件
        const canvas = this.node.getComponent(Canvas);
        
        if (canvas) {
            // 设置分辨率适配
            canvas.alignCanvasWithScreen = true;
            
            // 获取画布大小
            const size = canvas.getCanvasSize();
            console.log(`画布大小: ${size.width} x ${size.height}`);
        }
    }
}

1.2 Sprite组件

Sprite组件用于显示2D图片。

复制代码
import { _decorator, Component, Node, Sprite, SpriteFrame } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('SpriteExample')
export class SpriteExample extends Component {
    @property({ type: SpriteFrame })
    public spriteFrame: SpriteFrame = null!;
​
    start() {
        // 获取Sprite组件
        const sprite = this.node.getComponent(Sprite);
        
        // 设置SpriteFrame
        sprite.spriteFrame = this.spriteFrame;
        
        // 设置渲染模式
        sprite.type = Sprite.Type.SIMPLE;
        
        // 设置颜色
        sprite.color.set(255, 255, 255, 255);
    }
}

Sprite渲染模式

复制代码
// 普通模式
sprite.type = Sprite.Type.SIMPLE;
​
// 九宫格模式(适合UI按钮等可拉伸元素)
sprite.type = Sprite.Type.SLICED;
​
// 平铺模式
sprite.type = Sprite.Type.TILED;
​
// 填充模式(适合进度条等)
sprite.type = Sprite.Type.FILLED;

1.3 Label组件

Label组件用于显示文字。

复制代码
import { _decorator, Component, Node, Label } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('LabelExample')
export class LabelExample extends Component {
    start() {
        const label = this.node.getComponent(Label);
        
        // 设置文字内容
        label.string = 'Hello, Cocos Creator!';
        
        // 设置字体大小
        label.fontSize = 24;
        
        // 设置颜色
        label.color.set(255, 0, 0, 255);
        
        // 设置对齐方式
        label.horizontalAlign = Label.HorizontalAlign.CENTER;
        label.verticalAlign = Label.VerticalAlign.CENTER;
        
        // 设置溢出处理
        label.overflow = Label.Overflow.CLAMP;
        
        // 设置是否换行
        label.enableWrapText = true;
    }
}

1.4 Button组件

Button组件用于响应用户点击。

复制代码
import { _decorator, Component, Node, Button } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('ButtonExample')
export class ButtonExample extends Component {
    @property({ type: Node })
    public buttonNode: Node = null!;
​
    start() {
        const button = this.buttonNode.getComponent(Button);
        
        // 设置按钮交互状态
        button.interactable = true;
        
        // 添加点击事件
        button.clickEvents.push({
            target: this.node,
            component: 'ButtonExample',
            handler: 'onButtonClick',
            customEventData: 'custom data'
        });
        
        // 通过代码添加点击事件
        this.buttonNode.on('click', this.onButtonClick, this);
    }
    
    onButtonClick(event: any, customData?: string) {
        console.log('按钮被点击!');
        console.log('自定义数据:', customData);
    }
}

Button过渡效果

复制代码
import { _decorator, Component, Node, Button } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('ButtonTransition')
export class ButtonTransition extends Component {
    start() {
        const button = this.node.getComponent(Button);
        
        // 设置过渡类型
        button.transition = Button.Transition.COLOR;
        
        // 设置不同状态的颜色
        const colorBlock = button.color;
        colorBlock.normal = new Color(255, 255, 255, 255);
        colorBlock.pressed = new Color(200, 200, 200, 255);
        colorBlock.hover = new Color(230, 230, 230, 255);
        colorBlock.disabled = new Color(100, 100, 100, 255);
        button.color = colorBlock;
    }
}

1.5 ProgressBar组件

ProgressBar组件用于显示进度。

复制代码
import { _decorator, Component, Node, ProgressBar } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('ProgressBarExample')
export class ProgressBarExample extends Component {
    @property({ type: Node })
    public progressBarNode: Node = null!;
    
    private progressBar: ProgressBar | null = null;
    private currentProgress: number = 0;
​
    start() {
        this.progressBar = this.progressBarNode.getComponent(ProgressBar);
        
        // 设置进度范围
        this.progressBar.totalLength = 100;
        this.progressBar.progress = 0;
        
        // 设置方向
        this.progressBar.direction = ProgressBar.Direction.LEFT_TO_RIGHT;
        
        // 开始加载动画
        this.startLoading();
    }
    
    startLoading() {
        const interval = setInterval(() => {
            this.currentProgress += 5;
            
            if (this.progressBar) {
                this.progressBar.progress = this.currentProgress / 100;
            }
            
            if (this.currentProgress >= 100) {
                clearInterval(interval);
                console.log('加载完成!');
            }
        }, 100);
    }
}

1.6 ScrollView组件

ScrollView组件用于滚动显示内容。

复制代码
import { _decorator, Component, Node, ScrollView, Label } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('ScrollViewExample')
export class ScrollViewExample extends Component {
    @property({ type: Node })
    public scrollViewNode: Node = null!;
    
    @property({ type: Node })
    public contentNode: Node = null!;
​
    start() {
        const scrollView = this.scrollViewNode.getComponent(ScrollView);
        
        // 设置滚动方向
        scrollView.horizontal = false;
        scrollView.vertical = true;
        
        // 设置回弹效果
        scrollView.bounceEnabled = true;
        
        // 设置惯性滚动
        scrollView.inertia = true;
        
        // 添加列表项
        this.createListItems();
    }
    
    createListItems() {
        for (let i = 0; i < 20; i++) {
            const itemNode = new Node(`Item_${i}`);
            const label = itemNode.addComponent(Label);
            label.string = `列表项 ${i + 1}`;
            label.fontSize = 24;
            
            // 设置位置
            itemNode.setPosition(0, -i * 50, 0);
            
            // 添加到content节点
            itemNode.parent = this.contentNode;
        }
        
        // 更新content大小
        this.contentNode.setContentSize(400, 20 * 50);
    }
}

2 动画系统

2.1 Animation组件

Animation组件用于播放动画剪辑。

复制代码
import { _decorator, Component, Node, Animation } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('AnimationExample')
export class AnimationExample extends Component {
    @property({ type: Node })
    public animatedNode: Node = null!;
    
    private animation: Animation | null = null;
​
    start() {
        this.animation = this.animatedNode.getComponent(Animation);
        
        if (this.animation) {
            // 播放动画
            this.animation.play('walk');
            
            // 设置循环模式
            const state = this.animation.getState('walk');
            if (state) {
                state.wrapMode = Animation.WrapMode.Loop;
            }
        }
    }
    
    playAnimation() {
        if (this.animation) {
            // 播放指定动画
            this.animation.play('jump');
            
            // 播放下一个动画
            this.animation.playNext();
        }
    }
    
    pauseAnimation() {
        if (this.animation) {
            this.animation.pause();
        }
    }
    
    resumeAnimation() {
        if (this.animation) {
            this.animation.resume();
        }
    }
    
    stopAnimation() {
        if (this.animation) {
            this.animation.stop();
        }
    }
}

2.2 创建动画剪辑

复制代码
import { _decorator, Component, Node, AnimationClip, animation } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('CreateAnimation')
export class CreateAnimation extends Component {
    start() {
        // 创建动画剪辑
        const clip = new AnimationClip();
        clip.name = 'custom_animation';
        clip.duration = 1; // 1秒
        clip.sample = 30; // 30帧/秒
        
        // 创建曲线
        const curve = new animation.BasicCurve();
        
        // 添加关键帧(位置动画)
        const positions: number[] = [];
        const times: number[] = [];
        
        times.push(0);
        positions.push(0, 0, 0); // 起始位置
        
        times.push(0.5);
        positions.push(100, 100, 0); // 中间位置
        
        times.push(1);
        positions.push(0, 0, 0); // 结束位置
        
        curve.keys = times;
        curve.values = positions;
        
        // 设置曲线目标
        clip.addCurve('position', curve);
        
        // 添加到Animation组件
        const animation = this.node.getComponent(Animation);
        if (animation) {
            animation.addClip(clip);
            animation.play('custom_animation');
        }
    }
}

2.3 动画事件

复制代码
import { _decorator, Component, Node, Animation } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('AnimationEvent')
export class AnimationEvent extends Component {
    start() {
        const animation = this.node.getComponent(Animation);
        
        if (animation) {
            // 监听动画事件
            animation.on(Animation.EventType.FINISHED, this.onAnimationFinished, this);
            animation.on(Animation.EventType.LOOP, this.onAnimationLoop, this);
            
            // 监听特定动画状态
            const state = animation.getState('attack');
            if (state) {
                state.on('frame', this.onFrame, this);
            }
        }
    }
    
    onAnimationFinished(type: Animation.EventType, state: any) {
        console.log('动画播放完成:', state.name);
    }
    
    onAnimationLoop(type: Animation.EventType, state: any) {
        console.log('动画循环:', state.name);
    }
    
    onFrame(frame: number, state: any) {
        console.log(`当前帧: ${frame}`);
    }
}

3 音频系统

3.1 AudioSource组件

AudioSource组件用于播放音频。

复制代码
import { _decorator, Component, Node, AudioSource, AudioClip } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('AudioExample')
export class AudioExample extends Component {
    @property({ type: AudioClip })
    public bgmClip: AudioClip = null!;
    
    @property({ type: AudioClip })
    public sfxClip: AudioClip = null!;
    
    private audioSource: AudioSource | null = null;
​
    start() {
        // 获取AudioSource组件
        this.audioSource = this.node.getComponent(AudioSource);
        
        if (!this.audioSource) {
            // 如果没有,添加一个
            this.audioSource = this.node.addComponent(AudioSource);
        }
        
        // 播放背景音乐
        this.playBGM();
    }
    
    playBGM() {
        if (this.audioSource) {
            this.audioSource.clip = this.bgmClip;
            this.audioSource.loop = true;
            this.audioSource.volume = 0.5;
            this.audioSource.play();
        }
    }
    
    playSFX() {
        // 创建临时AudioSource播放音效
        const tempNode = new Node('TempAudio');
        const tempSource = tempNode.addComponent(AudioSource);
        tempSource.clip = this.sfxClip;
        tempSource.loop = false;
        tempSource.volume = 0.8;
        tempSource.play();
        
        // 播放完成后销毁临时节点
        setTimeout(() => {
            tempNode.destroy();
        }, this.sfxClip.duration * 1000);
    }
    
    stopAudio() {
        if (this.audioSource) {
            this.audioSource.stop();
        }
    }
    
    pauseAudio() {
        if (this.audioSource) {
            this.audioSource.pause();
        }
    }
    
    resumeAudio() {
        if (this.audioSource) {
            this.audioSource.resume();
        }
    }
}

4 物理系统

4.1 物理组件

Cocos Creator 3.x提供了完整的2D和3D物理系统。

2D物理组件

复制代码
import { _decorator, Component, Node, RigidBody2D, Collider2D, PhysicsSystem2D } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('Physics2DExample')
export class Physics2DExample extends Component {
    @property({ type: Node })
    public playerNode: Node = null!;
​
    start() {
        // 获取刚体组件
        const rigidBody = this.playerNode.getComponent(RigidBody2D);
        
        if (rigidBody) {
            // 设置质量
            rigidBody.mass = 1;
            
            // 设置重力缩放
            rigidBody.gravityScale = 1;
            
            // 设置是否受重力影响
            rigidBody.gravityScale = 1;
            
            // 设置速度
            rigidBody.linearVelocity = new Vec2(100, 200);
            
            // 设置角速度
            rigidBody.angularVelocity = 0;
            
            // 设置是否允许旋转
            rigidBody.fixedRotation = true;
        }
        
        // 开启物理系统
        PhysicsSystem2D.instance.enable = true;
        
        // 设置重力
        PhysicsSystem2D.instance.gravity = new Vec2(0, -100);
    }
}

碰撞检测

复制代码
import { _decorator, Component, Node, Collider2D, Contact2DType } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('CollisionDetection')
export class CollisionDetection extends Component {
    onLoad() {
        const collider = this.node.getComponent(Collider2D);
        
        if (collider) {
            // 监听碰撞事件
            collider.on(Contact2DType.BEGIN_CONTACT, this.onBeginContact, this);
            collider.on(Contact2DType.END_CONTACT, this.onEndContact, this);
            collider.on(Contact2DType.PRE_SOLVE, this.onPreSolve, this);
            collider.on(Contact2DType.POST_SOLVE, this.onPostSolve, this);
        }
    }
    
    onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D) {
        console.log(`开始碰撞: ${otherCollider.node.name}`);
        
        // 检查碰撞对象标签
        if (otherCollider.node.tag === 1) {
            console.log('碰到了敌人!');
        }
    }
    
    onEndContact(selfCollider: Collider2D, otherCollider: Collider2D) {
        console.log(`结束碰撞: ${otherCollider.node.name}`);
    }
    
    onPreSolve(selfCollider: Collider2D, otherCollider: Collider2D) {
        console.log('碰撞前处理');
    }
    
    onPostSolve(selfCollider: Collider2D, otherCollider: Collider2D) {
        console.log('碰撞后处理');
    }
}

4.2 射线检测

复制代码
import { _decorator, Component, Node, PhysicsSystem2D, Vec2 } from 'cc';
const { ccclass, property } = _decorator;
​
@ccclass('RaycastExample')
export class RaycastExample extends Component {
    start() {
        // 射线检测
        const start = new Vec2(0, 0);
        const end = new Vec2(100, 100);
        
        const results = PhysicsSystem2D.instance.raycast(start, end);
        
        if (results.length > 0) {
            console.log(`检测到 ${results.length} 个碰撞`);
            
            for (const result of results) {
                console.log(`碰撞对象: ${result.collider.node.name}`);
                console.log(`碰撞点: ${result.point}`);
            }
        }
    }
}

5 网络系统

5.1 HTTP请求

复制代码
import { _decorator, Component, Node } from 'cc';
import { HttpRequest } from 'cc/net';
const { ccclass, property } = _decorator;
​
@ccclass('HttpExample')
export class HttpExample extends Component {
    async fetchData() {
        try {
            // GET请求
            const response = await HttpRequest.get('https://api.example.com/data');
            console.log('GET响应:', response);
            
            // POST请求
            const postData = {
                username: 'player1',
                score: 100
            };
            const postResponse = await HttpRequest.post('https://api.example.com/save', postData);
            console.log('POST响应:', postResponse);
        } catch (error) {
            console.error('请求失败:', error);
        }
    }
}

5.2 WebSocket

复制代码
import { _decorator, Component, Node } from 'cc';
import { WebSocket } from 'cc/net';
const { ccclass, property } = _decorator;
​
@ccclass('WebSocketExample')
export class WebSocketExample extends Component {
    private ws: WebSocket | null = null;
​
    connect() {
        // 创建WebSocket连接
        this.ws = new WebSocket('wss://game.example.com/ws');
        
        // 监听连接事件
        this.ws.onOpen(() => {
            console.log('WebSocket连接成功');
            
            // 发送消息
            this.ws?.send(JSON.stringify({
                type: 'join',
                room: 'game1'
            }));
        });
        
        // 监听消息
        this.ws.onMessage((event: any) => {
            const data = JSON.parse(event.data);
            console.log('收到消息:', data);
            
            // 处理消息
            this.handleMessage(data);
        });
        
        // 监听错误
        this.ws.onError((error: any) => {
            console.error('WebSocket错误:', error);
        });
        
        // 监听关闭
        this.ws.onClose((code: number, reason: string) => {
            console.log(`WebSocket关闭: ${code} - ${reason}`);
        });
        
        // 连接
        this.ws.connect();
    }
    
    handleMessage(data: any) {
        switch (data.type) {
            case 'joinSuccess':
                console.log('加入房间成功');
                break;
            case 'gameStart':
                console.log('游戏开始');
                break;
            case 'update':
                console.log('游戏状态更新:', data.state);
                break;
        }
    }
    
    sendMessage(message: any) {
        if (this.ws && this.ws.readyState === WebSocket.OPEN) {
            this.ws.send(JSON.stringify(message));
        }
    }
    
    disconnect() {
        this.ws?.close();
    }
}

6 总结

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

  1. UI系统的核心组件(Sprite、Label、Button、ProgressBar、ScrollView)

  2. 动画系统的使用(Animation组件、动画剪辑、动画事件)

  3. 音频系统的使用(AudioSource组件)

  4. 物理系统的基本操作(刚体、碰撞检测、射线检测)

  5. 网络系统的使用(HTTP请求、WebSocket)

这些子系统构成了Cocos Creator 3.x游戏开发的基础,掌握它们可以帮助你开发出功能丰富的游戏。

相关推荐
大圣编程1 小时前
Python中continue语句的用法是什么?
开发语言·前端·python
yuhaiqiang1 小时前
随手 vibecoding 的浏览器插件已经 6000 多次下载,聊聊他的产品设计
前端·后端·面试
之歆2 小时前
Vue商品详情与放大镜组件
前端·javascript·vue.js
再吃一根胡萝卜3 小时前
如何把小米 MiMo 接入 CodeBuddy,打造私有 Agent
前端
负责的蛋挞4 小时前
异步HttpModule的实现方式
java·服务器·前端
丹宇码农6 小时前
把 HLS 字幕玩出花:zwPlayer 如何让 M3U8 视频支持全文搜索、翻译与码率自适应
前端·javascript·音视频·hls·视频播放器
2501_943782356 小时前
【共创季稿事节】猜数字游戏:二分法思维与交互式反馈
前端·游戏·microsoft·harmonyos·鸿蒙·鸿蒙系统
GV191rLvq7 小时前
基于Socket实现的最简单的Web服务器【ASP.NET原理分析】
服务器·前端·asp.net
吠品7 小时前
LangChain 里 tool_call_id 为空?一次 MCP 工具集成的排查记录
前端