unityController - ユーザーインタラクション

onResize メソッドは、 index.html の Web ページのユーザー操作に使用されるすべてのメソッドが含まれています。すべてのキー入力機能とクリック機能は、このセクションにあります。

onKeyDown

onKeyDown(event: KeyboardEvent)

onKeyDown メソッドが、ウィンドウが選択されたときにどのキーが押されたかに応じて、指定の機能をトリガします。

changeOffset
値を変更して、ビデオ遅延オフセットを変更する。
toggleGenvidOverlay
Genvid オーバーレイの表示、非表示を切り替える。
client.videoPlayer.isPaused
ビデオが一時停止しているかどうかを示すブール値を返す。
client.videoPlayer.play
ビデオを再生する。
client.videoPlayer.pause
ビデオを一時停止する。
client.videoPlayer.getMuted
ビデオサウンドがミュートされているかどうかを示すブール値を返す。
client.videoPlayer.setMuted
引数に応じて、音声のミュートの有効、無効を切り替える。
client.videoPlayer.setVolume
送信された引数にビデオボリュームを設定する。
client.videoPlayer.getVolume
現在のビデオボリュームを取得する。
onHelpActivation
ヘルプオーバーレイの表示、非表示を切り替える。
        onKeyDown(event: KeyboardEvent) {
            // Seems to be the most cross-platform way to determine keys:
            // Ref: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code

            let code = event.code || this.getKeyCode(event);
            if (code === "Equal" || code === "NumpadAdd") {
                this.changeOffset(+1, event);
            } else if (code === "Minus" || code === "NumpadSubtract") {
                this.changeOffset(-1, event);
            } else if (code === "NumpadMultiply") {
                this.changeOffset(0, event);
            } else if (code === "KeyG") {
                this.toggleGenvidOverlay();
            }
            else if (code === "Space") {
                if (this.client.videoPlayer.isPaused()) {
                    this.client.videoPlayer.play();
                } else {
                    this.client.videoPlayer.pause();
                }
                event.preventDefault();
            }
            else if (code === "KeyM") {
                this.onMute();
            }
            else if (code === "KeyZ") {
                this.promptOverlay = <HTMLDivElement>document.querySelector("#prompt_overlay");
                this.client.videoPlayer.setVolume(this.client.videoPlayer.getVolume() - 20);
                this.promptOverlay.style.visibility = "visible";
                this.timeVisiblePrompt = 0;
                this.volumeChange = 2;
            }
            else if (code === "KeyX") {
                this.promptOverlay = <HTMLDivElement>document.querySelector("#prompt_overlay");
                this.client.videoPlayer.setVolume(this.client.videoPlayer.getVolume() + 20);
                this.promptOverlay.style.visibility = "visible";
                this.timeVisiblePrompt = 0;
                this.volumeChange = 1;
            }
            else if (code === "KeyH") {
                this.onHelpActivation();
            }
        }

getKeyCode

getKeyCode(event: KeyboardEvent)

getKeyCode メソッドは、さまざまなブラウザで適切な keyCode を取得します。

        // Compatibility code for browsers (Safari) not having KeyboardEvent.code.
        getKeyCode(event: KeyboardEvent) {
            if (event.keyCode) {
                console.log(event.keyCode, event.code);
                if (65 <= event.keyCode && event.keyCode <= 90) {
                    return "Key" + String.fromCharCode(event.keyCode);
                } else {
                    switch (event.keyCode) {
                        case 13: return "Enter";
                        case 106: return "NumpadMultiply";
                        case 107: return "NumpadAdd";
                        case 109: return "NumpadSubtract";
                        case 110: return "NumpadDecimal";
                        case 111: return "NumpadDivide";
                        case 187: return "Equal";
                        case 188: return "Comma";
                        case 189: return "Minus";
                        case 190: return "Period";
                        case 222: return "Backquote";
                    }
                }
            }
        }

onResize

onResize()

onResize メソッドは、 index.html の Web ページで使用されているさまざまなオーバーレイのサイズを変更します。この関数の影響を受けるオーバーレイは、次のとおりです。

  • videoOverlay,
  • canvas3d,
  • promptOverlay (サウンド調整に使用)、および
  • 各オブジェクト名のアニメーション div。

