175 lines
4.1 KiB
GDScript
175 lines
4.1 KiB
GDScript
@tool
|
|
class_name CollisionSwitcher
|
|
extends Node
|
|
|
|
|
|
signal switched(new_color: CollisionSwitcher.ObjectColor)
|
|
|
|
|
|
enum ObjectColor {
|
|
White,
|
|
Black,
|
|
}
|
|
|
|
|
|
enum Collisions {
|
|
GREY_WORLD = 1 << 0,
|
|
GREY_ENEMY = 1 << 4,
|
|
|
|
BLACK_WORLD = 1 << 1,
|
|
BLACK_ENEMY = 1 << 2,
|
|
BLACK_PLAYER = 1 << 3,
|
|
|
|
WHITE_WORLD = 1 << 5,
|
|
WHITE_ENEMY = 1 << 6,
|
|
WHITE_PLAYER = 1 << 7,
|
|
|
|
GREY = GREY_WORLD | GREY_ENEMY,
|
|
BLACK = BLACK_WORLD | BLACK_ENEMY | BLACK_PLAYER,
|
|
WHITE = WHITE_WORLD | WHITE_ENEMY | WHITE_PLAYER,
|
|
}
|
|
|
|
enum State {
|
|
Black,
|
|
White,
|
|
TransitionToBlack,
|
|
TransitionToWhite,
|
|
}
|
|
|
|
|
|
const COLLISION_WHITE_SHIFT = 4
|
|
|
|
const MIN_INTENSITY = 0.0
|
|
const MAX_INTENSITY = 1.0
|
|
|
|
const SHADER_SWITCH_COLORS = "shader_parameter/switch_colors"
|
|
const SHADER_INTENSITY = "shader_parameter/intensity"
|
|
|
|
|
|
@export var objects : Array[CollisionObject2D] = []
|
|
|
|
@export var initial_state := State.White
|
|
|
|
|
|
var _materials : Array[Material]
|
|
|
|
|
|
var _state : State:
|
|
set(value):
|
|
_state = value
|
|
if is_node_ready():
|
|
_apply_color()
|
|
|
|
var _intensity_tween : Tween
|
|
|
|
var _grey_layers : Dictionary[CollisionObject2D, int] = {}
|
|
var _color_layers : Dictionary[CollisionObject2D, int] = {}
|
|
|
|
var _grey_masks : Dictionary[CollisionObject2D, int] = {}
|
|
var _color_masks : Dictionary[CollisionObject2D, int] = {}
|
|
|
|
|
|
func _ready() -> void:
|
|
for object in objects:
|
|
_grey_layers[object] = _get_grey_collision(object.collision_layer)
|
|
_color_layers[object] = _get_color_collision(object.collision_layer)
|
|
_grey_masks[object] = _get_grey_collision(object.collision_mask)
|
|
_color_masks[object] = _get_color_collision(object.collision_mask)
|
|
|
|
_state = initial_state
|
|
|
|
_apply_color()
|
|
|
|
|
|
func add_material(material: Material) -> void:
|
|
_materials.append(material)
|
|
_apply_color_to_material(material)
|
|
|
|
|
|
func switch_color(switch_time := 0.0) -> void:
|
|
if _intensity_tween != null and _intensity_tween.is_running(): return #TODO
|
|
|
|
if is_zero_approx(switch_time):
|
|
_state = State.Black if _state == State.White else State.White
|
|
_emit_switch_signal()
|
|
else:
|
|
_state = State.TransitionToBlack if _state == State.White else State.TransitionToWhite
|
|
|
|
_intensity_tween = create_tween()
|
|
_intensity_tween.tween_method(_set_shader_internsity, 0.0, MAX_INTENSITY, switch_time) \
|
|
.set_ease(Tween.EASE_OUT_IN) \
|
|
.set_trans(Tween.TRANS_SINE)
|
|
_intensity_tween.finished.connect(_update_state)
|
|
|
|
|
|
func _get_grey_collision(collision: int) -> int:
|
|
return collision & Collisions.GREY
|
|
|
|
|
|
func _get_color_collision(collision: int) -> int:
|
|
var black_collision := collision & Collisions.BLACK
|
|
var white_collision := (collision & Collisions.WHITE) >> COLLISION_WHITE_SHIFT
|
|
return black_collision | white_collision
|
|
|
|
|
|
func _set_shader_internsity(value: float) -> void:
|
|
for material in _materials:
|
|
material.set(SHADER_INTENSITY, value)
|
|
|
|
|
|
func _update_state() -> void:
|
|
match _state:
|
|
State.TransitionToBlack:
|
|
_state = State.Black
|
|
State.TransitionToWhite:
|
|
_state = State.White
|
|
_emit_switch_signal()
|
|
|
|
|
|
func _apply_color() -> void:
|
|
for object in objects:
|
|
_apply_color_to_object(object)
|
|
|
|
for material in _materials:
|
|
_apply_color_to_material(material)
|
|
|
|
|
|
func _apply_color_to_object(object: CollisionObject2D) -> void:
|
|
var layer := 0
|
|
var mask := 0
|
|
var grey_layer := _grey_layers[object]
|
|
var color_layer := _color_layers[object]
|
|
var grey_mask := _grey_masks[object]
|
|
var color_mask := _color_masks[object]
|
|
|
|
match _state:
|
|
State.Black:
|
|
layer = grey_layer | color_layer
|
|
mask = grey_mask | color_mask
|
|
State.White:
|
|
layer = grey_layer | (color_layer << COLLISION_WHITE_SHIFT)
|
|
mask = grey_mask | (color_mask << COLLISION_WHITE_SHIFT)
|
|
State.TransitionToBlack, State.TransitionToWhite:
|
|
layer = grey_layer | color_layer | (color_layer << COLLISION_WHITE_SHIFT)
|
|
mask = grey_mask | color_mask | (color_mask << COLLISION_WHITE_SHIFT)
|
|
|
|
object.collision_layer = layer
|
|
object.collision_mask = mask
|
|
|
|
|
|
func _apply_color_to_material(material: Material) -> void:
|
|
var is_black := _state == State.Black or _state == State.TransitionToBlack
|
|
material.set(SHADER_SWITCH_COLORS, is_black)
|
|
|
|
|
|
func _emit_switch_signal() -> void:
|
|
var color : ObjectColor
|
|
match _state:
|
|
State.White:
|
|
color = ObjectColor.White
|
|
State.Black:
|
|
color = ObjectColor.Black
|
|
_:
|
|
return
|
|
switched.emit(color)
|