TypeScript基礎



# TypeScriptでゲームを作りたい
あほげーに投稿してあほになりたい
ということで調べてたらたまたま作っちゃうおじさんの初心者向けページを見つけたので一気にモチベ↑
https://hothukurou.com/blog/post-2122

あと、もしかするとポートフォリオになるかも(ならないかも)

## 前提条件
作っちゃうおじさんの通りにやったので環境は同じ(ライブラリはpixi.js)
一回最低限のソースだけで作って確認したかったので作っちゃうおじさん製フレームワークのようなものは使わない。
## 使ったもの
###### TypeScript
jsは動的型付けなので嫌い、静的型付けなら好き
TypeScriptは静的型付けなので好き
###### VSCode
2021年1月現在、開発環境はやっぱりこれ一強
###### Webpack
複数のjs,tsファイルをひとまとめにしてくれる
###### pixi.js
簡単で軽いゲームの制作に向いてるらしい

# 作ったもの
https://github.com/Wa-taro/CollideBall
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676040/8ff450f1-dbef-1b58-12ae-3eac0731523f.png)
###動き
ボールが画面の縁に当たったら跳ね返る

# ホットコンパイルについて
下記3つを用意

```terminal:ターミナル1
tsc -w
```
```terminal:ターミナル2
npx webpack-cli -w
```
拡張機能のLiveServerを起動
# コードの説明
### フォルダ構成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/676040/fd222735-b921-4af3-9a39-bc34a7c4f279.png)
#### index.html
ブラウザが最初に認識する例のあれ
#### script.ts
index.htmlが最初に読み込むファイル
#### ball.ts
ballの速度等が含まれた型定義
#### node_modules
ライブラリや標準クラス等
#### dist
ホットコンパイル結果
## index.html
```html:index.html
<html lang="ja">

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1.0" />
    <title>ボールがぶつかるのを見るだけ</title>
</head>

<body>
    <script src="./dist/main.js"></script>
</body>

</html>
```
Webpackが`ts`を`main.js`に変換してるのでscriptタグでは`./dist/main.js`を参照している
他は(多分)一般的なhtml

## script.tsについて
### 全体
```typescript:script.ts
import * as PIXI from "pixi.js";
import { Ball } from "./ball";

let gameWidth = 600;
let gameHeight = 800;

//サイズを指定してPIXI.Appricationを呼ぶ
const app = new PIXI.Application({ width: gameWidth, height: gameHeight });
// index.htmlのbody部にappを追加(append)する (app.viewはcanvasのdom要素)
document.body.appendChild(app.view);
// canvasの周りを点線枠で囲う (canvasの位置がわかりやすいので入れている)
app.renderer.view.style.border = "2px dashed black";
// canvasの背景色
app.renderer.backgroundColor = 0xa0a0a0;

// 画像"GrayBall.jpg"の読み込み
PIXI.Loader.shared.add("resources/GrayBall.png");

PIXI.Loader.shared.load((loader, resources) => {
    const ball: Ball = new Ball();
    ball.sprite = new PIXI.Sprite(resources["resources/GrayBall.png"].texture);
    ball.xSpeed = 1;
    ball.ySpeed = 1;
    ball.heightSize = 100;
    ball.widthSize = 100;

    // ゲーム用のシーンを生成
    const gameScene = new PIXI.Container();
    // ゲームシーンを画面に追加
    app.stage.addChild(gameScene);

    gameScene.addChild(ball.sprite); // ボールをシーンに追加



    function gameLoop() //フレーム毎処理
    {
        ball.sprite.x += ball.xSpeed;
        ball.sprite.y += ball.ySpeed;

        //画面縁当たり判定
        if (ball.sprite.y + ball.heightSize >= gameHeight
            || ball.sprite.y <= 0) {
            ball.ySpeed = -ball.ySpeed
        }
        if (ball.sprite.x + ball.widthSize >= gameWidth
            || ball.sprite.x <= 0) {
            ball.xSpeed = -ball.xSpeed
        }
    }

    app.ticker.add(gameLoop);
});
```
### 詳細
```typescript:冒頭
import * as PIXI from "pixi.js";
import { Ball } from "./ball";

let gameWidth = 600;
let gameHeight = 800;

//サイズを指定してPIXI.Appricationを呼ぶ
const app = new PIXI.Application({ width: gameWidth, height: gameHeight });
// index.htmlのbody部にappを追加(append)する (app.viewはcanvasのdom要素)
document.body.appendChild(app.view);
// canvasの周りを点線枠で囲う (canvasの位置がわかりやすいので入れている)
app.renderer.view.style.border = "2px dashed black";
// canvasの背景色
app.renderer.backgroundColor = 0xa0a0a0;

// 画像"GrayBall.jpg"の読み込み
PIXI.Loader.shared.add("resources/GrayBall.png");
```
書いてあるままではあるが、説明
PIXIをImport
別ファイルball.tsをImport
ゲームの幅、高さを宣言
PIXI.spplicationを使ってapplicationを生成
生成したapplicationをhtmlのbody部へ入れる
ゲーム箇所周りに点線をつける
背景を明るめのグレーにする
ballのimageを渡しておく

