From c06e5a6ada74268ab47cec899d3c26f2b05846ac Mon Sep 17 00:00:00 2001 From: Wynd Date: Tue, 17 Sep 2024 21:37:22 +0300 Subject: [PATCH] Arrow shooters and better cell to cell movement for players --- entities/player/player.gd | 68 +++++++++++++++++++-------- entities/player/player.tscn | 6 +-- project.godot | 7 +++ puzzles/arrow/arrow.gd | 25 ++++++++++ puzzles/arrow/arrow.png | Bin 0 -> 117 bytes puzzles/arrow/arrow.png.import | 34 ++++++++++++++ puzzles/arrow/arrow.tscn | 21 +++++++++ puzzles/arrow/arrow_shooter.gd | 19 ++++++++ puzzles/arrow/arrow_shooter.tscn | 11 +++++ puzzles/button/button.gd | 5 +- puzzles/main_tile_layer.gd | 8 ++-- puzzles/room_manager/room_manager.gd | 2 +- scenes/assets/main_tileset.tres | 12 +++-- scenes/assets/tileset.png | Bin 701 -> 645 bytes scenes/main.tscn | 39 +++++++++++++-- 15 files changed, 221 insertions(+), 36 deletions(-) create mode 100644 puzzles/arrow/arrow.gd create mode 100644 puzzles/arrow/arrow.png create mode 100644 puzzles/arrow/arrow.png.import create mode 100644 puzzles/arrow/arrow.tscn create mode 100644 puzzles/arrow/arrow_shooter.gd create mode 100644 puzzles/arrow/arrow_shooter.tscn diff --git a/entities/player/player.gd b/entities/player/player.gd index 2236d05..0dd3744 100644 --- a/entities/player/player.gd +++ b/entities/player/player.gd @@ -2,7 +2,9 @@ class_name Player extends CharacterBody2D @onready var raycast: RayCast2D = $RayCast2D -@onready var tile_map: MainLevel = $"../TileMap" +@onready var sprite: Sprite2D = $Sprite2D +@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") @export var speed: float = 40 @export var respawn_point: Marker2D @@ -11,23 +13,35 @@ const TILE_SIZE = 8 var is_moving = false var should_move = false +var is_dead = false var input_dir: Vector2 +var respawn_time: int = 10 func _ready(): _respawn() pass func _process(delta): - _try_interact() - pass + if not is_dead: + _try_get_input() + _try_interact() + if is_dead: + if respawn_time > 0: + respawn_time -= 1 + elif respawn_time <= 0: + _respawn() func _physics_process(delta): - _try_move() + _try_move(delta) func _respawn(): position = respawn_point.position - -func _try_move(): + sprite.global_position = position + is_dead = false + is_moving = false + should_move = false + +func _try_get_input(): should_move = false if Input.is_action_pressed("move_up"): input_dir = Vector2.UP @@ -42,28 +56,44 @@ func _try_move(): input_dir = Vector2.LEFT should_move = true - if should_move and !is_moving: + if should_move and not is_moving: raycast.target_position = input_dir * 8 raycast.force_raycast_update() - + if raycast.is_colliding(): return - is_moving = true - var tween = create_tween() - tween.tween_property(self, "position", position + input_dir * TILE_SIZE, 0.25) - tween.tween_callback(func(): - is_moving = false - _post_movement_check() + 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 ) -func _post_movement_check(): - var is_death_tile = tile_map.is_death_tile(global_position) - if is_death_tile: - die() + global_position = tile_map.map_to_local(target_tile) + + var is_death_tile = map.is_death_tile(global_position) + if is_death_tile: + die() + return + + is_moving = true + sprite.global_position = tile_map.map_to_local(current_tile) + + +func _try_move(delta: int): + if not is_moving or is_dead: + return + + sprite.global_position = sprite.global_position.move_toward(global_position, 0.5) + + if global_position == sprite.global_position: + is_moving = false + return func die(): - _respawn() + is_dead = true + is_moving = false + respawn_time = 10 func _try_interact(): raycast.target_position = input_dir * 8 diff --git a/entities/player/player.tscn b/entities/player/player.tscn index eb2306b..6f9f49e 100644 --- a/entities/player/player.tscn +++ b/entities/player/player.tscn @@ -46,16 +46,16 @@ size = Vector2(8, 8) [node name="Player" type="CharacterBody2D"] z_index = 10 -collision_mask = 3 +collision_mask = 15 script = ExtResource("1_jrd75") -[node name="Camera2D" type="Camera2D" parent="."] - [node name="Sprite2D" type="Sprite2D" parent="."] texture_filter = 1 texture = ExtResource("1_qfnf0") hframes = 2 +[node name="Camera2D" type="Camera2D" parent="Sprite2D"] + [node name="AnimationPlayer" type="AnimationPlayer" parent="."] libraries = { "": SubResource("AnimationLibrary_dx4e7") diff --git a/project.godot b/project.godot index c2d4ccd..a1cfed5 100644 --- a/project.godot +++ b/project.godot @@ -53,6 +53,13 @@ jump={ ] } +[layer_names] + +2d_physics/layer_1="Entities" +2d_physics/layer_2="Terrain" +2d_physics/layer_3="Puzzle" +2d_physics/layer_4="Projectiles" + [rendering] textures/canvas_textures/default_texture_filter=0 diff --git a/puzzles/arrow/arrow.gd b/puzzles/arrow/arrow.gd new file mode 100644 index 0000000..7c0d13d --- /dev/null +++ b/puzzles/arrow/arrow.gd @@ -0,0 +1,25 @@ +class_name Arrow +extends Node2D + +@onready var sprite: Sprite2D = $Sprite2D + +var _direction: Vector2i +var _speed: int = 50 + +func _ready(): + if _direction.x > 0: + sprite.flip_h = true + +func shoot(dir: Vector2i, speed: int): + _direction = dir + _speed = speed + +func _physics_process(delta): + var move = _direction * _speed * delta + position = position + move + + +func _on_area_2d_body_entered(body): + if body is Player: + body.die() + queue_free() diff --git a/puzzles/arrow/arrow.png b/puzzles/arrow/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..883e7233fe44eaf6bca1d161680fbe082deb9c7e GIT binary patch literal 117 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|^gUf1LnNjq zCnzvT6ncL6?ESx8yP?pouBPiydIAu*JX_G*FF)T%$gFXKv<5rF`UL{drtTAP0cvIN MboFyt=akR{0HmQJBLDyZ literal 0 HcmV?d00001 diff --git a/puzzles/arrow/arrow.png.import b/puzzles/arrow/arrow.png.import new file mode 100644 index 0000000..87f2be7 --- /dev/null +++ b/puzzles/arrow/arrow.png.import @@ -0,0 +1,34 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://de8lejw21tx6h" +path="res://.godot/imported/arrow.png-a9a36bfbd72d1cbac04ba2d3bfba852e.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://puzzles/arrow/arrow.png" +dest_files=["res://.godot/imported/arrow.png-a9a36bfbd72d1cbac04ba2d3bfba852e.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 diff --git a/puzzles/arrow/arrow.tscn b/puzzles/arrow/arrow.tscn new file mode 100644 index 0000000..74dd6ee --- /dev/null +++ b/puzzles/arrow/arrow.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=4 format=3 uid="uid://0p0jl4g1ha4v"] + +[ext_resource type="Texture2D" uid="uid://de8lejw21tx6h" path="res://puzzles/arrow/arrow.png" id="1_nkjxg"] +[ext_resource type="Script" path="res://puzzles/arrow/arrow.gd" id="1_v7o4i"] + +[sub_resource type="RectangleShape2D" id="RectangleShape2D_2m4dq"] +size = Vector2(8, 3) + +[node name="Arrow" type="Node2D"] +script = ExtResource("1_v7o4i") + +[node name="Sprite2D" type="Sprite2D" parent="."] +texture = ExtResource("1_nkjxg") + +[node name="Area2D" type="Area2D" parent="."] + +[node name="CollisionShape2D" type="CollisionShape2D" parent="Area2D"] +position = Vector2(0, -0.5) +shape = SubResource("RectangleShape2D_2m4dq") + +[connection signal="body_entered" from="Area2D" to="." method="_on_area_2d_body_entered"] diff --git a/puzzles/arrow/arrow_shooter.gd b/puzzles/arrow/arrow_shooter.gd new file mode 100644 index 0000000..544575f --- /dev/null +++ b/puzzles/arrow/arrow_shooter.gd @@ -0,0 +1,19 @@ +extends RayCast2D + +@onready var arrow: PackedScene = preload("res://puzzles/arrow/arrow.tscn") +@onready var timer: Timer = $ShootTimer +@onready var shoot_dir: Vector2i = self.target_position.normalized() + +@export var arrow_speed: int = 400 +@export var shoot_timer: float = 3.0 + +func _ready(): + timer.start(shoot_timer) + +func _process(delta): + pass + +func _on_shoot_timer_timeout(): + var inst: Arrow = arrow.instantiate() + inst.shoot(shoot_dir, arrow_speed) + add_child(inst) diff --git a/puzzles/arrow/arrow_shooter.tscn b/puzzles/arrow/arrow_shooter.tscn new file mode 100644 index 0000000..71c2400 --- /dev/null +++ b/puzzles/arrow/arrow_shooter.tscn @@ -0,0 +1,11 @@ +[gd_scene load_steps=2 format=3 uid="uid://dpkj44krp378g"] + +[ext_resource type="Script" path="res://puzzles/arrow/arrow_shooter.gd" id="1_tk6ny"] + +[node name="ArrowShooter" type="RayCast2D"] +target_position = Vector2(0, 8) +script = ExtResource("1_tk6ny") + +[node name="ShootTimer" type="Timer" parent="."] + +[connection signal="timeout" from="ShootTimer" to="." method="_on_shoot_timer_timeout"] diff --git a/puzzles/button/button.gd b/puzzles/button/button.gd index 7fb99c0..ccf4154 100644 --- a/puzzles/button/button.gd +++ b/puzzles/button/button.gd @@ -4,10 +4,13 @@ extends Area2D @export var nodes: Array[Node2D] +var state = false + func _on_body_entered(body): if body is Player: + state = not state for node in nodes: if node is TileMapLayer: var layer = node as TileMapLayer layer.enabled = !layer.enabled - sprite.frame = 1 if not layer.enabled else 0 + sprite.frame = 1 if state else 0 diff --git a/puzzles/main_tile_layer.gd b/puzzles/main_tile_layer.gd index 72ac396..1dd5fc2 100644 --- a/puzzles/main_tile_layer.gd +++ b/puzzles/main_tile_layer.gd @@ -1,8 +1,8 @@ class_name MainLevel extends Node -func _get_tile_data(position: Vector2): - var results = [] +func _get_tile_data(position: Vector2) -> Array[TileData]: + var results: Array[TileData] = [] for layer in self.get_children(): if not (layer as TileMapLayer).enabled: continue @@ -12,14 +12,14 @@ func _get_tile_data(position: Vector2): results.push_back(tile_data) return results -func is_walkable_tile(position: Vector2): +func is_walkable_tile(position: Vector2) -> bool: var results = _get_tile_data(position) for tile_data in results: if (tile_data as TileData).get_custom_data("walkable"): return true return false -func is_death_tile(position: Vector2): +func is_death_tile(position: Vector2) -> bool: var is_death_tile = false var results = _get_tile_data(position) for tile_data in results: diff --git a/puzzles/room_manager/room_manager.gd b/puzzles/room_manager/room_manager.gd index a3de3e5..aa2b6e3 100644 --- a/puzzles/room_manager/room_manager.gd +++ b/puzzles/room_manager/room_manager.gd @@ -9,7 +9,7 @@ signal finish_room func _process(delta): pass -func is_room_finished(): +func is_room_finished() -> bool: for puzzle in mandatory_puzzles: if !puzzle.is_complete: return false diff --git a/scenes/assets/main_tileset.tres b/scenes/assets/main_tileset.tres index 4ac6db4..b70f2be 100644 --- a/scenes/assets/main_tileset.tres +++ b/scenes/assets/main_tileset.tres @@ -41,15 +41,17 @@ texture_region_size = Vector2i(8, 8) 3:0/0 = 0 3:0/0/probability = 0.05 3:0/0/custom_data_0 = true -0:6/0 = 0 -1:6/0 = 0 -2:6/0 = 0 -1:7/0 = 0 -0:7/0 = 0 +6:2/0 = 0 +6:2/0/physics_layer_1/polygon_0/points = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4) +7:2/0 = 0 +7:2/0/physics_layer_1/polygon_0/points = PackedVector2Array(-4, -4, 4, -4, 4, 4, -4, 4) [resource] tile_size = Vector2i(8, 8) physics_layer_0/collision_layer = 1 +physics_layer_0/collision_mask = 9 +physics_layer_1/collision_layer = 2 +physics_layer_1/collision_mask = 3 custom_data_layer_0/name = "walkable" custom_data_layer_0/type = 1 custom_data_layer_1/name = "death" diff --git a/scenes/assets/tileset.png b/scenes/assets/tileset.png index e0da672df88f55718a34578396ff7fdfe3e5129c..5cfb634bcf23feeb6e8aa58e37367236650528ac 100644 GIT binary patch delta 607 zcmV-l0-*i91%(BWF@HZvL_t(|ob8u8PQySDh9`*L4OFSQ0R;y@LWn+!te~7Cb>y0c zD_F52M31aU7A11w8~6xzO#y`|(7<@TFN2ft_&>>7&+f$9dF9%l=rcu@)9ott+Qa5y-G7oVu0kRr8V&6LHr6z% zsD|sDp_`X7J4+(xj*m{Xd#&nncn1)5BW{y#S7~SSDlX$)sL^LGu0lF+{@TIi^tv?? zb)BX&p7q&ynd;Igo$)*tSx!kDeLVaVjn*9lTjZszBZ;Hk)&So^sItu(uoVaB`06cSssW5zMAaK%HeVVY zP}L=k`kB$6r}VKQayvk#yp&D)tmCQy_v@Rj+i2w}eQbhY+{jTrFR#zd%j>h3%C96_TC-9j;QL= zt3d9|0TOAvs|J{i=QTCr%<<8QaZNHvAK;5mFVL4Hj*L~_)ddpmFau0!Z;Cw2Rb5*D z%-GWWM;!s*Gp|x)IaPJpl6CJok~pIK^^H|$zjx#SOu~ips{7Np`T*DZzt4bQ?*Q5D z+4_D))>xC-e7T=KU`Tu_{de?#Ji0SJ2^UQej9ZVXKK%M4@b7N{UG)3N``$kQ00000 t000000000000000000000002C#~T?-e%YT%EI0rF002ovPDHLkV1g9YCb0kj delta 664 zcmV;J0%!e&1-%83F@JYSL_t(|ob8&uPQyS9$K8rO3rwAP0|p)d2_be=RUn>%8D(bS z6{1EJVn-2D)DdOK8)RlmmM#o1gaNrYzR#4jkl>$GU47?9_xJgHS1F?)nABh)d6?UV zy*Qg*8J}}>atwKz!O_WaqyO^y7UC#`Jk1n;Bu_KApC?{(cz=FcH0;y!82|u`x()z} zHMJZrTo(*oKeaJf6xw&Nf2f^nSry#}06<-Fn|(h|l*w~k;$867M^4XYFn0dh!P)ex z(E_MJ(}_oa6i-u~iqeV4HcvB%qj3Gf=W*LcCmCSd<1T+)x>LHS0nbm1M$nN?G5|nb zVcPP3?oZ(>4}b6_7)9&0fo4cJNmbZmMGm}&sRizq)4F0XHm z0Vt~iM(t#@=OtOz0PXv)%wt_aLO@C3O z@G6iy3jl?RchvxscpT#^jvVYC8pkM|+yi{^xeK%Y7cz^lV==2?-zKK`pLO>8q>OKWx{SqOa^lJ60yhDtAtJUj>``i3_1&X4rsZZxa z{d$Kac?*7pFHxS?jqm>++-BXIDzjymo)B*s*< y&n0GvL9kwYxX<7*odkWm<8Oq|F*vj!d;+@_I}w