Godot4.1.3でシューティングゲームを作っていきます。
スピードアップ!
アップグレードアイテムが、スピードアップの時にゲットした場合、プレイヤー機の速度がアップするように実装します。
github
本記事で実装したものをgithubで公開しています。
Playerシーンにアップグレードアイテム検知用のArea3Dを追加
Playerシーンが、アップグレードアイテムの衝突を検知できるようにします。
敵との当たり判定用のCollisionShape3Dは小さくて、アイテムを取り逃してしまう可能性があるため、アップグレードアイテム専用のArea3Dを追加します。
player.tscnを開き、Area3Dの「item_sensor」を追加し、子ノードにCollisionShape3Dを追加します。
res://character/player/player.tscn
CollisionShape3DのShapeプロパティは新規SphereShape3Dを設定し、半径を3mにしました。
playerシーンとアップグレードアイテムのCollision設定をして衝突を検知する
playerシーンに追加したArea3Dのitem_sensorが、upgrade_itemシーンの衝突を検知できるように、Collisionセクションを設定します。
アップグレードアイテム用のLayer名を追加
プロジェクト設定のLayer Names/3D物理を開き、Layer6に「UpgradeItem」を追加します。
upgrade_itemシーンのCollision設定
res://character/item/upgrade_item.tscnを開き、ルートノードを選択して、インスペクターのcollisionセクションのLayerプロパティの6番をチェックします。
アップグレードアイテム自体は、衝突を検知しないので、Maskプロパティはチェック不要です。
res://character/item/upgrade_item.tscn
playerシーンのCollision設定
追加したArea3Dのitem_sensorで、アップグレードアイテムを検知したいので、item_sensorを選択した状態で、Collisionセクションを設定します。
アップグレードアイテムを検知したいので、Maskの6番のみチェックします。検知されることは想定していないので、Layerはチェック無しです。
res://character/player/player.tscn
スピードアップアイテム取得すると、Player機を速くする
以下の式を使います。
Player機の速度 = 基準速度[m/s] × 倍率
基準速度は25m/s、倍率の初期値は1.0にして、スピードアップアイテムを取るたびに、倍率を0.4ずつ上げます。最大3.0倍にします。
初期値 25m/s × 1.0 = 25m/s
1段階目 25m/s × 1.4 = 35m/s
2段階目 25m/s × 1.8 = 45m/s
3段階目 25m/s × 2.2 = 55m/s
4段階目 25m/s × 2.6 = 65m/s
5段階目 25m/s × 3.0 = 75m/s
player.gdを修正します。
まず、Area3Dの「item_sensor」を選択した状態で、インスペクターの横のノード/シグナルの「area_entered(area : Area3D)」をダブルクリックして、player.gdに接続します。
下記のように修正します。
res://character/player/player.gd
extends Area3D
# Player
-@export var _d_speed_mps = 100.0
+@export var _d_speed_mps = 25.0
@export var _d_hp = 1.0
# ドラッグ操作検知用
var _f_is_screen_touch = false # 画面にタッチ(ドラッグ含む)している場合true、タッチしていない場合はfalse
var _v2_drag_pos = Vector2.ZERO # 最新のタッチ位置・ドラッグ位置
# タッチしたときの、3D上のタッチ位置とPlayer位置
var _v_first_touch_pos = null
var _v_first_touch_player_pos = Vector3.ZERO
# 画面をタッチした位置から、検索する3Dオブジェクトまでの最大距離
@export var _d_ray_length_m = 1000 # [m]十分な長さにする
# レーザーの発射タイミング
@export var _scn_laser : PackedScene
@export var _d_firing_interval_sec = 0.2
var _d_firing_remain_time_sec = 0
+# アップグレードアイテムで性能
+const _d_speed_magnification_max : float = 3.0
+const _d_speed_magnification_min : float = 1.0
+var _d_speed_magnification = _d_speed_magnification_min
func _input(event):
# 画面にタッチしている状態と、タッチしていない状態を判断する
if event is InputEventScreenTouch:
_f_is_screen_touch = event.is_pressed()
# ドラッグ位置(タッチ位置)を更新する
_v2_drag_pos = event.position
elif event is InputEventScreenDrag:
# ドラッグしているということは、タッチしている。(参考:InputEventScreenDragの場合、event.is_pressed()は常にfalse)
_f_is_screen_touch = true
# ドラッグ位置(タッチ位置)を更新する
_v2_drag_pos = event.position
else:
pass
func _physics_process(delta):
if _f_is_screen_touch:
var camera = get_viewport().get_camera_3d()
# カメラを利用して3D空間のカメラの3D位置と、カメラからタッチしたピクセルを見た方向の1000m先の3D位置を計算する
var from3d = camera.project_ray_origin(_v2_drag_pos)
var to3d = from3d + camera.project_ray_normal(_v2_drag_pos) * _d_ray_length_m
# 3D ray physics queryの作成
var query = PhysicsRayQueryParameters3D.create(from3d, to3d)
query.collide_with_areas = true # Area3Dを検知できるようにする
# spaceと呼ばれる、物理3D空間状態の情報を利用して、Area3Dを含む衝突位置を計算する
var space_state = get_world_3d().direct_space_state
var result = space_state.intersect_ray(query)
if result:
# 衝突位置を取得
var v_drag_pos = result.position
v_drag_pos.y = global_position.y # Y方向には移動しないための設定
if _v_first_touch_pos == null :
# 初めてタッチしたときの、3D位置を記憶する
_v_first_touch_pos = v_drag_pos
# 初めてタッチしたときの、プレイヤーの3D位置を記憶する
_v_first_touch_player_pos = global_position
else:
pass
# 3D空間の移動目標位置
var v_target_pos = _v_first_touch_player_pos + ( v_drag_pos - _v_first_touch_pos )
# Player位置から移動目標位置までの相対位置を計算
var v_target : Vector3 = v_target_pos - global_position
# 移動目標位置に向かう速度ベクトルを生成
- var v_velocity : Vector3 = v_target.normalized() * _d_speed_mps
+ var v_velocity : Vector3 = v_target.normalized() * _d_speed_mps * _d_speed_magnification
if v_target.length() < ( v_velocity * delta ).length():
# 目的地までの距離が、delta当たりの移動量よりも小さい場合は、飛び越えてしまうため、Playerの位置を目標位置にする
global_position = v_target_pos
else:
# CharacterBody3Dのvelocityに速度を設定して動かす
position += v_velocity * delta
else:
# タッチ位置に衝突したものが無い
pass
else:
# タッチしていない場合はnullを設定することで、次にタッチしたときに、新しいタッチ位置とPlayer位置を記憶する
_v_first_touch_pos = null
if _f_is_screen_touch:
# タイミングをとりながらlaser発射
if _d_firing_remain_time_sec > 0:
# 次の発射までの残り時間を減算するのみ
_d_firing_remain_time_sec -= delta
else:
# レーザーを発射する
var scn : Area3D = _scn_laser.instantiate()
scn.set_pos(global_position)
g_val.node_lasers.add_child(scn)
# 発射間隔を設定
_d_firing_remain_time_sec = _d_firing_interval_sec
else:
# タッチしたときにすぐ、レーダーが発射するようにする
_d_firing_remain_time_sec = 0
# HPが0になった場合、Playerは消滅する
if _d_hp <= 0:
queue_free()
func _on_area_entered(area):
# 敵もしくは敵の弾の攻撃があたったため、HPを0にする
_d_hp = 0.0
+func _on_item_sensor_area_entered(area):
+ # アップグレードアイテム
+ if area.en_item_kind == g_val.EnItemKind.SPEED_UP :
+ # パワーアップアイテム
+ _d_speed_magnification = clampf(_d_speed_magnification + 0.4, _d_speed_magnification_min, _d_speed_magnification_max)
+ else:
+ pass
+ area.queue_free()
変更点ですが、まず、Player機の基準速度を_d_speed_mpsに設定します。
-@export var _d_speed_mps = 100.0
+@export var _d_speed_mps = 25.0
倍率は_d_speed_magnificationです。初期値の1.0を設定しています。
+# アップグレードアイテムで性能
+const _d_speed_magnification_max : float = 3.0
+const _d_speed_magnification_min : float = 1.0
+var _d_speed_magnification = _d_speed_magnification_min
またplayer機の速度の計算する式に、倍率_d_speed_magnificationを掛け算するようにしました。
- var v_velocity : Vector3 = v_target.normalized() * _d_speed_mps
+ var v_velocity : Vector3 = v_target.normalized() * _d_speed_mps * _d_speed_magnification
下記が、アップグレードアイテムをゲットしたときの処理です。
areaはupgrade_item.tscnシーンなので、upgrade_item.gdのen_item_kindを参照することで、スピードアップかパワーアップの判別が可能です。
スピードアップの場合、倍率に0.4を加算します。clampfで1.0~3.0にクランプします。
最後に、アップグレードアイテムシーンを、queue_freeで解放します。
+func _on_item_sensor_area_entered(area):
+ # アップグレードアイテム
+ if area.en_item_kind == g_val.EnItemKind.SPEED_UP :
+ # パワーアップアイテム
+ _d_speed_magnification = clampf(_d_speed_magnification + 0.4, _d_speed_magnification_min, _d_speed_magnification_max)
+ else:
+ pass
+ area.queue_free()
終わりに
次はレーザーをパワーアップするようにします。
以上です。