```typescript:処理の始め
PIXI.Loader.shared.load((loader, resources) => {
    const ball: Ball = new Ball();
    ball.sprite = new PIXI.Sprite(resources["resources/GrayBall.png"].texture);
    ball.xSpeed = 1;
    ball.ySpeed = 1;
    ball.heightSize = 100;
    ball.widthSize = 100;

    // ゲーム用のシーンを生成
    const gameScene = new PIXI.Container();
    // ゲームシーンを画面に追加
    app.stage.addChild(gameScene);

    gameScene.addChild(ball.sprite); // ボールをシーンに追加
```
`PIXI.Loader.shared.load((loader, resources) =>`がPIXIで処理をするための決り文句
load後に行われる処理を記述する
ballを宣言、各プロパティ？に値を代入する
spriteに画像情報を渡す
x,y のスピードに1をセット
ballの高さ、幅に100をセット
シーン(objectのcollection)を作成
さっき作成した`const app = new PIXI.Application({ width: gameWidth, height: gameHeight });`に対してシーンをセット
シーンに対してball情報をセット

```typescript:アルゴリズム箇所
    function gameLoop() //フレーム毎処理
    {
        ball.sprite.x += ball.xSpeed;
        ball.sprite.y += ball.ySpeed;

        //画面縁当たり判定
        if (ball.sprite.y + ball.heightSize >= gameHeight
            || ball.sprite.y <= 0) {
            ball.ySpeed = -ball.ySpeed
        }
        if (ball.sprite.x + ball.widthSize >= gameWidth
            || ball.sprite.x <= 0) {
            ball.xSpeed = -ball.xSpeed
        }
    }
```
PIXI側で用意されているyに対して作成したball.ySpeedを足す
xも同様

##### 画面縁当たり判定
`ball.sprite.y + ball.heightSize >= gameHeight`画面下側にhitしたかチェック
`ball.sprite.y <= 0`画面上部にhitしたかチェック
上記どちらかがtureならばyのエネルギーの向きを180度逆にする
※xも同様

```typescript:最終箇所
    app.ticker.add(gameLoop);
```
PIXIのticker(フレーム毎に繰り返す処理)に`function gameLoop()`を追加する
## ball.tsについて
### 全体
```typescript:ball.ts
export class Ball {
    sprite: PIXI.Sprite;
    xSpeed: number;
    ySpeed: number;
    heightSize: number;
    widthSize: number;
}
```
説明いるか？
一応....
`sprite` PIXI.SpriteというPIXIの画像オブジェクト標準クラス
`xSpeed` xに毎フレーム足していく想定で作った
`yxSpeed` 上と同じ
`heightSize` 画面下側の当たり判定をする際に位置情報に足す必要があるので
`widthSize` 画面右側の当たり判定をする際に位置情報に足す必要があるので