Cambio de paleta

El sprite guarda índices de paleta en vez de colores, así que rotar la paleta repinta todo el arte.

El editor de arriba está ejecutando este proyecto. Cambia una línea y se recarga.

Clases de Godot usadas

Sprite2DImageTextureShaderMaterial

El código

scripts/main.gd
extends Node

const PALETTE: Array = ['#2b3a67', '#8da5f3', '#8eef97', '#f3d48d', '#fc7f7f']
const ART: Array = [
	'00011111000',
	'00122222100',
	'01233333210',
	'12344444321',
	'12344444321',
	'01233333210',
	'00122222100',
	'00011111000',
]


func _ready() -> void:
	var background: ColorRect = ColorRect.new()
	background.color = Color('#12141a')
	add_child(background)
	background.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)

	var material: ShaderMaterial = ShaderMaterial.new()
	material.shader = Get.shader('palette')
	material.set_shader_parameter('palette_texture', _make_palette())
	material.set_shader_parameter('palette_size', PALETTE.size())

	var sprite: Sprite2D = Sprite2D.new()
	sprite.texture = _make_art()
	sprite.material = material
	sprite.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST
	sprite.scale = Vector2(28, 28)
	sprite.position = get_viewport().get_visible_rect().size * 0.5
	add_child(sprite)

	var label: Label = Label.new()
	label.text = 'the sprite stores palette indices, the shader picks the colors'
	label.position = Vector2(40, 40)
	label.add_theme_color_override('font_color', Color('#999999'))
	add_child(label)


func _make_art() -> ImageTexture:
	var image: Image = Image.create(ART[0].length(), ART.size(), false, Image.FORMAT_RGBA8)

	for y in ART.size():
		for x in ART[0].length():
			var index: int = int(ART[y][x])
			var value: float = float(index) / PALETTE.size()
			image.set_pixel(x, y, Color(value, value, value, 1.0))

	return ImageTexture.create_from_image(image)


func _make_palette() -> ImageTexture:
	var image: Image = Image.create(PALETTE.size(), 1, false, Image.FORMAT_RGBA8)

	for i in PALETTE.size():
		image.set_pixel(i, 0, Color(PALETTE[i]))

	return ImageTexture.create_from_image(image)
shaders/palette.gdshader
shader_type canvas_item;

uniform sampler2D palette_texture: filter_nearest;
uniform int palette_size = 5;
uniform float cycle_speed = 0.6;

void fragment() {
	float index = texture(TEXTURE, UV).r;

	if (index < 0.01) {
		discard;
	}

	// the pixel stores the index and not the color, so cycling the palette repaints the whole art
	float slot = floor(index * float(palette_size) - 0.5);
	float shifted = mod(slot + floor(TIME * cycle_speed), float(palette_size));

	COLOR = texture(palette_texture, vec2((shifted + 0.5) / float(palette_size), 0.5));
}

Más ejemplos de Shaders