「毎日Unity」の技術ブログ

開発で役立つ情報を発信する

【JavaScript】多角形の座標配列が時計回りか判別する方法

多角形の座標配列が時計回りか判別する方法を記事にしました。

[ 判別方法 ]

各隣接頂点間のベクトルの外積の総和を求めます。総和が正なら時計回り、負なら反時計回りです。

function IsClockwise(_Points)
{
    let Sum = 0;
    for (let i = 0; i < _Points.length; i++) {
        const Vec1 = _Points[i];
        const Vec2 = _Points[(i + 1) % _Points.length];

        Sum += Vec1.x * Vec2.y - Vec1.y * Vec2.x;
    }

    return Sum > 0;
}

オンラインブラウザゲームの作成方法(2)

今回の記事では前回の記事で作成したものを無料で公開する方法を解説します。

[ 公開方法 ]

package.jsonを更新

前回の記事で作成した「tmp」フォルダ内にある「package.json」ファイルに「"dependencies"」を下記のように書き加えます。
「〇〇〇」の部分はそれぞれのバージョンにします。バージョンの確認方法は前回の記事に書いてあります。

{
  "name": "tmp",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": 
  {
    "start": "node server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^〇〇〇",
    "webpack-cli": "^〇〇〇"
  },
  "dependencies": 
  {
    "express": "^〇〇〇",
    "socket.io": "^〇〇〇"
  }
}

GitHubにアップロード

下記にアクセスします。
※「GitHub」のアカウントを持っていない方は先に作成してください。
github.com
「New」をクリックします。

「Repository name」を入力して「Add a README file」にチェックを入れた後に「Create repository」をクリックします。

「Add file」から「Upload files」をクリックします。

前回の記事で作成した「tmp」フォルダ内にある「public」「package.json」「server.js」の3つを「Drop to upload your files」にドラッグアンドドロップしてアップロードします。

アップロードが完了したら「Commit changes」をクリックします。

下記のような画面になっていれば完了です。

RenderとGitHubをコネクト

下記にアクセスします。
※「Render」のアカウントを持っていない方は先に作成してください。
render.com
「Get Started for Free」をクリックします。

「New Web Service」をクリックします。

「Build and deploy from a Git repository」にチェックを入れて「Next」をクリックします。

先ほど「GitHub」で作成したRepositoryの「Connect」をクリックします。
※「Render」に「GitHub」のアカウントを接続してない方は先に接続してください。

「Region」を「Singapoer (Southeast Asia)」、「Build Command」を「npm install」、「Instance Type」を「Free」にした後に「Create Web Service」をクリックします。
クリックすると自動でデプロイが始まります。デプロイ完了までに数分かかります。

「Logs」の一番最後に「Your service is live 🎉」と出ればアプリが公開できています。

[ 動作確認 ]

https://〇〇〇.onrender.com」にアクセスします。

アクセスすると白い円が表示されるはずです。WASDで白い円は操作できます。

[ 関連記事 ]

[ 参考文献 ]

paiza.hatenablog.com

オンラインブラウザゲームの作成方法(1)

今回の記事ではローカル環境で動作確認するまでのやり方を解説しています。

[ 環境構築 ]

Node.jsのインストール

下記にアクセスします。
nodejs.org
「Download Node.js (LTS)」をクリックして「Node.js」をダウンロードします。

ダウンロードが完了したらダウンロードフォルダ内にある「node-v20.12.1-x64.msi」を起動します。

「Next」をクリックします。

「I accept the terms in the License Agreement」にチェックを入れて「Next」をクリックします。

「Node.js」のインストール先を指定して「Next」をクリックします。

「Next」をクリックします。

「Next」をクリックします。

「Install」をクリックします。

下記のウィンドウが表示されたらインストール完了です。

コマンドプロンプトで「node -v」を実行して「Node.js」のバージョンが表示されれば「Node.js」はインストールされています。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>node -v
v20.12.1

C:\Users\EDunity>

Expressのインストール

コマンドプロンプトで「npm install express」を実行して「Express」をインストールします。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>npm install express

up to date, audited 97 packages in 1s

15 packages are looking for funding
  run `npm fund` for details

3 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

C:\Users\EDunity>

コマンドプロンプトで「npm list express」を実行して「Express」のバージョンが表示されれば「Express」はインストールされています。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>npm list express
EDunity@ C:\Users\EDunity
`-- express@4.19.2


C:\Users\EDunity>

Socket.ioのインストール

コマンドプロンプトで「npm install socket.io」を実行して「Socket.io」をインストールします。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>npm install socket.io

added 23 packages, and audited 120 packages in 2s

15 packages are looking for funding
  run `npm fund` for details

3 moderate severity vulnerabilities

To address all issues (including breaking changes), run:
  npm audit fix --force

Run `npm audit` for details.

C:\Users\EDunity>

コマンドプロンプトで「npm list socket.io」を実行して「Socket.io」のバージョンが表示されれば「Socket.io」はインストールされています。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>npm list socket.io
EDunity@ C:\Users\EDunity
`-- socket.io@4.7.5


C:\Users\EDunity>

Webpackのインストール

コマンドプロンプトで次のコマンドを順番に実行します。
「cd desktop」「mkdir tmp」「cd tmp」「npm init -y」「npm install webpack webpack-cli --save-dev」
これらのコマンドはデスクトップに「tmp」フォルダを作成してその中に「Webpack」をインストールするコマンドです。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>cd desktop

C:\Users\EDunity\Desktop>mkdir tmp

C:\Users\EDunity\Desktop>cd tmp

C:\Users\EDunity\Desktop\tmp>npm init -y
Wrote to C:\Users\EDunity\Desktop\tmp\package.json:

