diff --git a/enemies/police_car/weak_point.gd b/enemies/police_car/weak_point.gd index 3199bac..7cc9503 100644 --- a/enemies/police_car/weak_point.gd +++ b/enemies/police_car/weak_point.gd @@ -8,6 +8,7 @@ func _ready() -> void: func hit(projectile: PlayerProjectile, _damage: float) -> bool: if projectile == null: return false + if not projectile.can_hit_weak_points: return false var angle := projectile.velocity.angle_to(-parent.velocity) var weak_point_hit := rad_to_deg(angle) < 25. diff --git a/player/guns/mini_gun.gd b/player/guns/mini_gun.gd index acffeed..0f0960b 100644 --- a/player/guns/mini_gun.gd +++ b/player/guns/mini_gun.gd @@ -6,6 +6,7 @@ func fire(aim_angle: float) -> void: var player_projectile: PlayerProjectile = preload("res://player/projectile/player_projectile.tscn").instantiate() player_projectile.init(dir) player_projectile.damage = 5 + player_projectile.can_hit_weak_points = false player_projectile.global_position = global_position + Vector3.UP * 0.5 get_tree().current_scene.add_child(player_projectile) fire_clock = 60. / fire_rate diff --git a/player/guns/mortar.gd b/player/guns/mortar.gd new file mode 100644 index 0000000..fd97a0d --- /dev/null +++ b/player/guns/mortar.gd @@ -0,0 +1,37 @@ +class_name Mortar +extends Gun + +func calculate_projectile_velocity(source: Vector3, target: Vector3, max_height: float) -> Vector3: + assert(is_equal_approx(source.y, target.y), "Source and target must be at the same height.") + assert(max_height > 0.0, "Max height must be positive.") + + # Flatten to the horizontal plane and get range + direction + var horizontal_offset := Vector3(target.x - source.x, 0.0, target.z - source.z) + var R := horizontal_offset.length() + assert(R > 0.0, "Source and target must not be the same point.") + var direction := horizontal_offset / R + + var g := MortarProjectile.GRAVITY + + # Angle whose tangent is 4H/R — peaks exactly at max_height + var angle := atan(4.0 * max_height / R) + + # Speed derived from v = sqrt(2gH + gR²/8H) + var speed := sqrt(2.0 * g * max_height + (g * R * R) / (8.0 * max_height)) + + var horizontal_speed := speed * cos(angle) + var vertical_speed := speed * sin(angle) + + return direction * horizontal_speed + Vector3.UP * vertical_speed + +func fire(_aim_angle: float) -> void: + var pos: Vector3 = Player.instance.get_node("%Reticle").global_position + pos.y = global_position.y + var vel := calculate_projectile_velocity(global_position, pos, 10.) + + var proj := preload("res://player/projectile/mortar_projectile.tscn").instantiate() + proj.velocity = vel + proj.global_position = global_position + get_tree().current_scene.add_child(proj) + + fire_clock = 60. / fire_rate diff --git a/player/guns/mortar.gd.uid b/player/guns/mortar.gd.uid new file mode 100644 index 0000000..228e7d1 --- /dev/null +++ b/player/guns/mortar.gd.uid @@ -0,0 +1 @@ +uid://ftrngxkkycl1 diff --git a/player/player.gd b/player/player.gd index 3bec349..8aab7cf 100644 --- a/player/player.gd +++ b/player/player.gd @@ -28,7 +28,7 @@ var state := State.NORMAL var dash_direction: Vector2 var stamina := 1.0 -@onready var gun: Gun = %MiniGun +@onready var gun: Gun = %Mortar func _init() -> void: instance = self diff --git a/player/player.tscn b/player/player.tscn index 777a0b9..de7fc69 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -4,6 +4,7 @@ [ext_resource type="Script" uid="uid://cjdxibg3pnans" path="res://player/score_label.gd" id="2_onrkg"] [ext_resource type="Script" uid="uid://fv1n5noqdfg2" path="res://player/guns/basic_gun.gd" id="3_g1dw6"] [ext_resource type="Script" uid="uid://b87cyvu2m5b1k" path="res://player/guns/mini_gun.gd" id="4_yw30f"] +[ext_resource type="Script" uid="uid://ftrngxkkycl1" path="res://player/guns/mortar.gd" id="5_qjkh3"] [sub_resource type="FastNoiseLite" id="FastNoiseLite_onrkg"] @@ -99,3 +100,8 @@ script = ExtResource("3_g1dw6") unique_name_in_owner = true script = ExtResource("4_yw30f") fire_rate = 800.0 + +[node name="Mortar" type="Node3D" parent="Guns" unique_id=1321220525] +unique_name_in_owner = true +script = ExtResource("5_qjkh3") +fire_rate = 250.0 diff --git a/player/projectile/mortar_projectile.gd b/player/projectile/mortar_projectile.gd new file mode 100644 index 0000000..e6cb094 --- /dev/null +++ b/player/projectile/mortar_projectile.gd @@ -0,0 +1,17 @@ +class_name MortarProjectile +extends Node3D + +var velocity: Vector3 + +const GRAVITY := 40. + +func _process(delta: float) -> void: + position += velocity * delta + velocity += GRAVITY * Vector3.DOWN * delta + + if position.y <= 0.: + var explosion := preload("res://player/explosion/explosion.tscn").instantiate() + explosion.position = position + add_sibling(explosion) + + queue_free() diff --git a/player/projectile/mortar_projectile.gd.uid b/player/projectile/mortar_projectile.gd.uid new file mode 100644 index 0000000..c4529cc --- /dev/null +++ b/player/projectile/mortar_projectile.gd.uid @@ -0,0 +1 @@ +uid://dgnyxjs1f61lc diff --git a/player/projectile/mortar_projectile.tscn b/player/projectile/mortar_projectile.tscn new file mode 100644 index 0000000..4a124af --- /dev/null +++ b/player/projectile/mortar_projectile.tscn @@ -0,0 +1,11 @@ +[gd_scene format=3 uid="uid://i5lihai81ec1"] + +[ext_resource type="Script" uid="uid://dgnyxjs1f61lc" path="res://player/projectile/mortar_projectile.gd" id="1_7aq8w"] + +[sub_resource type="SphereMesh" id="SphereMesh_7aq8w"] + +[node name="MortarProjectile" type="Node3D" unique_id=1380191443] +script = ExtResource("1_7aq8w") + +[node name="MeshInstance3D" type="MeshInstance3D" parent="." unique_id=380266621] +mesh = SubResource("SphereMesh_7aq8w") diff --git a/player/projectile/player_projectile.gd b/player/projectile/player_projectile.gd index f19143f..77dd075 100644 --- a/player/projectile/player_projectile.gd +++ b/player/projectile/player_projectile.gd @@ -10,6 +10,7 @@ var health: int = 1: if v == 0: queue_free() var damage := 10. +var can_hit_weak_points := true func _on_collision(node: Node3D): if node.has_method("hit"):