プロック崩しのサンプルを作ったので、簡単に説明をします。
目次
プロック崩しサンプル
プロジェクトのダウンロード
プロジェクトファイルは GitHubにアップロードしているので、こちらからダウンロードできます。
Mainシーン
Mainシーンでゲーム全体の管理をしています。
ノードの構成は以下のとおりです。
- WallLayer: 外壁レイヤー。パドルやボールはここから出られない
- BlockLayer: 壊せるブロックを管理するレイヤー
- MainLayer: ボールとパドルがあるレイヤー
- UILayer: UIを配置するレイヤー
Mainシーンは以下の4つの状態を持っています。
## 状態.
enum eState {
READY, # 開始.
MAIN, # メイン.
GAMEOVER, # ゲームオーバー.
GAMECLEAR, # ゲームクリア.
}
まずゲーム開始直後に表示される “READY” を1秒間表示した後、MAIN状態でゲームプレイを行います。もしボールが画面下に落下したら、残りボールを減らして次のボールを出現させます。残りのボールがなくなったら GAMEOVER 状態となります。
ブロックがすべてなくなれば GAMECLEAR状態となります。
ボールの落下判定はボールが一定の高さを超えたときとしました。
const DEADLINE_Y = 800 # 死亡判定.
## 更新 > メイン.
func _update_main(delta:float) -> void:
...
if _ball.position.y > DEADLINE_Y:
# 死亡.
damage()
ゲームクリア判定(ブロックがすべてなくなったかどうか)は、ブロックレイヤー(BlockLayer)から子ノードがすべてなくなったかどうかで行っています。
## 更新 > メイン.
func _update_main(delta:float) -> void:
if _block_layer.get_child_count() == 0:
# ブロックがすべてなくなればクリア.
_state = eState.GAMECLEAR
return
...
オブジェクトの種類ごとに CanvasLayer をわけておくと、こういった判定がやりやすくておすすめです。
Maker2D というノードは、位置情報を明示的に定義するのに便利です。
今回はボールの出現位置を定義するのに使用しました。
ブロック(Block)オブジェクト
ブロックは Block.tscn / .gd で実装しています。
Blockオブジェクト自体は大したことはしていませんが、色情報をエディタ上で反映させたいため、”@tool” キーワードを使用しています。
@tool # エディタでも _processを呼び出したい.
extends StaticBody2D
...
## 更新.
func _process(delta: float) -> void:
# 色を設定.
_spr.modulate = COLOR_TBL[color]
“@tool” キーワードを指定すると、エディタ上でも “_process()” が実行されるようになります。
これによりインスペクタから直接色を変更できるようになります。
ボール(Ball)オブジェクト
ボールは Ball.tscn / .gd で実装しています。
跳ね返り処理は move_and_collide() の戻り値の KinematicCollision2D が有効かどうかで判定できます。
## 更新.
func _update(delta: float) -> void:
# 回転.
_spr.rotation += _rot_speed * delta
_spr.rotation *= 0.995 # 減衰する.
# 衝突処理.
var col = move_and_collide(_velocity * delta)
_collide(col)
衝突処理の _collide()。
## 衝突処理.
func _collide(col:KinematicCollision2D) -> void:
if col == null:
return # 衝突していない.
# 衝突した.
var collider = col.get_collider()
if collider is Block:
# ブロックならダメージを与える.
collider.damage(1)
# 法線を取得する.
var n = col.get_normal()
# 回転.
var delta_angle = n.angle_to(_velocity)
_rot_speed += delta_angle * 3
# 跳ね返り処理.
if collider is Paddle:
# パドルの場合は法線を無視して跳ね返り方向が変わる.
var dx = position.x - collider.position.x
var rate = abs(dx / 64.0)
if rate > 1.0:
rate = 1.0 # 1.0を超えない想定.
_velocity.x = 0.9 * _speed * rate * sign(dx)
# 常に上方向に跳ね返る.
_velocity.y = (0.9 * rate - 1) * _speed
else:
_velocity = _velocity.bounce(n)
# 加速する.
_speed += SPEED_UP
if _speed > MAX_SPEED:
_speed = MAX_SPEED # 最高速度は超えない.
_velocity = _velocity.normalized() * _speed
最初の注意点として、衝突するオブジェクトは Paddle(パドル)と Block(ブロック) の2種類があります。
それぞれ異なる処理が必要となります。
- Blockとの衝突: 消滅処理 (damage) の呼び出しをする。衝突の法線に沿って跳ね返る
- Paddleとの衝突: 跳ね返り方向を特殊な方法で行う
BallとBlockが衝突した際には Block が消えてほしいので、Block の damage() を呼び出して消滅処理を行います。
また Paddle と衝突したときには、物理法則とは異なる特殊な跳ね返りを行います。具体的には中心から放射上の方向に跳ね返るようにします。
物理法則とあっていませんが、このようにパドルのどこにぶつけるかで移動方向を調整できると、ゲームプレイの自由度が上がっておすすめです。