|
|
|
|
Reply From: |
Zylann |
One problem about moving to a target using only 4 directions is that there are multiple vectors that lead to the same result.
It may always be in two phases: one going horizontally, then vertically, but the other way around also works. If your AI is as far as the target in both X and Y, which direction should it take first? (1,0) or (0,1)?
Now, if you just want a vector to a point but that uses only horizontal or vertical directions, you can isolate the problem into a function, like this:
static func get_direction(from, to):
var diff = to - from
if abs(diff.x) > abs(diff.y):
return Vector2(sign(diff.x), 0)
else:
return Vector2(0, sign(diff.y))
But again, you need to think about the effect of this across time, because applying the same approach as a “float” direction will make your AI oscillate weirdly as soon as it reaches the point where X and Y distances are equal.
Hi,
Thank you for the function, but it doesnt work still - if you perfectly align the target position and the from, the node starts moving diagonally towards the target rapidly switching between moving vertically and horizontally
blurymind | 2017-10-23 13:48
This is exactly what I warned you about, read my answer again
The function should work in order to give you an immediate 4-direction vector, but it’s not going to solve your problem on its own, you need to think about how your AI behaves across multiple frames. Beware, I also mean this function shouldn’t be used every single frame, because it would cause weird oscillations.
Maybe you need to remember in which direction your AI is going.
For example, you might start going upwards because the target is mostly upwards. You continue going up vertically until it gets horizontally aligned with the target. Then, change direction and go horizontally towards the target.
You may want to refine this algorithm if the target moves though.
That’s a two-phase movement because you want to constrain to 4 directions, and the only way for an AI to go from A to B is to do an angled path.
Zylann | 2017-10-23 17:54
Hi I solved it by introducing grid based movement,so direction is changed only per tile.
Btw is there a way to turn your function into an 8 direction one?
blurymind | 2017-10-23 18:23
Aaah too bad, I came up with something:
extends Sprite
var _dir = null
func _ready():
set_process(true)
func _process(delta):
var target = get_global_mouse_pos()
var pos = get_pos()
if target == pos:
return
if _dir == null:
_dir = get_direction(pos, target)
else:
var diff = target - pos
diff = Vector2(floor(diff.x), floor(diff.y))
var is_vertical = _dir.x == 0
if is_vertical:
if sign(diff.y) != _dir.y or diff.y == 0:
_dir = get_direction(pos, target)
else:
if sign(diff.x) != _dir.x or diff.x == 0:
_dir = get_direction(pos, target)
var speed = 100.0
set_pos(pos + _dir * speed * delta)
static func get_direction(from, to):
var diff = to - from
if abs(diff.x) > abs(diff.y):
return Vector2(sign(diff.x), 0)
else:
return Vector2(0, sign(diff.y))
For 8 directions I don’t know, unfortunately I don’t have time left to investigate an example right now.
Also keep in mind that the “oscillation” still applies on a turn-based grid, it just means it will pick horizontal and vertical alternatively each turn
Zylann | 2017-10-23 18:27