[开发者心得] 【预制体】如何制作一个丝滑的秋千-联机版

[复制链接]
1471 |2
疏影横斜水清浅 发表于 2023-2-22 13:44:02 | 显示全部楼层 |阅读模式
首先我们一起来看看单机版秋千存在的问题


从视频中我们可以看到,单机版中无法同步秋千的摇摆动作,同时UI显示上也有问题
那么接下来就让我们一起来解决这个问题吧
我们需要让秋千摇摆同步给其他玩家,并且关闭其他玩家的可交互UI
同步代码如下
/**秋千是否被坐下-需要属性同步给其他玩家 */
     @Core.Property({ replicated: true, hideInEditor: true, onChanged: "changeState" })
     private isSitDown: boolean = false;

     /**服务端调用设置属性同步并播放摆动动画 */
     @Core.Function(Core.Server)
     setIsSitDown(_isSitDown: boolean) {
         this.isSitDown = _isSitDown;
     }
     /**当状态发生改变时 */
     changeState() {
         if (this.isSitDown) {
            //开启秋千摇摆
             this.startSway();
             if ((this._interactive != null) && !(this._interactive.interactiveCharacter() === Gameplay.getCurrentPlayer().character)) {
                 if (this._seatUI) {
                    //隐藏交互UI
                     UI.UIManager.instance.hideUI(this._seatUI);
                 }
             }
         }
         else {
            //停止秋千摇摆
             this.stopSway();
             if ((this._trigger != null) && this._trigger.isInArea(Gameplay.getCurrentPlayer().character)) {
                //在触发器的内玩家都显示当前秋千可交互ui
                 UI.UIManager.instance.showUI(this._seatUI, UI.UILayerBottom, this.interaction, this.cancelInteraction);
             }
         }
     }
然后在触发器判断UI显示位置需要添加判断是否当前玩家进入,UI点击交互位置不再是简单的播放秋千摇摆,而是要改成我们新增的属性同步方法,SwingScript整体代码如下
/** 
* AUTHOR: 疏影横斜水清浅
* TIME: 2023.02.22-10.20.05
*/

import Seat from "./Seat";

@Core.Class
export default class SwingScript extends Core.Script {

    //#region  相关变量定义
    /**UI持有 */
    private _seatUI: Seat;
    /**触发器 */
    private _trigger: Gameplay.Trigger;
    /**交互器是否交互中,如果交互中让离开触发器事件失效(交互器bug有一定几率在交互时触发触发器离开事件) */
    private _isInInteractive: boolean = false;
    /**交互器 */
    private _interactive: Gameplay.Interactor;
    /**坐姿 */
    @Core.Property({ displayName: "坐姿guid", group: "秋千设置" })
    public sittingPositionGuid: string = "4175";
    /**离开秋千位置 */
    private _exitPosition: Type.Vector;
    /**秋千旋转开始角度 */
    @Core.Property({ displayName: "开始旋转角度", group: "秋千设置" })
    public startRotation: Type.Rotation = new Type.Rotation(27, 0, 0)
    /**秋千结束旋转角度 */
    @Core.Property({ displayName: "结束旋转角度", group: "秋千设置" })
    public endRotation: Type.Rotation = new Type.Rotation(-27, 0, 0)
    /**秋千晃动一次用时 */
    @Core.Property({ displayName: "旋转持续时时间 单位:秒", group: "秋千设置" })
    public duration: number = 1;
    /**秋千开始晃动延迟 */
    @Core.Property({ displayName: "旋转延迟时间 单位:秒", group: "秋千设置" })
    public delayTime: number = 1;
    /**旋转动画Tween */
    private _tween: Util.TweenUtil.Tween<Type.Rotation> = null;
    //#endregion

