PG0でゲームプログラミング

# はじめに
[PG0](https://pg0.jp/)は、プログラミング学習を目的としたプログラミング言語です。
PG0の詳細は『[初心者用プログラミング言語「PG0」のススメ](https://qiita.com/nakka_/items/adfe04d701640a72015d)』を参照してください。

PG0はシンプルなプログラミング言語です。ゲームプログラミングで利用するのはPG0を拡張したPG0.5になります。

https://qiita.com/nakka_/items/138f64bf4f5d6782e601

# 特徴
PG0は手続き型のプログラミング言語で、シングルスレッドで動作します。
ゲームプログラミングにおいても同様にシングルスレッドで動作し、イベント処理はありません。キー入力やタッチ入力はイベント処理ではなく入力状態を確認するAPIを利用します。
昔のBASICでゲームを作成していた感覚に近いかもしれません。

# 基本サンプル
## 描画の開始
PG0でゲームプログラミングをするにはPG0のWeb版で画面描画API(screen.pg0)をインポートします。
他に乱数を使う場合は数値処理API(math.pg0)をインポートします。
画面描画API、数値処理APIのリファレンスは以下になります。

https://pg0.jp/doc/pg0.5_lib.html

以下のインポート文により利用することができます。
```php:PG0
#import("lib/screen.pg0")
#import("lib/math.pg0")
```

描画を開始するにはstartScreen()を使います。

```php:PG0
#import("lib/screen.pg0")
#import("lib/math.pg0")

startScreen(1920, 1080, {"color": "#fff"})
```

## 線の描画
線を描画するにはdrawLine()を使います。

```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

drawLine(100, 100, 500, 500, {"color": "#000", "width": 8})
sleep(3000)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199093/b039fd27-d650-86d5-c249-4399f12ff714.png)

## 四角の描画
四角を描画するにはdrawRect()を使います。

```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

drawRect(500, 300, 400, 300, {"color": "#00f", "fill": 1})
sleep(3000)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199093/b7f10764-9652-7d1c-48a5-14076de14022.png)

## 円の描画
円を描画するにはdrawCircle()を使います。

```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

drawCircle(500, 500, 400, {"color": "#00f", "fill": 1})
sleep(3000)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199093/cbaa6e71-bc02-2320-097b-6e2e4d6ff699.png)

## テキストの描画
テキストを描画するにはdrawText()を使います。

```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

drawText("Hello, world!", 640, 450, {"color": "#000", "fontstyle": "bold", "fontsize": 100})
sleep(3000)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199093/a212e3d4-0c3d-b144-6b4a-1f4f0f32eee1.png)

## 色の判定
指定座標の色を判定するにはrgbToPoint()を使います。
rgbToPoint()で取得した色データをrgbToHex()に渡すとカラーコードを取得できます。

```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

drawCircle(500, 500, 400, {"color": "#00f", "fill": 1})
var pt = rgbToPoint(500, 500)
drawText(pt, 0, 0, {"color": "#000", "fontsize": 50})
drawText(rgbToHex(pt), 0, 70, {"color": "#000", "fontsize": 50})
sleep(3000)
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199093/3e4ef351-9d7a-9492-d52d-98b41f110a3b.png)

## タッチ判定 (マウスクリック判定)
タッチされているかを判定するにはinTouch()を使います。
inTouch()の戻り値は連想配列で"touch"キーが1の場合はタッチされていることを示します。
"x"キーと"y"キーにはタッチ座標が入ります。

以下はタッチされた位置を丸で追いかけるサンプルです。
```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

while (1) {
	var t = inTouch()
	if (t["touch"]) {
		drawRect(0, 0, 1920, 1080, {"color": "#fff", "fill": 1})
		drawCircle(t["x"], t["y"], 100, {"color": "#000", "fill": 1})
	}
}
```

実際に動作するサンプルはこちら。
https://pg0.jp/dev/?cid=6a05e274-a1c3-4c52-9b18-fea72b9037d1

## キー入力
入力されているキーを取得するにはinKey()を使います。
引数を指定するとキーの状態を返し、引数を指定しない場合は押されているキーを返します。

以下は入力されたキーを画面表示するサンプルです。
```php:PG0
#import("lib/screen.pg0")

startScreen(1920, 1080, {"color": "#fff"})

