Skip to content

Instantly share code, notes, and snippets.

@Shilo
Last active February 4, 2024 12:23
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Shilo/b2f1e7f58f476184e1960623690c3097 to your computer and use it in GitHub Desktop.
Save Shilo/b2f1e7f58f476184e1960623690c3097 to your computer and use it in GitHub Desktop.
Simple runtime tilemap editor that will draw the a terrain from a tileset. (Left click = place, Right click = remove, Middle click = pan)
class_name TileMapEditor extends TileMap
enum InputState {
NONE,
PLACE,
REMOVE,
PAN
}
var input_state: InputState = InputState.NONE
var pan_start_position: Vector2 = Vector2.ZERO
var last_tile_position: Vector2 = Vector2.ZERO
func _unhandled_input(event: InputEvent):
if event is InputEventMouseButton:
on_mouse_button(event)
elif event is InputEventMouseMotion:
on_mouse_move()
func on_mouse_button(event: InputEventMouseButton):
if event.button_index == MOUSE_BUTTON_LEFT:
update_input_state(event, InputState.PLACE)
elif event.button_index == MOUSE_BUTTON_RIGHT:
update_input_state(event, InputState.REMOVE)
elif event.button_index == MOUSE_BUTTON_MIDDLE:
update_input_state(event, InputState.PAN)
func update_input_state(event: InputEventMouseButton, target_state: InputState):
var pressed := event.pressed
if pressed:
input_state = target_state
elif input_state == target_state:
input_state = InputState.NONE
update_input(pressed)
func on_mouse_move():
if input_state == InputState.NONE:
return
update_input(false)
func update_input(start: bool = false):
if input_state == InputState.PLACE:
place_tile(start)
elif input_state == InputState.REMOVE:
remove_tile(start)
elif input_state == InputState.PAN:
pan_map(start)
func place_tile(start: bool = false):
var tile_position := cur_tile_position()
var path := [tile_position] if start else tile_path(last_tile_position, tile_position)
set_cells_terrain_connect(0, path, 0, 0)
#for tile in path: set_cell(0, tile, 0, Vector2i(0, 0))
last_tile_position = tile_position
func remove_tile(start: bool = false):
var tile_position := cur_tile_position()
var path := [tile_position] if start else tile_path(last_tile_position, tile_position)
set_cells_terrain_connect(0, path, 0, -1)
#for tile in path: set_cell(0, tile)
last_tile_position = tile_position
func pan_map(start: bool):
if start:
pan_start_position = get_local_mouse_position()
return
position += get_local_mouse_position() - pan_start_position
func cur_tile_position() -> Vector2:
return Vector2i(get_local_mouse_position()) / tile_set.tile_size
func tile_path(start: Vector2, end: Vector2) -> Array:
var path := []
var delta := end - start
var step := delta.normalized()
var distance := delta.length()
for i in range(0, int(distance) + 1):
path.append(start + step * i)
if distance < 1:
path.append(end)
return path
@Shilo
Copy link
Author

Shilo commented Feb 4, 2024

Might be able to optimize it by not redrawing the current tile when moving mouse. But TileMap may optimize this anyhow.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment