feat: improved dragon walking behaviour

This commit is contained in:
Gerard Gascón 2025-04-10 22:52:28 +02:00
parent b4594bdd43
commit d8419cb9a4
8 changed files with 150 additions and 66 deletions

View file

@ -8,7 +8,7 @@ class_name DragonEntity
@export var min_exit_time: float
@export var max_exit_time: float
signal on_pick(dragon_id: int, position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, dragon_name: String)
signal on_pick(dragon_id: int, position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D)
signal on_quit(dragon_id: int)
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
@ -43,13 +43,9 @@ func _input_event(viewport, event, shape_idx) -> void:
if event is InputEventMouseButton \
and event.button_index == MOUSE_BUTTON_LEFT \
and event.is_pressed():
on_pick.emit(id, position + $CollisionShape2D.position, dragon.hat.texture, dragon.shirt.texture, dragon.shoes.texture, dragon.name_label.text)
on_pick.emit(id, position + $CollisionShape2D.position, dragon.hat.texture, dragon.shirt.texture, dragon.shoes.texture)
queue_free()
func dress(hat: Texture2D, shirt: Texture2D, shoes: Texture2D):
dragon.dress(hat, shirt, shoes)
func set_dragon_name(dragon_name: String):
dragon.set_dragon_name(dragon_name)

View file

@ -5,11 +5,6 @@ class_name DragonSprite
@export var hat: Sprite2D
@export var shirt: Sprite2D
@export var shoes: Sprite2D
@export var name_label: Label
func _ready() -> void:
name_label.hide()
func dress(hat: Texture2D, shirt: Texture2D, shoes: Texture2D):
@ -18,13 +13,9 @@ func dress(hat: Texture2D, shirt: Texture2D, shoes: Texture2D):
self.shoes.texture = shoes
func set_dragon_name(dragon_name: String):
name_label.text = dragon_name
func walk_left():
$Sprite.scale.x = 1
func _on_area_2d_mouse_entered() -> void:
name_label.show()
func _on_area_2d_mouse_exited() -> void:
name_label.hide()
func walk_right():
$Sprite.scale.x = -1

View file

@ -9,12 +9,11 @@
[sub_resource type="RectangleShape2D" id="RectangleShape2D_oaoux"]
size = Vector2(76, 88)
[node name="Dragon" type="Node2D" node_paths=PackedStringArray("hat", "shirt", "shoes", "name_label")]
[node name="Dragon" type="Node2D" node_paths=PackedStringArray("hat", "shirt", "shoes")]
script = ExtResource("1_oaoux")
hat = NodePath("Sprite/Hat")
shirt = NodePath("Sprite/Shirt")
shoes = NodePath("Sprite/Shoes")
name_label = NodePath("Label")
[node name="Area2D" type="Area2D" parent="."]
@ -35,16 +34,5 @@ texture = ExtResource("4_oaoux")
[node name="Shoes" type="Sprite2D" parent="Sprite"]
texture = ExtResource("5_stf6f")
[node name="Label" type="Label" parent="."]
offset_left = -10.0
offset_top = 78.0
offset_right = 86.0
offset_bottom = 101.0
theme_override_colors/font_color = Color(1, 1, 1, 1)
theme_override_colors/font_outline_color = Color(0, 0, 0, 1)
theme_override_constants/outline_size = 5
text = "AAAAAAAA"
horizontal_alignment = 1
[connection signal="mouse_entered" from="Area2D" to="." method="_on_area_2d_mouse_entered"]
[connection signal="mouse_exited" from="Area2D" to="." method="_on_area_2d_mouse_exited"]

View file

