I'm trying to learn how to set up an isometric point-and-click game. I have a ChacterBody2D that moves towards wherever the user clicks, and a tilemap with some tiles placed around.
How do I code it so the player only moves if the user has clicked on a valid tile? And to prevent the user from flying across void spaces?
Player Movement Script
extends CharacterBody2D
@export var speed = 400
var target
func _ready():
target = global_position
func _input(event):
if event is InputEventMouseButton and event.pressed:
target = get_global_mouse_position()
print(event)
func _physics_process(delta):
velocity = global_position.direction_to(target) * speed
if global_position.distance_to(target) > 10:
move_and_collide(velocity * delta)
Thank you!
I'm trying to learn how to set up an isometric point-and-click game. I have a ChacterBody2D that moves towards wherever the user clicks, and a tilemap with some tiles placed around.
How do I code it so the player only moves if the user has clicked on a valid tile? And to prevent the user from flying across void spaces?
Player Movement Script
extends CharacterBody2D
@export var speed = 400
var target
func _ready():
target = global_position
func _input(event):
if event is InputEventMouseButton and event.pressed:
target = get_global_mouse_position()
print(event)
func _physics_process(delta):
velocity = global_position.direction_to(target) * speed
if global_position.distance_to(target) > 10:
move_and_collide(velocity * delta)
Thank you!
Share Improve this question edited Feb 15 at 0:09 DarkBee 15.6k8 gold badges72 silver badges116 bronze badges asked Feb 14 at 23:59 Samuel ShumakeSamuel Shumake 213 bronze badges 2 |
3 Answers
Reset to default 0I was able to get this working using get_node() to find the TileMapLayer. For some reason, the normal reference wasn't working but this worked for me
extends CharacterBody2D
@export var speed = 200
var target
var map
func _ready():
target = global_position
map = get_node("/root/Node2D/TileMapLayer")
func _input(event):
if event is InputEventMouseButton and event.pressed:
var mouse_pos = get_global_mouse_position()
var cell_coord = map.local_to_map(mouse_pos)
print(cell_coord)
if (map.get_cell_tile_data(cell_coord)): # If null tile or not
target = mouse_pos
func _physics_process(delta):
velocity = global_position.direction_to(target) * speed
if global_position.distance_to(target) > 10:
move_and_collide(velocity * delta)
You are working with a TileMap, composed of a TileSet composed of "many little pieces". Every piece of your tileset is basically a "piece repeated a certain amount of times". Since Godot 4.0 you can use scenes as tiles. I didn't test this, but if u can use scenes then you can attach script to them. This means that you can send signals from childs to father. So your code could seem just like this.
In Tile.gd
signal pressed_on_me(my_coordinates)
...
if event is InputEventMouseButton and event.pressed:
pressed_on_me.emit(my_coordinates)
In father.gd (which can be map2 or TileMapLayer, depends what you prefer)
func _on_pressed_on_me(my_coordinates):
// move action...
In this way:
- If u press in a non-valid tile, nothing happens because no signal will be emitted
- A tile has a specific coordinate, so you don't have to check for non-valid input
- You separate actions, so if in a future u want to add "special tiles" (lava tiles, water tiles....) you can just configure your tile to have a different speed/effect without touching too much code (or at least you are gonna "touch less your code" than creating something monholitic).
Hope this helps. Greetings
extends CharacterBody2D
@onready var map: TileMapLayer = get_parent().get_node("TileMapLayer")
func _physics_process(_delta: float) -> void:
if Input.is_action_just_pressed("left_click"):
var mouse_position := get_global_mouse_position()
if is_cell_valid(mouse_position):
# Here, write code to move code to the desired block
pass
func is_cell_valid(mouse_position: Vector2) -> bool:
var grid_position := map.local_to_map(mouse_position)
if map.get_cell_source_id(grid_position) == -1:
return false
return true
map = get_node("/root/Node2D/TileMapLayer")
andvar mouse_pos = get_global_mouse_position()
var cell_coord = map.local_to_map(mouse_pos)
– Samuel Shumake Commented Feb 16 at 15:52