index.html ページに表示するビデオストリームのサイズ値を取得し、このサイズを元に他のオーバーレイを調整します。このサンプルでは、オブジェクトが適切に選択できるようにするために、適切なオーバーレイサイズが必要となるため、サイズ変更が不可欠です。また、ビデオ内のオブジェクトの目印にするために、適切な場所に WebGL の輪を表示する必要があります。

        // Allow to adjust the various overlay when resizing the windows - needed to see the PromptOverlay and Name moving div
        onResize() {
            let refElement = this.client.videoElem; // The element to match.
            let refElementSize = refElement ? genvidMath.vec2(refElement.clientWidth, refElement.clientHeight) : genvidMath.vec2(1280, 720);
            let refElementRatio = refElementSize.x / refElementSize.y;
            let videoRatio = this.client.videoAspectRatio;
            let pos: genvidMath.IVec2;
            let size: genvidMath.IVec2;
            if (videoRatio >= refElementRatio) {
                // Top+Bottom bars, fill width fully, shrink height.
                let ey = refElementSize.x / videoRatio;
                let dy = refElementSize.y - ey;
                // Center vertically.
                let y = dy * 0.5;
                pos = genvidMath.vec2(0, Math.round(y));
                size = genvidMath.vec2(refElementSize.x, Math.round(ey));
            } else {
                // Left+Right bars, fill height fully, shrink width.
                let ex = refElementSize.y * videoRatio;
                let dx = refElementSize.x - ex;
                // Center horizontally.
                let x = dx * 0.5;
                pos = genvidMath.vec2(Math.round(x), 0);
                size = genvidMath.vec2(Math.round(ex), refElementSize.y);
            }
            let style = this.videoOverlay.style;
            let cur_pos = genvidMath.vec2(parseInt(style.left), parseInt(style.top));
            let cur_size = genvidMath.vec2(parseInt(style.width), parseInt(style.height));

            if (!genvidMath.equal2D(cur_size, size, 0.9) || !genvidMath.equal2D(cur_pos, pos, 0.9)) {
                this.videoOverlay.style.left = pos.x + "px";
                this.videoOverlay.style.width = size.x + "px";
                this.videoOverlay.style.top = pos.y + "px";
                this.videoOverlay.style.height = size.y + "px";
                this.canvas3d.width = size.x;
                this.canvas3d.height = size.y;
                this.genvidWebGL.setViewport(0, 0, size.x, size.y); // Render in the whole area.
            }

            if (this.lastSelection != null) {
                this.onSelect(this.lastSelection, true);
            }
            else {
                for (let nameSelect of this.cubeDiv) {
                    nameSelect.style.backgroundColor = "#181818";
                }
            }
        }

toggleFullScreen

toggleFullScreen()

toggleFullScreen メソッドは、ビデオのフルスクリーンを有効または無効にします。checkFullScreen 関数でフルスクリーンの状態を確認し、適切な状態に調整します。

すでにフルスクリーンである場合は、Web ブラウザ機能に従ってフルスクリーンをキャンセルし、フルスクリーンボタンアイコンも調整します。

フルスクリーンでない場合は、 video_area 要素を取得します。その後、Web ブラウザ機能でフルスクリーンを有効にし、フルスクリーンボタンアイコンを更新します。

        toggleFullScreen() {
            let doc = <any>document;
            if (this.checkFullScreen()) {
                if (doc.exitFullscreen) {
                    doc.exitFullscreen();
                } else if (doc.mozCancelFullScreen) {
                    doc.mozCancelFullScreen();
                } else if (doc.webkitExitFullscreen) {
                    doc.webkitExitFullscreen();
                } else if (doc.msExitFullscreen) {
                    doc.msExitFullscreen();
                }
                this.fullScreenElement.classList.remove("fa-compress");
                this.fullScreenElement.classList.add("fa-expand");
            } else {
                let element = <any>document.querySelector("#video_area");
                if (element.requestFullscreen) {
                    element.requestFullscreen();
                } else if (element.mozRequestFullScreen) {
                    element.mozRequestFullScreen();
                } else if (element.webkitRequestFullscreen) {
                    element.webkitRequestFullscreen();
                } else if (element.msRequestFullscreen) {
                    element.msRequestFullscreen();
                }
                this.fullScreenElement.classList.remove("fa-expand");
                this.fullScreenElement.classList.add("fa-compress");
            }
        }

onMute

onMute()

onMute メソッドは、ビデオプレイヤーがミュート/ミュート解除されるたびに呼び出されます。

