Skip to content
TweenUtil

Utils / TweenUtil

TweenUtil Class

Animation (from in between) is a concept that allows you to change property of objects in a smooth way. You just need to tell it which property to change, what final values they should have when the session ends, and how long this will take, The interpolation engine will be responsible for calculating the values from the starting point to the ending point.

Usage example: create a script named TweenExample, place it in the object bar, open the script, modify the original content as follows, save and run the game, press G key, a missile will be randomly generate in the scene and fly to the destination according to the set trajectory.

ts
@Component
export default class TweenExample extends Script {

    protected async onStart(): Promise<void> {
        this.useUpdate = true;
        if (SystemUtil.isClient()) {
            let char = (await Player.asyncGetLocalPlayer()).character;
            InputUtil.onKeyDown(Keys.G, async () => {
                let daoDan = new DaoDanScript(char.worldTransform.position, new Vector(Math.random() * 1000, Math.random() * 1000, 0));
            })
        }
    }

    protected onUpdate(dt: number): void {
        TweenUtil.TWEEN.update();
    }

}

class DaoDanScript {

    //Missile prefab
    private prefab: GameObject

    //Constructor. When new, a position is passed in for initialization
    constructor(bornPos: Vector, toPos: Vector) {
        this.init(bornPos, toPos)
    }

    //Initialize DaoDan
    private async init(bornPos: Vector, toPos: Vector) {
        // Use object pool to create prefab and set position of prefab
        const bombAssetId = "44948";
        const fireAssetId = "13404";
        const cubeAssetId = "197386";
        this.prefab = await GameObjPool.asyncSpawn(cubeAssetId, GameObjPoolSourceType.Asset);
        this.prefab.setVisibility(PropertyStatus.Off, false);
        GameObject.asyncSpawn({ guid: bombAssetId }).then(obj => {
            obj.attachToGameObject(this.prefab);
            obj.localTransform.position = new Vector(0, 0, 0);
            obj.localTransform.rotation = new Rotation(0, -90, 0);
        })
        EffectService.playOnGameObject(fireAssetId, this.prefab, {position:new Vector(0, 0, 0), rotation:new Rotation(0, -90, 0), scale: new Vector(2, 2, 2)});
        this.prefab.worldTransform.position = bornPos;
        this.fireToPos(toPos);
    }

    //The missile flies towards a coordinate
    private async fireToPos(targetPos: Vector) {
        // Play the takeoff animation first
        this.fireReadyAnim()

        // Create a special effect (warning effect) at the target location
        EffectService.playAtPosition("155714", targetPos, {loopCount:1});

        // Deconstructing the starting point coordinates (to facilitate Tween's transition)
        let startLoc = { x: this.prefab.worldTransform.position.x, y: this.prefab.worldTransform.position.y, z: this.prefab.worldTransform.position.z }
        // Deconstruct the coordinates of target point (convenient for Tween to transition)
        let targetLoc = { x: targetPos.x, y: targetPos.y, z: targetPos.z }

        // Previous Frame position
        let lastPos: Vector = this.prefab.worldTransform.position.clone()
        // Current frame position
        let nowPos: Vector = Vector.zero
        // Position of middlemen (avoid frequent visits to new Vector)
        let tempPos: Vector = Vector.zero

        // Create a Tween starting from the position of the missile
        const newTween = new mw.Tween(this.prefab.worldTransform.position.clone())

        newTween.to({
            // X-axis flight path (these path points can be freely defined)
            x: [
                startLoc.x + 1000 + Math.random() * 2000,
                startLoc.x + 3000 + Math.random() * 2000,
                startLoc.x + 5000 + Math.random() * 2000,
                targetLoc.x],

            // Y-axis flight path (these path points can be freely defined)
            y: [
                startLoc.y + 1000 + Math.random() * 2000,
                startLoc.y + 3000 + Math.random() * 2000,
                startLoc.y + 5000 + Math.random() * 2000,
                targetLoc.y],

            // Z axis flight path (these path points can be defined freely)
            z: [
                550 + Math.random() * 1000,
                750 + Math.random() * 1000,
                950 + Math.random() * 1000,
                750 + Math.random() * 1000,
                550 + Math.random() * 1000,
                targetLoc.z]
        // The entire process lasts for 3000 milliseconds
        }, 3000)

            //Linear interpolation: completely linear, without transitions at turns, straight forward and backward;
Bezier interpolation: Smooth the entire process to form a curve;
CatmullRom interpolation: Smooth turns, only smooth at turns
            // Using CatmullRom interpolation
            .interpolation(TweenUtil.Interpolation.CatmullRom)
            .onUpdate((value) => {
                // Assign value (transition value) to tempPos and nowPos for computation in each loop
                tempPos.set(value.x, value.y, value.z)
                nowPos.set(value.x, value.y, value.z)
                // Set the coordinates of the rocket as transition values
                this.prefab.worldTransform.position = tempPos
                // Calculate the real-time orientation of the rocket according to the position of the previous frame and the position of this frame
                this.prefab.worldRotation = nowPos.subtract(lastPos).toRotation()
                // Assign this frame value to lastPos for the next operation
                lastPos.set(value.x, value.y, value.z)
            })

        // When Tween finishes playing
        newTween.onComplete(() => {
            const bombEffectId = "7786";
            // Play an explosion effect at the end position
            EffectService.playEffectAtLocation(bombEffectId, this.prefab.worldTransform.position, 1)
            // Reset the rotation of the rocket
            this.prefab.worldTransform.rotation = Rotation.zero
            // Return the rocket to the prefab
            GameObjPool.despawn(this.prefab)
        })

        // Wait one second before playing (to wait until the takeoff animation is played)
        setTimeout(() => {
            newTween.start()
        }, 1000);
    }

