Files
Hugo Locurcio bac1e69164 Use static typing in all demos (#1063)
This leads to code that is easier to understand and runs
faster thanks to GDScript's typed instructions.

The untyped declaration warning is now enabled on all projects
where type hints were added. All projects currently run without
any untyped declration warnings.

Dodge the Creeps and Squash the Creeps demos intentionally don't
use type hints to match the documentation, where type hints haven't
been adopted yet (given its beginner focus).
2024-06-01 12:12:18 +02:00

141 lines
4.2 KiB
GDScript

# 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")
class_name Node25D
extends Node2D
# 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