Skip to content

Commit

Permalink
v0.3 (#167)
Browse files Browse the repository at this point in the history
* DIRTY: first run

* tests

* fix swimming, crouch and prone

* failed overhaul, new state machine is too simplistic

* new state machine updates

* reshuffle logic

* another reshuffle

* inputui and muzzle flash

# Conflicts:
#	addons/nodot/weapons/MuzzleFlash3D.gd
  • Loading branch information
krazyjakee authored Nov 19, 2024
1 parent 89e15df commit 8693ae5
Show file tree
Hide file tree
Showing 62 changed files with 1,506 additions and 1,426 deletions.
32 changes: 25 additions & 7 deletions addons/nodot/Nodot.gd
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,39 @@ static func get_children_of_type(parent: Node, type: Variant) -> Array[Node]:


## Returns the first child of the given type
static func get_first_child_of_type(parent: Node, type: Variant):
static func get_first_child_of_type(parent: Node, type: Variant) -> Node:
var children = get_children_of_type(parent, type)
if children.size() > 0:
return children[0]

## Clears all children of a node
static func free_all_children(parent: Node) -> void:
for child in parent.get_children():
child.queue_free()
return null

## Find the first parent of a specific type
static func get_first_parent_of_type(node: Node, type: Variant):
static func get_first_parent_of_type(node: Node, type: Variant) -> Node:
var current_node = node
while current_node != null:
if is_instance_of(current_node, type):
return current_node
current_node = current_node.get_parent()
return null

## Find all siblings of a specific type
static func get_siblings_of_type(node: Node, type: Variant) -> Array[Node]:
var parent = node.get_parent()
var siblings: Array[Node] = []
for sibling in parent.get_children():
if sibling != node and is_instance_of(sibling, type):
siblings.append(sibling)
return siblings

## Find the first sibling of a specific type
static func get_first_sibling_of_type(node: Node, type: Variant) -> Node:
var parent = node.get_parent()
for sibling in parent.get_children():
if sibling != node and is_instance_of(sibling, type):
return sibling
return null

## Clears all children of a node
static func free_all_children(parent: Node) -> void:
for child in parent.get_children():
child.queue_free()
1 change: 0 additions & 1 deletion addons/nodot/autoload/DebugManager.gd
Original file line number Diff line number Diff line change
Expand Up @@ -50,5 +50,4 @@ func get_custom_field_values(node: Node, keys: Array[String]):
for property in node.get_property_list():
if keys.has(property.name):
values[property.name] = node.get(property.name)

return values
27 changes: 27 additions & 0 deletions addons/nodot/character/CharacterExtension3D.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# A base node to add extension logic to NodotCharacter3D
class_name CharacterExtensionBase3D extends StateHandler

var character: CharacterBody3D
var third_person_camera: ThirdPersonCamera

func _get_configuration_warnings():
return [] if get_parent() is CharacterBody3D else ["This state should be a child of a CharacterBody3D."]

func _notification(what: int) -> void:
if what == NOTIFICATION_READY:
if character == null:
character = get_parent()

if get_parent() is NodotCharacter3D:
if character.camera is ThirdPersonCamera:
third_person_camera = character.camera

_state_machine = character.sm
_state_machine._available_states[name] = self

if has_method("setup"):
setup()

## Override this
func setup():
pass
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ class_name NodotCharacter3D extends CharacterBody3D
## Is the character used by the player
@export var is_current_player: bool = false: set = _is_current_player_changed
@export var camera: Camera3D = Camera3D.new()
## Gravity for the character
@export var gravity: float = 9.8
## The maximum speed a character can fall
@export var terminal_velocity := 190.0

signal current_camera_changed(old_camera: Camera3D, new_camera: Camera3D)

Expand Down Expand Up @@ -65,23 +69,11 @@ func face_target(target_position: Vector3, weight: float) -> void:
var target_rot = rotation
rotation.y = lerp_angle(initial_rotation.y, target_rot.y, weight)

## If in multiplayer mode this checks if the client has authority. If singleplayer it will always return true
func is_authority():
if !NetworkManager.enabled or is_multiplayer_authority():
return true
func cap_velocity(velocity: Vector3) -> Vector3:
# Check if the velocity exceeds the terminal velocity
if velocity.length() > terminal_velocity:
# Cap the velocity to the terminal velocity, maintaining direction
return velocity.normalized() * terminal_velocity
else:
return false

## If in multiplayer mode this checks if the client owns this node. If singleplayer it will always return true
func is_authority_owner():
if !NetworkManager.enabled or get_multiplayer_authority() == multiplayer.get_unique_id():
return true
else:
return false

## If in multiplayer mode, this checks of the client is the host. If singleplayer it will always return true
func is_host():
if !NetworkManager.enabled or multiplayer.is_server():
return true
else:
return false
# If it's below terminal velocity, return it unchanged
return velocity
44 changes: 44 additions & 0 deletions addons/nodot/character/NpcCharacter3D.gd
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
## The base class for Nodot NPC characters
class_name NpcCharacter3D extends CharacterBody3D

## (optional) The character state machine. If not assigned, is created automatically
@export var sm: StateMachine
@export var nav: NavigationAgent3D
@export var turn_rate: float = 0.1

var target_position: Vector3 = Vector3.ZERO: set = _set_target_position
var at_destination: bool = false

func _notification(what: int):
if what == NOTIFICATION_READY:
if nav:
nav.velocity_computed.connect(_on_navigation_agent_3d_velocity_computed)

func _is_on_floor() -> Node:
var collision_info: KinematicCollision3D = move_and_collide(Vector3(0, -0.1, 0), true)
if !collision_info: return null
if collision_info.get_collision_count() == 0: return null
if collision_info.get_angle() > floor_max_angle: return null
if global_position.y - collision_info.get_position().y < 0: return null
return collision_info.get_collider(0)

func _set_target_position(new_position: Vector3):
target_position = new_position
if nav:
nav.set_target_position(new_position)

func _on_navigation_agent_3d_velocity_computed(safe_velocity):
velocity = velocity.move_toward(safe_velocity, .25)

## Turn to face the target. Essentially lerping look_at
func face_target(target_position: Vector3, weight: float = turn_rate) -> void:
if Vector2(target_position.x, target_position.z).is_equal_approx(Vector2(global_position.x, global_position.z)):
return
# First look directly at the target
var initial_rotation = rotation
look_at(target_position)
rotation.x = initial_rotation.x
rotation.z = initial_rotation.z
# Then lerp the next rotation
var target_rot = rotation
rotation.y = lerp_angle(initial_rotation.y, target_rot.y, weight)
Loading

0 comments on commit 8693ae5

Please sign in to comment.