2023-10-02 13:12:08 +00:00
|
|
|
extends Area2D
|
|
|
|
class_name Ghost
|
2023-10-02 15:53:13 +00:00
|
|
|
## Ghost previewing the instantiation of a scene.
|
2023-10-02 13:12:08 +00:00
|
|
|
|
2023-10-08 01:56:29 +00:00
|
|
|
|
|
|
|
## Color to modulate this with if the body currently isn't overlapping anything.
|
|
|
|
@export var valid_color: Color = Color.WHITE
|
|
|
|
|
|
|
|
## Color to modulate this with if the body currently is overlapping something.
|
|
|
|
@export var invalid_color: Color = Color.RED
|
|
|
|
|
|
|
|
|
|
|
|
## The [Instantiator] to use to spawn the ghosted item.
|
|
|
|
@onready var instantiator: Instantiator = $Instantiator
|
|
|
|
|
|
|
|
## The [OverlapChecker] to use to see if a solid block is overlapping the ghost.
|
|
|
|
@onready var overlap_checker: OverlapChecker = $OverlapChecker
|
|
|
|
|
|
|
|
## The [PlaceableAreaChecker] to use to see if the ghost is currently inside the placeable area.
|
|
|
|
@onready var placeable_area_checker: PlaceableAreaChecker = $PlaceableAreaChecker
|
|
|
|
|
|
|
|
## The [OverlapFreer] to use to delete the [PhysicsBody2D] behind the ghost before instantiation.
|
|
|
|
@onready var overlap_freer: OverlapFreer = $OverlapFreer
|
|
|
|
|
2023-10-02 15:53:13 +00:00
|
|
|
## The [CollisionShape2D] to use to check for placement checks.
|
|
|
|
##
|
|
|
|
## MUST consist of a [RectangleShape2D].
|
|
|
|
@onready var placement_shape: CollisionShape2D = $PlacementShape
|
2023-10-02 14:22:03 +00:00
|
|
|
|
2023-10-02 15:53:13 +00:00
|
|
|
## The [Sprite2D] node previewing the scene.
|
|
|
|
@onready var preview_sprite: Sprite2D = $PlacementShape/PreviewSprite
|
2023-10-02 14:22:03 +00:00
|
|
|
|
2023-10-13 00:04:43 +00:00
|
|
|
## The position the ghost should have when a new body starts being placed.
|
|
|
|
@onready var starting_position: Vector2 = position
|
2023-10-02 16:29:05 +00:00
|
|
|
|
2023-10-13 00:04:43 +00:00
|
|
|
## The rotation the ghost should have when a new body starts being placed.
|
|
|
|
@onready var starting_rotation_radians: float = rotation
|
|
|
|
|
|
|
|
|
|
|
|
## Whether this object can currently be placed.
|
|
|
|
var can_place: bool = false:
|
|
|
|
get:
|
|
|
|
return can_place
|
|
|
|
set(value):
|
|
|
|
if value != can_place:
|
|
|
|
can_place_changed.emit(value)
|
|
|
|
can_place = value
|
|
|
|
modulate = valid_color if value else invalid_color
|
|
|
|
|
|
|
|
## Emitted when [can_place] changes value.
|
|
|
|
signal can_place_changed(to: bool)
|
2023-10-02 14:22:03 +00:00
|
|
|
|
2023-10-05 22:09:24 +00:00
|
|
|
|
2023-10-02 16:29:05 +00:00
|
|
|
func _ready():
|
2023-10-12 19:45:52 +00:00
|
|
|
# Initialize the Area's collision mask
|
2023-10-13 00:04:43 +00:00
|
|
|
collision_mask = overlap_checker.overlap_mask | placeable_area_checker.overlap_mask | overlap_freer.overlap_mask
|
2023-10-02 16:29:05 +00:00
|
|
|
|
2023-10-08 01:56:29 +00:00
|
|
|
## Update the value of [can_place].
|
2023-10-12 19:45:52 +00:00
|
|
|
func update_state():
|
|
|
|
# DIRTY HACK: Relies on the placeable area being perfectly surrounded by solid bodies.
|
2023-10-08 01:56:29 +00:00
|
|
|
can_place = overlap_checker.is_overlapping_with == null and placeable_area_checker.is_overlapping_with != null
|
2023-10-02 16:29:05 +00:00
|
|
|
|
2023-10-13 00:04:43 +00:00
|
|
|
## For retro-compatibility, configure this for the placement of a [PurchasableItem].
|
|
|
|
func COMPAT_set_to_purchasable_item(pi: PurchasableItem):
|
|
|
|
instantiator.scene_to_instantiate = pi.item_scene
|
|
|
|
placement_shape.shape = pi.get_node("ConverterPlacementBody").get_node("FullConverterShape").shape
|
|
|
|
placement_shape.scale = pi.item_scene.scale
|
|
|
|
preview_sprite.texture = pi.item_icon
|
|
|
|
position = starting_position
|
|
|
|
rotation = starting_rotation_radians
|
|
|
|
|
2023-10-02 16:29:05 +00:00
|
|
|
|
2023-10-13 00:04:43 +00:00
|
|
|
## Configure this for the placement of a [ShopItem].
|
2023-10-12 19:45:52 +00:00
|
|
|
func set_to_shop_item(si: ShopItem):
|
2023-10-13 00:04:43 +00:00
|
|
|
instantiator.scene_to_instantiate = si.placement_scene
|
|
|
|
placement_shape.shape = si.placement_shape # TODO: Hmmm. Not the best interface.
|
|
|
|
placement_shape.scale = si.placement_scene.scale
|
|
|
|
preview_sprite.texture = si.placement_texture
|
|
|
|
position = starting_position
|
|
|
|
rotation = starting_rotation_radians
|
2023-10-12 19:45:52 +00:00
|
|
|
|
2023-10-13 00:04:43 +00:00
|
|
|
## Emitted when [materialize] is called.
|
|
|
|
signal materialized(what: Node)
|
2023-10-12 19:45:52 +00:00
|
|
|
|
2023-10-13 00:04:43 +00:00
|
|
|
## Try to materialize the scene, returning it if the instantiation was successful, or null if it wasn't.
|
|
|
|
##
|
|
|
|
## Remember to try the placement again if this returns null!
|
|
|
|
func materialize() -> Node:
|
2023-10-02 18:28:08 +00:00
|
|
|
if not can_place:
|
|
|
|
return null
|
2023-10-13 00:04:43 +00:00
|
|
|
overlap_freer.area_queue_free()
|
2023-10-08 01:56:29 +00:00
|
|
|
var inst = instantiator.instantiate()
|
2023-10-13 00:04:43 +00:00
|
|
|
materialized.emit(inst)
|
2023-10-08 01:56:29 +00:00
|
|
|
return inst
|