この関数を呼び出すと、 getMuted() を呼び出してミュート状態を取得し、オーディオ、ボリュームアップなどのアイコンの見やすさ、オーバーレイメッセージを調整することができます。

        // Depending on the status, mute or unmute the video player audio
        onMute() {
            const muteIcon = document.querySelector("#mute-button i");
            this.promptOverlay = <HTMLDivElement>document.querySelector("#prompt_overlay");
            if (this.client.videoPlayer.getMuted()) {
                muteIcon.classList.remove("fa-volume-off");
                muteIcon.classList.add("fa-volume-up");
                this.client.videoPlayer.setMuted(false);
                this.promptOverlay.style.visibility = "visible";
                this.promptOverlay.textContent = "Volume is unmuted";
                this.timeVisiblePrompt = 0;
            } else {
                muteIcon.classList.remove("fa-volume-up");
                muteIcon.classList.add("fa-volume-off");
                this.client.videoPlayer.setMuted(true);
                this.promptOverlay.style.visibility = "visible";
                this.promptOverlay.textContent = "Volume is muted";
                this.timeVisiblePrompt = 0;
            }
        }

showOverlay

showOverlay()

showOverlay メソッドは、Genvid オーバーレイを表示します。

        // Change the style to display the Genvid overlay
        showOverlay() {
            this.genvidOverlay.style.display = "block";
        }

hideOverlay

hideOverlay()

showOverlay メソッドは、Genvid オーバーレイを非表示にします。

        // Change the style to hide the Genvid overlay
        hideOverlay() {
            this.genvidOverlay.style.display = "none";
        }

clickCube

clickCube(event: MouseEvent)

clickCube は、WebGL オーバーレイをクリックしてキューブが選択されたと pickCube メソッドが判断した場合に、 true を戻します。そうでない場合は、この関数でイベントの伝達を処理します。

        // Method used when clicking on the WebGL overlay
        clickCube(event: MouseEvent) {
            let best = this.pickCube(event);
            if (best) {
                return true;
            } else {
                // Continue propagation.
                return false;
            }
        }

pickCube

pickCube(event: MouseEvent)

pickCube メソッドは、WebGL オーバーレイをクリックした時にキューブが選択されているかどうかを確認します。

  1. ゲームデータが有効かどうかを確認し、無効の場合は、他の検証を行いません。

  2. ウィンドウ内でクリックした位置を取得します。

  3. その後、この座標を投影空間に変換します。

                if (this.lastGameData == null) {
                    return false;
                }
    
                // [0, 1] coordinates in the window.
                let rect = this.canvas3d.getBoundingClientRect();
                let x = event.pageX - rect.left; // More robust to recompute from pageX/pageY.
                let y = event.pageY - rect.top;
                let p01 = genvidMath.vec2(x / rect.width, y / rect.height);
                // [-1, 1] coordinates in projection space.
                let p = genvidMath.mad2D(p01, genvidMath.vec2(2, -2), genvidMath.vec2(-1, 1));
                let mat = this.convertMatrix(this.lastGameData.MatProjView);
                let best = null;
                let bestDist = Infinity;
    
  4. 各オブジェクトの座標を確認するループ処理を開始します。

  5. このループ処理で、オブジェクトの座標を取得し、検索するゾーンの半径を適用します。

  6. 最後に、座標がオブジェクトゾーン内にあるかどうかを検索し、距離に応じて最良の結果として保持します (2 つのオブジェクトが近い場合、ゾーンまでの距離が小さいものが選択されます)。

                for (let cube of this.lastGameData.cubes) {
                    let pos3D = genvidMath.vec3(cube.mat.e03, cube.mat.e13, cube.mat.e23);
                    let radius = 1.0;
                    let pos2D_rad2D = this.projectWithRadius(mat, pos3D, radius);
                    let pos2D = pos2D_rad2D[0];
                    let rad2D = pos2D_rad2D[1];
    
                    let pos2D_to_p = genvidMath.sub2D(p, pos2D);
                    let d = genvidMath.length2D(pos2D_to_p);
                    if (d < rad2D && d < bestDist) {
                        best = cube.name;
                        bestDist = d;
                    }
                }
    
                if (event.ctrlKey || event.metaKey) {
                    this.toggleSelection(best);
                    this.onSelect(best, false);
                } else if (best != null) {
                    this.setSelection(best);
                    this.onSelect(best, false);
                }
                return best;
    

toggleSelection

toggleSelection(name)

toggleSelection メソッドは送信されたオブジェクト名を選択状態として追加します。

        // Select a cube via the circle
        toggleSelection(name) {
            if (!this.removeFromArray(this.selection, name)) {
                this.addToSelection(name);
            }
        }

setSelection

setSelection(name)

setSelection メソッドは、選択したオブジェクトが選択された状態になるように選択リストをリセットします。

        // Set the selection to a specific cube
        setSelection(name) {
            this.selection = [];
            if (name) {
                this.selection.push(name);
                this.client.sendEventObject({ select: name });
            }
        }

isSelected

isSelected(name)

