# HTMLで動くかんたん2Dゲーム講座
これはWebGLを扱うライブラリPIXI.JSを使った講座の資料です.
必要な知識...JavaScriptの文法 参考: https://hackmd.io/@wbelucky/rJHtfAW68
## まず環境構築ゼロでハローワールド
まずは以下のようなHTMLの雛形を用意します.
テキストを編集できるものなら何でもいいですが, VSCodeがあると便利です!
```html
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pixi テスト</title>
</head>
<body>
</body>
```
bodyの中に今回扱うライブラリである, PIXI.JSのCDNのリンクを貼ります. これで PIXIオブジェクトが使えるようになります.
```html
...
...
</head>
<body>
<!-- from https://github.com/pixijs/pixi.js#cdn-install-via-cdnjs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.3/pixi.min.js"></script>
<script type="text/javascript">
// 今回はここにJavaScriptを書いていきます
</script>
</body>
```
scriptタグの中にJavaScriptを書いていきます.
まず, PIXIのアプリケーションを作るのに必要な機能がまとまったオブジェクトである, appを作成します.
HTMLElementであるapp.viewをhtmlに追加します.
```javascript
const gameWidth = 800;
const gameHeight = 600;
const app = new PIXI.Application({ width: gameWidth, height: gameHeight });
document.body.appendChild(app.view);
```
ここで800px×600pxの黒い画面が出ればOk
ここに試しに正方形を描画していきます.
```javascript
const gameWidth = 800;
const gameHeight = 600;
const app = new PIXI.Application({ width: gameWidth, height: gameHeight });
document.body.appendChild(app.view);
const square = new PIXI.Graphics()
.beginFill(0xFF3gameHeight / 2)
.drawRect(0, 0, 100, 100);
app.stage.addChild(square);
```
これによって, 左上の点が(0, 0)で, 幅(width)が100px, 高さ(height)が100pxの正方形が描画できました. (PIXI.JSでは右に向かってx軸, 左に向かってy軸)
HTML要素として描画されているappのstageにaddChildによって付け加えられた子孫要素が描画されます.
最後の`app.stage.addChild(square)`を忘れずに.
### 移動, 回転
正方形を移動させてみましょう.
square.x, square.yを変更させることで移動させることができます.
今回は(gameWidth / 2, gameHeight / 2)画面中央に移動させます.
```javascript
...
...
const square = new PIXI.Graphics()
.beginFill(0xFF3gameHeight / 2)
.drawRect(0, 0, 100, 100);
square.x = gameWidth / 2;
square.y = gameHeight / 2;
app.stage.addChild(square);
```
この正方形を回転させてみます.
app.ticker.addに関数を渡すことで, 毎フレーム実行される処理を書くことができます.
```javascript
..const app = new PIXI.Application({ width: gameWidth, height: gameHeight });
...document.body.appendChild(app.view);
const square = new PIXI.Graphics()
.beginFill(0xFF3gameHeight / 2)
.drawRect(0, 0, 100, 100);
square.x = gameWidth / 2;
square.y = gameHeight / 2;
app.stage.addChild(square);
// 追加
app.ticker.add(() => {
square.rotation += 0.01;
})
```
すると, 正方形の左上を中心に回転しています
![](https://i.imgur.com/qKCH3k1.png)
正方形の中心を回転軸にしたいときは, 基準点を変える必要があります.
基準点は今回のPIXI.GraphicsなどのPIXI.Containerを継承するものはpivot, PIXI.Spriteならanchorという変数を調整することで変更できます.
```javascript
...
document.body.appendChild(app.view);
const square = new PIXI.Graphics()
.beginFill(0xFF3gameHeight / 2)
.drawRect(0, 0, 100, 100);
square.x = gameWidth / 2;
square.y = gameHeight / 2;
// 追加
square.pivot.x = 50;
square.pivot.y = 50;
app.stage.addChild(square);
...
```
これによって, 正方形の中心部分が基準点となり, その点がsquareのpositionである(gameWidth / 2, gameHeight / 2)に来るようになりました.
### インタラクティブの導入
ユーザーからの入力を受け取れるようにします.
まずクリックです.
PIXI.GraphicsなどのPIXI.Containerは, interactiveプロパティとhitAreaプロパティを設定することによって, クリックやタッチしたときの処理をonメソッドによって記述することができます.
クリックしたら画面内のどこかに飛ぶようにしてみます.
```javascript
...
square.pivot.x = 50;
square.pivot.y = 50;
// 追加
square.interactive = true;
square.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
square.buttonMode = true;
square.on('pointerdown', () => {
square.x = Math.random() * gameWidth;
square.y = Math.random() * gameHeight;
});
app.stage.addChild(square);
...
```
クリックが離れたとき... やモバイル端末のタップがされたとき... などのイベントを取ることができます.
pointerdown系統はクリックもタップも扱えるので使っておいて損はないはずです.
https://pixijs.download/dev/docs/PIXI.InteractionManager.html#event:click
クリックの他にも, キーボード入力を取りたいときはWebAPIのキーイベントを使うことができます https://developer.mozilla.org/ja/docs/Web/API/Document/keydown_event
### ゲームっぽくする
20秒間でどれだけ赤いやつをクリックできたかゲームを作ってみましょう.
まずスコアを表示しておくテキストをつくります.
PIXI.JSは様々なフィルターやフォントが使えます.
https://pixijs.io/examples/ を参考に何が使えそうか見てみるといいです.
ここでは https://pixijs.io/examples/#/text/text.js に落ちてたフォントのテキストを作ります.
```javascript
...
document.body.appendChild(app.view);
// 追加
const style = new PIXI.TextStyle({
fontFamily: 'Arial',
fontSize: 36,
fontStyle: 'italic',
fontWeight: 'bold',
fill: ['#ffffff', '#00ff99'], // gradient
stroke: '#4a1850',
strokeThickness: 5,
dropShadow: true,
dropShadowColor: '#000000',
dropShadowBlur: 4,
dropShadowAngle: Math.PI / 6,
dropShadowDistance: 6,
wordWrap: true,
wordWrapWidth: 440,
});
const scoreText = new PIXI.Text('SCORE: 0', style);
// Spriteの基準点を設定
scoreText.anchor.set(0.5, 0.5);
scoreText.x = gameWidth / 2;
scoreText.y = gameHeight / 4;
app.stage.addChild(scoreText);
// 追加ここまで
const square = new PIXI.Graphics()
.beginFill(0xFF3gameHeight / 2)
.drawRect(0, 0, 100, 100);
...
```
スコアのテキストの更新が必要です.
ここで新たな変数 scoreを導入して, クリックされたときにテキストを更新するようにしましょう.
```javascript
square.interactive = true;
square.hitArea = new PIXI.Rectangle(0, 0, 100, 100);
square.buttonMode = true;
let score = 0; // 追加
square.on('pointerdown', () => {
square.x = Math.random() * gameWidth;
square.y = Math.random() * gameHeight;
score++; // 追加
scoreText.text = `SCORE: ${score}`;
});
app.stage.addChild(square);
```
ここでapp.stage.addChild(scoreText)ではなく, square.addChild(square)とするとどうなるでしょう? スコア自体もぐるぐる回転することになります.
app.stageやgraphicsなどは PIXI.Containerを継承しています. PIXI.ContainerはaddChildメソッドにより子要素を持つことができ, 子要素は親要素の基準点の位置や回転角をもとに相対的に描画されます.
こんな感じで実装していきましょう!
完成版: https://gist.github.com/WBelucky/8c1a3d433b6ad2d38030a469a0d3ad6c/pixi-example.html
## 画像を扱う
画像は事前に読み込むための `app.loader`を使います. その後, PIXI.Spriteを生成して操作します.
```html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<!-- from https://github.com/pixijs/pixi.js#cdn-install-via-cdnjs -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/5.1.3/pixi.min.js"></script>
<script type="text/javascript">
const app = new PIXI.Application();
document.body.appendChild(app.view);
// ローカルの画像(chromeのfile:// )だとクロスオリジン間リソース共有ができないので, HTTPサーバーを建てるか, http/httpsのプロトコルで持ってくるといい.
app.loader.add('giogio', 'https://f.easyuploader.app/eu-prd/upload/20200826101212_63756f33683568306a77.jpg').load((loader, resources) => {
const giogio = new PIXI.Sprite(resources.giogio.texture);
giogio.x = app.renderer.width / 2;
giogio.y = app.renderer.height / 2;
giogio.anchor.x = 0.5;
giogio.anchor.y = 0.5;
app.stage.addChild(giogio);
app.ticker.add(() => {
giogio.rotation += 0.01;
});
});
</script>
</body>
</html>
```
## さらなる開発
まず VSCodeとnodejsを入れよう!
npmからpixi.jsを落としてきて, 開発!
parcelというバンドラーがかんたん!
TypeScript開発でバリバリ補完!
pixi.jsのexample https://pixijs.io/examples/
pixi.jsのdocs https://pixijs.download/dev/docs/index.html
pixi.jsと一緒に使える素晴らしいツールたち
https://github.com/cursedcoder/awesome-pixijs
* 例えば物理演算をしてくれるp2.jsだったり, live2dモデルやSpineモデルを動かせるものだったり...