    //#region 相关事件定义
    private triggerOnEnter;
    private triggerOnLeave;
    private interaction;
    private cancelInteraction;
    private startSway;
    private stopSway;
    initAction() {
        this.triggerOnEnter = (other: Core.GameObject) => {
            if (other instanceof Gameplay.Character) {
                if ((other as Gameplay.Character).player.getPlayerID() === Gameplay.getCurrentPlayer().getPlayerID()) {
                    //当前交互物无人,显示sitUI
                    if (!this._interactive.interactiveCharacter()) {
                        if (this._seatUI == null) {
                            this._seatUI = UI.UIManager.instance.create(Seat);
                        }
                        UI.UIManager.instance.showUI(this._seatUI, UI.UILayerBottom, this.interaction, this.cancelInteraction);
                    }
                }
            }
        }

        this.triggerOnLeave = (other: Core.GameObject) => {
            if (other instanceof Gameplay.Character) {
                if (!this._isInInteractive && (other as Gameplay.Character).player.getPlayerID() === Gameplay.getCurrentPlayer().getPlayerID()) {
                    UI.UIManager.instance.hideUI(this._seatUI);
                }
            }
        }

        this.interaction = () => {
            if (this._interactive.interactiveCharacter()) {
                UI.UIManager.instance.hideUI(this._seatUI);
            }
            else {
                this.setIsSitDown(true);
                this._isInInteractive = true;
                this._interactive.enterInteractiveState(Gameplay.getCurrentPlayer().character);
            }
        }

        this.cancelInteraction = () => {
            if (this._interactive.interactiveCharacter() === Gameplay.getCurrentPlayer().character) {
                this.setIsSitDown(false);
                this._interactive.exitInteractiveState(this._exitPosition);
                this._isInInteractive = false;
            }
        }

        this.startSway = () => {
            if (this._tween === null) {
                /**设置初始值 */
                this._tween = new Util.TweenUtil.Tween(this.startRotation.clone());
                /**设置结束值与动画时间 */
                this._tween.to(this.endRotation, this.duration * 1000);
                /**设置运行逻辑 */
                this._tween.onUpdate((rotation) => {
                    this.gameObject.relativeRotation = rotation;
                })
                /**设置变化曲线 */
                this._tween.easing(Util.TweenUtil.Easing.Sinusoidal.InOut);
                /**设置启动延迟时间 */
                this._tween.delay(this.delayTime * 1000);
                /**设置启动后关闭延迟时间 */
                this._tween.onStart(() => {
                    this._tween.delay(0);
                })
                /**设置来回摇摆循环模式 */
                this._tween.repeat(Infinity).yoyo(true);
                /**设置结束逻辑 */
                this._tween.onStop(() => {
                    this.gameObject.relativeRotation = Type.Rotation.zero;
                    this.useUpdate = false;
                })
                /**启动动画 */
                this._tween.start();
                this.useUpdate = true;
            } else {
                setTimeout(() => {
                    this._tween.start();
                }, this.delayTime * 1000);
            }
        }

        this.stopSway = () => {
            this._tween.stop();
        }
    }
    //#endregion

    /**秋千是否被坐下-需要属性同步给其他玩家 */
    @Core.Property({ replicated: true, hideInEditor: true, onChanged: "changeState" })
    private isSitDown: boolean = false;

    /**服务端调用设置属性同步并播放摆动动画 */
    @Core.Function(Core.Server)
    setIsSitDown(_isSitDown: boolean) {
        this.isSitDown = _isSitDown;
    }
    /**当状态发生改变时 */
    changeState() {
        if (this.isSitDown) {
            //开启秋千摇摆
            this.startSway();
            if ((this._interactive != null) && !(this._interactive.interactiveCharacter() === Gameplay.getCurrentPlayer().character)) {
                if (this._seatUI) {
                    //隐藏交互UI
                    UI.UIManager.instance.hideUI(this._seatUI);
                }
            }
        }
        else {
            //停止秋千摇摆
            this.stopSway();
            if ((this._trigger != null) && this._trigger.isInArea(Gameplay.getCurrentPlayer().character)) {
                //在触发器的内玩家都显示当前秋千可交互ui
                UI.UIManager.instance.showUI(this._seatUI, UI.UILayerBottom, this.interaction, this.cancelInteraction);
            }
        }
    }

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected async onStart(): Promise<void> {
        if (Util.SystemUtil.isClient()) {
            //加载秋千交互姿势
            if (!Util.AssetUtil.isAssetExist(this.sittingPositionGuid)) {
                await Util.AssetUtil.asyncDownloadAsset(this.sittingPositionGuid);
            }
            this.initAction();
            this._trigger = this.gameObject.getChildByName("trigger") as Gameplay.Trigger;
            this._interactive = this.gameObject.getChildByName("interaction") as Gameplay.Interactor;
            let exitObj = (this.gameObject.getChildByName("exitPosition") as Core.GameObject);
            this._exitPosition = exitObj.worldLocation
            /**为触发器添加进入事件 */
            this._trigger.onEnter.add(this.triggerOnEnter)
            /**为触发器添加离开事件 */
            this._trigger.onLeave.add(this.triggerOnLeave)
        }

    }
}
最后让我们一起看看效果吧!!!


回复

使用道具 举报

逝水无痕 发表于 2023-2-22 14:08:53 | 显示全部楼层
牛!!!
回复

使用道具 举报

唯美傷飛上天 发表于 2023-2-24 16:15:06 | 显示全部楼层
给孩子送和个预制体
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表