@tool extends Node2D ## Visual and collision bounds share the node origin, in native game pixels. @export_enum("fighter", "boss", "butterfly", "bee", "shot", "enemy_shot", "explosion", "enemy_explosion") var kind := "fighter": set(value): kind = value queue_redraw() @export var damaged := false @export var radius := 6.0 var animation_time := 0.0 var spinning := false var spin_time := 0.0 @export var heading := Vector2.DOWN const SHEET = preload("res://games/galaga/art/spr_galaga.png") const DIRECTION_ROWS := {"boss":36, "boss_damaged":54, "butterfly":72, "bee":108} func _ready() -> void: texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST if kind not in ["shot", "enemy_shot"]: var sprite_material := ShaderMaterial.new() sprite_material.shader = preload("res://games/galaga/actors/sprite.gdshader") material = sprite_material func _process(_delta: float) -> void: queue_redraw() func _draw() -> void: # Quantize the rendered center in native 224x288 coordinates, before the # view's integer enlargement. Keep simulation positions precise. draw_set_transform(position.round()-position) if kind in ["shot", "enemy_shot"]: draw_rect(Rect2(-1, -3, 2, 6), Color.CYAN if kind == "shot" else Color.SALMON) return if kind == "explosion": var frame := mini(3, int(animation_time * 12)) draw_texture_rect_region(SHEET, Rect2(-16,-16,32,32), Rect2(145 + frame * 34, 1, 32,32)) return if kind == "enemy_explosion": var frame := mini(4, int(animation_time * 15)) draw_texture_rect_region(SHEET, Rect2(-16,-16,32,32), Rect2(289+frame*34,1,32,32)) return var source := Vector2(108,0) var destination := Rect2(-8,-8,16,16) if kind=="fighter" and spinning: var facing := Vector2.UP.rotated(spin_time*TAU*2) var column := 6-clampi(roundi(atan2(absf(facing.x),absf(facing.y))/(PI/12)),0,6) source=Vector2(column*18,0) if facing.x>0: destination.size.x=-16 if facing.y>0: destination.size.y=-16 if kind in ["boss", "butterfly", "bee"]: # Seven authored angles from right to down, at 15-degree intervals. # Mirror these pixels into the other quadrants; never rotate the texture. var column := 6 - clampi(roundi(atan2(absf(heading.x),absf(heading.y))/(PI/12)),0,6) # Adjacent rows are different sprites, not interchangeable wing frames. var row: int = DIRECTION_ROWS["boss_damaged" if kind == "boss" and damaged else kind] source = Vector2(column*18,row) if heading.x < 0: destination.size.x = -16 if heading.y < 0: destination.size.y = -16 draw_texture_rect_region(SHEET, destination, Rect2(source+Vector2.ONE,Vector2(16,16))) if Engine.is_editor_hint(): draw_arc(Vector2.ZERO, radius, 0, TAU, 24, Color(0,1,0,0.5))