More map work, new teleporter logic, ball course puzzle logic and camera shake logic

master
Wynd 2024-09-21 18:25:26 +03:00
parent 13a1e445b9
commit 167d48cbcf
27 changed files with 826 additions and 156 deletions

View File

@ -5,6 +5,7 @@ extends CharacterBody2D
@onready var sprite: Sprite2D = $Sprite2D @onready var sprite: Sprite2D = $Sprite2D
@onready var map: MainLevel = get_tree().root.get_child(0).get_node("TileMap") @onready var map: MainLevel = get_tree().root.get_child(0).get_node("TileMap")
@onready var tile_map: TileMapLayer = get_tree().root.get_child(0).get_node("TileMap/TileMapLayer") @onready var tile_map: TileMapLayer = get_tree().root.get_child(0).get_node("TileMap/TileMapLayer")
@onready var camera: Camera2D = $Sprite2D/Camera2D
@export var speed: float = 40 @export var speed: float = 40
@export var respawn_point: Marker2D @export var respawn_point: Marker2D
@ -16,6 +17,10 @@ var should_move = false
var is_dead = false var is_dead = false
var input_dir: Vector2 var input_dir: Vector2
var respawn_time: int = 10 var respawn_time: int = 10
var can_teleport := true
var rng := RandomNumberGenerator.new()
var camera_shake: float = 0.0
var camera_shake_fade: float = 0.0
func _ready(): func _ready():
_respawn() _respawn()
@ -25,6 +30,7 @@ func _process(delta):
if not is_dead: if not is_dead:
_try_get_input() _try_get_input()
_try_interact() _try_interact()
_shake_camera(delta)
if is_dead: if is_dead:
if respawn_time > 0: if respawn_time > 0:
respawn_time -= 1 respawn_time -= 1
@ -95,6 +101,10 @@ func die():
is_moving = false is_moving = false
respawn_time = 10 respawn_time = 10
func apply_camera_shake(strength: float = 10.0, fade: float = 5.0):
camera_shake = strength
camera_shake_fade = fade
func _try_interact(): func _try_interact():
raycast.target_position = input_dir * 8 raycast.target_position = input_dir * 8
raycast.force_raycast_update() raycast.force_raycast_update()
@ -105,3 +115,16 @@ func _try_interact():
(collider as PuzzleElement).interact(self) (collider as PuzzleElement).interact(self)
pass pass
pass pass
func teleport(pos: Vector2i):
global_position = pos
can_teleport = false
func _shake_camera(delta):
if camera_shake > 0:
camera_shake = lerpf(camera_shake, 0, camera_shake_fade * delta)
camera.offset = Vector2(rng.randf_range(-camera_shake, camera_shake), rng.randf_range(-camera_shake, camera_shake))
func _on_area_entered(area: Area2D):
if area.is_in_group("death"):
die()

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=7 format=3 uid="uid://dpn82ibpmpb6u"] [gd_scene load_steps=8 format=3 uid="uid://dpn82ibpmpb6u"]
[ext_resource type="Script" path="res://entities/player/player.gd" id="1_jrd75"] [ext_resource type="Script" path="res://entities/player/player.gd" id="1_jrd75"]
[ext_resource type="Texture2D" uid="uid://dxkxa6e6ue1b6" path="res://entities/assets/bat.png" id="1_qfnf0"] [ext_resource type="Texture2D" uid="uid://dxkxa6e6ue1b6" path="res://entities/assets/bat.png" id="1_qfnf0"]
@ -44,6 +44,9 @@ _data = {
[sub_resource type="RectangleShape2D" id="RectangleShape2D_l7fhd"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_l7fhd"]
size = Vector2(8, 8) size = Vector2(8, 8)
[sub_resource type="RectangleShape2D" id="RectangleShape2D_x0fgp"]
size = Vector2(6, 6)
[node name="Player" type="CharacterBody2D"] [node name="Player" type="CharacterBody2D"]
z_index = 10 z_index = 10
collision_mask = 15 collision_mask = 15
@ -68,3 +71,12 @@ shape = SubResource("RectangleShape2D_l7fhd")
[node name="RayCast2D" type="RayCast2D" parent="."] [node name="RayCast2D" type="RayCast2D" parent="."]
target_position = Vector2(0, 8) target_position = Vector2(0, 8)
collision_mask = 3 collision_mask = 3
[node name="Area2D" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
shape = SubResource("RectangleShape2D_x0fgp")
[node name="AudioStreamPlayer2D" type="AudioStreamPlayer2D" parent="."]
[connection signal="area_entered" from="Area2D" to="." method="_on_area_entered"]

View File

@ -31,9 +31,9 @@ func _on_shoot_timer_timeout():
add_child(inst) add_child(inst)
_arrows_shot.push_back(inst) _arrows_shot.push_back(inst)
func _on_visibility_changed(): func reset():
for arrow in _arrows_shot: for arrow in _arrows_shot:
if arrow != null: if arrow != null:
arrow.queue_free() arrow.queue_free()
offset_start_time = _default_offset offset_start_time = _default_offset
is_stopped = !visible is_stopped = true

View File

@ -8,5 +8,4 @@ script = ExtResource("1_tk6ny")
[node name="ShootTimer" type="Timer" parent="."] [node name="ShootTimer" type="Timer" parent="."]
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
[connection signal="timeout" from="ShootTimer" to="." method="_on_shoot_timer_timeout"] [connection signal="timeout" from="ShootTimer" to="." method="_on_shoot_timer_timeout"]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 211 B

After

Width:  |  Height:  |  Size: 214 B

View File

@ -0,0 +1,77 @@
class_name Ball
extends StaticBody2D
@onready var raycast: RayCast2D = $RayCast2D
@onready var sprite: Sprite2D = $Sprite2D
@onready var animation_player: AnimationPlayer = $AnimationPlayer
@onready var map: MainLevel = get_tree().root.get_child(0).get_node("TileMap")
@onready var tile_map: TileMapLayer = get_tree().root.get_child(0).get_node("TileMap/TileMapLayer")
@onready var puzzle: BallCoursePuzzle = $"../"
@export var start_position: Node2D
@export var movement_dir: Vector2 = Vector2(0, 0)
var can_roll := false
var input_dir: Vector2
var is_moving := false
# Called when the node enters the scene tree for the first time.
func _ready():
reset()
input_dir = movement_dir.normalized()
func _physics_process(delta):
_try_move(delta)
func _process(delta):
if can_roll:
if not animation_player.is_playing():
animation_player.play(&"roll")
if is_moving:
return
raycast.target_position = input_dir * 8
raycast.force_raycast_update()
var collider: Node2D = raycast.get_collider()
if collider and collider.is_in_group("fake_wall"):
collider.queue_free()
queue_free()
if raycast.is_colliding():
return
var current_tile: Vector2i = tile_map.local_to_map(global_position)
var target_tile: Vector2i = Vector2i(
current_tile.x + input_dir.x,
current_tile.y + input_dir.y
)
global_position = tile_map.map_to_local(target_tile)
var is_death_tile = map.is_death_tile(global_position)
if is_death_tile:
reset()
return
is_moving = true
sprite.global_position = tile_map.map_to_local(current_tile)
func _try_move(delta: int):
if not is_moving:
return
sprite.global_position = sprite.global_position.move_toward(global_position, 0.35)
if global_position == sprite.global_position:
is_moving = false
return
func reset():
can_roll = false
animation_player.stop()
global_position = start_position.global_position
func _on_area_entered(area: Area2D):
if area.is_in_group("death"):
puzzle.reset()

View File

@ -1,18 +1,77 @@
[gd_scene load_steps=4 format=3 uid="uid://dtya31nfxo0h7"] [gd_scene load_steps=9 format=3 uid="uid://dtya31nfxo0h7"]
[ext_resource type="Texture2D" uid="uid://ccs76qyn4ua40" path="res://puzzles/assets/ball.png" id="1_3p6vy"] [ext_resource type="Texture2D" uid="uid://ccs76qyn4ua40" path="res://puzzles/assets/ball.png" id="1_3p6vy"]
[ext_resource type="Script" path="res://puzzles/ball/ball.gd" id="1_8r0ul"]
[sub_resource type="PhysicsMaterial" id="PhysicsMaterial_8in3v"] [sub_resource type="PhysicsMaterial" id="PhysicsMaterial_8in3v"]
[sub_resource type="Animation" id="Animation_2lwo2"]
length = 0.001
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite2D:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0),
"transitions": PackedFloat32Array(1),
"update": 0,
"values": [0.0]
}
[sub_resource type="Animation" id="Animation_r6vqa"]
resource_name = "roll"
length = 3.0
loop_mode = 1
tracks/0/type = "value"
tracks/0/imported = false
tracks/0/enabled = true
tracks/0/path = NodePath("Sprite2D:rotation")
tracks/0/interp = 1
tracks/0/loop_wrap = true
tracks/0/keys = {
"times": PackedFloat32Array(0, 3),
"transitions": PackedFloat32Array(1, 1),
"update": 0,
"values": [0.0, 6.28319]
}
[sub_resource type="AnimationLibrary" id="AnimationLibrary_srpra"]
_data = {
"RESET": SubResource("Animation_2lwo2"),
"roll": SubResource("Animation_r6vqa")
}
[sub_resource type="RectangleShape2D" id="RectangleShape2D_we7nh"] [sub_resource type="RectangleShape2D" id="RectangleShape2D_we7nh"]
size = Vector2(14, 14) size = Vector2(14, 14)
[sub_resource type="CircleShape2D" id="CircleShape2D_eid6d"]
radius = 7.0
[node name="Ball" type="StaticBody2D"] [node name="Ball" type="StaticBody2D"]
collision_layer = 2
physics_material_override = SubResource("PhysicsMaterial_8in3v") physics_material_override = SubResource("PhysicsMaterial_8in3v")
script = ExtResource("1_8r0ul")
[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
libraries = {
"": SubResource("AnimationLibrary_srpra")
}
autoplay = "roll"
[node name="Sprite2D" type="Sprite2D" parent="."] [node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("1_3p6vy") texture = ExtResource("1_3p6vy")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."] [node name="CollisionShape2D" type="CollisionShape2D" parent="."]
shape = SubResource("RectangleShape2D_we7nh") shape = SubResource("RectangleShape2D_we7nh")
[node name="RayCast2D" type="RayCast2D" parent="."]
target_position = Vector2(8, 0)
[node name="Area2D" type="Area2D" parent="."]
[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"]
shape = SubResource("CircleShape2D_eid6d")
[connection signal="visibility_changed" from="." to="." method="_on_visibility_changed"]
[connection signal="area_entered" from="Area2D" to="." method="_on_area_entered"]

View File

@ -0,0 +1,19 @@
class_name BallCoursePuzzle
extends Puzzle
@export var ball: Ball
@export var traps: Array[GroundButton]
func _process(delta):
var is_finished = true
if ball != null:
is_finished = false
if is_finished:
complete()
func reset():
ball.reset()
for trap in traps:
trap.reset()

View File

@ -0,0 +1,9 @@
class_name BallButton
extends GroundButton
@export var ball: Ball
func _flip():
sprite.frame = 1 if is_active else 0
if is_active and ball and not ball.can_roll:
ball.can_roll = true

View File

@ -4,18 +4,29 @@ extends Area2D
@onready var sprite = $Sprite2D @onready var sprite = $Sprite2D
@export var nodes: Array[Node2D] @export var nodes: Array[Node2D]
@export var is_active = false
var default_state = false
var is_active = false func _ready():
default_state = is_active
_flip()
func _on_body_entered(body): func _on_body_entered(body):
if body is Player: if body is Player:
is_active = not is_active is_active = not is_active
sprite.frame = 1 if is_active else 0 _flip()
for node in nodes:
if node is TileMapLayer: func _flip():
var layer = node as TileMapLayer $Sprite2D.frame = 1 if is_active else 0
layer.enabled = !layer.enabled for node in nodes:
else: if node is TileMapLayer:
node.visible = false if is_active else true var layer = node as TileMapLayer
node.process_mode = PROCESS_MODE_DISABLED if is_active else PROCESS_MODE_INHERIT layer.enabled = !layer.enabled
node.set_physics_process(!is_active) else:
node.visible = false if is_active else true
node.process_mode = PROCESS_MODE_DISABLED if is_active else PROCESS_MODE_INHERIT
node.set_physics_process(!is_active)
func reset():
is_active = default_state
_flip()

View File

@ -1,8 +1,10 @@
class_name Puzzle class_name Puzzle
extends Node extends Node
signal complete_puzzle(puzzle_name: String) @onready var sfx = preload("res://scenes/assets/jingles/win.wav")
@onready var audio_player: AudioStreamPlayer2D = get_tree().root.get_child(0).get_node("Player/AudioStreamPlayer2D")
signal complete_puzzle
var is_complete = false; var is_complete = false;
@ -12,4 +14,6 @@ func complete():
is_complete = true is_complete = true
audio_player.stream = sfx
audio_player.play()
complete_puzzle.emit() complete_puzzle.emit()

View File

@ -0,0 +1,14 @@
extends PuzzleManager
@onready var player: Player = get_tree().root.get_child(0).get_node("Player")
@export var ball_puzzle_elements: Array[Node2D]
func _on_finish_room():
pass
func _on_ball_puzzle_complete_puzzle():
player.apply_camera_shake(10, 5)
for elem in ball_puzzle_elements:
elem.queue_free()

View File

@ -0,0 +1,7 @@
extends PuzzleManager
@export var next_room_stairs: Node2D
func _on_finish_room():
next_room_stairs.visible = true
next_room_stairs.process_mode = Node.PROCESS_MODE_INHERIT

View File

@ -0,0 +1,22 @@
[gd_scene load_steps=4 format=3 uid="uid://dgatvman85cq7"]
[ext_resource type="Script" path="res://puzzles/teleporter/teleporter.gd" id="1_f3ibl"]
[ext_resource type="Texture2D" uid="uid://cbuibrshdpkm1" path="res://scenes/assets/tileset.png" id="2_obpvk"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kuq27"]
size = Vector2(6, 5)
[node name="Stairs" type="Area2D"]
script = ExtResource("1_f3ibl")
[node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("2_obpvk")
hframes = 8
vframes = 8
frame = 20
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(0, 0.5)
shape = SubResource("RectangleShape2D_kuq27")
[connection signal="body_entered" from="." to="." method="_on_body_entered"]

View File

@ -0,0 +1,22 @@
[gd_scene load_steps=4 format=3 uid="uid://36rwjmb572qd"]
[ext_resource type="Script" path="res://puzzles/teleporter/teleporter.gd" id="1_3xtjc"]
[ext_resource type="Texture2D" uid="uid://cbuibrshdpkm1" path="res://scenes/assets/tileset.png" id="2_j0ckt"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_kuq27"]
size = Vector2(6, 5)
[node name="Stairs" type="Area2D"]
script = ExtResource("1_3xtjc")
[node name="Sprite2D" type="Sprite2D" parent="."]
texture = ExtResource("2_j0ckt")
hframes = 8
vframes = 8
frame = 21
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(0, 0.5)
shape = SubResource("RectangleShape2D_kuq27")
[connection signal="body_entered" from="." to="." method="_on_body_entered"]

View File

@ -0,0 +1,16 @@
extends Area2D
# 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):
pass
func _on_body_exited(body):
if body is Player:
(body as Player).can_teleport = true

View File

@ -0,0 +1,15 @@
[gd_scene load_steps=3 format=3 uid="uid://cr5ddcb7bxa5x"]
[ext_resource type="Script" path="res://puzzles/teleporter/teleport_location.gd" id="1_tqrxf"]
[sub_resource type="RectangleShape2D" id="RectangleShape2D_xddm4"]
size = Vector2(7, 7)
[node name="TeleportLocation" type="Area2D"]
script = ExtResource("1_tqrxf")
[node name="CollisionShape2D" type="CollisionShape2D" parent="."]
position = Vector2(0.5, 0.5)
shape = SubResource("RectangleShape2D_xddm4")
[connection signal="body_exited" from="." to="." method="_on_body_exited"]

View File

@ -1,8 +1,7 @@
extends Area2D extends Area2D
@export var teleport_marker: Marker2D @export var teleport_marker: Node2D
func _on_body_entered(body): func _on_body_entered(body):
if body is Player: if body is Player and (body as Player).can_teleport:
body.global_position = teleport_marker.global_position (body as Player).teleport(teleport_marker.global_position)

View File

@ -1 +1 @@
3,0,0,0,120,16,4,1,204,0,1,128,0,256,1,0,0,0,0,4,36,1,3,0,39,1,2,0,40,1,1,0,41,1,0,0,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1, 3,0,0,0,120,16,4,1,62,0,2,128,0,256,1,0,0,0,0,3,41,4,2,0,44,4,0,0,47,4,3,0,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,

Binary file not shown.

View File

@ -2,7 +2,7 @@
importer="wav" importer="wav"
type="AudioStreamWAV" type="AudioStreamWAV"
uid="uid://dfc8jx220imb7" uid="uid://dvbepjvyfdw5k"
path="res://.godot/imported/fail.wav-c48208a4611d55d0dcd0f0dbeab5bae3.sample" path="res://.godot/imported/fail.wav-c48208a4611d55d0dcd0f0dbeab5bae3.sample"
[deps] [deps]

View File

@ -0,0 +1 @@
3,0,0,0,120,16,4,1,112,0,4,128,0,256,1,0,0,0,0,4,52,4,4,0,55,4,0,0,57,4,1,0,59,4,2,0,0,1,0,1,0,-1,-1,-1,-1,-1,-1,-1,

Binary file not shown.

View File

@ -0,0 +1,24 @@
[remap]
importer="wav"
type="AudioStreamWAV"
uid="uid://fhwh6f2jmr6m"
path="res://.godot/imported/win.wav-cc3fddf798237bb35a77f0272b1dd857.sample"
[deps]
source_file="res://scenes/assets/jingles/win.wav"
dest_files=["res://.godot/imported/win.wav-cc3fddf798237bb35a77f0272b1dd857.sample"]
[params]
force/8_bit=false
force/mono=false
force/max_rate=false
force/max_rate_hz=44100
edit/trim=false
edit/normalize=false
edit/loop_mode=0
edit/loop_begin=0
edit/loop_end=-1
compress/mode=0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 986 B

After

Width:  |  Height:  |  Size: 1018 B

File diff suppressed because one or more lines are too long