    //Takeoff stage animation
    private fireReadyAnim() {
        let tempRotate: Rotation = Rotation.zero
        let startPos: Vector = this.prefab.worldTransform.position.clone()

        let tweenA = new mw.Tween({ y: 0 }).to({ y: 60 + Math.random() * 30 }, 1000).onUpdate((value) => {
            tempRotate.y = value.y
            this.prefab.worldTransform.rotation = tempRotate
        }).start().easing(TweenUtil.Easing.Cubic.Out)

        let tweenB = new mw.Tween(startPos).to(startPos.clone().add(new mw.Vector(0, 0, Math.random() * 100)), 1000).onUpdate((value) => {
            this.prefab.worldTransform.position = value
        }).start().easing(TweenUtil.Easing.Cubic.Out)
    }
}
@Component
export default class TweenExample extends Script {

    protected async onStart(): Promise<void> {
        this.useUpdate = true;
        if (SystemUtil.isClient()) {
            let char = (await Player.asyncGetLocalPlayer()).character;
            InputUtil.onKeyDown(Keys.G, async () => {
                let daoDan = new DaoDanScript(char.worldTransform.position, new Vector(Math.random() * 1000, Math.random() * 1000, 0));
            })
        }
    }

    protected onUpdate(dt: number): void {
        TweenUtil.TWEEN.update();
    }

}

class DaoDanScript {

    //Missile prefab
    private prefab: GameObject

    //Constructor. When new, a position is passed in for initialization
    constructor(bornPos: Vector, toPos: Vector) {
        this.init(bornPos, toPos)
    }

    //Initialize DaoDan
    private async init(bornPos: Vector, toPos: Vector) {
        // Use object pool to create prefab and set position of prefab
        const bombAssetId = "44948";
        const fireAssetId = "13404";
        const cubeAssetId = "197386";
        this.prefab = await GameObjPool.asyncSpawn(cubeAssetId, GameObjPoolSourceType.Asset);
        this.prefab.setVisibility(PropertyStatus.Off, false);
        GameObject.asyncSpawn({ guid: bombAssetId }).then(obj => {
            obj.attachToGameObject(this.prefab);
            obj.localTransform.position = new Vector(0, 0, 0);
            obj.localTransform.rotation = new Rotation(0, -90, 0);
        })
        EffectService.playOnGameObject(fireAssetId, this.prefab, {position:new Vector(0, 0, 0), rotation:new Rotation(0, -90, 0), scale: new Vector(2, 2, 2)});
        this.prefab.worldTransform.position = bornPos;
        this.fireToPos(toPos);
    }

