class_name Ball extends CharacterBody2D ## A ball that bounces off everything and speeds up slightly on each bounce. ## Emitted for every contact, so the game can react to what the ball touched. signal hit(ball: Ball, other: Node) ## A superball destroys one indestructible block, then turns back into a normal ball. var superball := false: set(value): superball = value queue_redraw() func throw() -> void: var angle := deg_to_rad(randf_range(-Params.THROW_ANGLE, Params.THROW_ANGLE)) velocity = Vector2(sin(angle), -cos(angle)) * Params.INITIAL_SPEED func _physics_process(delta: float) -> void: var motion := velocity * delta for i in 4: var collision := move_and_collide(motion) if collision == null: break var other := collision.get_collider() as Node var normal := collision.get_normal() var bounce: float = other.get_meta("bounce", 1.0) velocity = velocity.bounce(normal) * Params.BALL_BOUNCE * bounce motion = collision.get_remainder().bounce(normal) hit.emit(self, other) if is_queued_for_deletion(): return _kick_power_ups() ## Power-ups are 1/1000 of a ball's mass: they get knocked away and the ball doesn't notice. func _kick_power_ups() -> void: for power_up: PowerUp in get_tree().get_nodes_in_group("power_ups"): var offset := power_up.global_position - global_position var dist := offset.length() if dist == 0.0 or dist > Params.BALL_RADIUS + PowerUp.RADIUS: continue var normal := offset / dist var approach := (power_up.linear_velocity - velocity).dot(normal) if approach < 0.0: power_up.linear_velocity -= 2.0 * approach * normal hit.emit(self, power_up) func _draw() -> void: draw_circle(Vector2.ZERO, Params.BALL_RADIUS, Params.COLOR_ORANGE if superball else Params.COLOR_GREY, true, -1.0, true)