From f73f093ae27ac0635f779b14bd2f45f9ba0877fb Mon Sep 17 00:00:00 2001 From: Michael Campbell Date: Thu, 19 Feb 2026 00:04:31 -0500 Subject: [PATCH] gun system + minigun --- enemies/police_car/police_car.gd | 9 +++++++-- enemies/police_car/weak_point.gd | 2 +- player/explosion/hit_area.gd | 2 +- player/guns/base_gun.gd | 11 +++++++++++ player/guns/base_gun.gd.uid | 1 + player/guns/basic_gun.gd | 10 ++++++++++ player/guns/basic_gun.gd.uid | 1 + player/guns/mini_gun.gd | 13 +++++++++++++ player/guns/mini_gun.gd.uid | 1 + player/player.gd | 24 ++++++++++++------------ player/player.tscn | 13 +++++++++++++ player/projectile/player_projectile.gd | 3 ++- world/building/building.gd | 18 +++++++++++------- 13 files changed, 84 insertions(+), 24 deletions(-) create mode 100644 player/guns/base_gun.gd create mode 100644 player/guns/base_gun.gd.uid create mode 100644 player/guns/basic_gun.gd create mode 100644 player/guns/basic_gun.gd.uid create mode 100644 player/guns/mini_gun.gd create mode 100644 player/guns/mini_gun.gd.uid diff --git a/enemies/police_car/police_car.gd b/enemies/police_car/police_car.gd index 848d98b..92fe5c7 100644 --- a/enemies/police_car/police_car.gd +++ b/enemies/police_car/police_car.gd @@ -3,6 +3,8 @@ extends CharacterBody3D @export var dot_curve: Curve +var health := 10. + func _physics_process(delta: float) -> void: %NavAgent.target_position = Player.instance.global_position @@ -15,8 +17,11 @@ func _physics_process(delta: float) -> void: rotation.y = Vector2(velocity.x, -velocity.z).angle() -func hit(_proj: PlayerProjectile) -> bool: - queue_free() +func hit(_proj: PlayerProjectile, damage: float) -> bool: + health -= damage + if health <= 0: + queue_free() + return true diff --git a/enemies/police_car/weak_point.gd b/enemies/police_car/weak_point.gd index 381d210..3199bac 100644 --- a/enemies/police_car/weak_point.gd +++ b/enemies/police_car/weak_point.gd @@ -6,7 +6,7 @@ func _ready() -> void: assert(get_parent() is PoliceCar) parent = get_parent() -func hit(projectile: PlayerProjectile) -> bool: +func hit(projectile: PlayerProjectile, _damage: float) -> bool: if projectile == null: return false var angle := projectile.velocity.angle_to(-parent.velocity) diff --git a/player/explosion/hit_area.gd b/player/explosion/hit_area.gd index a62ca1a..9852982 100644 --- a/player/explosion/hit_area.gd +++ b/player/explosion/hit_area.gd @@ -2,7 +2,7 @@ extends Area3D func _on_collision(node: Node3D): if node.has_method("hit"): - node.hit(null) + node.hit(null, INF) func _ready() -> void: body_entered.connect(_on_collision) diff --git a/player/guns/base_gun.gd b/player/guns/base_gun.gd new file mode 100644 index 0000000..9fe6423 --- /dev/null +++ b/player/guns/base_gun.gd @@ -0,0 +1,11 @@ +@abstract +class_name Gun +extends Node3D + +var fire_clock := 0. + +@export_custom(PROPERTY_HINT_NONE, "suffix:rounds per minute") +var fire_rate := 125. + +@abstract +func fire(aim_angle: float) -> void diff --git a/player/guns/base_gun.gd.uid b/player/guns/base_gun.gd.uid new file mode 100644 index 0000000..82c510a --- /dev/null +++ b/player/guns/base_gun.gd.uid @@ -0,0 +1 @@ +uid://v3nmgfwx8ivi diff --git a/player/guns/basic_gun.gd b/player/guns/basic_gun.gd new file mode 100644 index 0000000..c58f16a --- /dev/null +++ b/player/guns/basic_gun.gd @@ -0,0 +1,10 @@ +class_name BasicGun +extends Gun + +func fire(aim_angle: float) -> void: + var dir := Vector3.RIGHT.rotated(Vector3.UP, aim_angle) + var player_projectile: PlayerProjectile = preload("res://player/projectile/player_projectile.tscn").instantiate() + player_projectile.init(dir) + 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/basic_gun.gd.uid b/player/guns/basic_gun.gd.uid new file mode 100644 index 0000000..5f7d90a --- /dev/null +++ b/player/guns/basic_gun.gd.uid @@ -0,0 +1 @@ +uid://fv1n5noqdfg2 diff --git a/player/guns/mini_gun.gd b/player/guns/mini_gun.gd new file mode 100644 index 0000000..acffeed --- /dev/null +++ b/player/guns/mini_gun.gd @@ -0,0 +1,13 @@ +class_name MiniGun +extends Gun + +func fire(aim_angle: float) -> void: + var dir := Vector3.RIGHT.rotated(Vector3.UP, aim_angle) + var player_projectile: PlayerProjectile = preload("res://player/projectile/player_projectile.tscn").instantiate() + player_projectile.init(dir) + player_projectile.damage = 5 + player_projectile.global_position = global_position + Vector3.UP * 0.5 + get_tree().current_scene.add_child(player_projectile) + fire_clock = 60. / fire_rate + + Player.instance.velocity += -dir * 10. diff --git a/player/guns/mini_gun.gd.uid b/player/guns/mini_gun.gd.uid new file mode 100644 index 0000000..13f2de8 --- /dev/null +++ b/player/guns/mini_gun.gd.uid @@ -0,0 +1 @@ +uid://b87cyvu2m5b1k diff --git a/player/player.gd b/player/player.gd index f66f6ce..3bec349 100644 --- a/player/player.gd +++ b/player/player.gd @@ -28,6 +28,8 @@ var state := State.NORMAL var dash_direction: Vector2 var stamina := 1.0 +@onready var gun: Gun = %MiniGun + func _init() -> void: instance = self @@ -38,10 +40,14 @@ func _process_stamina(delta: float) -> void: stamina = move_toward(stamina, 1., delta * 0.2) %StaminaBar.value = stamina -func _process_movement() -> void: +func exp_lerp(a: Variant, b: Variant, decay: float, dt: float) -> Variant: + return lerp(a, b, 1 - exp(-decay * dt)) + +func _process_movement(delta: float) -> void: var input = Input.get_vector("move_left", "move_right", "move_up", "move_down") input.normalized() - velocity = Vector3(input.x, 0., input.y) * MOVE_SPEED + var desired_velocity = Vector3(input.x, 0., input.y) * MOVE_SPEED + velocity = exp_lerp(velocity, desired_velocity, 20, delta) move_and_slide() if Input.is_action_just_pressed("dash") and stamina >= 1. and not input.is_zero_approx(): @@ -76,7 +82,6 @@ func _process_aim() -> void: %Reticle.position = to_mouse_pos -var fire_clock := 0. func _process_shoot(delta: float) -> void: var clock_mul := 1. @@ -84,14 +89,9 @@ func _process_shoot(delta: float) -> void: State.DASHING: clock_mul = 2.5 State.LOCKED: clock_mul = 2.5 - fire_clock -= delta * clock_mul - if Input.is_action_pressed("fire") and fire_clock <= 0.: - var dir := Vector3.RIGHT.rotated(Vector3.UP, aim_angle) - var player_projectile: PlayerProjectile = preload("res://player/projectile/player_projectile.tscn").instantiate() - player_projectile.init(dir) - player_projectile.global_position = global_position + Vector3.UP * 0.5 - add_sibling(player_projectile) - fire_clock = 60. / 125. + gun.fire_clock -= delta * clock_mul + if Input.is_action_pressed("fire") and gun.fire_clock <= 0.: + gun.fire(aim_angle) func _process_cam_shake(delta: float) -> void: shake_duration -= delta @@ -110,7 +110,7 @@ func _process_cam_shake(delta: float) -> void: func _process(delta: float) -> void: match state: - State.NORMAL: _process_movement() + State.NORMAL: _process_movement(delta) State.DASHING: _process_dash() State.LOCKED: pass diff --git a/player/player.tscn b/player/player.tscn index a7f44b8..777a0b9 100644 --- a/player/player.tscn +++ b/player/player.tscn @@ -2,6 +2,8 @@ [ext_resource type="Script" uid="uid://dhin7ux2njfja" path="res://player/player.gd" id="1_4flbx"] [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"] [sub_resource type="FastNoiseLite" id="FastNoiseLite_onrkg"] @@ -86,3 +88,14 @@ offset_top = -27.0 offset_right = 196.0 offset_bottom = -4.0 text = "Stamina" + +[node name="Guns" type="Node3D" parent="." unique_id=2018109083] + +[node name="BasicGun" type="Node3D" parent="Guns" unique_id=1677055720] +unique_name_in_owner = true +script = ExtResource("3_g1dw6") + +[node name="MiniGun" type="Node3D" parent="Guns" unique_id=416187827] +unique_name_in_owner = true +script = ExtResource("4_yw30f") +fire_rate = 800.0 diff --git a/player/projectile/player_projectile.gd b/player/projectile/player_projectile.gd index 7efdf93..f19143f 100644 --- a/player/projectile/player_projectile.gd +++ b/player/projectile/player_projectile.gd @@ -9,10 +9,11 @@ var health: int = 1: health = v if v == 0: queue_free() +var damage := 10. func _on_collision(node: Node3D): if node.has_method("hit"): - if node.hit(self): + if node.hit(self, damage): health -= 1 func _ready() -> void: diff --git a/world/building/building.gd b/world/building/building.gd index 5e5d13f..dcff7db 100644 --- a/world/building/building.gd +++ b/world/building/building.gd @@ -1,16 +1,20 @@ class_name Building extends CollisionObject3D +var health := 10. + func _ready() -> void: scale.y = randf_range(.5, 1.25) -func hit(_proj: PlayerProjectile) -> bool: - print("boom!") - SignalBus.building_destroyed.emit(self) - collision_layer = 1 # World collision only +func hit(_proj: PlayerProjectile, damage: float) -> bool: + health -= damage + if health <= 0.: + print("boom!") + SignalBus.building_destroyed.emit(self) + collision_layer = 1 # World collision only - %Mesh.hide() - %DestroyedMesh.show() - %GPUParticles3D.preprocess = randf() + %Mesh.hide() + %DestroyedMesh.show() + %GPUParticles3D.preprocess = randf() return true