171 lines
4.0 KiB
GDScript
171 lines
4.0 KiB
GDScript
class_name OverworldEntity extends CharacterBody3D
|
|
|
|
enum Direction {
|
|
SOUTH,
|
|
WEST,
|
|
NORTH,
|
|
EAST,
|
|
}
|
|
|
|
var speed:float = 150;
|
|
var friction:float = 8.5;
|
|
var gravity:float = 30;
|
|
|
|
@export var direction = Direction.SOUTH:
|
|
set(newDirection):
|
|
direction = newDirection;
|
|
_updateMaterial();
|
|
|
|
var meshInstance:MeshInstance3D;
|
|
var underFootTile:int = -1;
|
|
var underFootPosition:Vector3;
|
|
|
|
var withinMapBounds:MapBounds;
|
|
var withinBoundsLastFrame:bool = true;
|
|
|
|
func _updateMaterial():
|
|
if !meshInstance:
|
|
return
|
|
var material:ShaderMaterial = meshInstance.get_surface_override_material(0)
|
|
if !material:
|
|
return
|
|
material.set_shader_parameter("direction", direction)
|
|
|
|
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 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 = 256;
|
|
var h = w;
|
|
var tw = 48;
|
|
var th = tw;
|
|
var column = int(roundf(min.x * w)) / tw;
|
|
var row = int(roundf(min.y * h)) / th;
|
|
var columns = 768 / tw;
|
|
underFootPosition = result.position;
|
|
underFootTile = column % columns + row * columns;
|
|
|
|
# Events
|
|
func _ready() -> void:
|
|
meshInstance = get_node("MeshInstance3D")
|
|
_updateTileData();
|
|
_updateMaterial();
|
|
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)
|
|
|
|
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();
|