CameraController.gd 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107
  1. extends Spatial
  2. # Handle the motion of both players' camera as well as communication with the
  3. # SplitScreen shader to achieve the dynamic split screen effet
  4. #
  5. # Cameras are place on the segment joining the two players, either in the middle
  6. # if players are close enough or at a fixed distance if they are not.
  7. # In the first case, both cameras being at the same location, only the view of
  8. # the first one is used for the entire screen thus allowing the players to play
  9. # on a unsplit screen.
  10. # In the second case, the screen is split in two with a line perpendicular to the
  11. # segement joining the two players.
  12. #
  13. # The points of customization are:
  14. # max_separation: the distance between players at which the view starts to split
  15. # split_line_thickness: the thickness of the split line in pixels
  16. # split_line_color: color of the split line
  17. # adaptive_split_line_thickness: if true, the split line thickness will vary
  18. # depending on the distance between players. If false, the thickness will
  19. # be constant and equal to split_line_thickness
  20. export(float) var max_separation = 20.0
  21. export(float) var split_line_thickness = 3.0
  22. export(Color, RGBA) var split_line_color = Color.black
  23. export(bool) var adaptive_split_line_thickness = true
  24. onready var player1 = $'../Player1'
  25. onready var player2 = $'../Player2'
  26. onready var camera1: Camera = $'Viewport1/Camera1'
  27. onready var camera2: Camera = $'Viewport2/Camera2'
  28. onready var view: TextureRect = $'View'
  29. func _ready():
  30. _on_size_changed()
  31. _update_splitscreen()
  32. get_viewport().connect("size_changed", self, "_on_size_changed")
  33. view.material.set_shader_param('viewport1', $Viewport1.get_texture())
  34. view.material.set_shader_param('viewport2', $Viewport2.get_texture())
  35. func _process(_delta):
  36. _move_cameras()
  37. _update_splitscreen()
  38. func _move_cameras():
  39. var position_difference = _compute_position_difference_in_world()
  40. var distance = clamp(_compute_horizontal_length(position_difference), 0, max_separation)
  41. position_difference = position_difference.normalized() * distance
  42. camera1.translation.x = player1.translation.x + position_difference.x / 2.0
  43. camera1.translation.z = player1.translation.z + position_difference.z / 2.0
  44. camera2.translation.x = player2.translation.x - position_difference.x / 2.0
  45. camera2.translation.z = player2.translation.z - position_difference.z / 2.0
  46. func _update_splitscreen():
  47. var screen_size = get_viewport().get_visible_rect().size
  48. var player1_position = camera1.unproject_position(player1.translation) / screen_size
  49. var player2_position = camera2.unproject_position(player2.translation) / screen_size
  50. var thickness
  51. if adaptive_split_line_thickness:
  52. var position_difference = _compute_position_difference_in_world()
  53. var distance = _compute_horizontal_length(position_difference)
  54. thickness = lerp(0, split_line_thickness, (distance - max_separation) / max_separation)
  55. thickness = clamp(thickness, 0, split_line_thickness)
  56. else:
  57. thickness = split_line_thickness
  58. view.material.set_shader_param('split_active', _get_split_state())
  59. view.material.set_shader_param('player1_position', player1_position)
  60. view.material.set_shader_param('player2_position', player2_position)
  61. view.material.set_shader_param('split_line_thickness', thickness)
  62. view.material.set_shader_param('split_line_color', split_line_color)
  63. # Split screen is active if players are too far apart from each other.
  64. # Only the horizontal components (x, z) are used for distance computation
  65. func _get_split_state():
  66. var position_difference = _compute_position_difference_in_world()
  67. var separation_distance = _compute_horizontal_length(position_difference)
  68. return separation_distance > max_separation
  69. func _on_size_changed():
  70. var screen_size = get_viewport().get_visible_rect().size
  71. $Viewport1.size = screen_size
  72. $Viewport2.size = screen_size
  73. view.rect_size = screen_size
  74. view.material.set_shader_param('viewport_size', screen_size)
  75. func _compute_position_difference_in_world():
  76. return player2.translation - player1.translation
  77. func _compute_horizontal_length(vec):
  78. return Vector2(vec.x, vec.z).length()