class_name PowerUp extends RigidBody2D ## A small token that falls from the top. Catch it with the paddle to collect it. ## Emitted from a physics callback; connect it deferred before adding or resizing bodies. signal collected(kind: Kind) enum Kind { TRIPLE_BALLS, PADDLE, SUPERBALL, SLOW, CATCH, SHIELD, BIG_BALL, FIREBALL, RUSH, LASER, FREEZE, BOMB, HOMING, } const RADIUS := 12.0 const GLYPH_SIZE := 18 const FONT := preload("res://assets/fonts/abel.ttf") ## Per kind: name, colour, the letter on the token, first level it drops at, and its weight ## in the random pick. Triple balls are not in the pick: they drop when the ball is idle. ## Power-downs (down = true) get likelier as the levels go up. const KINDS := { Kind.TRIPLE_BALLS: { name = "Triple balls", color = Params.COLOR_PINK, glyph = "3", unlock = 0, weight = 0.0 }, Kind.PADDLE: { name = "Paddle size", color = Params.COLOR_BLUE, glyph = "P", unlock = 0, weight = 1.0 }, Kind.SUPERBALL: { name = "Super ball", color = Params.COLOR_ORANGE, glyph = "X", unlock = 0, weight = 0.6 }, Kind.SLOW: { name = "Slow-mo", color = Color("#5fb3ff"), glyph = "Z", unlock = 2, weight = 0.8 }, Kind.CATCH: { name = "Catch", color = Color("#8be28b"), glyph = "C", unlock = 4, weight = 0.8 }, Kind.SHIELD: { name = "Shield", color = Color("#f4f4f0"), glyph = "U", unlock = 6, weight = 0.7 }, Kind.BIG_BALL: { name = "Big ball", color = Color("#c9c9c9"), glyph = "O", unlock = 8, weight = 0.7 }, Kind.FIREBALL: { name = "Fireball", color = Params.COLOR_FIRE, glyph = "F", unlock = 12, weight = 0.6 }, Kind.RUSH: { name = "Rush", color = Params.COLOR_PINK, glyph = "!", unlock = 15, weight = 0.4, down = true }, Kind.LASER: { name = "Laser", color = Params.COLOR_RED, glyph = "L", unlock = 20, weight = 0.6 }, Kind.FREEZE: { name = "Freeze", color = Color("#d6f3ff"), glyph = "*", unlock = 25, weight = 0.6 }, Kind.BOMB: { name = "Bomb ball", color = Params.COLOR_BOMB, glyph = "B", unlock = 30, weight = 0.6 }, Kind.HOMING: { name = "Homing", color = Color("#ff8a8a"), glyph = "H", unlock = 40, weight = 0.5 }, } var kind := Kind.PADDLE func _ready() -> void: add_to_group("power_ups") body_entered.connect(_on_body_entered) ## Weight of [param kind] in the random pick at [param level]; 0 when not unlocked yet. static func weight(kind: Kind, level: int) -> float: var info: Dictionary = KINDS[kind] if level < info.unlock: return 0.0 if info.get("down", false): return info.weight * Params.power_down_factor(level) return info.weight func _on_body_entered(body: Node) -> void: if body is Paddle: collected.emit(kind) queue_free() elif body.is_in_group("bottom"): queue_free() func _draw() -> void: var color: Color = KINDS[kind].color draw_circle(Vector2.ZERO, RADIUS, color, true, -1.0, true) # Dark letters on light tokens, light letters on dark ones. var ink := Params.COLOR_BACK if color.get_luminance() > 0.5 else Color.WHITE var text: String = KINDS[kind].glyph var text_size := FONT.get_string_size(text, HORIZONTAL_ALIGNMENT_LEFT, -1, GLYPH_SIZE) draw_string(FONT, Vector2(-text_size.x / 2.0, FONT.get_ascent(GLYPH_SIZE) / 2.0 - 1.0), text, HORIZONTAL_ALIGNMENT_LEFT, -1, GLYPH_SIZE, ink)