[预制体] 【预制体】自由移动相机与拍照截图功能

[复制链接]
1260 |4
疏影横斜水清浅 发表于 2023-2-27 10:38:39 | 显示全部楼层 |阅读模式
首先让我们一起看看最终实现效果吧


预制体的结构如下:
1.photograph脚本-负责配置相关属性与打开交互UI
2.photographUI脚本-负责实现交互相关逻辑
3.将photograph脚本挂载在预制体上保存即可

1

1

2

2

photograph脚本代码如下
/** 
* AUTHOR: 疏影横斜水清浅
* TIME: 2023.02.24-10.46.01
*/
import photographUI from "./photographUI";

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

    @Core.Property({ displayName: "远近距离", group: "拍照动效属性", })
    public lengthArm: number = 300;
    @Core.Property({ displayName: '白光起始透明度', group: "拍照动效属性" })
    public initRenderOpacity: number = 0.1;
    @Core.Property({ displayName: '白光结束透明度', group: "拍照动效属性" })
    public endRenderOpacity: number = 0.65;
    @Core.Property({ displayName: '渐变到白光时间:单位-毫秒', group: "拍照动效属性" })
    public moveWhiteTime: number = 200;
    @Core.Property({ displayName: '白光停留时间:单位-毫秒', group: "拍照动效属性" })
    public stayWhilteTime: number = 3;
    @Core.Property({ displayName: '图片移动时间:单位-毫秒', group: "拍照动效属性" })
    public imageMoveTime: number = 1000;
    @Core.Property({ displayName: '最终图片的比例', group: "拍照动效属性" })
    public endImageProportion: number = 0.65;
    @Core.Property({ displayName: '最终图片旋转角度', group: "拍照动效属性" })
    public endImageRotation: number = -8;

    /** 当脚本被实例后,会在第一帧更新前调用此函数 */
    protected onStart(): void {
        if (Util.SystemUtil.isClient()) {
            UI.UIManager.instance.show(photographUI, this.lengthArm,this.initRenderOpacity, this.endRenderOpacity,
                this.moveWhiteTime, this.stayWhilteTime, this.imageMoveTime, this.endImageProportion, this.endImageRotation);
        }
    }

}
photographUI脚本代码如下
/** 
* AUTHOR: 疏影横斜水清浅
* TIME: 2023.02.24-10.46.01
*/

import DefaultUI_Generate from "../../../JavaScripts/ui-generate/DefaultUI_generate";

import photographUI_Generate from "./ui-generate/photographUI_generate";

export default class photographUI extends photographUI_Generate {

        private isFreeCamera = false;
        /**
         * 构造UI文件成功后,在合适的时机最先初始化一次
         */
        protected onStart() {
                //设置能否每帧触发onUpdate
                this.canUpdate = true;
                this.layer = UI.UILayerMiddle;
                this.initCamera();
                this.UIBtnEventBind();

        }

        onShow(_lengthArm: number, _initRenderOpacity: number, _endRenderOpacity: number,
                _moveWhiteTime: number, _stayWhilteTime: number, _imageMoveTime: number, _endImageProportion: number, _endImageRotation: number) {
                this.lengthArm = _lengthArm;
                this.initRenderOpacity = _initRenderOpacity;
                this.endRenderOpacity = _endRenderOpacity;
                this.moveWhiteTime = _moveWhiteTime;
                this.stayWhilteTime = _stayWhilteTime;
                this.imageMoveTime = _imageMoveTime;
                this.endImageProportion = _endImageProportion;
                this.endImageRotation = _endImageRotation;

                //相机臂相关参数初始化
                this.bar_lengthCamera.currentValue = 0.5;
                this.oldBarCur = this.bar_lengthCamera.currentValue;
                //相关参数初始化
                this.mSlotCanvasInitSize = WindowUtil.getViewportSize();
                this.mSlotCanvasToSize = new Type.Vector2(this.mSlotCanvasInitSize.x * this.endImageProportion, this.mSlotCanvasInitSize.y * this.endImageProportion);
                this.mSlotCanvasToPosition = new Type.Vector2(this.mSlotCanvasInitSize.x / 2 - this.mSlotCanvasToSize.x / 2, this.mSlotCanvasInitSize.y / 2 - this.mSlotCanvasToSize.y / 2);
                this.slotCanvasData = {
                        imagePosition: Type.Vector2.zero,
                        imageSize: this.mSlotCanvasInitSize.clone(), imageRotation: 0
                }
        }

