extends CharacterBody3D class_name OverworldEntity const PauseSystem = preload("res://scripts/System/PauseSystem.gd") enum Direction { NORTH, SOUTH, WEST, EAST } var speed:float = 150; var friction:float = 8.5; var gravity:float = 30; var direction = Direction.SOUTH; var meshInstance:MeshInstance3D; var underFootTile:int = -1; var underFootPosition:Vector3; var withinMapBounds:MapBounds; var withinBoundsLastFrame:bool = true; func getSystems() -> Systems: return get_tree().current_scene.get_node("Systems") as Systems; func getDirectionVector() -> Vector3: match direction: Direction.NORTH: return Vector3(0, 0, -1); Direction.SOUTH: return Vector3(0, 0, 1); Direction.WEST: return Vector3(-1, 0, 0); Direction.EAST: return Vector3(1, 0, 0); return Vector3(0, 0, 0); func getDirectionToFace(position:Vector3) -> Direction: var diff = position - self.position; if abs(diff.x) > abs(diff.z): if diff.x > 0: return Direction.EAST; else: return Direction.WEST; else: if diff.z > 0: return Direction.SOUTH; else: return Direction.NORTH; return Direction.SOUTH; # Virtual Methods func updateMovement(delta) -> void: pass func updateOverworldLogic(delta) -> void: pass func isPaused() -> bool: var pause = getSystems().PAUSE; var ps = pause.getPauseState(); if ps == PauseSystem.PauseType.NOT_PAUSED: return false; elif ps == PauseSystem.PauseType.FULLY_PAUSED: return true; elif ps == PauseSystem.PauseType.ENTITY_PAUSED: if pause.entities.find(self) != -1: return true; return false elif ps == PauseSystem.PauseType.CUTSCENE_PAUSED: if pause.entities.find(self) != -1: return false; return true; return false; # Private methods func _updateTileData() -> void: # ray cast down var offset = Vector3(0, 0, 0.426); var query = PhysicsRayQueryParameters3D.create( position + offset, position + Vector3(0, -1, 0) + offset ) query.collide_with_areas = true query.exclude = [self] var result = get_world_3d().direct_space_state.intersect_ray(query) if !result or !result.collider: return; var collider = result.collider; var colliderMesh = collider.get_node("../"); if !colliderMesh or !(colliderMesh is ArrayMesh) or !colliderMesh.mesh or colliderMesh.mesh.get_surface_count() == 0: return; # Get the face index (triangle) var arrays = colliderMesh.mesh.surface_get_arrays(0); var indiceIdx = result.face_index * 3; # Get each indice of the triangle var index0 = arrays[Mesh.ARRAY_INDEX][indiceIdx+0]; var index1 = arrays[Mesh.ARRAY_INDEX][indiceIdx+1]; var index2 = arrays[Mesh.ARRAY_INDEX][indiceIdx+2]; # Get each uv of each indice var uv0:Vector2 = arrays[Mesh.ARRAY_TEX_UV][index0]; var uv1:Vector2 = arrays[Mesh.ARRAY_TEX_UV][index1]; var uv2:Vector2 = arrays[Mesh.ARRAY_TEX_UV][index2]; # Determine the lowest texture coordinate var min = Vector2(min(uv0.x, uv1.x, uv2.x), min(uv0.y, uv1.y, uv2.y)); # Convert to column/row var w = 768; var h = w; var tw = 48; var th = tw; var column = int(roundf(min.x * w)) / 48; var row = int(roundf(min.y * h)) / 48; var columns = 768 / 48; underFootPosition = result.position; underFootTile = column % columns + row * columns; # Events func _ready() -> void: meshInstance = get_node("MeshInstance3D") _updateTileData(); pass func _process(delta:float) -> void: if isPaused(): return; # Handle entity leaving map bounds if !withinMapBounds: if !withinBoundsLastFrame: print("Entity ", self.name, " was out of map bounds for two frames"); withinBoundsLastFrame = false; else: withinBoundsLastFrame = true; # Update logic updateOverworldLogic(delta) # Set shader direction. var material:ShaderMaterial = meshInstance.get_surface_override_material(0) material.set_shader_parameter("direction", direction) func _physics_process(delta: float) -> void: if isPaused(): return; # Update movement updateMovement(delta); # Gravity and friction if !is_on_floor(): velocity.y -= gravity * delta; else: velocity += -(velocity * friction * delta); if velocity.length() != 0: _updateTileData(); # Update character controller. move_and_slide();