Making a sprite randomly move within borders on an isometric plane

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Mango_05

Hi Godot Experts, I am relatively new to Godot and I am having an issue with random character movement on an isometric plane.

I am attempting to recreate an old game I used to play called Ninja Farm that was unfortunately deleted by the developers.

Image Reference

I would like for the ninjas (AI) to randomly move around the scene while staying within the borders of the isometric view. They will then stay in that position for a few seconds, then move in another random direction to create the effect of wandering. Any idea on how to approach this?, I have looked up previous forums and videos but none seem to be relevant to the random movement within borders.

The tilemap I am using for the ground is in isometric view and each tile is 32x16. The area of which I would like the AI to be able to move is 15 tiles by 15 tiles - a square.

Thank you for taking the time to read this. If any more information is required, please ask, thanks.

:bust_in_silhouette: Reply From: timothybrentwood

AStar path finding is going to be your best most performant option here, a video about it can be found here : https://www.youtube.com/watch?v=Ad6Us73smNs

Here is some code that does generally what you want. Note that it does not account for two characters attempting to move to the same grid position at the same time.

extends KinematicBody2D
  
var move_timer : Timer
var can_move = true
var world_destination = null
var speed = 25
var velocity_vector = Vector2.ZERO

func _ready() -> void:
	move_timer = Timer.new()
	move_timer.one_shot = true
	move_timer.wait_time = 3
	move_timer.connect("timeout", self, "_on_move_timer_timeout")
	self.add_child(move_timer)

func _physics_process(delta: float) -> void:
	if world_destination:
		move_towards_world_destination(delta)
	elif can_move:
		set_world_destination()

func move_towards_world_destination(delta):
	# move towards world_destination in sync with physics step
	var direction_vector = self.position.direction_to(world_destination).normalized()
	velocity_vector = move_and_slide(velocity_vector + (direction_vector * speed * delta))
	
	# arrived at world_destination
	if abs(self.position.distance_to(world_destination)) < 0.05:
		# snap our position to world_destination to avoid any funny business
		self.position = world_destination
		world_destination = null
		velocity_vector = Vector2.ZERO
		can_move = false
		move_timer.start()

func set_world_destination():
	var move_directions = [Vector2.UP, Vector2.DOWN, Vector2.LEFT, Vector2.RIGHT]
	var current_grid_position = get_current_grid_position()
	randomize()
	# set a random adjacent tile to our potential_grid_position 
	var potential_grid_position = current_grid_position + move_directions[randi() % move_directions.size()]
	
	# make sure we select a tile within our wonder zone
	while not is_inside_wander_zone(potential_grid_position):
		randomize()
		potential_grid_position = current_grid_position + move_directions[randi() % move_directions.size()]
	
	# set our world_destination
	world_destination = get_world_position_from_grid_position(potential_grid_position)
	
func is_inside_wander_zone(grid_position):
	# here is where you can define the grid coordinates of your wander zone
	var wander_zone_start = Vector2(0,0)
	var wander_zone_end = Vector2(15,15)
	var inside_wander_zone = false
	if wander_zone_start.x <= grid_position.x and grid_position.x <= wander_zone_end.x:
		if wander_zone_start.y <= grid_position.y and grid_position.y <= wander_zone_end.y:
			inside_wander_zone = true
	return inside_wander_zone

# here is where you would need to translate self.position to a grid position
func get_current_grid_position():
	var some_translation
	var current_grid_position = self.position * some_translation
	return current_grid_position

# here is here you would need to translate a grid position to a world position
func get_world_position_from_grid_position(grid_position):
	var some_translation
	var current_world_position = grid_position * some_translation
	return current_world_position

# when our timer times out we can move again
func _on_move_timer_timeout():
	can_move = true