        //记录原先的进度条值
        private oldBarCur: number;
        //为界面上的UI进度条等绑定相关函数
        UIBtnEventBind() {
                this.btn_camera.onClicked.add(() => {
                        this.btn_camera.visibility = UI.SlateVisibility.Collapsed;
                        this.img_Btncamera.visibility = UI.SlateVisibility.Collapsed;
                        this.cameraCanvas.visibility = UI.SlateVisibility.Visible;
                        Gameplay.getCurrentPlayer().character.moveEnable = false;
                        this.startFreeCamera();
                        //相机臂相关参数初始化
                        this.bar_lengthCamera.currentValue = 0.5;
                        this.oldBarCur = this.bar_lengthCamera.currentValue;
                });

                this.btn_close.onClicked.add(() => {
                        this.btn_camera.visibility = UI.SlateVisibility.Visible;
                        this.img_Btncamera.visibility = UI.SlateVisibility.SelfHitTestInvisible;
                        this.cameraCanvas.visibility = UI.SlateVisibility.Collapsed;
                        this.canvasPircture.visibility = UI.SlateVisibility.Collapsed;
                        this.text_path.visibility = UI.SlateVisibility.Collapsed;
                        Gameplay.getCurrentPlayer().character.moveEnable = true;
                        this.stopFreeCamera();
                });

                this.virtualJoystickPanel.onInputDir.add((vec2: Type.Vector2) => {
                        this.directionOfXY = vec2.normalize();
                });

                this.btn_shoot.onClicked.add(() => {
                        this.startShotTween();
                });

                this.btn_closePircture.onClicked.add(() => {
                        this.canvasPircture.visibility = UI.SlateVisibility.Collapsed;
                        this.text_path.visibility = UI.SlateVisibility.Collapsed;
                });

                this.bar_lengthCamera.sliderMinValue = 0;
                this.bar_lengthCamera.sliderMaxValue = 1;
                this.bar_lengthCamera.onSliderValueChanged.add((value) => {
                        let newValue = this._cameraSystem.targetArmLength + (value - this.oldBarCur) * this.lengthArm;
                        this._cameraSystem.targetArmLength = newValue;
                        this.oldBarCur = this.bar_lengthCamera.currentValue;
                });
        }

        //#region 相机移动相关
        private _cameraAnchor: Core.GameObject
        private _cameraSystem: Gameplay.CameraSystem;
        private _oldCameraSetting: Gameplay.CameraSystemData;

        initCamera() {
                this._cameraAnchor = Core.GameObject.spawnGameObject("Anchor");
                this._cameraSystem = Gameplay.getCurrentPlayer().character.cameraSystem;
        }

        startFreeCamera() {
                this._cameraSystem.followTargetEnable = false;
                this._cameraAnchor.transform = Gameplay.getCurrentPlayer().character.cameraSystem.cameraWorldTransform;

                this._oldCameraSetting = this._cameraSystem.getCurrentSettings();
                this._cameraSystem.applySettings(this.FREE_VIEW_CAMERA_SETTING);
                this._cameraSystem.attachToGameObject(this._cameraAnchor);
                // let radian = Math.PI / 2;
                // let _cameraAnchorForRightVectorX = this._cameraAnchor.forwardVector.x * Math.cos(radian) - this._cameraAnchor.forwardVector.y * Math.sin(radian);
                // let _cameraAnchorForRightVectorY = this._cameraAnchor.forwardVector.x * Math.sin(radian) + this._cameraAnchor.forwardVector.y * Math.cos(radian);
                // this._cameraAnchorForRightVector = new Type.Vector(_cameraAnchorForRightVectorX, _cameraAnchorForRightVectorY, 0);
                //因为sin cos 九十度的特殊性,简化成下面这一句
                this._cameraAnchorForRightVector = new Type.Vector(-this._cameraAnchor.forwardVector.y, this._cameraAnchor.forwardVector.x, 0);
                this.isFreeCamera = true;
        }

