Blobby/src/Actors/BlobbyCam.gd
Jakob Feldmann 4238855751 Many added feats:
Invincibility Shader (simple)
New Death Shader dissolving
Pit Areas
Invincibility fixes for spikes and flying laser cutters
Vending Machine
Better global and level stats tracking
2023-04-04 16:45:38 +02:00

207 lines
8.3 KiB
GDScript

extends Camera2D
var horizontal_facing = 0
var vertical_facing = 0
var camera_vertical_shift = 0
var right_move_time: float = 0
var left_move_time: float = 0
var slow_time: float = 0
var original_limit_left: int
var original_limit_right: int
var original_limit_bottom: int
var original_limit_top: int
var camera_is_panning: bool = false
var target_offset: Vector2 = Vector2(0,0)
export var camera_horizontal_shift = 60
export var offset_reset_seconds := 1
export var offset_adapt_seconds := 1
onready var levelState := $"%LevelState"
onready var signalManager := $"%SignalManager"
onready var shiftLeft = $CameraAnimationPlayer.get_animation("shiftingLeft")
onready var shiftRight = $CameraAnimationPlayer.get_animation("shiftingRight")
onready var shiftCenter = $CameraAnimationPlayer.get_animation("shiftingCenter")
onready var anim_player = $CameraAnimationPlayer
onready var original_x_zoom = zoom.x
onready var original_y_zoom = zoom.y
onready var blobby = get_node("%Blobby")
onready var screen_rect = Vector2(ProjectSettings.get_setting("display/window/size/width") * zoom.x, ProjectSettings.get_setting("display/window/size/height") * zoom.y )
var image = Image.new()
var texture = ImageTexture.new()
var prev_pos: Vector2
# Gets the camera limits from the tilemap of the level
# Requires "TileMap" to be a sibling of blobby
func _ready():
_set_boundaries()
print(screen_rect)
self.position = blobby.global_position
image.create(128, 2, false, Image.FORMAT_RGBAH)
# TODO Test Performance
_update_lighting_shader()
# TODO Trigger when needed
signalManager.connect("terminal_activated", self, "_on_SignalManager_terminal_activated")
signalManager.connect("player_died", self, "_death_cam")
func _on_SignalManager_terminal_activated():
get_node("LightAnimationPlayer").play("Pulsing")
func _physics_process(delta: float) -> void:
if(anim_player.is_playing()):
position = blobby.position
prev_pos = position
_update_lighting_shader()
return
var player_vel = (blobby.position - prev_pos)/delta
# TODO Take average of velocity here
if(abs(player_vel.x) >= blobby.max_velocity["walk"] * 0.97
&& (sign(player_vel.x) == sign(target_offset.x) || target_offset.x == 0)):
if(player_vel.x > 0):
right_move_time += delta
left_move_time = max(0, left_move_time - delta)
slow_time = max(0, slow_time - delta)
else:
left_move_time += delta
right_move_time = max(0, right_move_time - delta)
slow_time = max(0, slow_time - delta)
elif(abs(player_vel.x) <= blobby.max_velocity["walk"] * 0.9
|| sign(player_vel.x) != sign(target_offset.x) || target_offset.x == 0):
slow_time += delta
left_move_time = max(0, left_move_time - delta)
right_move_time = max(0, right_move_time - delta)
_adapt_to_movement(player_vel)
position = blobby.position
prev_pos = position
_update_lighting_shader()
func _set_boundaries():
# This is ok, because it only happens on initialization
# But it is also quite fickle
var tilemap = get_node("./%TileMap")
# TODO: This goes wrong when overwriting old tiles with new sprites
# New pngs -> completely new tiles and rebuild map
var rect = tilemap.get_used_rect()
var cell_size = tilemap.cell_size
limit_right = rect.end.x * cell_size.x
limit_left = rect.position.x * cell_size.x
limit_top = rect.position.y * cell_size.y
limit_bottom = rect.end.y * cell_size.y
original_limit_left = limit_left
original_limit_right = limit_right
original_limit_top = limit_top
original_limit_bottom = limit_bottom
var screen_size = get_viewport_rect()
var h_pixels = limit_right - limit_left
var v_pixels = limit_bottom - limit_top
# TODO: Fix that it can zoom both?
if screen_size.end.x * original_x_zoom - h_pixels > 0:
zoom.x = h_pixels / screen_size.end.x
zoom.y = zoom.x
if screen_size.end.y * original_y_zoom - v_pixels > 0:
zoom.y = v_pixels / screen_size.end.y
zoom.x = zoom.y
# Smoothing the camera limits in godot ruins something
func _adapt_to_movement(velocity: Vector2) -> void:
var offset_track
var center = get_camera_screen_center()
var left_edge_pos = center.x - screen_rect.x/2 + camera_horizontal_shift
var right_edge_pos = center.x + screen_rect.x/2 - camera_horizontal_shift
if(left_move_time >= offset_adapt_seconds && !anim_player.is_playing()):
left_move_time = 0
target_offset.x = -camera_horizontal_shift
if(offset == target_offset ||
left_edge_pos + target_offset.x - 24 < limit_left ||
right_edge_pos + target_offset.x + 24 > limit_right ):
return
offset_track = shiftLeft.find_track(".:offset")
shiftLeft.track_set_key_value(offset_track, 0, offset)
shiftLeft.track_set_key_value(offset_track, 1, target_offset)
# limit_left = original_limit_left + camera_horizontal_shift
var limit_left_track = shiftLeft.find_track(".:limit_left")
var new_limit_left = original_limit_left + camera_horizontal_shift
shiftLeft.track_set_key_value(limit_left_track, 0, limit_left)
shiftLeft.track_set_key_value(limit_left_track, 1, new_limit_left)
anim_player.play("shiftingLeft")
elif(right_move_time >= offset_adapt_seconds && !anim_player.is_playing()):
right_move_time = 0
target_offset.x = camera_horizontal_shift
if(offset == target_offset ||
left_edge_pos + target_offset.x - 24 < limit_left ||
right_edge_pos + target_offset.x + 24 > limit_right ):
return
offset_track = shiftRight.find_track(".:offset")
shiftRight.track_set_key_value(offset_track, 0, offset)
shiftRight.track_set_key_value(offset_track, 1, target_offset)
# limit_right = original_limit_right - camera_horizontal_shift
var limit_right_track = shiftRight.find_track(".:limit_right")
var new_limit_right = original_limit_right - camera_horizontal_shift
shiftRight.track_set_key_value(limit_right_track, 0, limit_right)
shiftRight.track_set_key_value(limit_right_track, 1, new_limit_right)
anim_player.play("shiftingRight")
elif(slow_time >= offset_reset_seconds):
slow_time = 0
target_offset.x = 0
if(offset == target_offset):
return
if(left_edge_pos > limit_left && limit_right > right_edge_pos):
offset_track = shiftCenter.find_track(".:offset")
shiftCenter.track_set_key_value(offset_track, 0, offset)
shiftCenter.track_set_key_value(offset_track, 1, target_offset)
var limit_left_track = shiftCenter.find_track(".:limit_left")
var limit_right_track = shiftCenter.find_track(".:limit_right")
var limit_top_track = shiftCenter.find_track(".:limit_top")
var limit_bottom_track = shiftCenter.find_track(".:limit_bottom")
shiftCenter.track_set_key_value(limit_left_track, 0, limit_left)
shiftCenter.track_set_key_value(limit_right_track, 0, limit_right)
shiftCenter.track_set_key_value(limit_top_track, 0, limit_top)
shiftCenter.track_set_key_value(limit_bottom_track, 0, limit_bottom)
shiftCenter.track_set_key_value(limit_left_track, 1, original_limit_left)
shiftCenter.track_set_key_value(limit_right_track, 1,original_limit_right)
shiftCenter.track_set_key_value(limit_top_track, 1, original_limit_top)
shiftCenter.track_set_key_value(limit_bottom_track, 1, original_limit_bottom)
anim_player.play("shiftingCenter")
return
func reset_limits() -> void:
limit_left = original_limit_left
limit_right = original_limit_right
limit_bottom = original_limit_bottom
limit_top = original_limit_top
func _death_cam():
$CameraAnimationPlayer.play("deathCamJustZoom")
func _update_lighting_shader():
# Props to gameendaevour
# TODO get this into a central world update management system
var lights = get_tree().get_nodes_in_group("light")
image.lock()
for i in lights.size():
var light = lights[i]
# TODO To make the lighting affect all layers properly
# I would have the access the global positions of nodes in different Z layers
# without the projection to the global center layer.
# var vtrans = get_canvas_transform()
# var top_left = -vtrans.origin / vtrans.get_scale()
# var vsize = get_viewport_rect().size
# var t = Transform2D(0, (top_left + 0.5*vsize/vtrans.get_scale()).rotated(rotation))
image.set_pixel(i, 0, Color(
light.position.x, light.position.y,
light.strength, light.radius
))
image.set_pixel(i, 1, light.color)
image.unlock()
texture.create_from_image(image)
material.set_shader_param("n_lights", lights.size())
material.set_shader_param("light_data", texture)
material.set_shader_param("global_transform", get_global_transform())
material.set_shader_param("viewport_transform", get_viewport_transform())