1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
class_name ComponentMovement
extends Node
signal direction_changed
@export_node_path("CharacterBody2D") var entityPath: NodePath
@onready var entity: CharacterBody2D = get_node(entityPath)
@export_node_path("AnimatedSprite2D") var spritePath: NodePath
@onready var sprite: AnimatedSprite2D = get_node(spritePath)
@export var SPEED: float
const DIRECTIONS = [Vector2.UP, Vector2.RIGHT, Vector2.DOWN, Vector2.LEFT]
var CURRENT_DIRECTION = Vector2.UP
var LAST_DIRECTION = Vector2.UP
var was_colliding = false
var animations: Dictionary = {
"default": "default",
"up": "up",
"down": "down",
"left": "left",
"right": "right",
}
@export var timer_time: float = 3.0
@onready var MovementTimer: Timer = Timer.new()
@export var follows: bool = false
@export_range(1, 100, 1) var follow_chance: int = 100
func _ready():
MovementTimer.wait_time = timer_time
MovementTimer.autostart = true
MovementTimer.connect("timeout", Callable(_on_movement_timer_timeout))
add_child(MovementTimer)
func physics_process(delta):
if CURRENT_DIRECTION == Vector2.UP:
entity.velocity.y -= SPEED/2
if sprite.sprite_frames.has_animation(animations["up"]):
sprite.play(animations["up"])
elif CURRENT_DIRECTION == Vector2.DOWN:
entity.velocity.y += SPEED/2
if sprite.sprite_frames.has_animation(animations["down"]):
sprite.play(animations["down"])
elif CURRENT_DIRECTION == Vector2.LEFT:
entity.velocity.x -= SPEED/2
if sprite.sprite_frames.has_animation(animations["left"]):
sprite.play(animations["left"])
elif CURRENT_DIRECTION == Vector2.RIGHT:
entity.velocity.x += SPEED/2
if sprite.sprite_frames.has_animation(animations["right"]):
sprite.play(animations["right"])
if sprite.sprite_frames.has_animation(animations["default"]):
sprite.play(animations["default"])
var collision = entity.move_and_collide(entity.velocity * delta)
entity.velocity = entity.velocity.lerp(Vector2(0, 0), 1) # speed too low => no collision
# todo movement along grid (maybe move position to current tile center)
var target_grid_position = Utilities.from_grid_to_position(Utilities.get_level_position(entity) + CURRENT_DIRECTION)
entity.position = entity.position.move_toward(target_grid_position, delta*SPEED/2)
# todo or set velocity to tiles per SPEED per second somehow, instead of Timer
if collision:
was_colliding = true
if MovementTimer.time_left > 0:
_on_movement_timer_timeout()
else:
was_colliding = false
return collision
func set_animations(new_animations: Dictionary):
animations.merge(new_animations, true)
func _on_movement_timer_timeout():
var randomize_direction = false
if false and follows and randi_range(0, 100) <= follow_chance:
var player_direction = entity.position.direction_to(Global.player.position)
var query = PhysicsRayQueryParameters2D.new()
query.set_from(entity.position)
query.set_to(Global.player.position)
query.set_collision_mask(entity.collision_mask)
var intersection = entity.get_world_2d().direct_space_state.intersect_ray(query)
if intersection:
randomize_direction = true
if abs(player_direction.x) >= abs(player_direction.y):
if player_direction.x >= 0:
CURRENT_DIRECTION = Vector2.RIGHT
elif player_direction.x < 0:
CURRENT_DIRECTION = Vector2.LEFT
elif abs(player_direction.y) > abs(player_direction.x):
if player_direction.y >= 0:
CURRENT_DIRECTION = Vector2.DOWN
elif player_direction.y < 0:
CURRENT_DIRECTION = Vector2.UP
if was_colliding and LAST_DIRECTION == CURRENT_DIRECTION:
randomize_direction = true
else:
randomize_direction = true
if randomize_direction:
var directions = DIRECTIONS.duplicate()
directions.erase(CURRENT_DIRECTION)
directions.shuffle()
if not directions.is_empty():
CURRENT_DIRECTION = directions[0]
emit_signal("direction_changed", CURRENT_DIRECTION)
LAST_DIRECTION = CURRENT_DIRECTION
if not sprite.sprite_frames.has_animation(animations["default"]):
var frame = sprite.frame
var progress = sprite.frame_progress
if CURRENT_DIRECTION == Vector2.UP and sprite.sprite_frames.has_animation(animations["up"]):
sprite.play(animations["up"])
elif CURRENT_DIRECTION == Vector2.DOWN and sprite.sprite_frames.has_animation(animations["down"]):
sprite.play(animations["down"])
elif CURRENT_DIRECTION == Vector2.LEFT and sprite.sprite_frames.has_animation(animations["left"]):
sprite.play(animations["left"])
elif CURRENT_DIRECTION == Vector2.RIGHT and sprite.sprite_frames.has_animation(animations["right"]):
sprite.play(animations["right"])
sprite.set_frame_and_progress(frame, progress)
MovementTimer.start()
|