Cocos Creator引擎开发:VR角色技能与战斗系统_(3).VR角色控制器与移动系统

VR角色控制器与移动系统

在虚拟现实游戏中,角色控制器和移动系统是实现沉浸式体验的重要组成部分。本节将详细介绍如何在Cocos Creator引擎中实现一个VR角色控制器,包括基本的移动、转向、跳跃和交互功能。我们将从以下几个方面进行讲解:

  1. 角色控制器的基本概念

  2. 设置环境和导入资源

  3. 角色移动的实现

  4. 角色转向的实现

  5. 角色跳跃的实现

  6. 角色交互的实现

  7. 优化和调试

1. 角色控制器的基本概念

在虚拟现实游戏中,角色控制器负责管理角色的移动、转向、跳跃和其他交互行为。一个好的角色控制器可以显著提升玩家的沉浸感和游戏体验。角色控制器通常需要与VR头显和手柄进行交互,以实现自然的移动和操作。

2. 设置环境和导入资源

在开始编写角色控制器之前,我们需要先设置好Cocos Creator的开发环境,并导入必要的VR资源。

2.1 设置Cocos Creator环境

  1. 安装Cocos Creator:确保你已经安装了最新版本的Cocos Creator。你可以在Cocos官方网站下载并安装。

  2. 创建新项目:打开Cocos Creator,创建一个新的项目。选择一个合适的项目目录,并命名为“VRGame”。

  3. 配置VR支持:在项目设置中启用VR支持。进入“项目设置” -> “引擎功能” -> “虚拟现实”,勾选“启用虚拟现实支持”。

2.2 导入VR资源

  1. 导入VR模型:从3D建模软件中导出VR角色模型(如FBX格式),并将其导入到Cocos Creator的资源管理器中。

  2. 导入VR环境:导入一个虚拟现实环境的模型,如一个房间或户外场景。

  3. 导入VR手柄模型:导入VR手柄模型,以便在场景中显示手柄。

3. 角色移动的实现

角色移动是VR游戏中最基本的功能之一。我们将使用Cocos Creator的脚本来实现角色的基本移动。

3.1 创建角色节点

  1. 创建角色节点:在场景中创建一个空节点,命名为“Player”。

  2. 添加模型:将导入的VR角色模型拖拽到“Player”节点下。

  3. 添加组件:为“Player”节点添加一个脚本组件,命名为“PlayerController”。

3.2 编写移动脚本


// PlayerController.js