        stopFreeCamera() {
                this.isFreeCamera = false;
                this._cameraSystem.applySettings(this._oldCameraSetting);
                this._cameraSystem.cancelCameraLockTarget();
                this._cameraSystem.followTargetEnable = true;
        }

        private moveLocation = Type.Vector.zero;
        /**上升下落速度 */
        private speedZ = 5;
        /**X,Y移动 */
        private directionOfXY = Type.Vector2.zero;
        /**X,Y移动速度 */
        private _speedXY = 5;
        private _cameraAnchorForRightVector;
        onUpdate() {
                if (this.isFreeCamera) {
                        if (this.btn_up.isPressed()) {
                                this.moveLocation.z += this.speedZ;
                        }
                        if (this.btn_down.isPressed()) {
                                this.moveLocation.z -= this.speedZ;
                        }
                        this.moveLocation.add(this._cameraAnchor.forwardVector.multiply(
                                this.directionOfXY.y * this._speedXY));
                        this.moveLocation.add((this._cameraAnchorForRightVector).clone().multiply(
                                this.directionOfXY.x * this._speedXY));
                        this._cameraAnchor.worldLocation = this._cameraAnchor.worldLocation.add(this.moveLocation);
                        this.moveLocation = Type.Vector.zero;
                }
        }

        // 自由视角时摄像机设置(不能将视角K为上下90°(P分量),否则重置摄像机将出现异常)
        private readonly FREE_VIEW_CAMERA_SETTING: Gameplay.CameraSystemData = {
                /** 摄像机相对Transform */
                cameraRelativeTransform: new Type.Transform(),
                /** 摄像机世界Transform */
                cameraWorldTransform: new Type.Transform(),
                /** 投影模式 */
                cameraProjectionMode: Gameplay.CameraProjectionMode.Perspective,
                /** 正交宽度 */
                orthoWidth: 512,
                /** 正交视图近平面距离 */
                orthoNearClipPlane: 0,
                /** 正交视图远平面距离 */
                orthoFarClipPlane: 2097152,
                /** 距离调整 */
                targetArmLength: 0,
                /** 开启摄像机位置延迟 */
                enableCameraLocationLag: false,
                /** 摄像机位置延迟速度 */
                cameraLocationLagSpeed: 0,
                /** 开启摄像机旋转延迟 */
                enableCameraRotationLag: false,
                /** 摄像机旋转延迟速度 */
                cameraRotationLagSpeed: 0,
                /** 视场 */
                cameraFOV: 90,
                /** 摄像机位置模式 */
                cameraLocationMode: Gameplay.CameraLocationMode.LocationFollow,
                /** 摄像机朝向模式 */
                cameraRotationMode: Gameplay.CameraRotationMode.RotationControl,
                /** 是否有摄像机碰撞 */
                enableCameraCollision: false,
                /** 挂点位置偏移 */
                targetOffset: new Type.Vector(0, 0, 0),
                /** 摄像机位置偏移 */
                slotOffset: new Type.Vector(0, 0, 0),
                /** 向上限制角度 */
                cameraUpLimitAngle: 89.9,
                /** 向下限制角度 */
                cameraDownLimitAngle: 89.9,
                /** 是否开启物体透明 */
                enableFadeEffect: false,
                /** 物体透明度 */
                fadeEffectValue: 0,
                /** 开启碰撞抬高 */
                enableRaiseCamera: false,
                /** 抬高高度 */
                raiseCameraHeight: 0
        };
        //#endregion

        //#region 拍照截图相关
        //相关属性参数暴露
        //远近距离拉扯
        private lengthArm;
        //白光起始透明度
        private initRenderOpacity;
        //白光结束透明度
        private endRenderOpacity;
        //渐变到白光时间:单位-毫秒
        private moveWhiteTime;
        //白光停留时间:单位-毫秒
        private stayWhilteTime;
        //图片移动时间:单位-毫秒
        private imageMoveTime;
        //最终图片的比例
        private endImageProportion;
        //最终图片旋转角度
        private endImageRotation;
        //#endregion

