Godot Version
4.3
Question
Update:
Edited to format code snippets.
Also, while writing out my question I actually solved my issue, kind of, by just hard coding the source_id and alternate_tile. I would still appreciate anyone taking the time to glance at this to help me understand how this works and how I can possibly get these values dynamically.
I’m making a game that will use this level editor after I get the bugs worked out of it and the game will have multiple tile sets and atlas’ so generating the source_id, atlas_coords, and alternate_tile by code would be nice.
End of Update
Hello everyone, first post here. I have several questions but I’ll try to keep it as brief as possible (I fail). I have read everything I can find, including the docs, and I still can’t understand this method.
I’m following a tutorial to build an in-game level editor.
The thing is, this tutorial is in Godot 3.x and I’m trying to update it for 4.3 to use modern methods etc. In previous versions of Godot all you needed to set a cell were the x,y coords and a tile ID iirc. Now we also need source_id, atlas_coords, and alternative_tile. I think I have a clunky brute force method for getting the atlas coords but I’m not even sure I understand what source_id or alternative_tile are asking for.
Like, the atlas_coords are a vector2i but the alternative_tile is an int. I would have expected the alternative_tile to also be a vector2i that points to a different tile as an alternate. So, I think I don’t understand what it actually is. I just have it set to 0 so that the code works but I have no idea why this works or what it means. Can anyone explain?
I don’t know what the source_id is either. Is this the atlas id? I’m assuming it is.
I know I can get both of these values by looking at the map, selecting a specific tile, and then hard coding the values but I want to get them dynamically so that a level can be built in the game by the player.
As far as I can tell, the only methods that can get these values would require a tile to already be placed in the map. I’m trying to get these values so that a tile can be chosen by the player and then placed in an empty map.
I would like to be able to get these values by an id like I have set up for the item selector.
In particular, I don’t really like this array of atlas coords right below this paragraph. It feels like a brute force method. Is there a better way to do this? As I mentioned above, the game will have multiple tile sets so it might not always have 9 coordinate values like this.
# array of vectors that correspond to tile atlas locations
var tile_atlas = [Vector2i(0, 0), Vector2i(1, 0), Vector2i(2, 0),
Vector2i(0, 1), Vector2i(1, 1), Vector2i(2, 1),
Vector2i(0, 2), Vector2i(1, 2), Vector2i(2, 2)]
Set Cell Docs:
My scripts:
item_texture.gd:
extends TextureRect
@export var this_scene: PackedScene
@export var tile:bool = false
@export var tile_id = 0
@onready var object_cursor = get_node("/root/main/Editor_Object")
@onready var cursor_sprite = object_cursor.get_node("Sprite2D")
func _ready():
connect("gui_input", Callable(self, "_item_clicked"))
pass # Replace with function body.
func _item_clicked(event):
if(event is InputEvent):
if(!tile):
if(event.is_action_pressed("mb_left")):
object_cursor.current_item = this_scene
cursor_sprite.texture = texture
Global.place_tile = false
else:
if(event.is_action_pressed("mb_left")):
Global.place_tile = true
Global.current_tile = tile_id
cursor_sprite.texture = self.texture
pass
Editor_Object.gd:
extends Node2D
var can_place = true
var is_panning = false
@export var cam_pan_speed = 10
@export var cam_zoom_speed = 0.2
@onready var level = get_node("/root/main/Level")
@onready var cam_container = get_node("/root/main/cam_container")
@onready var cam = cam_container.get_node("Camera2D")
@onready var tile_map_layer:TileMapLayer = level.get_node("Tiles")
var current_item
# array of vectors that correspond to tile atlas locations
var tile_atlas = [Vector2i(0, 0), Vector2i(1, 0), Vector2i(2, 0),
Vector2i(0, 1), Vector2i(1, 1), Vector2i(2, 1),
Vector2i(0, 2), Vector2i(1, 2), Vector2i(2, 2)]
# Called when the node enters the scene tree for the first time.
func _ready():
cam.make_current()
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta):
global_position = get_global_mouse_position()
if(!Global.place_tile):
if(current_item != null and can_place and Input.is_action_just_pressed("mb_left")):
var new_item = current_item.instantiate()
level.add_child(new_item)
new_item.global_position = get_global_mouse_position()
else:
if(can_place):
if(Input.is_action_pressed("mb_left")):
place_tile()
if(Input.is_action_pressed("mb_right")):
remove_tile()
move_editor()
is_panning = Input.is_action_pressed("mb_middle")
pass
#TileMap Methods
func place_tile():
var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position())
var atlas_coords = tile_atlas[Global.current_tile]
tile_map_layer.set_cell(
clicked_cell,
0,
atlas_coords,
0)
func remove_tile():
var clicked_cell = tile_map_layer.local_to_map(tile_map_layer.get_local_mouse_position())
var atlas_coords = tile_atlas[Global.current_tile]
tile_map_layer.set_cell(
clicked_cell,
0,
atlas_coords,
-1)
#General Editor Methods
func move_editor():
if(Input.is_action_pressed("w")):
cam_container.global_position.y -= cam_pan_speed
if(Input.is_action_pressed("s")):
cam_container.global_position.y += cam_pan_speed
if(Input.is_action_pressed("a")):
cam_container.global_position.x -= cam_pan_speed
if(Input.is_action_pressed("d")):
cam_container.global_position.x += cam_pan_speed
pass
func _unhandled_input(event):
if(event is InputEventMouseButton and event.is_pressed()):
if(event.button_index == MOUSE_BUTTON_WHEEL_UP):
cam.zoom += Vector2(cam_zoom_speed, cam_zoom_speed)
if(event.button_index == MOUSE_BUTTON_WHEEL_DOWN):
cam.zoom -= Vector2(cam_zoom_speed, cam_zoom_speed)
if(event is InputEventMouseMotion and is_panning):
cam_container.global_position -= event.relative / cam.zoom