@ -101,14 +101,13 @@ func _load_game():
var hat: Texture2D = hat_outfits.get_texture(d['hat'])
var shirt: Texture2D = shirt_outfits.get_texture(d['shirt'])
var shoes: Texture2D = shoes_outfits.get_texture(d['shoes'])
_pick_dragon(d['id'], d['pos'], hat, shirt, shoes, d['name'], false)
_pick_dragon(d['id'], d['pos'], hat, shirt, shoes, false)
print(_save_load.contents_to_save)
func _instantiate_dragon_ingame(position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, dragon_name: String, id: int) -> DragonEntity:
var dragon: DragonEntity = dragon_ingame.instantiate()
dragon.dress(hat, shirt, shoes)
dragon.set_dragon_name(dragon_name)
add_child(dragon)
dragon.id = id
dragon.position = position
@ -118,8 +117,8 @@ func _instantiate_dragon_ingame(position: Vector2, hat: Texture2D, shirt: Textur
return dragon
func _pick_dragon(id: int, position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, dragon_name: String, drag: bool = true):
var dragon: Dragon = _instantiator.instantiate(position, hat, shirt, shoes, dragon_name, drag)
func _pick_dragon(id: int, position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, drag: bool = true):
var dragon: Dragon = _instantiator.instantiate(position, hat, shirt, shoes, drag)
dragon.id = id
_dragon_entities[id] = dragon
dragon.place_back.connect(_dragon_place_back)

View file

@ -9,6 +9,9 @@ var dragging_start_position: Vector2i = Vector2i()
var _initial_drag_requested: bool = false
signal on_drag()
signal on_drop()
func _ready() -> void:
set_process_input(true)
@ -33,9 +36,11 @@ func _input(event) -> void:
if event.pressed:
dragging = true
on_drag.emit()
dragging_start_position = Vector2i(get_global_mouse_position())
else:
dragging = false
on_drop.emit()
if _is_inside_main_window():
_destroy_dragon()

View file

@ -1,23 +1,43 @@
extends Window
class_name Dragon
@export var dragon_speed: float = 20.0
@export var dragon_speed_min: float = 20.0
@export var dragon_speed_max: float = 20.0
var dragon_speed: float = 0.0
@export var dragon: DragonSprite
@onready var _actual_position: Vector2 = position
var main_window_rect: Rect2i
@export var draggable: Draggable
var _walking: bool = false
var _thinking_path: bool = false
var _target_pos: Vector2
var rng: RandomNumberGenerator = RandomNumberGenerator.new()
var _fall_speed: float
signal place_back(dragon: Dragon)
var id: int
enum State {
WALKING_IDLE,
WALKING,
FLYING,
FLYING_IDLE,
FALLING,
DRAGGING
}
var current_state: State = State.WALKING_IDLE
func _ready() -> void:
draggable.on_drag.connect(_on_drag)
draggable.on_drop.connect(_on_drop)
current_state = State.FALLING
func on_place_back() -> void:
place_back.emit(self)
@ -26,50 +46,135 @@ func start_dragon_drag()-> void:
draggable.queue_initial_drag()
func _process(delta: float) -> void:
if draggable.dragging:
_actual_position = position
_walking = false
return
if not _walking:
if not _thinking_path:
_thinking_path = true
await get_tree().create_timer(rng.randf_range(2, 7)).timeout
_pick_random_screen_position()
return
_move_to_target(delta)
match current_state:
State.DRAGGING:
_thinking_path = false
_actual_position = position
State.WALKING_IDLE:
if not _thinking_path:
_think_path()
State.FLYING_IDLE:
if not _thinking_path:
_think_path()
State.WALKING:
_move_to_target(delta)
State.FALLING:
_fall(delta)
State.FLYING:
_move_to_target(delta)
func dress(hat: Texture2D, shirt: Texture2D, shoes: Texture2D):
dragon.dress(hat, shirt, shoes)
func set_dragon_name(dragon_name: String):
dragon.set_dragon_name(dragon_name)
func _think_path():
_thinking_path = true
await get_tree().create_timer(rng.randf_range(2, 7)).timeout
dragon_speed = rng.randf_range(dragon_speed_min, dragon_speed_max)
match current_state:
State.WALKING_IDLE:
var decision: int = rng.randi_range(0, 99)
if decision < 30:
_pick_random_screen_fly_position()
else:
_pick_random_screen_walk_position()
State.FLYING_IDLE:
var decision: int = rng.randi_range(0, 99)
if decision < 30:
_fall_speed = 0
current_state = State.FALLING
else:
_pick_random_screen_fly_position()
func _fall(delta: float) -> void:
_fall_speed += 30 * delta
_actual_position.y += _fall_speed
position.y = _actual_position.y
var ground_height: int = _ground_height()
if position.y >= ground_height:
current_state = State.WALKING_IDLE
position.y = ground_height
_actual_position.y = ground_height
func _move_to_target(delta: float):
if _actual_position.distance_to(_target_pos) > 10.0:
if _actual_position.distance_to(_target_pos) > 2.0:
var direction: Vector2 = (_target_pos - _actual_position).normalized()
_actual_position += dragon_speed * direction * delta
position = _actual_position
if direction.x > 0:
dragon.walk_right()
elif direction.x < 0:
dragon.walk_left()
return
_walking = false
match current_state:
State.FLYING:
current_state = State.FLYING_IDLE
State.WALKING:
current_state = State.WALKING_IDLE
func _pick_random_screen_position() -> void:
_walking = true
_thinking_path = false
func _on_drag():
current_state = State.DRAGGING
func _on_drop():
var ground_height: int = _ground_height()
if position.y >= ground_height:
current_state = State.WALKING_IDLE
position.y = ground_height
_actual_position.y = ground_height
else:
_fall_speed = 0
current_state = State.FALLING
func _get_display_limits() -> Rect2i:
var display_index: int = DisplayServer.window_get_current_screen()
var work_area_position: Vector2i = DisplayServer.screen_get_usable_rect(display_index).position
var work_area_size: Vector2i = DisplayServer.screen_get_usable_rect(display_index).size
return Rect2i(work_area_position + Vector2i(10, 10), work_area_size - Vector2i(20, 10) - size)
func _ground_height() -> int:
var limits: Rect2i = _get_display_limits()
return limits.end.y
func _pick_random_screen_fly_position() -> void:
current_state = State.FLYING
_thinking_path = false
var limits: Rect2i = _get_display_limits()
var random_pos: Vector2i = Vector2i(
work_area_position.x + rng.randi_range(10, work_area_size.x - 10 - size.x),
work_area_position.y + rng.randi_range(10, work_area_size.y - 10 - size.y)
rng.randi_range(limits.position.x, limits.end.x),
rng.randi_range(limits.position.y, limits.end.y)
)
_target_pos = random_pos
func _pick_random_screen_walk_position() -> void:
current_state = State.WALKING
_thinking_path = false
var limits: Rect2i = _get_display_limits()
var random_pos: Vector2i = Vector2i(
rng.randi_range(limits.position.x, limits.end.x),
_ground_height()
)
_target_pos = random_pos
func get_taskbar_height():
return DisplayServer.screen_get_size().y - DisplayServer.screen_get_usable_rect().size.y

View file

@ -13,7 +13,8 @@ borderless = true
transparent = true
content_scale_mode = 2
script = ExtResource("1_ctdir")
dragon_speed = 100.0
dragon_speed_min = 50.0
dragon_speed_max = 120.0
dragon = NodePath("Dragon")
draggable = NodePath("DragDropDetector")

View file

@ -10,11 +10,11 @@ func _init(dragon: PackedScene, viewport: Viewport, window: Window) -> void:
_dragon_template = dragon
func instantiate(position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, dragon_name: String, drag: bool) -> Node:
func instantiate(position: Vector2, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, drag: bool) -> Node:
if drag == false:
return _instantiate_dragon(position, hat, shirt, shoes, dragon_name, drag)
return _instantiate_dragon(position, hat, shirt, shoes, drag)
var relative_position: Vector2i = _calculate_relative_position(position)
return _instantiate_dragon(relative_position, hat, shirt, shoes, dragon_name, drag)
return _instantiate_dragon(relative_position, hat, shirt, shoes, drag)
func _calculate_window_scale() -> Vector2:
@ -29,7 +29,7 @@ func _calculate_relative_position(position: Vector2) -> Vector2i:
return Vector2i(Vector2(position) * scale)
func _instantiate_dragon(relative_position: Vector2i, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, dragon_name: String, drag: bool) -> Node:
func _instantiate_dragon(relative_position: Vector2i, hat: Texture2D, shirt: Texture2D, shoes: Texture2D, drag: bool) -> Node:
var dragon: Dragon = _dragon_template.instantiate()
var window_position: Vector2i = DisplayServer.window_get_position()
@ -40,7 +40,6 @@ func _instantiate_dragon(relative_position: Vector2i, hat: Texture2D, shirt: Tex
else:
dragon.position = window_position + relative_position - dragon.size / 2
dragon.dress(hat, shirt, shoes)
dragon.set_dragon_name(dragon_name)
var size: float = _calculate_window_scale().y
dragon.main_window_rect = Rect2i(window_position, window_size)