        //#region 拍照闪烁动效
        private _tween_Shot: Util.TweenUtil.Tween<{ maskNum: number }> = null;
        private startShotTween() {
                this.img_mask.renderOpacity = 0;
                this.img_mask.visibility = UI.SlateVisibility.SelfHitTestInvisible;
                if (this._tween_Shot === null) {
                        this._tween_Shot = new Util.TweenUtil.Tween({ maskNum: this.initRenderOpacity });
                        this._tween_Shot.to({ maskNum: this.endRenderOpacity }, this.moveWhiteTime);
                        /**设置运行逻辑 */
                        this._tween_Shot.onUpdate((data) => {
                                this.img_mask.renderOpacity = data.maskNum;
                        }).onComplete(() => {
                                setTimeout(() => {
                                        this.img_mask.renderOpacity = 0;
                                        this.img_mask.visibility = UI.SlateVisibility.Collapsed;
                                        MobileEditor.screenShot(Util.WindowUtil.getViewportSize(),
                                                Type.Vector2.zero, Util.WindowUtil.getViewportSize().x, WindowUtil.getViewportSize().y, (str: string) => {
                                                        this.setSlotImg(str);
                                                        this.text_path.visibility = UI.SlateVisibility.Visible;
                                                        this.text_path.text = "截图保存路径为:" + str;
                                                })
                                }, this.stayWhilteTime);

                        });
                        /**设置变化曲线 */
                        this._tween_Shot.easing(Util.TweenUtil.Easing.Exponential.In);
                        this._tween_Shot.start();
                } else {
                        this._tween_Shot.start();
                }
        }

        /**
        * 照片动效
        * @param path
        */
        private _tween_showImage: Util.TweenUtil.Tween<{ imagePosition: Type.Vector2, imageSize: Type.Vector2, imageRotation: number }> = null;
        private mSlotCanvasInitSize: Type.Vector2;
        private mSlotCanvasToSize: Type.Vector2;
        private mSlotCanvasToPosition: Type.Vector2;
        private slotCanvasData;
        private setSlotImg(path: string) {
                this.canvasPircture.position = Type.Vector2.zero;
                this.canvasPircture.size = this.mSlotCanvasInitSize;
                this.canvasPircture.renderTransformAngle = 0;
                this.canvasPircture.visibility = UI.SlateVisibility.SelfHitTestInvisible;
                this.img_showPircture.setImageByFile(path);

                if (this._tween_showImage === null) {
                        this._tween_showImage = new Util.TweenUtil.Tween(this.slotCanvasData);

                        this._tween_showImage.to({
                                imagePosition: this.mSlotCanvasToPosition.clone(),
                                imageSize: this.mSlotCanvasToSize.clone(), imageRotation: this.endImageRotation
                        }, this.imageMoveTime);

                        this._tween_showImage.onUpdate((data) => {
                                this.canvasPircture.position = data.imagePosition;
                                this.canvasPircture.size = data.imageSize;
                                this.canvasPircture.renderTransformAngle = data.imageRotation;
                        });
                        this._tween_showImage.start();
                } else {
                        this.slotCanvasData.imagePosition.set(0, 0);
                        this.slotCanvasData.imageSize.set(this.mSlotCanvasInitSize.x, this.mSlotCanvasInitSize.y)
                        this.slotCanvasData.imageRotation = 0;
                        this._tween_showImage.start();
                }
        }
        //#endregion
}
实现的预制体: photograph.zip (11.6 KB, 下载次数: 68)
回复

使用道具 举报

空伊伊 发表于 2023-2-27 11:52:25 | 显示全部楼层
本帖最后由 空伊伊 于 2023-2-27 11:54 编辑

这个好这个好
回复

使用道具 举报

犯困嫌疑人 发表于 2023-2-27 18:03:19 | 显示全部楼层
这个牛逼啊。
回复

使用道具 举报

吃到苦就是得到了甜 发表于 2023-2-27 18:10:02 | 显示全部楼层
这个牛!收藏
回复

使用道具 举报

众里嫣然一顾 发表于 2023-2-28 09:45:01 | 显示全部楼层
回复

使用道具 举报

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