    //The missile flies towards a coordinate
    private async fireToPos(targetPos: Vector) {
        // Play the takeoff animation first
        this.fireReadyAnim()

        // Create a special effect (warning effect) at the target location
        EffectService.playAtPosition("155714", targetPos, {loopCount:1});

        // Deconstructing the starting point coordinates (to facilitate Tween's transition)
        let startLoc = { x: this.prefab.worldTransform.position.x, y: this.prefab.worldTransform.position.y, z: this.prefab.worldTransform.position.z }
        // Deconstruct the coordinates of target point (convenient for Tween to transition)
        let targetLoc = { x: targetPos.x, y: targetPos.y, z: targetPos.z }

        // Previous Frame position
        let lastPos: Vector = this.prefab.worldTransform.position.clone()
        // Current frame position
        let nowPos: Vector = Vector.zero
        // Position of middlemen (avoid frequent visits to new Vector)
        let tempPos: Vector = Vector.zero

        // Create a Tween starting from the position of the missile
        const newTween = new mw.Tween(this.prefab.worldTransform.position.clone())

        newTween.to({
            // X-axis flight path (these path points can be freely defined)
            x: [
                startLoc.x + 1000 + Math.random() * 2000,
                startLoc.x + 3000 + Math.random() * 2000,
                startLoc.x + 5000 + Math.random() * 2000,
                targetLoc.x],

            // Y-axis flight path (these path points can be freely defined)
            y: [
                startLoc.y + 1000 + Math.random() * 2000,
                startLoc.y + 3000 + Math.random() * 2000,
                startLoc.y + 5000 + Math.random() * 2000,
                targetLoc.y],

            // Z axis flight path (these path points can be defined freely)
            z: [
                550 + Math.random() * 1000,
                750 + Math.random() * 1000,
                950 + Math.random() * 1000,
                750 + Math.random() * 1000,
                550 + Math.random() * 1000,
                targetLoc.z]
        // The entire process lasts for 3000 milliseconds
        }, 3000)

            //Linear interpolation: completely linear, without transitions at turns, straight forward and backward;
Bezier interpolation: Smooth the entire process to form a curve;
CatmullRom interpolation: Smooth turns, only smooth at turns
            // Using CatmullRom interpolation
            .interpolation(TweenUtil.Interpolation.CatmullRom)
            .onUpdate((value) => {
                // Assign value (transition value) to tempPos and nowPos for computation in each loop
                tempPos.set(value.x, value.y, value.z)
                nowPos.set(value.x, value.y, value.z)
                // Set the coordinates of the rocket as transition values
                this.prefab.worldTransform.position = tempPos
                // Calculate the real-time orientation of the rocket according to the position of the previous frame and the position of this frame
                this.prefab.worldRotation = nowPos.subtract(lastPos).toRotation()
                // Assign this frame value to lastPos for the next operation
                lastPos.set(value.x, value.y, value.z)
            })

        // When Tween finishes playing
        newTween.onComplete(() => {
            const bombEffectId = "7786";
            // Play an explosion effect at the end position
            EffectService.playEffectAtLocation(bombEffectId, this.prefab.worldTransform.position, 1)
            // Reset the rotation of the rocket
            this.prefab.worldTransform.rotation = Rotation.zero
            // Return the rocket to the prefab
            GameObjPool.despawn(this.prefab)
        })

        // Wait one second before playing (to wait until the takeoff animation is played)
        setTimeout(() => {
            newTween.start()
        }, 1000);
    }

    //Takeoff stage animation
    private fireReadyAnim() {
        let tempRotate: Rotation = Rotation.zero
        let startPos: Vector = this.prefab.worldTransform.position.clone()

        let tweenA = new mw.Tween({ y: 0 }).to({ y: 60 + Math.random() * 30 }, 1000).onUpdate((value) => {
            tempRotate.y = value.y
            this.prefab.worldTransform.rotation = tempRotate
        }).start().easing(TweenUtil.Easing.Cubic.Out)

        let tweenB = new mw.Tween(startPos).to(startPos.clone().add(new mw.Vector(0, 0, Math.random() * 100)), 1000).onUpdate((value) => {
            this.prefab.worldTransform.position = value
        }).start().easing(TweenUtil.Easing.Cubic.Out)
    }
}

Table of contents

Properties

TWEEN: TweenGroup
Single case of global supplementary group. When create a mending room, if not specified, it will be added to the mending group by default

Properties

TWEEN

Static TWEEN: TweenGroup

Single case of global supplementary group. When create a mending room, if not specified, it will be added to the mending group by default