Post Game jam commit
This commit is contained in:
commit
6db2131520
164 changed files with 172524 additions and 0 deletions
24
scripts/AnimSprite.gd
Normal file
24
scripts/AnimSprite.gd
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
extends AnimatedSprite2D
|
||||
|
||||
var time = 0.0
|
||||
@export var float_str = 10.0
|
||||
@export var float_time = 2.0
|
||||
@export var float_offset = -12.0
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
time += delta
|
||||
# Calculate the new Y position using a sine wave
|
||||
position.y = sin(time * float_time) * float_str + float_offset
|
||||
queue_redraw()
|
||||
|
||||
func switch_mask(new : Types.mask_types):
|
||||
$MeleeMask.visible = false
|
||||
$RangedMask.visible = false
|
||||
$SpitMask.visible = false
|
||||
if (new == Types.mask_types.Melee):
|
||||
$MeleeMask.visible = true
|
||||
elif (new == Types.mask_types.Ranged):
|
||||
$RangedMask.visible = true
|
||||
elif (new == Types.mask_types.Spit):
|
||||
$SpitMask.visible = true
|
||||
1
scripts/AnimSprite.gd.uid
Normal file
1
scripts/AnimSprite.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c0e4uacrlcrk8
|
||||
110
scripts/camera.gd
Normal file
110
scripts/camera.gd
Normal file
|
|
@ -0,0 +1,110 @@
|
|||
extends Camera2D
|
||||
|
||||
@export var target_res : Vector2 = Vector2(480, 270)
|
||||
@export var target_zoom : float = 1
|
||||
@export var cam_speed : float = 5.0
|
||||
@export var min_speed : float = 0.1
|
||||
@export var ui_layer : CanvasLayer
|
||||
|
||||
# --- NEW VARIABLE ---
|
||||
# 0.0 = no movement, 0.5 = camera moves halfway to mouse, 1.0 = camera centers on mouse
|
||||
@export_range(0.0, 1.0) var mouse_look_strength : float = 0.15
|
||||
# --------------------
|
||||
|
||||
@export var shake_decay : float = 5.0
|
||||
@export var max_offset : Vector2 = Vector2(10, 10)
|
||||
|
||||
var pixel_material : ShaderMaterial
|
||||
|
||||
var scaling : Vector2
|
||||
var actual_pos : Vector2
|
||||
|
||||
var shake_trauma : float = 0.0
|
||||
|
||||
func _ready():
|
||||
# Safety check to prevent crash if node is missing
|
||||
if has_node("Pixelator"):
|
||||
pixel_material = get_node("Pixelator").material
|
||||
|
||||
get_viewport().size_changed.connect(_on_viewport_resized)
|
||||
EventBus.player_dmg.connect(_on_player_dmg)
|
||||
EventBus.screenshake.connect(_on_screenshake)
|
||||
|
||||
_on_viewport_resized()
|
||||
|
||||
|
||||
func _fract(x : Vector2) -> Vector2:
|
||||
return x - floor(x)
|
||||
|
||||
func _on_player_dmg():
|
||||
# Apply a default punchy shake when hit
|
||||
add_shake(0.5)
|
||||
|
||||
func _on_screenshake(intensity: float):
|
||||
add_shake(intensity)
|
||||
|
||||
func add_shake(amount: float):
|
||||
shake_trauma = clamp(shake_trauma + amount, 0.0, 1.0)
|
||||
|
||||
func _apply_shake():
|
||||
# Squaring trauma makes the shake feel more organic (stronger at start, tapers off)
|
||||
var amount = pow(shake_trauma, 2)
|
||||
var offset = Vector2(
|
||||
max_offset.x * amount * randf_range(-1, 1),
|
||||
max_offset.y * amount * randf_range(-1, 1)
|
||||
)
|
||||
# Apply floor to keep the shake aligned with your pixel grid
|
||||
global_position = floor(actual_pos + offset)
|
||||
|
||||
func _on_viewport_resized():
|
||||
var viewport_res : Vector2 = get_viewport().get_visible_rect().size
|
||||
scaling = Vector2(viewport_res.x / target_res.x, viewport_res.y / target_res.y)
|
||||
|
||||
if has_node("Pixelator"):
|
||||
var pixel_rect : ColorRect = get_node("Pixelator")
|
||||
pixel_rect.position = -target_res / 2.
|
||||
pixel_rect.size = target_res
|
||||
|
||||
zoom = scaling * target_zoom
|
||||
if ui_layer:
|
||||
ui_layer.scale = zoom
|
||||
EventBus.debug_print.emit("new scaling: " + str(scaling))
|
||||
|
||||
|
||||
func _process(delta : float):
|
||||
var parent_pos : Vector2 = get_parent().global_position
|
||||
|
||||
# --- NEW MOUSE LOOK LOGIC ---
|
||||
var mouse_pos = get_viewport().get_mouse_position()
|
||||
var vp_size = get_viewport().get_visible_rect().size
|
||||
var center = vp_size / 2.0
|
||||
|
||||
# Calculate how far mouse is from center
|
||||
var offset_from_center = mouse_pos - center
|
||||
|
||||
# Apply strength factor
|
||||
offset_from_center *= mouse_look_strength
|
||||
|
||||
# Convert screen pixels to world units by dividing by the current scaling/zoom
|
||||
# (We guard against division by zero just in case)
|
||||
if scaling.x != 0 and scaling.y != 0:
|
||||
var world_offset = offset_from_center / scaling
|
||||
parent_pos += world_offset
|
||||
# ---------------------------
|
||||
|
||||
var dist := actual_pos.distance_to(parent_pos)
|
||||
var speed : float = max(min_speed, dist * cam_speed) * delta
|
||||
|
||||
actual_pos = actual_pos.move_toward(parent_pos, speed)
|
||||
|
||||
if shake_trauma > 0:
|
||||
shake_trauma = max(shake_trauma - shake_decay * delta, 0)
|
||||
_apply_shake()
|
||||
else:
|
||||
global_position = floor(actual_pos)
|
||||
|
||||
var sub_pixels : Vector2 = floor(_fract(actual_pos) * scaling)
|
||||
|
||||
if pixel_material:
|
||||
pixel_material.set_shader_parameter("cam_pos", sub_pixels)
|
||||
pixel_material.set_shader_parameter("scaling", scaling)
|
||||
1
scripts/camera.gd.uid
Normal file
1
scripts/camera.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b5wg73yvuksot
|
||||
22
scripts/debug_ui.gd
Normal file
22
scripts/debug_ui.gd
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
extends Control
|
||||
|
||||
var lines : Array[String] = []
|
||||
|
||||
func _ready() -> void:
|
||||
EventBus.debug_print.connect(_on_debug_print)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
$Label.text = "FPS: " + str(Engine.get_frames_per_second()) + "\n"
|
||||
for l in lines:
|
||||
$Label.text += l + "\n"
|
||||
|
||||
|
||||
func _on_debug_print(msg : String):
|
||||
lines.append(msg)
|
||||
if len(lines) > 10:
|
||||
lines.pop_front()
|
||||
|
||||
|
||||
func _shortcut_input(event: InputEvent) -> void:
|
||||
if (event.is_action_pressed("debug")):
|
||||
visible = !visible
|
||||
1
scripts/debug_ui.gd.uid
Normal file
1
scripts/debug_ui.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://da2hsusvv3rxg
|
||||
12
scripts/dmg_flash.gd
Normal file
12
scripts/dmg_flash.gd
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
extends ColorRect
|
||||
|
||||
func _ready():
|
||||
EventBus.player_dmg.connect(flash_red)
|
||||
|
||||
|
||||
func flash_red():
|
||||
var tween = create_tween()
|
||||
|
||||
color.a = 0.3
|
||||
|
||||
tween.tween_property(self, "color:a", 0.0, 0.2).set_trans(Tween.TRANS_SINE)
|
||||
1
scripts/dmg_flash.gd.uid
Normal file
1
scripts/dmg_flash.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dgxs6odxyi6s4
|
||||
5
scripts/enemy_explosion.gd
Normal file
5
scripts/enemy_explosion.gd
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
extends GPUParticles2D
|
||||
|
||||
|
||||
func _on_finished() -> void:
|
||||
queue_free()
|
||||
1
scripts/enemy_explosion.gd.uid
Normal file
1
scripts/enemy_explosion.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b6f7w4uftych8
|
||||
36
scripts/enemy_spawn.gd
Normal file
36
scripts/enemy_spawn.gd
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
extends Node2D
|
||||
|
||||
@export var enemies: Array[PackedScene] # Drag your enemy .tscn here
|
||||
@export var num_circles: int = 3 # How many rings of enemies
|
||||
@export var enemies_per_circle: int = 8 # Base number of enemies
|
||||
@export var radius_step: float = 100.0 # Distance between each ring
|
||||
@export var initial_radius: float = 150.0
|
||||
|
||||
func _ready() -> void:
|
||||
spawn_concentric_horde()
|
||||
|
||||
func spawn_concentric_horde() -> void:
|
||||
for i in range(num_circles):
|
||||
# We calculate the radius for this specific ring
|
||||
var current_radius = initial_radius + (i * radius_step)
|
||||
|
||||
for j in range(enemies_per_circle):
|
||||
spawn_enemy_at_random_angle(current_radius)
|
||||
|
||||
func spawn_enemy_at_random_angle(radius: float) -> void:
|
||||
var random_angle = randf_range(0, 2 * PI)
|
||||
|
||||
|
||||
var spawn_pos = Vector2(
|
||||
radius * cos(random_angle),
|
||||
radius * sin(random_angle)
|
||||
)
|
||||
|
||||
var idx1 = randi() % len(enemies)
|
||||
var idx2 = randi() % len(enemies)
|
||||
var idx = min(idx1, idx2)
|
||||
print(idx)
|
||||
var enemy_instance = enemies[idx].instantiate()
|
||||
add_child(enemy_instance)
|
||||
|
||||
enemy_instance.position = spawn_pos
|
||||
1
scripts/enemy_spawn.gd.uid
Normal file
1
scripts/enemy_spawn.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://kyh2wu0jwdwd
|
||||
134
scripts/grass.gd
Normal file
134
scripts/grass.gd
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
@tool
|
||||
class_name GrassMultiMesh extends MultiMeshInstance2D
|
||||
|
||||
@export_group("Visuals")
|
||||
@export var texture_sheet : Texture2D
|
||||
@export var blade_size : Vector2 = Vector2(16, 16)
|
||||
@export var texture_sheet_size : Vector2 = Vector2(64, 16)
|
||||
@export var grass_tint : Color
|
||||
|
||||
@export_group("Editor")
|
||||
@export var editing : bool = false
|
||||
@export var brush_radius : float = 50.0
|
||||
@export var brush_density : int = 5
|
||||
|
||||
@export var grass_data : Array[Dictionary] = []
|
||||
|
||||
enum GrassState {NORMAL = 0, CUT = 1}
|
||||
|
||||
func _ready() -> void:
|
||||
if not multimesh:
|
||||
multimesh = MultiMesh.new()
|
||||
multimesh.transform_format = MultiMesh.TRANSFORM_2D
|
||||
multimesh.use_colors = true
|
||||
multimesh.use_custom_data = true
|
||||
|
||||
multimesh.mesh = _create_mesh_rect()
|
||||
|
||||
if material is ShaderMaterial:
|
||||
material.set_shader_parameter("frame_size", blade_size)
|
||||
material.set_shader_parameter("sheet_size", texture_sheet_size)
|
||||
|
||||
_rebuild_multimesh()
|
||||
|
||||
func _process(_delta):
|
||||
# move_grass_away(%Player.global_position, 25)
|
||||
if editing and Engine.is_editor_hint():
|
||||
if Input.is_key_pressed(KEY_K):
|
||||
_brush_paint()
|
||||
if Input.is_key_pressed(KEY_E):
|
||||
_brush_erase()
|
||||
queue_redraw()
|
||||
|
||||
func cut_grass_at(pos: Vector2, radius: float):
|
||||
_interact_with_grass(pos, radius, GrassState.CUT)
|
||||
|
||||
func move_grass_away(pos: Vector2, radius: float):
|
||||
var half = radius / 2
|
||||
var local_target = to_local(pos)
|
||||
for i in range(multimesh.instance_count):
|
||||
var t = multimesh.get_instance_transform_2d(i)
|
||||
var dist = t.origin.distance_squared_to(local_target)
|
||||
if dist < half * half:
|
||||
var custom_data = multimesh.get_instance_custom_data(i)
|
||||
|
||||
custom_data.r = (t.origin.x - local_target.x) * 2
|
||||
|
||||
multimesh.set_instance_custom_data(i, custom_data)
|
||||
elif dist < radius * radius:
|
||||
var custom_data = multimesh.get_instance_custom_data(i)
|
||||
|
||||
custom_data.r = grass_data[i]["rot"]
|
||||
|
||||
multimesh.set_instance_custom_data(i, custom_data)
|
||||
|
||||
func _interact_with_grass(global_target_pos: Vector2, radius: float, new_state: int):
|
||||
var local_target = to_local(global_target_pos)
|
||||
for i in range(multimesh.instance_count):
|
||||
var t = multimesh.get_instance_transform_2d(i)
|
||||
|
||||
if t.origin.distance_squared_to(local_target) < radius * radius:
|
||||
var custom_data = multimesh.get_instance_custom_data(i)
|
||||
|
||||
if int(custom_data.b) == new_state:
|
||||
continue
|
||||
|
||||
custom_data.b = float(new_state)
|
||||
|
||||
multimesh.set_instance_custom_data(i, custom_data)
|
||||
grass_data[i]["state"] = new_state
|
||||
|
||||
func _create_mesh_rect() -> QuadMesh:
|
||||
var mesh = QuadMesh.new()
|
||||
mesh.size = blade_size
|
||||
return mesh
|
||||
|
||||
func _rebuild_multimesh() -> void:
|
||||
multimesh.instance_count = grass_data.size()
|
||||
var pivot_offset = Vector2(0, -blade_size.y / 2.0)
|
||||
|
||||
for i in range(grass_data.size()):
|
||||
var d = grass_data[i]
|
||||
var xform = Transform2D().translated(d.pos).rotated(d.get("rot", 0.0)).translated(pivot_offset)
|
||||
|
||||
multimesh.set_instance_transform_2d(i, xform)
|
||||
multimesh.set_instance_color(i, grass_tint)
|
||||
|
||||
var custom = Color(
|
||||
randf(),
|
||||
float(d.get("tex_idx", 0)),
|
||||
float(d.get("state", 0)),
|
||||
0.0
|
||||
)
|
||||
multimesh.set_instance_custom_data(i, custom)
|
||||
|
||||
func _brush_paint() -> void:
|
||||
var s = Time.get_ticks_msec()
|
||||
print(s)
|
||||
seed(s)
|
||||
var mouse_pos = get_local_mouse_position()
|
||||
for i in range(brush_density):
|
||||
var angle = randf() * TAU
|
||||
var rad = sqrt(randf()) * brush_radius
|
||||
var pos = mouse_pos + Vector2(cos(angle), sin(angle)) * rad
|
||||
|
||||
var new_blade = {
|
||||
"pos": pos,
|
||||
"tex_idx": int((randf() ** (1.0/3.0)) * 8),
|
||||
"state": GrassState.NORMAL,
|
||||
"rot": randf_range(-0.1, 0.1)
|
||||
}
|
||||
grass_data.append(new_blade)
|
||||
|
||||
_rebuild_multimesh()
|
||||
|
||||
func _brush_erase() -> void:
|
||||
var mouse_pos = get_local_mouse_position()
|
||||
for i in range(grass_data.size() - 1, -1, -1):
|
||||
if grass_data[i].pos.distance_to(mouse_pos) < brush_radius:
|
||||
grass_data.remove_at(i)
|
||||
_rebuild_multimesh()
|
||||
|
||||
func _draw() -> void:
|
||||
if editing and Engine.is_editor_hint():
|
||||
draw_arc(get_local_mouse_position(), brush_radius, 0, TAU, 32, Color.YELLOW, 2.0)
|
||||
1
scripts/grass.gd.uid
Normal file
1
scripts/grass.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b5o4ky21bvg66
|
||||
11
scripts/health_bar.gd
Normal file
11
scripts/health_bar.gd
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
extends TextureRect
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
EventBus.health_changed.connect(_on_health_changed)
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_health_changed(new : int):
|
||||
texture.region = Rect2(0, new * 32, 0, 32)
|
||||
1
scripts/health_bar.gd.uid
Normal file
1
scripts/health_bar.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cj6pb1828dcfr
|
||||
20
scripts/hearts.gd
Normal file
20
scripts/hearts.gd
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
extends CPUParticles2D
|
||||
|
||||
@export var speed: float = 600.0
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
position += transform.x * speed * delta
|
||||
|
||||
func set_from_player(val):
|
||||
$Hitbox.from_player = val
|
||||
|
||||
func _on_hitbox_onhit() -> void:
|
||||
$Hitbox.queue_free()
|
||||
$Explosion.emitting = true
|
||||
emitting = false
|
||||
await get_tree().create_timer(1.2).timeout
|
||||
queue_free()
|
||||
|
||||
|
||||
func _on_timer_timeout() -> void:
|
||||
queue_free()
|
||||
1
scripts/hearts.gd.uid
Normal file
1
scripts/hearts.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dyyqm52cwjimy
|
||||
35
scripts/hitbox.gd
Normal file
35
scripts/hitbox.gd
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
class_name Hitbox extends Area2D
|
||||
|
||||
var from_player = true
|
||||
signal onhit;
|
||||
var hitplayer = false
|
||||
|
||||
#func _process(delta: float) -> void:
|
||||
#EventBus.cut_grass_at.emit(global_position, 14)
|
||||
|
||||
func _ready() -> void:
|
||||
body_entered.connect(_on_body_entered)
|
||||
|
||||
func _on_body_entered(body: Node) -> void:
|
||||
print(body)
|
||||
if body is Enemy and from_player:
|
||||
var bname := str(body.name)
|
||||
if body.has_method("hit"):
|
||||
body.hit()
|
||||
onhit.emit()
|
||||
body.knockback()
|
||||
EventBus.debug_print.emit("Hit: " + bname)
|
||||
else:
|
||||
EventBus.debug_print.emit("Hitbox touched " + bname + " but it lacks 'reduce_health' method.")
|
||||
if body is Player and not from_player and not hitplayer:
|
||||
var bname := str(body.name)
|
||||
if body.has_method("hit"):
|
||||
hitplayer = true
|
||||
body.hit()
|
||||
onhit.emit()
|
||||
EventBus.debug_print.emit("Hit: " + bname)
|
||||
else:
|
||||
EventBus.debug_print.emit("Hitbox touched " + bname + " but it lacks 'reduce_health' method.")
|
||||
EventBus.debug_print.emit(str(body))
|
||||
if body is TileMapLayer:
|
||||
onhit.emit()
|
||||
1
scripts/hitbox.gd.uid
Normal file
1
scripts/hitbox.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ejd25ul4j5pp
|
||||
119
scripts/magic_circle.gd
Normal file
119
scripts/magic_circle.gd
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
@tool
|
||||
class_name MagicCircle extends Node2D
|
||||
|
||||
|
||||
@export var base_rad : float = 20;
|
||||
@export var layer_rad_inc : float = 1.1;
|
||||
@export var layers : int = 10
|
||||
@export var vis_layers : float = 10.0
|
||||
@export var main_color : Color = Color(1, 1, 1, 1)
|
||||
@export var fixed_seed : int = 1234;
|
||||
@export var squish : float = 0.7
|
||||
@export var rot_speed : float = 0.1;
|
||||
@export var line_width : float = 0.6
|
||||
|
||||
var runes : Texture2D = load("res://assets/runes.png");
|
||||
|
||||
var rot = 0;
|
||||
var time = 0;
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready():
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(_delta):
|
||||
queue_redraw()
|
||||
|
||||
# absloute angle, NO rot
|
||||
func _draw_arc(radius, start_angle, end_angle, color, segments=10):
|
||||
var segment_size : float = (end_angle - start_angle) / segments
|
||||
var last_pos = Vector2(cos(start_angle), sin(start_angle)) * radius
|
||||
for i in range(segments+1):
|
||||
var angle = start_angle + (i * segment_size)
|
||||
|
||||
var next_pos = Vector2(cos(angle), sin(angle)) * radius
|
||||
draw_line(last_pos, next_pos, color, line_width)
|
||||
last_pos = next_pos
|
||||
|
||||
# yes rot
|
||||
func _draw_circle(radius, small_circles, small_radius, color, segments = 50):
|
||||
if (small_circles == 0):
|
||||
_draw_arc(radius, 0, 2*PI, color, segments)
|
||||
return
|
||||
|
||||
var arc_segments = segments / small_circles
|
||||
var arc_size = (2*PI) / small_circles
|
||||
# arc_length = angle * radius
|
||||
# angle = arc_length / radius
|
||||
var small_circle_angle = (small_radius / radius)
|
||||
|
||||
for i in range(small_circles):
|
||||
var small_angle = i * arc_size;
|
||||
var start_angle = i * arc_size + small_circle_angle
|
||||
var end_angle = (i + 1) * arc_size - small_circle_angle
|
||||
_draw_arc(radius, start_angle, end_angle, color, arc_segments)
|
||||
|
||||
var circle_pos = Vector2(cos(small_angle), sin(small_angle)) * radius
|
||||
draw_arc(circle_pos, small_radius, 0, 2*PI, 10, color, line_width)
|
||||
_draw_rand_rune(circle_pos, color)
|
||||
|
||||
func _draw_text_circle(radius, rune_num, color, segments = 50):
|
||||
_draw_circle(radius + 10, 0, 0, color, segments)
|
||||
_draw_circle(radius - 10, 0, 0, color, segments)
|
||||
var rune_diff = (2 * PI) / rune_num
|
||||
for i in range(rune_num):
|
||||
var angle = i * rune_diff
|
||||
var pos = Vector2(cos(angle), sin(angle)) * radius
|
||||
_draw_rand_rune(pos, color)
|
||||
|
||||
# yes rot
|
||||
func _draw_polygon(radius, segments, skip, color):
|
||||
var segment_angle = (2*PI) / segments
|
||||
var last_pos = Vector2(1, 0) * radius
|
||||
for i in range(segments +1):
|
||||
var angle = (i * skip) * segment_angle
|
||||
var next_pos = Vector2(cos(angle), sin(angle)) * radius
|
||||
draw_line(last_pos, next_pos, color, line_width)
|
||||
|
||||
last_pos = next_pos
|
||||
|
||||
func _draw_rand_rune(draw_pos, color):
|
||||
var pos = draw_pos
|
||||
pos.x -= 5;#
|
||||
pos.y -= 5
|
||||
draw_texture_rect_region(runes, Rect2(pos.x, pos.y, 10, 10), Rect2(rand_r(0, 4) * 10, 0, 10, 10), color)
|
||||
|
||||
# inclusive
|
||||
func rand_r(min_v, max_v):
|
||||
return randi() % (max_v - min_v + 1) + min_v
|
||||
|
||||
|
||||
func _draw():
|
||||
seed(fixed_seed)
|
||||
for i in range(1, layers):
|
||||
var layer_type = randf();
|
||||
var layer_counter = float(i) / layers # 0 - 1
|
||||
var layer_inv_counter = 1 - layer_counter # 1 - 0
|
||||
|
||||
var layer_dir = -1 if rand_r(0, 1) else 1;
|
||||
var layer_rot_mult = rand_r(1, 12) * rot_speed * layer_dir
|
||||
var layer_rot = Time.get_ticks_msec() * layer_inv_counter * layer_rot_mult * 0.001;
|
||||
|
||||
var layer_radius = i * pow(base_rad, layer_rad_inc)
|
||||
var layer_color = main_color
|
||||
layer_color.a = clamp(vis_layers - i, 0, 1)
|
||||
|
||||
draw_set_transform(Vector2.ZERO, layer_rot, Vector2(1, squish))
|
||||
if layer_type < 0.2:
|
||||
var small_circles = rand_r(0, 5)
|
||||
var small_radius = layer_radius * 0.1
|
||||
_draw_circle(layer_radius, small_circles, small_radius, layer_color)
|
||||
elif layer_type < 0.7:
|
||||
var vertices = rand_r(5, 8)
|
||||
var skip = rand_r(1, 2)
|
||||
_draw_polygon(layer_radius, vertices, skip, layer_color)
|
||||
elif layer_type <= 1:
|
||||
var rune_num = round(4 + layer_counter * 32)
|
||||
_draw_text_circle(layer_radius, rune_num, layer_color)
|
||||
1
scripts/magic_circle.gd.uid
Normal file
1
scripts/magic_circle.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://pyblew2m6xc3
|
||||
30
scripts/mask_bar.gd
Normal file
30
scripts/mask_bar.gd
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
extends TextureProgressBar
|
||||
|
||||
@export var threshold: float = 0.5
|
||||
@export var shake_intensity: float = 5.0
|
||||
|
||||
var original_x: float
|
||||
|
||||
func _ready() -> void:
|
||||
EventBus.mask_time_changed.connect(_on_time_changed)
|
||||
original_x = position.x
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if value / max_value <= threshold:
|
||||
apply_effects()
|
||||
else:
|
||||
position.x = original_x
|
||||
modulate = Color.WHITE
|
||||
|
||||
func _on_time_changed(new: float) -> void:
|
||||
value = new
|
||||
|
||||
func apply_effects() -> void:
|
||||
var danger_factor = 1.0 - (value / (max_value * threshold))
|
||||
danger_factor = clamp(danger_factor, 0.0, 1.0)
|
||||
|
||||
var flash = (sin(Time.get_ticks_msec() * 0.02) + 1.0) / 2.0
|
||||
modulate = Color.WHITE * (1 + flash * danger_factor)
|
||||
|
||||
var shake = sin(Time.get_ticks_msec() * 0.05) * shake_intensity * danger_factor
|
||||
position.x = original_x + shake
|
||||
1
scripts/mask_bar.gd.uid
Normal file
1
scripts/mask_bar.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cqrqqn2p0h0kb
|
||||
65
scripts/mask_drop.gd
Normal file
65
scripts/mask_drop.gd
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
class_name MaskDrop extends Node2D
|
||||
|
||||
@export var mask_type : Types.mask_types
|
||||
@onready var popup := $Popup
|
||||
@export var time_to_live = 14
|
||||
@export var initial_blink_speed: float = 0.7
|
||||
|
||||
var alive_time = 0
|
||||
var target_position : Vector2
|
||||
@onready var blink_timer = $Timer
|
||||
|
||||
func _ready() -> void:
|
||||
blink_timer.wait_time = initial_blink_speed
|
||||
blink_timer.timeout.connect(_on_timeout)
|
||||
blink_timer.start()
|
||||
blink_timer.paused = true
|
||||
$MeleeMask.rotate(randf() * PI - (PI / 2))
|
||||
$RangedMask.rotate(randf() * PI - (PI / 2))
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
alive_time += delta
|
||||
$MeleeMask.visible = false
|
||||
$RangedMask.visible = false
|
||||
$SpitMask.visible = false
|
||||
if (mask_type == Types.mask_types.Melee):
|
||||
$MeleeMask.visible = true
|
||||
elif (mask_type == Types.mask_types.Ranged):
|
||||
$RangedMask.visible = true
|
||||
elif (mask_type == Types.mask_types.Spit):
|
||||
$SpitMask.visible = true
|
||||
|
||||
var progress = alive_time / time_to_live
|
||||
if progress > 0.5:
|
||||
blink_timer.paused = false
|
||||
blink_timer.wait_time = lerp(initial_blink_speed, 0.02, progress)
|
||||
|
||||
if alive_time >= time_to_live:
|
||||
queue_free()
|
||||
|
||||
func show_popup():
|
||||
var tween = create_tween()
|
||||
tween.tween_property(popup, "modulate:a", 1, 0.2)
|
||||
tween.parallel().tween_property(popup, "position:y", -23, 0.2)
|
||||
|
||||
func hide_popup():
|
||||
var tween = create_tween()
|
||||
tween.tween_property(popup, "modulate:a", 0, 0.2)
|
||||
tween.parallel().tween_property(popup, "position:y", -16, 0.2)
|
||||
|
||||
func collect(target : Vector2):
|
||||
target_position = target
|
||||
var tween = create_tween()
|
||||
tween.set_trans(Tween.TRANS_EXPO)
|
||||
|
||||
tween.tween_method(_lerp_to_target, 0.0, 1.0, 0.3)
|
||||
|
||||
func _lerp_to_target(progression:float):
|
||||
global_position = lerp(global_position, target_position, progression)
|
||||
|
||||
if global_position.distance_to(target_position)<=10.0:
|
||||
queue_free()
|
||||
|
||||
func _on_timeout():
|
||||
|
||||
visible = !visible
|
||||
1
scripts/mask_drop.gd.uid
Normal file
1
scripts/mask_drop.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c576b1a6s5vw
|
||||
39
scripts/mask_ui.gd
Normal file
39
scripts/mask_ui.gd
Normal file
|
|
@ -0,0 +1,39 @@
|
|||
extends Label
|
||||
|
||||
var cur_mask : Types.mask_types
|
||||
var uses : int
|
||||
var health : int
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
EventBus.mask_changed.connect(_on_mask_changed)
|
||||
EventBus.mask_uses_changed.connect(_on_uses_changed)
|
||||
EventBus.health_changed.connect(_on_health_changed)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
update_text()
|
||||
|
||||
func update_text():
|
||||
var enemies = len(get_tree().get_nodes_in_group("enemy"))
|
||||
text = "Mask: " + _get_mask_name(cur_mask) + "\n" + \
|
||||
"Uses: " + str(uses) + "\n" + \
|
||||
"Health: " + str(health) + "\n" + \
|
||||
"Enemies: " + str(enemies)
|
||||
|
||||
func _get_mask_name(type : Types.mask_types):
|
||||
if (type == 0): return "Melee"
|
||||
if (type == 1): return "Ranged"
|
||||
if (type == 2): return "Spit"
|
||||
return ""
|
||||
|
||||
func _on_mask_changed(new : Types.mask_types):
|
||||
cur_mask = new
|
||||
update_text()
|
||||
|
||||
func _on_uses_changed(new : int):
|
||||
uses = new
|
||||
update_text()
|
||||
|
||||
func _on_health_changed(new : int):
|
||||
health = new
|
||||
update_text()
|
||||
1
scripts/mask_ui.gd.uid
Normal file
1
scripts/mask_ui.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cdm0kcipvrxyo
|
||||
25
scripts/portal.gd
Normal file
25
scripts/portal.gd
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
extends Sprite2D
|
||||
|
||||
@export var nextScene : String
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
var enemies = len(get_tree().get_nodes_in_group("enemy"))
|
||||
var player = get_tree().get_first_node_in_group("player")
|
||||
|
||||
if enemies == 0 and player:
|
||||
material.set_shader_parameter("intensity", 1.7)
|
||||
$MagicCircle.visible = true
|
||||
$Text.visible = true
|
||||
var player_dist = player.global_position.distance_to(global_position)
|
||||
if Input.is_action_just_pressed("interact") && player_dist < 70:
|
||||
SceneTransition.change_scene(nextScene)
|
||||
else:
|
||||
material.set_shader_parameter("intensity", 0)
|
||||
$MagicCircle.visible = false
|
||||
$Text.visible = false
|
||||
1
scripts/portal.gd.uid
Normal file
1
scripts/portal.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cioob0euvug4e
|
||||
20
scripts/proximity.gd
Normal file
20
scripts/proximity.gd
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
extends Node2D
|
||||
|
||||
@export var range : int = 50
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if has_node("%Player"):
|
||||
if %Player.global_position.distance_to(global_position) < range:
|
||||
show_ins()
|
||||
else:
|
||||
hide_ins()
|
||||
|
||||
func show_ins():
|
||||
var tween = create_tween()
|
||||
tween.tween_property(self, "modulate:a", 1, 0.2)
|
||||
tween.parallel().tween_property(self, "position:y", -23, 0.2)
|
||||
|
||||
func hide_ins():
|
||||
var tween = create_tween()
|
||||
tween.tween_property(self, "modulate:a", 0, 0.2)
|
||||
tween.parallel().tween_property(self, "position:y", -16, 0.2)
|
||||
1
scripts/proximity.gd.uid
Normal file
1
scripts/proximity.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c0wn3w7q2j470
|
||||
6
scripts/ranged_enemy.gd
Normal file
6
scripts/ranged_enemy.gd
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
extends Enemy
|
||||
|
||||
func _draw():
|
||||
if charge > 0.1:
|
||||
var color = Color.RED.lerp(Color.WHITE, charge / charge_time)
|
||||
draw_dashed_line(Vector2.ZERO, to_local(player.global_position), color, 1, 5)
|
||||
1
scripts/ranged_enemy.gd.uid
Normal file
1
scripts/ranged_enemy.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://buamdls133c2e
|
||||
8
scripts/scithe_attack.gd
Normal file
8
scripts/scithe_attack.gd
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
extends Node2D
|
||||
|
||||
|
||||
func set_from_player(val):
|
||||
$Anchor/Scithe/Hitbox.from_player = val
|
||||
|
||||
func _on_animation_player_animation_finished(_anim_name: StringName) -> void:
|
||||
queue_free()
|
||||
1
scripts/scithe_attack.gd.uid
Normal file
1
scripts/scithe_attack.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c1anp8np0aw0
|
||||
51
scripts/settings_menu.gd
Normal file
51
scripts/settings_menu.gd
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
extends NinePatchRect
|
||||
|
||||
@export var volume_slider : HSlider
|
||||
@export var fullscreen_check : CheckBox
|
||||
@export var vsync_check : CheckBox
|
||||
|
||||
|
||||
func _ready():
|
||||
_update_settings()
|
||||
|
||||
Settings.apply_all()
|
||||
|
||||
func _update_settings():
|
||||
volume_slider.value = Settings.master_volume
|
||||
fullscreen_check.button_pressed = Settings.fullscreen
|
||||
vsync_check.button_pressed = Settings.vsync
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
_update_settings()
|
||||
if (event.is_action_pressed("ui_cancel")):
|
||||
get_viewport().set_input_as_handled()
|
||||
visible = !visible
|
||||
get_tree().paused = visible
|
||||
elif (event.is_action_pressed("fullscreen")):
|
||||
get_viewport().set_input_as_handled()
|
||||
Settings.fullscreen = !Settings.fullscreen
|
||||
Settings.apply_fullscreen()
|
||||
|
||||
func _on_volume_changed(value: float):
|
||||
Settings.master_volume = value
|
||||
Settings.apply_volume()
|
||||
|
||||
func _on_fullscreen_toggled(enabled: bool):
|
||||
Settings.fullscreen = enabled
|
||||
Settings.apply_fullscreen()
|
||||
|
||||
func _on_max_fps_changed(value: float):
|
||||
Settings.max_fps = int(value)
|
||||
Settings.apply_max_fps()
|
||||
|
||||
func _on_vsync_toggled(enabled : bool):
|
||||
Settings.vsync = enabled
|
||||
Settings.apply_vsync()
|
||||
|
||||
func _on_exit_button_pressed() -> void:
|
||||
get_tree().quit()
|
||||
|
||||
|
||||
func _on_continue_button_pressed() -> void:
|
||||
visible = false
|
||||
get_tree().paused = visible
|
||||
1
scripts/settings_menu.gd.uid
Normal file
1
scripts/settings_menu.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://c62xd44e27oki
|
||||
10
scripts/shadow.gd
Normal file
10
scripts/shadow.gd
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
@tool
|
||||
class_name Shadow extends Node2D
|
||||
|
||||
@export var shadow_color: Color = Color(0, 0, 0, 0.3) # Semi-transparent black
|
||||
@export var shadow_size: float = 12
|
||||
|
||||
|
||||
func _draw():
|
||||
draw_set_transform(Vector2.ZERO, 0, Vector2(1, 0.7))
|
||||
draw_circle(Vector2.ZERO, shadow_size, shadow_color, true)
|
||||
1
scripts/shadow.gd.uid
Normal file
1
scripts/shadow.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://synocbtvgrf4
|
||||
12
scripts/singletons/event_bus.gd
Normal file
12
scripts/singletons/event_bus.gd
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
extends Node
|
||||
|
||||
signal dialogue_requested(text: String)
|
||||
signal dialogue_finished()
|
||||
signal debug_print(text : String)
|
||||
signal mask_changed(new : Types.mask_types)
|
||||
signal mask_uses_changed(new : int)
|
||||
signal health_changed(new : int)
|
||||
signal player_dmg()
|
||||
signal screenshake(intensity : float)
|
||||
signal mask_time_changed(time : float)
|
||||
signal cut_grass_at(p, r)
|
||||
1
scripts/singletons/event_bus.gd.uid
Normal file
1
scripts/singletons/event_bus.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://b31uw84k0w7x3
|
||||
71
scripts/singletons/scene_transition.gd
Normal file
71
scripts/singletons/scene_transition.gd
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
extends CanvasLayer
|
||||
|
||||
@onready var rect = $ColorRect
|
||||
@onready var log_display = $RichTextLabel
|
||||
|
||||
func _ready():
|
||||
rect.modulate.a = 0
|
||||
log_display.text = ""
|
||||
log_display.visible = false
|
||||
# Ensure the rect doesn't block clicks while invisible
|
||||
rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
## Combined function to handle both success and error transitions
|
||||
func change_scene(target_path: String, is_error: bool = false):
|
||||
rect.mouse_filter = Control.MOUSE_FILTER_STOP
|
||||
|
||||
# Set color based on status
|
||||
if is_error:
|
||||
rect.color = Color.CRIMSON
|
||||
else:
|
||||
rect.color = Color.from_string("#364388", Color.BLUE)
|
||||
|
||||
# Fade In
|
||||
var tween_in = create_tween()
|
||||
await tween_in.tween_property(rect, "modulate:a", 1.0, 0.3).finished
|
||||
|
||||
# Display Log
|
||||
log_display.visible = true
|
||||
var log_file = "res://hex.txt" if is_error else "res://log.txt"
|
||||
await display_log_file(log_file)
|
||||
|
||||
await get_tree().create_timer(0.5).timeout
|
||||
|
||||
# Change Scene
|
||||
var error = get_tree().change_scene_to_file(target_path)
|
||||
if error != OK:
|
||||
push_error("Failed to load scene: " + target_path)
|
||||
|
||||
# Cleanup and Fade Out
|
||||
log_display.visible = false
|
||||
log_display.text = ""
|
||||
|
||||
var tween_out = create_tween()
|
||||
await tween_out.tween_property(rect, "modulate:a", 0.0, 0.5).finished
|
||||
rect.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
func display_log_file(file_path: String):
|
||||
if not FileAccess.file_exists(file_path):
|
||||
log_display.add_text("ERROR: " + file_path + " not found in build.\n")
|
||||
# Check Project -> Export -> Resources -> Filters to include non-resource files
|
||||
return
|
||||
|
||||
var file = FileAccess.open(file_path, FileAccess.READ)
|
||||
if not file:
|
||||
log_display.add_text("ERROR: Could not open file.\n")
|
||||
return
|
||||
|
||||
# Reading line by line for that "hacker" effect
|
||||
while not file.eof_reached():
|
||||
var line = file.get_line()
|
||||
if line.strip_edges() == "": continue # Skip empty lines if desired
|
||||
|
||||
log_display.add_text(line + "\n")
|
||||
# Auto-scroll to bottom
|
||||
log_display.scroll_to_line(log_display.get_line_count())
|
||||
|
||||
var delay = 0#randf_range(0.0001, 0.00015)
|
||||
#if randf() > 0.95:
|
||||
#delay += 0.2 # Random "loading" hitch for realism
|
||||
|
||||
await get_tree().create_timer(delay).timeout
|
||||
1
scripts/singletons/scene_transition.gd.uid
Normal file
1
scripts/singletons/scene_transition.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dktk18oihl6xf
|
||||
36
scripts/singletons/settings.gd
Normal file
36
scripts/singletons/settings.gd
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
extends Node
|
||||
|
||||
var master_volume: float = 1.0
|
||||
var fullscreen: bool = false
|
||||
var vsync : bool = false
|
||||
var max_fps: int = 60
|
||||
|
||||
func apply_volume():
|
||||
var bus_index := AudioServer.get_bus_index("Master")
|
||||
AudioServer.set_bus_volume_db(
|
||||
bus_index,
|
||||
linear_to_db(master_volume)
|
||||
)
|
||||
|
||||
func apply_fullscreen():
|
||||
DisplayServer.window_set_mode(
|
||||
DisplayServer.WINDOW_MODE_FULLSCREEN if fullscreen
|
||||
else DisplayServer.WINDOW_MODE_WINDOWED
|
||||
)
|
||||
if not fullscreen:
|
||||
get_window().size = Vector2i(480*3, 270*3);
|
||||
|
||||
func apply_vsync():
|
||||
DisplayServer.window_set_vsync_mode(
|
||||
DisplayServer.VSYNC_ENABLED if vsync
|
||||
else DisplayServer.VSYNC_DISABLED
|
||||
)
|
||||
|
||||
func apply_max_fps():
|
||||
Engine.max_fps = max_fps
|
||||
|
||||
func apply_all():
|
||||
apply_volume()
|
||||
apply_fullscreen()
|
||||
apply_vsync()
|
||||
apply_max_fps()
|
||||
1
scripts/singletons/settings.gd.uid
Normal file
1
scripts/singletons/settings.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://cyoitmcbh2sw5
|
||||
72
scripts/singletons/sound_manager.gd
Normal file
72
scripts/singletons/sound_manager.gd
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
extends Node
|
||||
|
||||
const SFX_DEATH = preload("res://assets/sfx/death.mp3")
|
||||
const SFX_HEART = preload("res://assets/sfx/heart.mp3")
|
||||
const SFX_SWING = preload("res://assets/sfx/swing.mp3")
|
||||
const SFX_CLICK = preload("res://assets/sfx/click.mp3")
|
||||
|
||||
const MUSIC_TITLE = preload("res://assets/music/title.wav")
|
||||
|
||||
# Configuration
|
||||
var pool_size = 10
|
||||
var sfx_dict = {}
|
||||
var music_dict = {}
|
||||
var sfx_pool = []
|
||||
var current_pool_index = 0
|
||||
|
||||
@onready var music_player_1 := AudioStreamPlayer.new()
|
||||
@onready var music_player_2 := AudioStreamPlayer.new()
|
||||
|
||||
func _ready():
|
||||
process_mode = Node.PROCESS_MODE_ALWAYS
|
||||
|
||||
sfx_dict = {
|
||||
"death": SFX_DEATH,
|
||||
"heart": SFX_HEART,
|
||||
"swing": SFX_SWING,
|
||||
"click": SFX_CLICK
|
||||
}
|
||||
|
||||
music_dict = {
|
||||
"title": MUSIC_TITLE
|
||||
}
|
||||
|
||||
for i in range(pool_size):
|
||||
var asp = AudioStreamPlayer.new()
|
||||
asp.bus = "SFX"
|
||||
add_child(asp)
|
||||
sfx_pool.append(asp)
|
||||
|
||||
add_child(music_player_1)
|
||||
add_child(music_player_2)
|
||||
music_player_1.bus = "Music"
|
||||
music_player_2.bus = "Music"
|
||||
|
||||
|
||||
func play_sfx(sound_name: String):
|
||||
if sfx_dict.has(sound_name):
|
||||
var asp : AudioStreamPlayer = sfx_pool[current_pool_index]
|
||||
asp.stream = sfx_dict[sound_name]
|
||||
asp.play()
|
||||
current_pool_index = (current_pool_index + 1) % pool_size
|
||||
|
||||
func play_music(music_name: String, fade_duration: float = 1.0):
|
||||
if not music_dict.has(music_name): return
|
||||
var next_track = music_dict[music_name]
|
||||
|
||||
|
||||
var active = music_player_1 if music_player_1.playing else music_player_2
|
||||
var idle = music_player_2 if music_player_1.playing else music_player_1
|
||||
|
||||
if active.stream == next_track: return
|
||||
|
||||
idle.stream = next_track
|
||||
idle.volume_db = -80
|
||||
idle.play()
|
||||
|
||||
var tween = create_tween().set_parallel(true)
|
||||
tween.tween_property(active, "volume_db", -80, fade_duration)
|
||||
tween.tween_property(idle, "volume_db", 0, fade_duration)
|
||||
|
||||
await tween.finished
|
||||
active.stop()
|
||||
1
scripts/singletons/sound_manager.gd.uid
Normal file
1
scripts/singletons/sound_manager.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://buunplrqixmky
|
||||
7
scripts/singletons/types.gd
Normal file
7
scripts/singletons/types.gd
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
extends Node
|
||||
|
||||
enum mask_types {
|
||||
Melee,
|
||||
Ranged,
|
||||
Spit
|
||||
}
|
||||
1
scripts/singletons/types.gd.uid
Normal file
1
scripts/singletons/types.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ixakrcerxwlj
|
||||
3
scripts/singletons/world_state.gd
Normal file
3
scripts/singletons/world_state.gd
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
extends Node
|
||||
|
||||
var done_tuto = false
|
||||
1
scripts/singletons/world_state.gd.uid
Normal file
1
scripts/singletons/world_state.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://csi5hjjkyps56
|
||||
9
scripts/slash.gd
Normal file
9
scripts/slash.gd
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
extends AnimatedSprite2D
|
||||
|
||||
var from_player := false
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
$Hitbox.from_player = from_player
|
||||
|
||||
func _on_animation_finished() -> void:
|
||||
queue_free()
|
||||
1
scripts/slash.gd.uid
Normal file
1
scripts/slash.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://8it3jqarby3f
|
||||
45
scripts/spit.gd
Normal file
45
scripts/spit.gd
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
extends Node2D
|
||||
|
||||
@export var speed: float = 400.0
|
||||
@export var max_height: float = 100.0
|
||||
@export var payload : PackedScene
|
||||
var target_position: Vector2
|
||||
|
||||
@onready var sprite = $Bomb
|
||||
|
||||
var start_position: Vector2
|
||||
var distance_total: float
|
||||
var distance_covered: float = 0.0
|
||||
|
||||
var from_player = true
|
||||
|
||||
func set_from_player(value):
|
||||
from_player = value
|
||||
|
||||
func _ready():
|
||||
start_position = global_position
|
||||
distance_total = 150
|
||||
|
||||
func _process(delta):
|
||||
if distance_covered < distance_total:
|
||||
distance_covered += speed * delta
|
||||
var t = clamp(distance_covered / distance_total, 0.0, 1.0)
|
||||
|
||||
global_position = start_position.lerp(target_position, t)
|
||||
|
||||
var arc_y = 4 * max_height * t * (1 - t)
|
||||
|
||||
sprite.position.y = -arc_y
|
||||
else:
|
||||
global_position = target_position
|
||||
sprite.position.y = 0
|
||||
set_process(false)
|
||||
on_arrival()
|
||||
|
||||
func on_arrival():
|
||||
EventBus.screenshake.emit(1)
|
||||
var ins = payload.instantiate()
|
||||
ins.set_from_player(from_player)
|
||||
ins.global_position = global_position
|
||||
get_parent().add_child(ins)
|
||||
queue_free()
|
||||
1
scripts/spit.gd.uid
Normal file
1
scripts/spit.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://ctninfm8hkbp2
|
||||
14
scripts/spit_dragon.gd
Normal file
14
scripts/spit_dragon.gd
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
extends Enemy
|
||||
|
||||
func _draw():
|
||||
if charge > 0.1:
|
||||
var color = Color.RED.lerp(Color.WHITE, charge / charge_time)
|
||||
if player:
|
||||
draw_dashed_line(Vector2.ZERO, to_local(player.global_position), color, 1, 5)
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
super._process(delta)
|
||||
if (charge > 0.1):
|
||||
$Anim.play("attack")
|
||||
else:
|
||||
$Anim.play("default")
|
||||
1
scripts/spit_dragon.gd.uid
Normal file
1
scripts/spit_dragon.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://bpabecs0hf676
|
||||
10
scripts/spit_payload.gd
Normal file
10
scripts/spit_payload.gd
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
extends CPUParticles2D
|
||||
|
||||
func _ready() -> void:
|
||||
emitting = true
|
||||
|
||||
func set_from_player(value):
|
||||
$Hitbox.from_player = value
|
||||
|
||||
func _on_finished() -> void:
|
||||
queue_free()
|
||||
1
scripts/spit_payload.gd.uid
Normal file
1
scripts/spit_payload.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://8bsq7kvqky3d
|
||||
15
scripts/world_logic.gd
Normal file
15
scripts/world_logic.gd
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
extends Node2D
|
||||
|
||||
|
||||
# Called when the node enters the scene tree for the first time.
|
||||
func _ready() -> void:
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
# Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
func _process(delta: float) -> void:
|
||||
var player = get_tree().get_first_node_in_group("player")
|
||||
if player:
|
||||
if player.global_position.distance_to(global_position) > 600:
|
||||
player.hit()
|
||||
pass
|
||||
1
scripts/world_logic.gd.uid
Normal file
1
scripts/world_logic.gd.uid
Normal file
|
|
@ -0,0 +1 @@
|
|||
uid://dihbkd2fiwb8b
|
||||
Loading…
Add table
Add a link
Reference in a new issue