123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140 |
- # This node converts a 3D position to 2D using a 2.5D transformation matrix.
- # The transformation of its 2D form is controlled by its 3D child.
- @tool
- @icon("res://addons/node25d/icons/node_25d_icon.png")
- extends Node2D
- class_name Node25D
- # SCALE is the number of 2D units in one 3D unit. Ideally, but not necessarily, an integer.
- const SCALE = 32
- # Exported spatial position for editor usage.
- @export var spatial_position: Vector3:
- get:
- # TODO: Manually copy the code from this method.
- return get_spatial_position()
- set(value):
- # TODO: Manually copy the code from this method.
- set_spatial_position(value)
- # GDScript throws errors when Basis25D is its own structure.
- # There is a broken implementation in a hidden folder.
- # https://github.com/godotengine/godot/issues/21461
- # https://github.com/godotengine/godot-proposals/issues/279
- var _basisX: Vector2
- var _basisY: Vector2
- var _basisZ: Vector2
- # Cache the spatial stuff for internal use.
- var _spatial_position: Vector3
- var _spatial_node: Node3D
- # These are separated in case anyone wishes to easily extend Node25D.
- func _ready():
- Node25D_ready()
- func _process(_delta):
- Node25D_process()
- # Call this method in _ready, or before Node25D_process is first ran.
- func Node25D_ready():
- _spatial_node = get_child(0)
- # Changing the values here will change the default for all Node25D instances.
- _basisX = SCALE * Vector2(1, 0)
- _basisY = SCALE * Vector2(0, -0.70710678118)
- _basisZ = SCALE * Vector2(0, 0.70710678118)
- # Call this method in _process, or whenever the position of this object changes.
- func Node25D_process():
- _check_view_mode()
- if _spatial_node == null:
- return
- _spatial_position = _spatial_node.position
- var flat_pos = _spatial_position.x * _basisX
- flat_pos += _spatial_position.y * _basisY
- flat_pos += _spatial_position.z * _basisZ
- global_position = flat_pos
- func get_basis():
- return [_basisX, _basisY, _basisZ]
- func get_spatial_position():
- if not _spatial_node:
- _spatial_node = get_child(0)
- return _spatial_node.position
- func set_spatial_position(value):
- _spatial_position = value
- if _spatial_node:
- _spatial_node.position = value
- elif get_child_count() > 0:
- _spatial_node = get_child(0)
- # Change the basis based on the view_mode_index argument.
- # This can be changed or removed in actual games where you only need one view mode.
- func set_view_mode(view_mode_index):
- match view_mode_index:
- 0: # 45 Degrees
- _basisX = SCALE * Vector2(1, 0)
- _basisY = SCALE * Vector2(0, -0.70710678118)
- _basisZ = SCALE * Vector2(0, 0.70710678118)
- 1: # Isometric
- _basisX = SCALE * Vector2(0.86602540378, 0.5)
- _basisY = SCALE * Vector2(0, -1)
- _basisZ = SCALE * Vector2(-0.86602540378, 0.5)
- 2: # Top Down
- _basisX = SCALE * Vector2(1, 0)
- _basisY = SCALE * Vector2(0, 0)
- _basisZ = SCALE * Vector2(0, 1)
- 3: # Front Side
- _basisX = SCALE * Vector2(1, 0)
- _basisY = SCALE * Vector2(0, -1)
- _basisZ = SCALE * Vector2(0, 0)
- 4: # Oblique Y
- _basisX = SCALE * Vector2(1, 0)
- _basisY = SCALE * Vector2(-0.70710678118, -0.70710678118)
- _basisZ = SCALE * Vector2(0, 1)
- 5: # Oblique Z
- _basisX = SCALE * Vector2(1, 0)
- _basisY = SCALE * Vector2(0, -1)
- _basisZ = SCALE * Vector2(-0.70710678118, 0.70710678118)
- # Check if anyone presses the view mode buttons and change the basis accordingly.
- # This can be changed or removed in actual games where you only need one view mode.
- func _check_view_mode():
- if not Engine.is_editor_hint():
- if Input.is_action_just_pressed(&"forty_five_mode"):
- set_view_mode(0)
- elif Input.is_action_just_pressed(&"isometric_mode"):
- set_view_mode(1)
- elif Input.is_action_just_pressed(&"top_down_mode"):
- set_view_mode(2)
- elif Input.is_action_just_pressed(&"front_side_mode"):
- set_view_mode(3)
- elif Input.is_action_just_pressed(&"oblique_y_mode"):
- set_view_mode(4)
- elif Input.is_action_just_pressed(&"oblique_z_mode"):
- set_view_mode(5)
- # Used by YSort25D
- static func y_sort(a: Node25D, b: Node25D):
- return a._spatial_position.y < b._spatial_position.y
- static func y_sort_slight_xz(a: Node25D, b: Node25D):
- var a_index = a._spatial_position.y + 0.001 * (a._spatial_position.x + a._spatial_position.z)
- var b_index = b._spatial_position.y + 0.001 * (b._spatial_position.x + b._spatial_position.z)
- return a_index < b_index
|