{
  "name": "tmp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}



C:\Users\EDunity\Desktop\tmp>npm install webpack webpack-cli --save-dev

added 119 packages, and audited 120 packages in 7s

16 packages are looking for funding
  run `npm fund` for details

found 0 vulnerabilities

C:\Users\EDunity\Desktop\tmp>

この時点で「tmp」の中身は下記のようになっているはずです。

tmp
  ├ node_modules
  │  └ ...
  ├ package.json
  └ package-lock.json

「tmp」フォルダ内にある「package.json」ファイルの「"main"」と「"scripts"」を下記のように書き換えます。
「〇〇〇」の部分はそれぞれのバージョンにします。

{
  "name": "tmp",
  "version": "1.0.0",
  "description": "",
  "main": "server.js",
  "scripts": 
  {
    "start": "node server.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^〇〇〇",
    "webpack-cli": "^〇〇〇"
  }
}

雛形作成

「tmp」フォルダ内に「server.js」ファイルを作成して中身は下記のようにします。

const Express = require("express");
const Http = require("http");
const Path = require("path");
const SocketIO = require("socket.io");

const App = Express();
const Server = Http.Server(App);
const IO = SocketIO(Server);

class Player
{
    constructor(_ID, _Name, _PosX, _PosY)
    {
        this.ID = _ID;
        this.Name = _Name;
        this.Width = 64;
        this.Height = 64;
        this.PosX = _PosX;
        this.PosY = _PosY;
        this.Movement = {};
    }
};

const Port = process.env.PORT || 3000;
const FrameRate = 60;

const Players = {};

IO.on("connection", function(_Socket) 
{
    _Socket.on("Setup", function(_Name, _PosX, _PosY) 
    {
        if(_Name != null)
        {
            Players[_Socket.id] = new Player(_Socket.id, _Name, _PosX, _PosY);
        }
    });
    
    _Socket.on("Movement", function(_Movement) 
    {
        if(_Socket.id in Players)
        {
            Players[_Socket.id].Movement = _Movement;
        }
    });

    _Socket.on("disconnect", () =>
    {
        if(_Socket.id in Players)
        {
            delete Players[_Socket.id];
        }
    });
});

setInterval(function() 
{
    for(const i in Players) 
    {
        if(Players[i].Movement["w"])
        {
            Players[i].PosY -= 5;
        }
        if(Players[i].Movement["s"])
        {
            Players[i].PosY += 5;
        }
        if(Players[i].Movement["d"])
        {
            Players[i].PosX += 5;
        }
        if(Players[i].Movement["a"])
        {
            Players[i].PosX -= 5;
        }
    }

    IO.sockets.emit("Draw", Players);

}, 1000 / FrameRate);

App.use("/public", Express.static(__dirname + "/public"));

App.get("/", (_Request, _Response) => 
{
    _Response.sendFile(Path.join(__dirname, "/public/index.html"));
});

Server.listen(Port, function() 
{
    console.log("Starting Server on port " + Port + ".");
});

「tmp」フォルダの中に「public」フォルダを作成します。この時点で「tmp」の中身は下記のようになっているはずです。

tmp
 ├ node_modules
 │  └ ...
 ├ public
 ├ package-lock.json
 ├ package.json
 └ server.js

「public」フォルダ内に「index.html」ファイルを作成して中身は下記のようにします。

<html lang="ja">

<head>
    <title>tmp</title>
    <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/p5@1.4.0/lib/p5.js"></script>
    <script type="text/javascript" src="/socket.io/socket.io.js"></script>
    <script type="text/javascript" src="/public/game.js"></script>
    <link type="text/css" rel="stylesheet" href="/public/style.css">
</head>

<body>
    <hr>
    <div class="Parent">
        <div id="Parent">
        </div>
    </div>
    <hr>
</body>

</html>

「public」フォルダ内に「style.css」ファイルを作成し、中身は下記のようにします。

.Parent
{
    display:block;
    text-align:center;
}

「public」フォルダ内に「game.js」ファイルを作成して中身は下記のようにします。

const Socket = io();

let Canvas_Sketch;
const Width_Sketch = 600;
const Height_Sketch = 600;  

const Keys = ["w", "s", "d", "a"];
const Movement = {};

function setup() 
{
    Canvas_Sketch = createCanvas(Width_Sketch, Height_Sketch);
    Canvas_Sketch.parent("Parent");

    background(225);

    Socket.on("connect", function()
    {
        Socket.emit("Setup", prompt("Please enter your name."), Math.random() * Width_Sketch, Math.random() * Height_Sketch);
    });
}
function draw(){
}
function keyPressed() {
    if(Keys.includes(key))
    {
        Movement[key] = true;

        Socket.emit("Movement", Movement);
    }
}
function keyReleased() {
    if(Keys.includes(key))
    {
        Movement[key] = false;

        Socket.emit("Movement", Movement);
    }
}

Socket.on("Draw", function(_Players)
{
    background(225);

    for(const i in _Players) 
    {
        text(_Players[i].Name + "#" + _Players[i].ID, _Players[i].PosX + 15, _Players[i].PosY - 15);
        ellipse(_Players[i].PosX, _Players[i].PosY, 30, 30);
    }
});

この時点で「tmp」の中身は下記のようになっているはずです。

tmp
 ├ node_modules
 │  └ ...
 ├ public
 │  ├ index.html
 │  ├ style.css
 │  └ game.js
 ├ package.json
 ├ package-lock.json
 └ server.js

[ 動作確認 ]

コマンドプロンプトで「node desktop/tmp/server.js」を実行してサーバーを起動します。

Microsoft Windows [Version 10.0.19045.4170]
(c) Microsoft Corporation. All rights reserved.

C:\Users\EDunity>cd desktop

C:\Users\EDunity\Desktop>cd tmp

C:\Users\EDunity\Desktop\tmp>node server.js
Starting Server on port 3000.

下記にアクセスします。
http://localhost:3000/
アクセスすると白い円が表示されるはずです。WASDで白い円は操作できます。

[ 参考文献 ]

paiza.hatenablog.com

【JavaScript】フレームレートをコンソールに出力する方法

フレームレートをコンソールに出力する方法を自分用にメモ。

[ 方法 ]

コンソールにフレームレートを出力します。

let MaxFrameRate = Number.MIN_SAFE_INTEGER;
let MinFrameRate = Number.MAX_SAFE_INTEGER;

let LastMilliTime = 0;
let FrameCount = 0;

function FrameRate() {
    const CurrentMilliTime = performance.now();
    const MilliTimeDiff = CurrentMilliTime - LastMilliTime;

    if (MilliTimeDiff >= 1000) {
        const FrameRate = (FrameCount / MilliTimeDiff * 1000);

        if (MaxFrameRate < FrameRate) {
            MaxFrameRate = FrameRate;
        }

        if (MinFrameRate > FrameRate) {
            MinFrameRate = FrameRate;
        }

        console.log("FrameRate: " + FrameRate);
        console.log("MaxFrameRate: " + MaxFrameRate);
        console.log("MinFrameRate: " + MinFrameRate);

        LastMilliTime = CurrentMilliTime;
        FrameCount = 0;
    }

    FrameCount += 1;

    requestAnimationFrame(FrameRate);
}

FrameRate();

【JavaScript】Mapの使い方

Mapの使い方を自分用にメモすることにしました。

[ 使い方 ]

宣言

MapTestを宣言します。

let MapTest = new Map();

初期化

MapTestを初期化します。

let MapTest = new Map([
  ["abc", 0],
  ["def", 1],
  ["ghi", 2],
]);

要素の追加

MapTestにKeyが"jkl"でValueが3の要素を追加します。

MapTest.set("jkl", 3);

要素の消去

MapTestからKeyが"abc"の要素を消去します。

MapTest.delete("abc");

全要素の消去

MapTestの全要素を消去します。

MapTest.clear();

要素の取得

MapTestからKeyが"abc"の要素のValueを取得します。

MapTest.get("abc");

要素の置換

MapTestのKeyが"abc"の要素のValueを1に置換します。

MapTest.set("abc", 1);

長さを取得

MapTestの長さを取得します。

MapTest.size;

特定の要素を含むか

MapTestがKeyが"abc"の要素を含むかを求めます。

MapTest.has("abc");

Keyだけの配列を作成

MapTestのKeyだけの配列を作成します。

Array.from(MapTest.keys());

Valueだけの配列を作成

MapTestのValueだけの配列を作成します。

Array.from(MapTest.values());

【JavaScript】配列の使い方

配列の使い方を自分用にメモすることにしました。

[ 使い方 ]

宣言

配列としてArrayTestを宣言します。

let ArrayTest = [];
let ArrayTest = new Array();

初期化

ArrayListを初期化します。

let ArrayTest = ["abc", "def", "ghi"];
let Array = new Array("abc", "def", "ghi");

要素の追加

ArrayTestに"abc"という要素を追加します。

ArrayTest.push("abc");

要素の挿入

ArrayTestの2番目に"abc"という要素を追加します。

ArrayTest.splice(2, 0, "abc");

要素の消去

ArrayTestの0番目の要素を消去します。

ArrayTest.splice(0, 1);

全要素の消去

ArrayTestの全要素を消去します。

ArrayTest.splice();

要素の取得

ArrayTestの0番目の要素を取得します。

ArrayTest[0];

要素の置換

ArrayTestの0番目の要素を"def"に置換します。

ArrayTest[0] = "def";

長さを取得

ArrayTestの長さを取得します。

AryListTest.length;

特定の要素を含むか

ArrayTestが"abc"という要素を含むかを求めます。

AryListTest.includes("abc");

【Processing】配列ソート時に他の配列の要素の順番も連動させる方法

配列ソート時に他の配列の要素の順番も連動させる方法を自分用にメモ。

[ 方法 ]

ArrayAをソートした時にArrayBの要素の順番も連動するようにします。

import java.util.Arrays;

void setup()
{
    final int[] ArrayA = new int[]
    {
        2, 1, 3
    };
    final int[] ArrayB = new int[]
    {
        5, 6, 4
    };

    println("[ ソート前 ]");
    for (int i = 0; i < ArrayA.length; i++) 
    {
        println("ArrayA[" + i + "]: " + ArrayA[i]);
    }
    for (int i = 0; i < ArrayB.length; i++) 
    {
        println("ArrayB[" + i + "]: " + ArrayB[i]);
    }
    println();

    final int[] SortedArrayA = Arrays.copyOf(ArrayA, ArrayA.length);
    final int[] SortedArrayB = new int[ArrayB.length];

    Arrays.sort(SortedArrayA);//SortedArrayAを小さい順にソート

    for (int i = 0; i < SortedArrayA.length; i++) //SortedArrayAに基づいてSortedArrayBをソート
    {
        for (int j = 0; j < ArrayA.length; j++) 
        {
            if (SortedArrayA[i] == ArrayA[j]) 
            {
                SortedArrayB[i] = ArrayB[j];

                break;
            }
        }
    }

    println("[ ソート後 ]");
    for (int i = 0; i < ArrayA.length; i++) 
    {
        println("ArrayA[" + i + "]: " + ArrayA[i]);
    }
    for (int i = 0; i < ArrayB.length; i++) 
    {
        println("ArrayB[" + i + "]: " + ArrayB[i]);
    }
    println();
}
[ ソート前 ]
ArrayA[0]: 2
ArrayA[1]: 1
ArrayA[2]: 3
ArrayB[0]: 5
ArrayB[1]: 6
ArrayB[2]: 4

[ ソート後 ]
ArrayA[0]: 2
ArrayA[1]: 1
ArrayA[2]: 3
ArrayB[0]: 5
ArrayB[1]: 6
ArrayB[2]: 4