Feat/2 weapons foundation #6

Merged
Dotts merged 30 commits from feat/2-weapons-foundation into main 2026-06-04 22:22:16 -07:00
11 changed files with 104 additions and 7 deletions
Showing only changes of commit da16a3a757 - Show all commits
+1 -1
View File
@@ -82,7 +82,7 @@ func _build_environment() -> void:
environment.sky = sky environment.sky = sky
environment.ambient_light_source = Environment.AMBIENT_SOURCE_SKY environment.ambient_light_source = Environment.AMBIENT_SOURCE_SKY
environment.ambient_light_energy = 0.4 environment.ambient_light_energy = 0.4
environment.tonemap_mode = 2 # Filmic environment.tonemap_mode = Environment.TONE_MAPPER_FILMIC
environment.glow_enabled = true environment.glow_enabled = true
environment.glow_intensity = 0.3 environment.glow_intensity = 0.3
environment.glow_bloom = 0.1 environment.glow_bloom = 0.1
+2 -2
View File
@@ -146,9 +146,9 @@ func apply_impulse(force: Vector3) -> void:
# Tiny upward bump helps move_and_slide detach from the floor # Tiny upward bump helps move_and_slide detach from the floor
global_position.y += 0.1 global_position.y += 0.1
func take_damage(amount: float, hit_pos: Vector3, source: Node = null) -> void: func take_damage(amount: float, _hit_pos: Vector3, _source: Node3D = null) -> void:
# Show damage number for self-damage # Show damage number for self-damage
spawn_damage_number(amount, hit_pos) spawn_damage_number(amount, _hit_pos)
func _ensure_machine() -> MovementStateMachine: func _ensure_machine() -> MovementStateMachine:
if is_instance_valid(_machine): if is_instance_valid(_machine):
-1
View File
@@ -6,7 +6,6 @@ var params: MovementParams:
get: return machine.params get: return machine.params
var elapsed: float = 0.0 var elapsed: float = 0.0
var _initial_y_vel: float = 0.0
var _run_speed: float = 0.0 var _run_speed: float = 0.0
var _last_vel: Vector3 = Vector3.ZERO var _last_vel: Vector3 = Vector3.ZERO
+3
View File
@@ -146,6 +146,9 @@ func _shoot_hitscan() -> void:
if result.collider.has_method("take_damage"): if result.collider.has_method("take_damage"):
result.collider.take_damage(damage, result.position, player) result.collider.take_damage(damage, result.position, player)
else:
# Not a target, spawn a bullet hole
ImpactSpawner.spawn(get_tree(), "bullet", result.position, result.normal, 0.1)
# Add this hit to exclude so next loop goes through it # Add this hit to exclude so next loop goes through it
var exc = query.exclude var exc = query.exclude
+2 -2
View File
@@ -121,6 +121,6 @@ func _shoot_projectile() -> void:
_spawn_custom_projectile(origin, fire_dir) _spawn_custom_projectile(origin, fire_dir)
func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void: func _spawn_custom_projectile(_origin: Vector3, _fire_dir: Vector3) -> void:
# Overridden by specific weapons to instance their unique visual projectile # Virtual method for custom projectiles (e.g., bouncing, homing)
pass pass
+2
View File
@@ -195,6 +195,8 @@ func _shoot_hitscan() -> void:
if result.collider.has_method("take_damage"): if result.collider.has_method("take_damage"):
result.collider.take_damage(damage, result.position, player) result.collider.take_damage(damage, result.position, player)
else:
ImpactSpawner.spawn(get_tree(), "bullet", result.position, result.normal, 0.08)
# Spawn cosmetic tracer # Spawn cosmetic tracer
var tracer = Node3D.new() var tracer = Node3D.new()
+2
View File
@@ -7,6 +7,8 @@ var can_self_damage: bool = false
var falloff_curve: float = 1.0 # 1.0 is linear, 2.0 is quadratic (steep drop) var falloff_curve: float = 1.0 # 1.0 is linear, 2.0 is quadratic (steep drop)
func _on_hit(result: Dictionary) -> void: func _on_hit(result: Dictionary) -> void:
if not result.collider.has_method("take_damage"):
ImpactSpawner.spawn(get_tree(), "crater", result.position, result.normal, explosion_radius * 1.5)
_explode(result.position) _explode(result.position)
queue_free() queue_free()
+86
View File
@@ -0,0 +1,86 @@
extends Node
class_name ImpactSpawner
static var bullet_hole_mat: StandardMaterial3D = null
static var crater_mat: StandardMaterial3D = null
static var plasma_mat: StandardMaterial3D = null
static func _ensure_mats():
if bullet_hole_mat != null:
return
var make_tex = func(colors: Array, offsets: Array, size: int) -> Texture2D:
var g = Gradient.new()
# For Godot 4 Gradient, we set offsets and colors directly
var p_offsets = PackedFloat32Array()
var p_colors = PackedColorArray()
for o in offsets: p_offsets.append(o)
for c in colors: p_colors.append(c)
g.offsets = p_offsets
g.colors = p_colors
var t = GradientTexture2D.new()
t.gradient = g
t.fill = GradientTexture2D.FILL_RADIAL
t.fill_from = Vector2(0.5, 0.5)
t.fill_to = Vector2(0.5, 0.0)
t.width = size
t.height = size
return t
var tex_b = make_tex.call(
[Color(0.01, 0.01, 0.01, 1.0), Color(0.1, 0.1, 0.1, 0.8), Color(0.1, 0.1, 0.1, 0.0)],
[0.0, 0.3, 1.0], 32)
bullet_hole_mat = StandardMaterial3D.new()
bullet_hole_mat.albedo_texture = tex_b
bullet_hole_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
var tex_c = make_tex.call(
[Color(0.05, 0.05, 0.05, 0.9), Color(0.1, 0.1, 0.1, 0.6), Color(0.1, 0.1, 0.1, 0.0)],
[0.0, 0.5, 1.0], 128)
crater_mat = StandardMaterial3D.new()
crater_mat.albedo_texture = tex_c
crater_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
var tex_p = make_tex.call(
[Color(0.8, 0.9, 1.0, 1.0), Color(0.2, 0.6, 1.0, 0.8), Color(0.1, 0.3, 0.8, 0.0)],
[0.0, 0.2, 1.0], 64)
plasma_mat = StandardMaterial3D.new()
plasma_mat.albedo_texture = tex_p
plasma_mat.transparency = BaseMaterial3D.TRANSPARENCY_ALPHA
plasma_mat.emission_enabled = true
plasma_mat.emission_texture = tex_p
plasma_mat.emission_energy_multiplier = 2.0
static func spawn(scene_tree: SceneTree, type: String, pos: Vector3, normal: Vector3, size: float = 0.2):
_ensure_mats()
var mi = MeshInstance3D.new()
var qm = QuadMesh.new()
qm.size = Vector2(size, size)
var mat: StandardMaterial3D
if type == "bullet":
mat = bullet_hole_mat.duplicate()
elif type == "crater":
mat = crater_mat.duplicate()
elif type == "plasma":
mat = plasma_mat.duplicate()
qm.material = mat
mi.mesh = qm
scene_tree.current_scene.add_child(mi)
mi.global_position = pos + normal * 0.01
if abs(normal.dot(Vector3.UP)) < 0.999:
mi.look_at(mi.global_position - normal, Vector3.UP)
else:
mi.look_at(mi.global_position - normal, Vector3.RIGHT)
var duration = 5.0 if type == "crater" else 3.0
var tween = mi.create_tween()
tween.tween_interval(duration)
tween.tween_property(mat, "albedo_color:a", 0.0, 1.0)
tween.tween_callback(mi.queue_free)
+1
View File
@@ -0,0 +1 @@
uid://bf5h8cxi8kct2
+1
View File
@@ -100,6 +100,7 @@ func _spawn_custom_projectile(origin: Vector3, fire_dir: Vector3) -> void:
proj.max_range = max_range proj.max_range = max_range
proj.drop_gravity = projectile_gravity proj.drop_gravity = projectile_gravity
proj.owner_player = player proj.owner_player = player
proj.impact_type = "plasma"
# Spawn in the world # Spawn in the world
get_tree().current_scene.add_child(proj) get_tree().current_scene.add_child(proj)
+4 -1
View File
@@ -9,6 +9,7 @@ var owner_player: CharacterBody3D
var falloff_start: float = 10.0 var falloff_start: float = 10.0
var min_damage: float = 5.0 var min_damage: float = 5.0
var drop_gravity: float = 0.0 # For arc projectiles (nailgun might have slight drop, plasma none) var drop_gravity: float = 0.0 # For arc projectiles (nailgun might have slight drop, plasma none)
var impact_type: String = "bullet"
var logical_source = null var logical_source = null
var _previous_position: Vector3 var _previous_position: Vector3
@@ -58,6 +59,8 @@ func _on_hit(result: Dictionary) -> void:
if result.collider.has_method("take_damage"): if result.collider.has_method("take_damage"):
result.collider.take_damage(final_damage, result.position, owner_player) result.collider.take_damage(final_damage, result.position, owner_player)
else:
var size = 0.4 if impact_type == "plasma" else 0.15
ImpactSpawner.spawn(get_tree(), impact_type, result.position, result.normal, size)
# Spawn impact effect? Not needed yet for prototype.
queue_free() queue_free()