node_25d.gd 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. # This node converts a 3D position to 2D using a 2.5D transformation matrix.
  2. # The transformation of its 2D form is controlled by its 3D child.
  3. tool
  4. extends Node2D
  5. class_name Node25D, "res://addons/node25d/icons/node_25d_icon.png"
  6. # SCALE is the number of 2D units in one 3D unit. Ideally, but not necessarily, an integer.
  7. const SCALE = 32
  8. # Exported spatial position for editor usage.
  9. export(Vector3) var spatial_position setget set_spatial_position, get_spatial_position
  10. # GDScript throws errors when Basis25D is its own structure.
  11. # There is a broken implementation in a hidden folder.
  12. # https://github.com/godotengine/godot/issues/21461
  13. # https://github.com/godotengine/godot-proposals/issues/279
  14. var _basisX: Vector2
  15. var _basisY: Vector2
  16. var _basisZ: Vector2
  17. # Cache the spatial stuff for internal use.
  18. var _spatial_position: Vector3
  19. var _spatial_node: Spatial
  20. # These are separated in case anyone wishes to easily extend Node25D.
  21. func _ready():
  22. Node25D_ready()
  23. func _process(_delta):
  24. Node25D_process()
  25. # Call this method in _ready, or before Node25D_process is first ran.
  26. func Node25D_ready():
  27. _spatial_node = get_child(0)
  28. # Changing the values here will change the default for all Node25D instances.
  29. _basisX = SCALE * Vector2(1, 0)
  30. _basisY = SCALE * Vector2(0, -0.70710678118)
  31. _basisZ = SCALE * Vector2(0, 0.70710678118)
  32. # Call this method in _process, or whenever the position of this object changes.
  33. func Node25D_process():
  34. _check_view_mode()
  35. if _spatial_node == null:
  36. return
  37. _spatial_position = _spatial_node.translation
  38. var flat_pos = _spatial_position.x * _basisX
  39. flat_pos += _spatial_position.y * _basisY
  40. flat_pos += _spatial_position.z * _basisZ
  41. global_position = flat_pos
  42. func get_basis():
  43. return [_basisX, _basisY, _basisZ]
  44. func get_spatial_position():
  45. if not _spatial_node:
  46. _spatial_node = get_child(0)
  47. return _spatial_node.translation
  48. func set_spatial_position(value):
  49. _spatial_position = value
  50. if _spatial_node:
  51. _spatial_node.translation = value
  52. elif get_child_count() > 0:
  53. _spatial_node = get_child(0)
  54. # Change the basis based on the view_mode_index argument.
  55. # This can be changed or removed in actual games where you only need one view mode.
  56. func set_view_mode(view_mode_index):
  57. match view_mode_index:
  58. 0: # 45 Degrees
  59. _basisX = SCALE * Vector2(1, 0)
  60. _basisY = SCALE * Vector2(0, -0.70710678118)
  61. _basisZ = SCALE * Vector2(0, 0.70710678118)
  62. 1: # Isometric
  63. _basisX = SCALE * Vector2(0.86602540378, 0.5)
  64. _basisY = SCALE * Vector2(0, -1)
  65. _basisZ = SCALE * Vector2(-0.86602540378, 0.5)
  66. 2: # Top Down
  67. _basisX = SCALE * Vector2(1, 0)
  68. _basisY = SCALE * Vector2(0, 0)
  69. _basisZ = SCALE * Vector2(0, 1)
  70. 3: # Front Side
  71. _basisX = SCALE * Vector2(1, 0)
  72. _basisY = SCALE * Vector2(0, -1)
  73. _basisZ = SCALE * Vector2(0, 0)
  74. 4: # Oblique Y
  75. _basisX = SCALE * Vector2(1, 0)
  76. _basisY = SCALE * Vector2(-0.70710678118, -0.70710678118)
  77. _basisZ = SCALE * Vector2(0, 1)
  78. 5: # Oblique Z
  79. _basisX = SCALE * Vector2(1, 0)
  80. _basisY = SCALE * Vector2(0, -1)
  81. _basisZ = SCALE * Vector2(-0.70710678118, 0.70710678118)
  82. # Check if anyone presses the view mode buttons and change the basis accordingly.
  83. # This can be changed or removed in actual games where you only need one view mode.
  84. func _check_view_mode():
  85. if not Engine.editor_hint:
  86. if Input.is_action_just_pressed("forty_five_mode"):
  87. set_view_mode(0)
  88. elif Input.is_action_just_pressed("isometric_mode"):
  89. set_view_mode(1)
  90. elif Input.is_action_just_pressed("top_down_mode"):
  91. set_view_mode(2)
  92. elif Input.is_action_just_pressed("front_side_mode"):
  93. set_view_mode(3)
  94. elif Input.is_action_just_pressed("oblique_y_mode"):
  95. set_view_mode(4)
  96. elif Input.is_action_just_pressed("oblique_z_mode"):
  97. set_view_mode(5)
  98. # Used by YSort25D
  99. static func y_sort(a: Node25D, b: Node25D):
  100. return a._spatial_position.y < b._spatial_position.y
  101. static func y_sort_slight_xz(a: Node25D, b: Node25D):
  102. var a_index = a._spatial_position.y + 0.001 * (a._spatial_position.x + a._spatial_position.z)
  103. var b_index = b._spatial_position.y + 0.001 * (b._spatial_position.x + b._spatial_position.z)
  104. return a_index < b_index