Last active
January 1, 2025 05:53
-
-
Save statico/53cc1a0b154ae60ef8b238cb04d3035f to your computer and use it in GitHub Desktop.
Custom tile map for Godot 4.3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@tool | |
@icon("res://assets/icons/grid.svg") | |
class_name CustomTileMap | |
extends Node2D | |
@export var tile_size: Vector2 = Vector2(24, 24) | |
@export var texture: Texture2D: | |
set(value): | |
texture = value | |
if is_node_ready(): | |
_initialize(width, height) | |
var tiles: Array[Dictionary] = [] | |
var multimesh: MultiMeshInstance2D | |
var width: int = 0 | |
var height: int = 0 | |
var initialized: bool = false | |
func _ready() -> void: | |
if not initialized and texture: | |
_initialize(1, 1) # Initialize with minimum size | |
initialized = true | |
# Add support for tile coordinates and atlas | |
func set_cell(coords: Vector2i, atlas_id: int, tile_coords: Vector2i) -> void: | |
# Auto-expand the tilemap if needed | |
var new_width = maxi(width, coords.x + 1) | |
var new_height = maxi(height, coords.y + 1) | |
if new_width > width or new_height > height: | |
_initialize(new_width, new_height) | |
var index = coords.y * width + coords.x | |
if index < 0 or index >= tiles.size(): | |
return | |
# Calculate UV coordinates for the tile in the atlas | |
var uv_size = Vector2(tile_size.x / texture.get_width(), tile_size.y / texture.get_height()) | |
var uv_position = Vector2(tile_coords.x * uv_size.x, tile_coords.y * uv_size.y) | |
# Store tile data | |
tiles[index] = { | |
"atlas_id": atlas_id, | |
"tile_coords": tile_coords, | |
"uv_position": uv_position, | |
"uv_size": uv_size | |
} | |
# Update transform and UVs for this tile | |
if multimesh and multimesh.multimesh: # Add null check | |
var trans = Transform2D() | |
trans.origin = Vector2(coords.x * tile_size.x, coords.y * tile_size.y) | |
multimesh.multimesh.set_instance_transform_2d(index, trans) | |
multimesh.multimesh.set_instance_custom_data( | |
index, Color(uv_position.x, uv_position.y, uv_size.x, uv_size.y) | |
) | |
func _initialize(p_width: int, p_height: int) -> void: | |
width = p_width | |
height = p_height | |
# Resize tiles array | |
var old_size = tiles.size() | |
tiles.resize(width * height) | |
# Initialize MultiMesh if not already done | |
if not initialized: | |
multimesh = MultiMeshInstance2D.new() | |
add_child(multimesh) | |
initialized = true | |
# Create shader material for UV mapping | |
var shader_material = ShaderMaterial.new() | |
shader_material.shader = preload("res://assets/shaders/custom_tile_map.gdshader") | |
multimesh.material = shader_material | |
# Update MultiMesh | |
var mesh = MultiMesh.new() | |
mesh.use_custom_data = true | |
mesh.transform_format = MultiMesh.TRANSFORM_2D | |
mesh.instance_count = width * height | |
# Create base mesh (quad) for the tiles | |
var quad = QuadMesh.new() | |
quad.size = tile_size | |
mesh.mesh = quad | |
multimesh.multimesh = mesh | |
# Initialize new tile transforms | |
for i in range(old_size, tiles.size()): | |
var trans = Transform2D() | |
trans.origin = Vector2((i % width) * tile_size.x, floor(float(i) / width) * tile_size.y) | |
multimesh.multimesh.set_instance_transform_2d(i, trans) | |
multimesh.multimesh.set_instance_custom_data(i, Color(0, 0, 0, 0)) | |
func clear() -> void: | |
if not multimesh or not multimesh.multimesh: | |
return | |
for i in range(tiles.size()): | |
tiles[i] = {} | |
var trans = Transform2D() | |
trans.origin = Vector2((i % width) * tile_size.x, floor(float(i) / width) * tile_size.y) | |
multimesh.multimesh.set_instance_transform_2d(i, trans) | |
# Set UV to empty/transparent | |
multimesh.multimesh.set_instance_custom_data(i, Color(0, 0, 0, 0)) | |
func _to_string() -> String: | |
return "CustomTileMap(width: %d, height: %d)" % [width, height] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
shader_type canvas_item; | |
uniform sampler2D tile_atlas : filter_nearest; | |
uniform float shake_amount = 0.0; | |
uniform vec4 transparent_color : source_color = vec4(0.278431, 0.423529, 0.423529, 1); | |
uniform float threshold = 0.1; | |
uniform vec2 bounce_direction = vec2(0.0, 0.0); | |
uniform float bounce_amount = 0.0; | |
// Add varying variable declaration at the top | |
varying vec4 v_custom_data; | |
void vertex() { | |
// Pass INSTANCE_CUSTOM to fragment shader | |
v_custom_data = INSTANCE_CUSTOM; | |
// Add shake effect | |
if (shake_amount > 0.0) { | |
float shake_x = cos(TIME * 50.0) * shake_amount; | |
float shake_y = sin(TIME * 45.0) * shake_amount; | |
VERTEX.x += shake_x; | |
VERTEX.y += shake_y; | |
} | |
// Add bounce effect | |
VERTEX += bounce_direction * bounce_amount; | |
} | |
void fragment() { | |
// Use v_custom_data instead of INSTANCE_CUSTOM | |
vec2 uv_position = v_custom_data.xy; | |
vec2 uv_size = v_custom_data.zw; | |
// Calculate final UV coordinates | |
vec2 final_uv = uv_position + (UV * uv_size); | |
// Sample the texture | |
vec4 color = texture(tile_atlas, final_uv); | |
// Make specific color transparent | |
float difference = length(color - transparent_color); | |
if (difference < threshold) { | |
COLOR.a = 0.0; | |
} else { | |
COLOR = color; | |
} | |
// DEBUG - Just get it working! | |
COLOR = vec4(1.0, 0.0, 0.0, 1.0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment