Troca de paleta
O sprite guarda índices de paleta em vez de cores, então trocar a paleta repinta a arte inteira.
O editor acima está rodando este projeto. Mude uma linha e ele recarrega.
Classes do Godot usadas
Sprite2DImageTextureShaderMaterial
O 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));
}