isSelected メソッドは、オブジェクトが選択されているかどうかを判別します。

        // Verify if the cube is selected
        isSelected(name) {
            return this.selection.indexOf(name) !== -1;
        }

addToSelection

addToSelection(name)

addToSelection メソッドは、オブジェクトが前回選択されなかった場合に、オブジェクトを選択に追加します。

        // Add the cube selected to the selection list
        addToSelection(name) {
            if (name && !this.isSelected(name)) {
                this.selection.push(name);
            }
        }

changeOffset

changeOffset(direction, event)

changeOffset メソッドはビデオの遅延オフセットを追加、縮小、またはリセットします。引数の方向が 0 の場合、ビデオの遅延オフセットはリセットされ、それ以外の場合は送信された値に応じて変更されます。

        // Function that changed the delay offset depending of the key pressed
        private changeOffset(direction, event) {
            if (direction !== 0) {
                let delayDelta = 100 * direction;
                if (event.altKey) delayDelta *= 10;
                if (event.shiftKey) delayDelta /= 2;
                let newDelayOffset = this.client.delayOffset + delayDelta;
                this.client.delayOffset = newDelayOffset;
            } else {
                this.client.delayOffset = 0;
            }
        }

toggleGenvidOverlay

toggleGenvidOverlay()

toggleGenvidOverlay メソッドは、Genvid オーバーレイの表示、非表示を切り替えます。Genvid オーバーレイは、ストリームに関するさまざまなデータを表示します。

Raw Video
raw ビデオを受信した時間。
Est. Video
ビデオを受信した時点の推定時間。
Last Compose
直前の合成時間。
Est. Compose
推定合成時間。
Stream
ストリーミングが開始されてからの時間。
Latency
ストリームを見ている時に発生する遅延。
DelayOffset
ビデオの現在の遅延オフセット。
        // Display or remove the Genvid Overlay
        private toggleGenvidOverlay() {
            if (this.genvidOverlay.getAttribute("data-isHidden")) {
                this.genvidOverlay.setAttribute("data-isHidden", "");
                this.genvidOverlay.style.visibility = "visible";
                this.genvidOverlayButton.classList.remove("disabled");
            } else {
                this.genvidOverlay.setAttribute("data-isHidden", "true");
                this.genvidOverlay.style.visibility = "hidden";
                this.genvidOverlayButton.classList.add("disabled");
            }
        }

onHelpActivation

onHelpActivation()

onHelpActivation メソッドは、ヘルプオーバーレイの表示、非表示を切り替えます。

        // Display or remove the help overlay
        private onHelpActivation() {
            if (this.help_overlay.style.visibility === "visible") {
                this.help_overlay.style.visibility = "hidden";
            }
            else {
                this.help_overlay.style.visibility = "visible";
            }
        }

onCheer

onCheer(cubeName: string)

onCheer メソッドは、プレイヤーを応援するボタンをクリックしたときに、クライアントにイベントを送信します。イベントにはオブジェクト名が含まれます。

        // Upon cheering a player
        private onCheer(cubeName: string) {
            this.client.sendEventObject({ cheer: cubeName });
        }

onReset

onReset(cubeName: string)

onReset メソッドは、プレイヤーをリセットするボタンをクリックしたときに、イベントを送信します。イベントにはオブジェクト名が含まれます。

        // Reset the position of the cube
        private onReset(cubeName: string) {
            this.client.sendEventObject({ reset: cubeName });
        }

onColorChange

onColorChange(cube: string, color: string)

onColorChange メソッドは、プレイヤーの色を変更するボタンをクリックしたときにイベントを送信します。イベントには、オブジェクト名と色が含まれます。

        // Method used when clicking on a color to change the color of a cube
        private onColorChange(cube: string, color: string) {
            let evt = {
                key: ["changeColor", cube],
                value: color,
            };
            this.client.sendEvent([evt]);
        }

onSelect

onSelect(cubeName: string, selectionInterface: boolean)

onSelect メソッドは、ビデオストリームの下に表示されるプレイヤーテーブルをクリックした時に UI を変化させます。各テーブルの色をリセットし、選択したテーブルにのみ色を適用し、その後、WebGL の輪を選択します。

        // Select the cube from the interface
        private onSelect(cubeName: string, selectionInterface: boolean) {

            for (let nameSelect of this.cubeDiv) {
                nameSelect.style.backgroundColor = "#181818";
            }

            let cubeDiv = <HTMLDivElement>document.querySelector(".cube" + cubeName);
            this.lastSelection = cubeName;
            cubeDiv.style.backgroundColor = "#32324e";

            if (selectionInterface) {
                this.setSelection(cubeName);
            }
        }