save code

This commit is contained in:
xsl
2025-11-28 18:10:23 +08:00
commit fee064c3f0
49 changed files with 64353 additions and 0 deletions
+54
View File
@@ -0,0 +1,54 @@
@tool
extends Node3D
@export var play_particles: bool = false:
set(value):
if value:
_find_particles() # Always scan for new particles
_cleanup_delays() # Remove deleted particles from the list
_start_delays() # Ensure delays exist for new particles
_play_particles()
play_particles = false # Reset the checkbox immediately
var particle_systems: Array
@export var delays: Dictionary
@export var cleanDelays: bool = false:
set(value):
if value:
delays.clear()
cleanDelays = false
func _find_particles():
particle_systems.clear() # Always clear and re-detect
var existing_delays = delays.duplicate() # Preserve existing delays
for child in get_children():
if child is GPUParticles3D:
particle_systems.append(child)
if not existing_delays.has(child.name):
existing_delays[child.name] = 0.0 # Assign default delay
delays = existing_delays # Restore old delays + new ones
func _cleanup_delays(): # Remove delays for particles that no longer exist
var valid_particle_names = particle_systems.map(func(p): return p.name)
for key in delays.keys():
if key not in valid_particle_names:
delays.erase(key) # Remove old particle system references
func _start_delays():
for particle in particle_systems:
if not delays.has(particle.name):
delays[particle.name] = 0.0 # Keep existing delays, add new ones
func _play_particles():
for particle in particle_systems:
var delay = delays.get(particle.name, 0.0)
_playDelay(particle, delay)
func _playDelay(ps: GPUParticles3D, delay: float):
ps.emitting = false # Reset first (prevents issues)
await get_tree().create_timer(delay).timeout
ps.restart() # Works in play mode
ps.emitting = true # Start emitting
+1
View File
@@ -0,0 +1 @@
uid://dxhfn5g0spoim
+68
View File
@@ -0,0 +1,68 @@
extends RigidBody3D
@export var speed: float = 10.0
@export var muzzle_prefab: PackedScene
@export var impact_prefab: PackedScene
@export var delay_trails_start: float = 0.1
@export var trails: Array[GPUTrail3D]
var direction: Vector3 = Vector3.FORWARD
var fire_point_position: Vector3
func set_fire_point(fp_position: Vector3):
fire_point_position = fp_position
func _ready():
delay_trails()
spawn_muzzle()
contact_monitor = true
max_contacts_reported = 1
func _integrate_forces(state):
linear_velocity = direction * speed
var collision = state.get_contact_count()
if collision > 0:
var contact = state.get_contact_collider_position(0)
var normal = state.get_contact_local_normal(0)
spawn_impact(contact, normal)
queue_free()
func spawn_muzzle():
if muzzle_prefab:
var muzzle_instance = muzzle_prefab.instantiate()
call_deferred("add_child", muzzle_instance)
await get_tree().create_timer(0.001).timeout
muzzle_instance.global_transform.origin = fire_point_position
muzzle_instance.play_particles = true
await get_tree().create_timer(3.0).timeout
if is_instance_valid(muzzle_instance):
muzzle_instance.queue_free()
func spawn_impact(contact_point: Vector3 = Vector3.ZERO, contact_normal: Vector3 = Vector3.ZERO):
if impact_prefab:
var impact_instance = impact_prefab.instantiate()
get_tree().current_scene.add_child(impact_instance)
impact_instance.play_particles = true
impact_instance.global_transform.origin = contact_point
impact_instance.look_at(contact_point + contact_normal, Vector3.UP)
await get_tree().create_timer(3.0).timeout
if is_instance_valid(impact_instance):
impact_instance.queue_free()
func delay_trails():
if trails.is_empty():
return
for trail in trails:
if is_instance_valid(trail):
trail.speed_scale = 0 # Stop movement initially, avoids glitches
await get_tree().create_timer(delay_trails_start).timeout
for trail in trails:
if is_instance_valid(trail):
trail.speed_scale = 1 # Resume movement
+1
View File
@@ -0,0 +1 @@
uid://srxbm3tbdhyu
+19
View File
@@ -0,0 +1,19 @@
extends Node3D
@export var camera: Camera3D = null
@export var rotation_speed: float = 5.0
func _process(delta):
if camera:
var mouse_pos = get_viewport().get_mouse_position()
var ray_origin = camera.project_ray_origin(mouse_pos)
var ray_dir = camera.project_ray_normal(mouse_pos)
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_origin + ray_dir * 1000.0)
var result = space_state.intersect_ray(query)
var target_position = result["position"] if result else ray_origin + ray_dir * 10.0
var direction = (target_position - global_transform.origin).normalized()
var target_rotation = Quaternion(Vector3.FORWARD, direction)
transform.basis = Basis(transform.basis.get_rotation_quaternion().slerp(target_rotation, delta * rotation_speed))
+1
View File
@@ -0,0 +1 @@
uid://b86hxdolpatb8
+37
View File
@@ -0,0 +1,37 @@
extends Node3D
@export var camera: Camera3D = null
@export var fire_rate: float = 0.5
@export var aoe_lifetime: float = 7.0
@export var aoe_prefab: PackedScene
var can_fire: bool = true
func _process(_delta):
if Input.is_action_pressed("fire") and can_fire:
fire_aoe()
can_fire = false
await get_tree().create_timer(fire_rate).timeout
can_fire = true
func fire_aoe():
if not (aoe_prefab and camera):
return
var mouse_position = get_viewport().get_mouse_position()
var ray_origin = camera.project_ray_origin(mouse_position)
var ray_direction = camera.project_ray_normal(mouse_position) * 1000 # Long ray
var space_state = get_world_3d().direct_space_state
var query = PhysicsRayQueryParameters3D.create(ray_origin, ray_origin + ray_direction)
var result = space_state.intersect_ray(query)
if result.has("position"):
var aoe_instance = aoe_prefab.instantiate()
get_parent().add_child(aoe_instance)
aoe_instance.global_position = result["position"] # Spawn at hit position
aoe_instance.play_particles = true # Start particle effect
await get_tree().create_timer(aoe_lifetime).timeout
if is_instance_valid(aoe_instance):
aoe_instance.queue_free()
+1
View File
@@ -0,0 +1 @@
uid://bkdqbagbitktv
+31
View File
@@ -0,0 +1,31 @@
extends Node3D
@export var fire_rate: float = 0.5
@export var projectile_lifetime: float = 4.0
@export var projectile_prefab: PackedScene
@export var rotate_to_mouse: Node3D
@export var fire_point: Node3D
var can_fire: bool = true
func _process(_delta):
if Input.is_action_pressed("fire") and can_fire:
fire_projectile()
can_fire = false
await get_tree().create_timer(fire_rate).timeout
can_fire = true
func fire_projectile():
if projectile_prefab and fire_point and rotate_to_mouse:
var projectile_instance = projectile_prefab.instantiate()
get_parent().add_child(projectile_instance)
projectile_instance.global_position = fire_point.global_position
projectile_instance.set_fire_point(fire_point.global_transform.origin)
var direction = -rotate_to_mouse.global_transform.basis.z.normalized()
projectile_instance.direction = direction
projectile_instance.look_at(fire_point.global_position + -direction)
await get_tree().create_timer(projectile_lifetime).timeout
if projectile_instance:
projectile_instance.queue_free()
+1
View File
@@ -0,0 +1 @@
uid://gs00msx4i83u
+116
View File
@@ -0,0 +1,116 @@
class_name FreeLookCamera extends Camera3D
# Modifier keys' speed multiplier
const SHIFT_MULTIPLIER = 2.5
const ALT_MULTIPLIER = 1.0 / SHIFT_MULTIPLIER
@export_range(0.0, 1.0) var sensitivity: float = 0.25
# Mouse state
var _mouse_position = Vector2(0.0, 0.0)
var _total_pitch = 0.0
# Movement state
var _direction = Vector3(0.0, 0.0, 0.0)
var _velocity = Vector3(0.0, 0.0, 0.0)
var _acceleration = 30
var _deceleration = -10
var _vel_multiplier = 4
# Keyboard state
var _w = false
var _s = false
var _a = false
var _d = false
var _q = false
var _e = false
var _shift = false
var _alt = false
func _input(event):
# Receives mouse motion
if event is InputEventMouseMotion:
_mouse_position = event.relative
# Receives mouse button input
if event is InputEventMouseButton:
match event.button_index:
MOUSE_BUTTON_RIGHT: # Only allows rotation if right click down
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if event.pressed else Input.MOUSE_MODE_VISIBLE)
MOUSE_BUTTON_WHEEL_UP: # Increases max velocity
_vel_multiplier = clamp(_vel_multiplier * 1.1, 0.2, 20)
MOUSE_BUTTON_WHEEL_DOWN: # Decereases max velocity
_vel_multiplier = clamp(_vel_multiplier / 1.1, 0.2, 20)
# Receives key input
if event is InputEventKey:
match event.keycode:
KEY_W:
_w = event.pressed
KEY_S:
_s = event.pressed
KEY_A:
_a = event.pressed
KEY_D:
_d = event.pressed
KEY_Q:
_q = event.pressed
KEY_E:
_e = event.pressed
KEY_SHIFT:
_shift = event.pressed
KEY_ALT:
_alt = event.pressed
# Updates mouselook and movement every frame
func _process(delta):
_update_mouselook()
_update_movement(delta)
# Updates camera movement
func _update_movement(delta):
# Computes desired direction from key states
_direction = Vector3(
(_d as float) - (_a as float),
(_e as float) - (_q as float),
(_s as float) - (_w as float)
)
# Computes the change in velocity due to desired direction and "drag"
# The "drag" is a constant acceleration on the camera to bring it's velocity to 0
var offset = _direction.normalized() * _acceleration * _vel_multiplier * delta \
+ _velocity.normalized() * _deceleration * _vel_multiplier * delta
# Compute modifiers' speed multiplier
var speed_multi = 1
if _shift: speed_multi *= SHIFT_MULTIPLIER
if _alt: speed_multi *= ALT_MULTIPLIER
# Checks if we should bother translating the camera
if _direction == Vector3.ZERO and offset.length_squared() > _velocity.length_squared():
# Sets the velocity to 0 to prevent jittering due to imperfect deceleration
_velocity = Vector3.ZERO
else:
# Clamps speed to stay within maximum value (_vel_multiplier)
_velocity.x = clamp(_velocity.x + offset.x, -_vel_multiplier, _vel_multiplier)
_velocity.y = clamp(_velocity.y + offset.y, -_vel_multiplier, _vel_multiplier)
_velocity.z = clamp(_velocity.z + offset.z, -_vel_multiplier, _vel_multiplier)
translate(_velocity * delta * speed_multi)
# Updates mouse look
func _update_mouselook():
# Only rotates mouse if the mouse is captured
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
_mouse_position *= sensitivity
var yaw = _mouse_position.x
var pitch = _mouse_position.y
_mouse_position = Vector2(0, 0)
# Prevents looking up/down too far
pitch = clamp(pitch, -90 - _total_pitch, 90 - _total_pitch)
_total_pitch += pitch
rotate_y(deg_to_rad(-yaw))
rotate_object_local(Vector3(1,0,0), deg_to_rad(-pitch))
+1
View File
@@ -0,0 +1 @@
uid://dq7h3nectp4hy