Skip to content

UITextBarrage


WebGPU is not supported in your browser
Please upgrade to latest Chrome/Edge

ts
import { Engine3D, Scene3D, CameraUtil, HoverCameraController, Object3D, View3D, Color, Camera3D, ViewPanel, UITextField, TextAnchor, ComponentBase, AtmosphericComponent, webGPUContext, CResizeEvent } from "@orillusion/core";

class Sample_TextBarrage {
    private scene: Scene3D;
    private camera: Camera3D;

    async run() {
        // init engine
        await Engine3D.init();
        // create new Scene
        let scene = new Scene3D();
        this.scene = scene;

        // load base font
        await Engine3D.res.loadFont("https://cdn.orillusion.com/fnt/0.fnt");

        // add an Atmospheric sky enviroment
        let sky = scene.addComponent(AtmosphericComponent);
        sky.sunY = 0.6;

        // init camera3D
        let mainCamera = CameraUtil.createCamera3D(null, scene);
        mainCamera.perspective(60, Engine3D.aspect, 1, 2000.0);
        this.camera = mainCamera;

        // add a basic camera controller
        const hoverCameraController = mainCamera.object3D.addComponent(HoverCameraController);
        hoverCameraController.setCamera(0, 0, 20);

        // create a view with target scene and camera
        let view = new View3D();
        view.scene = scene;
        view.camera = mainCamera;

        // create UIpanel root
        let panelRoot: Object3D = new Object3D();
        const panel = panelRoot.addComponent(ViewPanel);
        // resize panel radio
        webGPUContext.addEventListener(CResizeEvent.RESIZE, () => panel.uiTransform.resize(Engine3D.width, Engine3D.height), this);

        // add to UIcanvas
        let canvas = view.enableUICanvas();
        canvas.addChild(panel.object3D);

        // Create text barrage
        const textCount = 100;
        for (let i = 0; i < textCount; ++i) {
            const textQuad = new Object3D();
            panelRoot.addChild(textQuad);
            const text = textQuad.addComponent(UITextField);
            text.color = new Color(1, 1, 1);
            text.fontSize = 32;
            text.alignment = TextAnchor.MiddleCenter;
            text.uiTransform.resize(300, 12);

            // Init and reset text barrage animation
            const barrage = textQuad.addComponent(TextBarrageAnimation);
            barrage.camera = this.camera;
            barrage.priorityOffset = textCount;
            barrage.play();
        }

        // start render
        Engine3D.startRenderView(view);
    }
}

class TextBarrageAnimation extends ComponentBase {
    // prettier-ignore
    static words = [ "GALACEAN", "galacean", "HELLO", "hello", "WORLD", "world", "TEXT", "text", "PEACE", "peace", "LOVE", "love", "abcdefg", "hijklmn", "opqrst", "uvwxyz", "ABCDEFG", "HIJKLMN", "OPQRST", "UVWXYZ", "~!@#$", "%^&*", "()_+" ];
    static colors = new Array(10).fill(1).map(() => Color.random());

    public camera: Camera3D;
    public priorityOffset: number = 0;

    private _speed: number = 0;
    private _isPlaying: boolean = false;
    private _text: UITextField;
    private lastTime: number = 0;

    play() {
        this._isPlaying = true;
    }

    start(): void {
        this._text = this.object3D.getComponent(UITextField);
        this.lastTime = Date.now();
        this._reset(true);
    }

    onUpdate(): void {
        if (this._isPlaying) {
            const now = Date.now();
            const dt = now - this.lastTime;
            this.lastTime = now;
            let halfWidth = Engine3D.width * 0.5,
                halfHeight = Engine3D.height * 0.5;
            let { x, y, width, height } = this._text.uiTransform;

            // move text to left
            this._text.uiTransform.x += this._speed * dt;
            // reset text position after pass the left side of the screen
            if (x < -halfWidth - width) {
                this._reset(false);
            }
            // limit y position in view port
            if (y < -halfHeight + height) this._text.uiTransform.y = -halfHeight + height;
            else if (y > halfHeight - height) this._text.uiTransform.y = halfHeight - height;
        }
    }

    private _reset(isFirst: boolean) {
        const text = this._text;
        const { words, colors } = TextBarrageAnimation;

        // Reset the text to render
        const wordLastIndex = words.length - 1;
        text.text = `${words[getRandomNum(0, wordLastIndex)]} ${words[getRandomNum(0, wordLastIndex)]}`;
        // Reset color
        text.color = colors[getRandomNum(0, colors.length - 1)];
        const halfWidth = Engine3D.width * 0.5;
        const halfHeight = Engine3D.height * 0.5;
        // Reset position
        this._text.uiTransform.x = isFirst ? getRandomNum(halfWidth, halfWidth * 3) : halfWidth + this._text.uiTransform.width;
        this._text.uiTransform.y = getRandomNum(-halfHeight + this._text.uiTransform.height, halfHeight - this._text.uiTransform.height);
        // Reset speed
        this._speed = getRandomNum(-500, -200) * 0.0003;
    }
}

/**
 * Get a random number between min and max
 * @param min
 * @param max
 */
function getRandomNum(min: number, max: number): number {
    const range = max - min;
    const rand = Math.random();
    return min + Math.round(rand * range);
}

new Sample_TextBarrage().run();