0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Godot4で3D風2D縦スクロールシューティングゲームを作る 13回目 スピードアップ

Posted at

Godot4.1.3でシューティングゲームを作っていきます。

スピードアップ!

 アップグレードアイテムが、スピードアップの時にゲットした場合、プレイヤー機の速度がアップするように実装します。

image.png

github

 本記事で実装したものをgithubで公開しています。

Playerシーンにアップグレードアイテム検知用のArea3Dを追加

 Playerシーンが、アップグレードアイテムの衝突を検知できるようにします。
 敵との当たり判定用のCollisionShape3Dは小さくて、アイテムを取り逃してしまう可能性があるため、アップグレードアイテム専用のArea3Dを追加します。
 player.tscnを開き、Area3Dの「item_sensor」を追加し、子ノードにCollisionShape3Dを追加します。
res://character/player/player.tscn
image.png
 CollisionShape3DのShapeプロパティは新規SphereShape3Dを設定し、半径を3mにしました。
image.png

playerシーンとアップグレードアイテムのCollision設定をして衝突を検知する

 playerシーンに追加したArea3Dのitem_sensorが、upgrade_itemシーンの衝突を検知できるように、Collisionセクションを設定します。

アップグレードアイテム用のLayer名を追加

 プロジェクト設定のLayer Names/3D物理を開き、Layer6に「UpgradeItem」を追加します。
image.png

upgrade_itemシーンのCollision設定

 res://character/item/upgrade_item.tscnを開き、ルートノードを選択して、インスペクターのcollisionセクションのLayerプロパティの6番をチェックします。
 アップグレードアイテム自体は、衝突を検知しないので、Maskプロパティはチェック不要です。
res://character/item/upgrade_item.tscn
image.png

playerシーンのCollision設定

 追加したArea3Dのitem_sensorで、アップグレードアイテムを検知したいので、item_sensorを選択した状態で、Collisionセクションを設定します。
 アップグレードアイテムを検知したいので、Maskの6番のみチェックします。検知されることは想定していないので、Layerはチェック無しです。
res://character/player/player.tscn
image.png

スピードアップアイテム取得すると、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()

終わりに

 次はレーザーをパワーアップするようにします。

以上です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?