<三>制作第一个3D游戏(进阶)

这一篇接着完善demo。

添加光照

光影是描述游戏的重要渲染特性,通过光源和阴影可以模拟更加真实的游戏世界,提供更好的沉浸感和代入感。
在创建项目时,场景默认带了一个挂载了 cc.DirectionalLight 组件的平行光 Main Light 节点。
虽然有光源,但运行时发现并没有阴影,阴影需要另外开启。

开启阴影

1.在层级管理器中选中场景节点,勾选Shadow组件上的Enable属性。

2.在 层级管理器 中选中 Light,然后在 属性检查器 的 Dynamic Shadow Settings 组件中勾选 Shadow Enabled 属性。
3.在 层级管理器 中选中需要显示阴影的 3D 节点,然后在 属性检查器 的 MeshRenderer 组件中将 ShadowCastingMode 属性设置为 ON。
按步骤开启阴影后发现运行时还是看不到阴影,应该是阴影的位置不对。
可以调整这个平行光的方向,让阴影的显示换个位置。

更换主角模型

到Cocos商城找一个免费又好看的人物模型作为新的主角模型。

将它拖拽到 层级管理器 中 Player 节点下的 Body 节点中,作为 Body 节点的子节点
移除Body上的胶囊体模型。

卡哇伊!~~~

优化动画

更换的萌妹模型有10个动画剪辑,其中就有Idle动画和Jump动画。这里需要把原来用Tween实现的动画逻辑给优化一下。
先查看一下动画:
选中资源管理器中的模型文件FBX

发现idle01和jump02都可以用,但jump02花里胡哨的动作太多了,只想要向上跳起的动作,所以需要重新剪辑一下。

修改后的PlayerCtrl

import { _decorator, Component, EventMouse, Input, input, Node, SkeletalAnimation, tween, v3, Vec3 } from 'cc';
import { EventMgr } from './EventMgr';
import { EventName } from './Enum';
const { ccclass, property } = _decorator;

@ccclass('PlayerController')
export class PlayerController extends Component {
    @property(SkeletalAnimation)
    player_Anim: SkeletalAnimation = null;
    private _isJumping: boolean = false;//是否跳跃中
    private _targetPos: Vec3 = v3();//目标位置
    private _curPos: Vec3 = v3();//当前位置
    private _jumpStep: number = 0;//跳跃步长,一步还是两步,根据步长计算目标位置
    private _curJumpTime: number = 0;//当前跳跃时间
    private _jumpTime: number = 0.5;//跳跃持续时间/每次跳跃的时长,匹配移动时长
    private _moveSpeed: number = 0;//移动速度
    private _deltaPos: Vec3 = v3();//每帧移动的距离

    private _curMoveStep: number = 0;//记录当前移动步数
    start() {
        //输入监听
        //input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
    }

    reset() {
        this._curPos = v3();
        this._targetPos = v3();
        this._isJumping = false;
        this._jumpStep = 0;
        this._curJumpTime = 0;
        this._moveSpeed = 0;
        this._deltaPos = v3();
        this._curMoveStep = 0;
    }
    /**
     * 是否开启关闭输入
     * @param active 
     */
    setInputActive(active: boolean) {
        if (active) {
            input.on(Input.EventType.MOUSE_UP, this.onMouseUp, this);
        } else {
            input.off(Input.EventType.MOUSE_UP, this.onMouseUp, this);
        }
    }
    onMouseUp(event: EventMouse) {
        //如果是鼠标左键,getButton 方法会返回 0,而如果是右键,则返回 2
        if (event.getButton() == 0) {
            //这里不要直接给_jumpStep赋值,因为需要判断是否正在跳跃中,否则会多次调用
            this.jumpByStep(1);
        } else if (event.getButton() == 2) {
            this.jumpByStep(2);
        }
    }
    /**
     * 辅助计算跳跃移动的信息(目标位置,跳跃时间等等),实现跳跃动画
     * @param step 
     * @returns 
     */
    jumpByStep(step: number) {
        if (this._isJumping) {
            //跳跃是一个完整的步骤,如果正在跳跃中不做任何响应
            return;
        }
        this._isJumping = true;
        this._jumpStep = step;
        //跳跃动画
        // tween(this.node.getChildByName("Body"))
        //     .to(this._jumpTime * 0.5, { position: v3(0, this._jumpStep * 0.5, 0) })
        //     .to(this._jumpTime * 0.5, { position: v3(0, 0, 0) })
        //     .start();
        this.player_Anim.getState("jump03").speed = 1.5;//设置动画速度(1.5)
        this.player_Anim.play("jump03");

        this._curJumpTime = 0;//重置跳跃时间
        this._moveSpeed = this._jumpStep / this._jumpTime;//计算移动速度
        this.node.getPosition(this._curPos);//获取当前位置
        Vec3.add(this._targetPos, this._curPos, v3(this._jumpStep, 0, 0));//计算目标位置

        this._curMoveStep += step;//记录移动步数
    }

    /**
     * 每一次跳跃结束回调
     */
    onOnceJumpEnd() {
        this.player_Anim.play("idle01");
        EventMgr.emit(EventName.JumpEnd, this._curMoveStep);//发射一次跳跃结束事件
    }


    update(deltaTime: number) {
        if (!this._isJumping) return;//如果没有跳跃,则不处理任何跳跃移动的逻辑
        this._curJumpTime += deltaTime;//计算当前跳跃时间
        if (this._curJumpTime >= this._jumpTime) {//如果已经完成一次完整的跳跃,则结束跳跃
            this.node.setPosition(this._targetPos);//强制逐句移动到目标位置
            this._isJumping = false;
            this.onOnceJumpEnd();
        } else {
            this.node.getPosition(this._curPos);//获取当前位置
            this._deltaPos.x = this._moveSpeed * deltaTime;//计算每帧移动的距离
            Vec3.add(this._curPos, this._curPos, this._deltaPos);//计算当前位置
            this.node.setPosition(this._curPos);//逐帧移动到当前位置
        }
    }
}


显示步长 && 用时

创建结算界面


其他更多的可能都是添加一些UI,不再赘述,后面慢慢再补充吧。

posted @ 2024-10-23 15:47  EricShx  阅读(61)  评论(0)    收藏  举报