cc.Class({

    extends: cc.Component,



    properties: {

        // 角色移动速度

        moveSpeed: 5,

        // 角色旋转速度

        rotateSpeed: 200,

    },



    // 初始化

    onLoad: function () {

        // 注册输入事件

        this.inputManager = cc.director.get inputManager();

        this.inputManager.enabled = true;

        this.inputManager.on(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

    },



    // 更新角色位置

    update: function (dt) {

        // 获取手柄输入

        let inputVector = new cc.Vec2();

        inputVector.x = this.inputManager.getAxis("Horizontal");

        inputVector.y = this.inputManager.getAxis("Vertical");



        // 计算移动方向

        let moveDirection = new cc.Vec3();

        moveDirection.x = inputVector.x * this.moveSpeed * dt;

        moveDirection.z = inputVector.y * this.moveSpeed * dt;



        // 更新角色位置

        this.node.position = this.node.position.add(moveDirection);

    },



    // 处理设备运动事件

    onDeviceMotion: function (event) {

        // 获取设备的旋转角度

        let rotation = event.rotation;



        // 更新角色旋转

        this.node.eulerAngles = new cc.Vec3(0, rotation.y * this.rotateSpeed, 0);

    },



    // 清理

    onDestroy: function () {

        // 注销输入事件

        this.inputManager.off(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

    }

});

3.3 配置输入轴

  1. 打开输入管理器:进入“项目设置” -> “输入管理器”。

  2. 添加输入轴:添加两个输入轴“Horizontal”和“Vertical”,分别对应手柄的左右摇杆。

4. 角色转向的实现

角色转向可以通过手柄的旋转或头显的头部运动来实现。我们将使用手柄的旋转来实现角色转向。

4.1 修改转向脚本


// PlayerController.js

cc.Class({

    extends: cc.Component,



    properties: {

        // 角色移动速度

        moveSpeed: 5,

        // 角色旋转速度

        rotateSpeed: 200,

    },



    // 初始化

    onLoad: function () {

        // 注册输入事件

        this.inputManager = cc.director.getInputManager();

        this.inputManager.enabled = true;

        this.inputManager.on(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

        this.inputManager.on(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);

    },



    // 更新角色位置

    update: function (dt) {

        // 获取手柄输入

        let inputVector = new cc.Vec2();

        inputVector.x = this.inputManager.getAxis("Horizontal");

        inputVector.y = this.inputManager.getAxis("Vertical");



        // 计算移动方向

        let moveDirection = new cc.Vec3();

        moveDirection.x = inputVector.x * this.moveSpeed * dt;

        moveDirection.z = inputVector.y * this.moveSpeed * dt;



        // 更新角色位置

        this.node.position = this.node.position.add(moveDirection);

    },



    // 处理设备运动事件

    onDeviceMotion: function (event) {

        // 获取设备的旋转角度

        let rotation = event.rotation;



        // 更新角色旋转

        this.node.eulerAngles = new cc.Vec3(0, rotation.y * this.rotateSpeed, 0);

    },



    // 处理手柄轴事件

    onAxisEvent: function (event) {

        if (event.name === "RightTrigger") {

            let rotation = this.node.eulerAngles.y + event.value * this.rotateSpeed * cc.director.getDeltaTime();

            this.node.eulerAngles = new cc.Vec3(0, rotation, 0);

        }

    },



    // 清理

    onDestroy: function () {

        // 注销输入事件

        this.inputManager.off(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

        this.inputManager.off(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);

    }

});

4.2 配置手柄轴

  1. 打开输入管理器:进入“项目设置” -> “输入管理器”。

  2. 添加手柄轴:添加一个手柄轴“RightTrigger”,对应手柄的右侧触发器。

5. 角色跳跃的实现

角色跳跃是VR游戏中常见的动作之一。我们将通过手柄的按键事件来实现角色的跳跃。

5.1 修改跳跃脚本


// PlayerController.js

cc.Class({

    extends: cc.Component,



    properties: {

        // 角色移动速度

        moveSpeed: 5,

        // 角色旋转速度

        rotateSpeed: 200,

        // 角色跳跃高度

        jumpHeight: 10,

        // 重力加速度

        gravity: -9.8,

        // 当前竖直速度

        verticalSpeed: 0,

        // 是否在空中

        isGrounded: false,

    },



    // 初始化

    onLoad: function () {

        // 注册输入事件

        this.inputManager = cc.director.getInputManager();

        this.inputManager.enabled = true;

        this.inputManager.on(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

        this.inputManager.on(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);

        this.inputManager.on(cc.InputEvent.EventType.KEY_DOWN, this.onKeyDown, this);

    },



    // 更新角色位置

    update: function (dt) {

        // 获取手柄输入

        let inputVector = new cc.Vec2();

        inputVector.x = this.inputManager.getAxis("Horizontal");

        inputVector.y = this.inputManager.getAxis("Vertical");



        // 计算移动方向

        let moveDirection = new cc.Vec3();

        moveDirection.x = inputVector.x * this.moveSpeed * dt;

        moveDirection.z = inputVector.y * this.moveSpeed * dt;



        // 更新角色位置

        this.node.position = this.node.position.add(moveDirection);



        // 应用重力

        if (!this.isGrounded) {

            this.verticalSpeed += this.gravity * dt;

            this.node.position = this.node.position.add(new cc.Vec3(0, this.verticalSpeed * dt, 0));

        }



        // 检查是否在地面上

        this.checkGround();

    },



    // 处理设备运动事件

    onDeviceMotion: function (event) {

        // 获取设备的旋转角度

        let rotation = event.rotation;



        // 更新角色旋转

        this.node.eulerAngles = new cc.Vec3(0, rotation.y * this.rotateSpeed, 0);

    },



    // 处理手柄轴事件

    onAxisEvent: function (event) {

        if (event.name === "RightTrigger") {

            let rotation = this.node.eulerAngles.y + event.value * this.rotateSpeed * cc.director.getDeltaTime();

            this.node.eulerAngles = new cc.Vec3(0, rotation, 0);

        }

    },



    // 处理按键事件

    onKeyDown: function (event) {

        if (event.keyCode === cc.KeyCode.SPACE && this.isGrounded) {

            this.isGrounded = false;

            this.verticalSpeed = this.jumpHeight;

        }

    },



    // 检查是否在地面上

    checkGround: function () {

        let groundCheckPosition = this.node.position.clone();

        groundCheckPosition.y -= 1; // 降低1单位检查地面

        let hit = cc.director.getCollisionManager().raycastClosest(new cc.Ray(this.node.position, groundCheckPosition));

        if (hit && hit.collider) {

            this.isGrounded = true;

            this.verticalSpeed = 0;

        }

    },



    // 清理

    onDestroy: function () {

        // 注销输入事件

        this.inputManager.off(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

        this.inputManager.off(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);

        this.inputManager.off(cc.InputEvent.EventType.KEY_DOWN, this.onKeyDown, this);

    }

});

5.2 配置跳跃按键

  1. 打开输入管理器:进入“项目设置” -> “输入管理器”。

  2. 添加按键:添加一个按键“Space”,对应手柄的跳跃按钮。

6. 角色交互的实现

角色与环境的交互是提升游戏沉浸感的关键。我们将实现角色与环境物体的交互,如拾取物品和触发事件。

6.1 添加交互物体

  1. 创建交互物体:在场景中创建一个空节点,命名为“InteractableObject”。

  2. 添加模型:将一个模型(如一个箱子)拖拽到“InteractableObject”节点下。

  3. 添加碰撞组件:为“InteractableObject”节点添加一个碰撞组件(如BoxCollider)。

6.2 编写交互脚本


// InteractableObject.js

cc.Class({

    extends: cc.Component,



    properties: {

        // 物体名称

        objectName: {

            default: "Box",

            tooltip: "物体的名称",

        },

    },



    // 初始化

    onLoad: function () {

        // 注册碰撞事件

        this.node.on(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);

    },



    // 处理触摸事件

    onTouchStart: function (event) {

        cc.log(`Interacted with ${this.objectName}`);

        // 这里可以添加更多的交互逻辑,如拾取物品、触发事件等

    },



    // 清理

    onDestroy: function () {

        // 注销碰撞事件

        this.node.off(cc.Node.EventType.TOUCH_START, this.onTouchStart, this);

    }

});

6.3 修改角色控制器脚本以支持交互


// PlayerController.js

cc.Class({

    extends: cc.Component,



    properties: {

        // 角色移动速度

        moveSpeed: 5,

        // 角色旋转速度

        rotateSpeed: 200,

        // 角色跳跃高度

        jumpHeight: 10,

        // 重力加速度

        gravity: -9.8,

        // 当前竖直速度

        verticalSpeed: 0,

        // 是否在空中

        isGrounded: false,

        // 交互距离

        interactDistance: 2,

    },



    // 初始化

    onLoad: function () {

        // 注册输入事件

        this.inputManager = cc.director.getInputManager();

        this.inputManager.enabled = true;

        this.inputManager.on(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

        this.inputManager.on(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);

        this.inputManager.on(cc.InputEvent.EventType.KEY_DOWN, this.onKeyDown, this);

        this.inputManager.on(cc.InputEvent.EventType.KEY_UP, this.onKeyUp, this);

    },



    // 更新角色位置

    update: function (dt) {

        // 获取手柄输入

        let inputVector = new cc.Vec2();

        inputVector.x = this.inputManager.getAxis("Horizontal");

        inputVector.y = this.inputManager.getAxis("Vertical");



        // 计算移动方向

        let moveDirection = new cc.Vec3();

        moveDirection.x = inputVector.x * this.moveSpeed * dt;

        moveDirection.z = inputVector.y * this.moveSpeed * dt;



        // 更新角色位置

        this.node.position = this.node.position.add(moveDirection);



        // 应用重力

        if (!this.isGrounded) {

            this.verticalSpeed += this.gravity * dt;

            this.node.position = this.node.position.add(new cc.Vec3(0, this.verticalSpeed * dt, 0));

        }



        // 检查是否在地面上

        this.checkGround();



        // 检查交互

        this.checkInteract();

    },



    // 处理设备运动事件

    onDeviceMotion: function (event) {

        // 获取设备的旋转角度

        let rotation = event.rotation;



        // 更新角色旋转

        this.node.eulerAngles = new cc.Vec3(0, rotation.y * this.rotateSpeed, 0);

    },



    // 处理手柄轴事件

    onAxisEvent: function (event) {

        if (event.name === "RightTrigger") {

            let rotation = this.node.eulerAngles.y + event.value * this.rotateSpeed * cc.director.getDeltaTime();

            this.node.eulerAngles = new cc.Vec3(0, rotation, 0);

        }

    },



    // 处理按键事件

    onKeyDown: function (event) {

        if (event.keyCode === cc.KeyCode.SPACE && this.isGrounded) {

            this.isGrounded = false;

            this.verticalSpeed = this.jumpHeight;

        }

        if (event.keyCode === cc.KeyCode.E) {

            // 模拟交互按钮按下

            this.interact();

        }

    },



    // 处理按键释放事件

    onKeyUp: function (event) {

        if (event.keyCode === cc.KeyCode.E) {

            // 模拟交互按钮释放

            cc.log("Interaction button released");

        }

    },



    // 检查是否在地面上

    checkGround: function () {

        let groundCheckPosition = this.node.position.clone();

        groundCheckPosition.y -= 1; // 降低1单位检查地面

        let hit = cc.director.getCollisionManager().raycastClosest(new cc.Ray(this.node.position, groundCheckPosition));

        if (hit && hit.collider) {

            this.isGrounded = true;

            this.verticalSpeed = 0;

        }

    },



    // 检查交互

    checkInteract: function () {

        // 发射光线检测交互物体

        let forward = this.node.forward.clone();

        forward.normalize();

        let endPosition = this.node.position.add(forward.mul(this.interactDistance));

        let hit = cc.director.getCollisionManager().raycastClosest(new cc.Ray(this.node.position, endPosition));

        if (hit && hit.collider) {

            // 如果检测到交互物体,存储其节点

            this.interactableObject = hit.collider.node;

        } else {

            this.interactableObject = null;

        }

    },



    // 交互

    interact: function () {

        if (this.interactableObject) {

            // 触发交互物体的交互事件

            this.interactableObject.emit("interact");

        }

    },



    // 清理

    onDestroy: function () {

        // 注销输入事件

        this.inputManager.off(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);

        this.inputManager.off(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);

        this.inputManager.off(cc.InputEvent.EventType.KEY_DOWN, this.onKeyDown, this);

        this.inputManager.off(cc.InputEvent.EventType.KEY_UP, this.onKeyUp, this);

    }

});

6.4 修改交互物体脚本以支持角色交互


// InteractableObject.js

cc.Class({

    extends: cc.Component,



    properties: {

        // 物体名称

        objectName: {

            default: "Box",

            tooltip: "物体的名称",

        },

    },



    // 初始化

    onLoad: function () {

        // 注册交互事件

        this.node.on("interact", this.onInteract, this);

    },



    // 处理碰撞事件

    onInteract: function (event) {

        cc.log(`Interacted with ${this.objectName}`);

        // 这里可以添加更多的交互逻辑,如拾取物品、触发事件等

    },



    // 清理

    onDestroy: function () {

        // 注销交互事件

        this.node.off("interact", this.onInteract, this);

    }

});

7. 优化和调试

在实现角色控制器和移动系统后,我们需要进行优化和调试,以确保性能和稳定性。

7.1 优化性能

  1. 减少不必要的计算:在update函数中,避免进行不必要的计算和属性访问。例如,可以缓存一些常量值,减少每帧的计算量。

    
    // PlayerController.js
    
    cc.Class({
    
        extends: cc.Component,
    
    
    
        properties: {
    
            // 角色移动速度
    
            moveSpeed: 5,
    
            // 角色旋转速度
    
            rotateSpeed: 200,
    
            // 角色跳跃高度
    
            jumpHeight: 10,
    
            // 重力加速度
    
            gravity: -9.8,
    
            // 当前竖直速度
    
            verticalSpeed: 0,
    
            // 是否在空中
    
            isGrounded: false,
    
            // 交互距离
    
            interactDistance: 2,
    
            // 缓存常量
    
            groundCheckOffset: 1,
    
            interactRayDirection: new cc.Vec3(0, -1, 0),
    
            interactRayLength: 2,
    
        },
    
    
    
        // 初始化
    
        onLoad: function () {
    
            // 注册输入事件
    
            this.inputManager = cc.director.getInputManager();
    
            this.inputManager.enabled = true;
    
            this.inputManager.on(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);
    
            this.inputManager.on(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);
    
            this.inputManager.on(cc.InputEvent.EventType.KEY_DOWN, this.onKeyDown, this);
    
            this.inputManager.on(cc.InputEvent.EventType.KEY_UP, this.onKeyUp, this);
    
        },
    
    
    
        // 更新角色位置
    
        update: function (dt) {
    
            // 获取手柄输入
    
            let inputVector = new cc.Vec2();
    
            inputVector.x = this.inputManager.getAxis("Horizontal");
    
            inputVector.y = this.inputManager.getAxis("Vertical");
    
    
    
            // 计算移动方向
    
            let moveDirection = new cc.Vec3();
    
            moveDirection.x = inputVector.x * this.moveSpeed * dt;
    
            moveDirection.z = inputVector.y * this.moveSpeed * dt;
    
    
    
            // 更新角色位置
    
            this.node.position = this.node.position.add(moveDirection);
    
    
    
            // 应用重力
    
            if (!this.isGrounded) {
    
                this.verticalSpeed += this.gravity * dt;
    
                this.node.position = this.node.position.add(new cc.Vec3(0, this.verticalSpeed * dt, 0));
    
            }
    
    
    
            // 检查是否在地面上
    
            this.checkGround();
    
    
    
            // 检查交互
    
            this.checkInteract();
    
        },
    
    
    
        // 处理设备运动事件
    
        onDeviceMotion: function (event) {
    
            // 获取设备的旋转角度
    
            let rotation = event.rotation;
    
    
    
            // 更新角色旋转
    
            this.node.eulerAngles = new cc.Vec3(0, rotation.y * this.rotateSpeed, 0);
    
        },
    
    
    
        // 处理手柄轴事件
    
        onAxisEvent: function (event) {
    
            if (event.name === "RightTrigger") {
    
                let rotation = this.node.eulerAngles.y + event.value * this.rotateSpeed * cc.director.getDeltaTime();
    
                this.node.eulerAngles = new cc.Vec3(0, rotation, 0);
    
            }
    
        },
    
    
    
        // 处理按键事件
    
        onKeyDown: function (event) {
    
            if (event.keyCode === cc.KeyCode.SPACE && this.isGrounded) {
    
                this.isGrounded = false;
    
                this.verticalSpeed = this.jumpHeight;
    
            }
    
            if (event.keyCode === cc.KeyCode.E) {
    
                // 模拟交互按钮按下
    
                this.interact();
    
            }
    
        },
    
    
    
        // 处理按键释放事件
    
        onKeyUp: function (event) {
    
            if (event.keyCode === cc.KeyCode.E) {
    
                // 模拟交互按钮释放
    
                cc.log("Interaction button released");
    
            }
    
        },
    
    
    
        // 检查是否在地面上
    
        checkGround: function () {
    
            let groundCheckPosition = this.node.position.clone();
    
            groundCheckPosition.y -= this.groundCheckOffset; // 降低1单位检查地面
    
            let hit = cc.director.getCollisionManager().raycastClosest(new cc.Ray(this.node.position, groundCheckPosition));
    
            if (hit && hit.collider) {
    
                this.isGrounded = true;
    
                this.verticalSpeed = 0;
    
            }
    
        },
    
    
    
        // 检查交互
    
        checkInteract: function () {
    
            // 发射光线检测交互物体
    
            let forward = this.node.forward.clone();
    
            forward.normalize();
    
            let endPosition = this.node.position.add(forward.mul(this.interactDistance));
    
            let hit = cc.director.getCollisionManager().raycastClosest(new cc.Ray(this.node.position, endPosition));
    
            if (hit && hit.collider) {
    
                // 如果检测到交互物体,存储其节点
    
                this.interactableObject = hit.collider.node;
    
            } else {
    
                this.interactableObject = null;
    
            }
    
        },
    
    
    
        // 交互
    
        interact: function () {
    
            if (this.interactableObject) {
    
                // 触发交互物体的交互事件
    
                this.interactableObject.emit("interact");
    
            }
    
        },
    
    
    
        // 清理
    
        onDestroy: function () {
    
            // 注销输入事件
    
            this.inputManager.off(cc.InputEvent.EventType.DEVICE_MOTION, this.onDeviceMotion, this);
    
            this.inputManager.off(cc.InputEvent.EventType.AXIS_EVENT, this.onAxisEvent, this);
    
            this.inputManager.off(cc.InputEvent.EventType.KEY_DOWN, this.onKeyDown, this);
    
            this.inputManager.off(cc.InputEvent.EventType.KEY_UP, this.onKeyUp, this);
    
        }
    
    });
    
    
  2. 优化碰撞检测:使用高效的碰撞检测方法,减少不必要的碰撞检测。例如,可以使用层次化的碰撞检测,或者减少碰撞检测的频率。

  3. 使用帧率适配:确保游戏的帧率适配不同设备的性能。可以在项目设置中调整帧率,或者使用动态帧率适配。

    
    // 在游戏启动时设置帧率
    
    cc.game.setFrameRate(60);
    
    
  4. 减少内存占用:优化资源的加载和卸载,减少内存占用。例如,可以使用资源池来管理频繁使用的资源。

7.2 调试

  1. 使用调试工具:Cocos Creator 提供了丰富的调试工具,可以在编辑器中开启调试模式,检查性能瓶颈和逻辑错误。

    • 性能面板:在编辑器中打开“调试” -> “性能面板”,查看每帧的性能数据。

    • 调试日志:在脚本中使用cc.log输出调试信息,帮助定位问题。

  2. 测试不同设备:在不同的VR设备上进行测试,确保角色控制器和移动系统在各种设备上都能正常工作。

  3. 回放测试:使用Cocos Creator的回放功能,记录和回放玩家的操作,以便于复现问题。

  4. 用户反馈:收集用户的反馈,了解他们在实际使用中的体验,及时优化和修复问题。

7.3 常见问题及解决方法

  1. 角色移动不流畅:检查角色的移动逻辑,确保每帧的移动计算是平滑的。可以尝试调整移动速度和重力加速度,或者优化碰撞检测。

  2. 角色旋转不自然:确保角色的旋转是基于头显或手柄的自然运动。可以调整旋转速度,或者使用插值算法平滑旋转。

  3. 交互检测不准确:检查交互检测的逻辑,确保光线检测的方向和长度是合理的。可以调整interactDistanceinteractRayDirection,或者使用更复杂的碰撞检测方法。

  4. 性能问题:使用性能面板识别性能瓶颈,优化资源加载、碰撞检测和不必要的计算。可以尝试减少场景中的物体数量,或者使用LOD(Level of Detail)技术。

通过以上步骤,我们可以实现一个功能完整、性能优化的VR角色控制器和移动系统。希望这些内容能帮助你在Cocos Creator中开发出更加沉浸式的虚拟现实游戏。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值