while (1) {
	drawRect(0, 0, 1920, 1080, {"color": "#fff", "fill": 1})
	var k = inKey()
	if (length(k) > 0) {
		drawText(k, 100, 500, {"color": "#000", "fontsize": 50})
	}
	sleep(0)
}
```

実際に動作するサンプルはこちら。
https://pg0.jp/dev/?cid=871b5f39-ef8a-4e47-82c4-60967e4f8453

## 乱数(ランダム)の生成
乱数を生成するにはrandom()を使います。

以下は1から10までの乱数を30個生成するサンプルです。
```php:PG0
#import("lib/math.pg0")

for (var i = 0; i < 30; i++) {
	print(int(random() * 10 + 1) + "\n")
}
```

実際に動作するサンプルはこちら。
https://pg0.jp/dev/?cid=7ee529f5-98df-4014-acc3-e29dcca94bd7

# ゲームサンプル
上記の基本サンプルを組み合わせて作ったゲームとなります。
ランダムに円を描画し、自分は線で円に当たらないように右端に移動します。
自分は常に下がり続けますが、画面をタッチするかスペースキーを押している間は上がり続けます。

```php:PG0
#import("lib/screen.pg0")
#import("lib/math.pg0")

// 初期化
var width = 1920, height = 1080
startScreen(width, height)

// 画面のクリア
drawRect(0, 0, width, height, {"color": "#ffffff", "fill": 1})
// 障害物(青い丸)を配置
for (var i = 0; i < 4; i++) {
	drawCircle(
		int(random() * (width - 500)) + 500,
		int(random() * height),
		int(random() * 100) + 100,
		{"color": "#0000ff", "fill": 1})
}

// ゲームループ	
var x = 0, y = height / 2
while (1) {
	// 前回座標の保存
	var px = x, py = y
	// 新しい座標
	x = x + 3
	if (inTouch()["touch"] || inKey(" ")) {
		// タッチしている時は上昇
		y = y - 3
	} else {
		// 下降
		y = y + 3
	}
	// 移動先の色を取得
	var color = rgbToHex(rgbToPoint(x, y))
	// 自分を描画
	drawLine(px, py, x, y, {"color": "#000000", "width": 8})
	if (x > width) {
		// 右端に到達するとクリア
		drawText("ゲームクリア", 400, 400, {"fontsize": 200})
		break
	}
	if (y < 0 || y > height || color == "#0000ff") {
		// 上下の壁か障害物(青い丸)に当たるとゲームオーバー
		drawText("ゲームオーバー", 330, 400, {"fontsize": 200})
		break
	}
	sleep(1) // 少し待機
}
sleep(3000) // 3秒待って終了
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/199093/1ea00a9e-d03f-81da-3006-b95ca6d6b2c7.png)


実際に動作するサンプルはこちら。
https://pg0.jp/dev/?cid=7983e236-21b7-4c56-a533-1be229855c3f

# その他のゲームサンプル

シューティングゲーム
https://pg0.jp/dev/?cid=ee90d3f7-d603-48d0-be2b-c433f3ffbfe0

えだまめジャンプゲーム
https://pg0.jp/dev/?cid=fa0cdb93-dff4-4b63-aa3e-f0beefa2c90d

えだまめボールゲーム
https://pg0.jp/dev/?cid=37c2e44c-8e4a-4c5b-83dd-9e7f71a94884

えだまめ脱出ゲーム
https://pg0.jp/dev/?cid=dabacb04-8258-43d2-8a14-ec94cbd7bddd

糸通しゲーム
https://pg0.jp/dev/?cid=e623ea4e-e73d-46a3-a82f-c09a08da088e

テニスゲーム
https://pg0.jp/dev/?cid=6efa828f-ef80-440d-9acf-e41f066401a1

テトリス
https://pg0.jp/dev/?cid=f04397f0-b631-4354-b15f-e4e0c5d8fab1

〇×ゲーム
https://pg0.jp/dev/?cid=c6fdfb6f-79f2-431e-85da-56f9669059bc

〇×ゲーム (消滅あり)
https://pg0.jp/dev/?cid=76366385-5629-4967-b856-e42f1c77f292

〇×ゲーム (消滅あり、COM対戦)
https://pg0.jp/dev/?cid=54d77784-259e-4fb7-bc61-9a4acddfead6