Initial commit
This commit is contained in:
19
actors/Enemies/Finite State Machiene/EnemyState.gd
Normal file
19
actors/Enemies/Finite State Machiene/EnemyState.gd
Normal file
@@ -0,0 +1,19 @@
|
||||
extends Node
|
||||
class_name EnemyState
|
||||
|
||||
signal Transitioned(state: EnemyState, new_state_name: String)
|
||||
var enemy_ref: BaseEnemy
|
||||
|
||||
func Enter() -> void:
|
||||
pass
|
||||
|
||||
func Exit() -> void:
|
||||
pass
|
||||
|
||||
func Update(_delta: float) -> void:
|
||||
pass
|
||||
|
||||
func Physics_Update(_delta: float) -> void:
|
||||
pass
|
||||
|
||||
#Transition State by calling Transitioned.emit(self, "name of other state")
|
||||
1
actors/Enemies/Finite State Machiene/EnemyState.gd.uid
Normal file
1
actors/Enemies/Finite State Machiene/EnemyState.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dvg03ta13bj84
|
||||
46
actors/Enemies/Finite State Machiene/EnemyStateMachiene.gd
Normal file
46
actors/Enemies/Finite State Machiene/EnemyStateMachiene.gd
Normal file
@@ -0,0 +1,46 @@
|
||||
extends Node
|
||||
class_name EnemyStateMachiene
|
||||
|
||||
@export var initial_state: EnemyState
|
||||
@export var enemy_ref: BaseEnemy
|
||||
|
||||
var current_state: EnemyState
|
||||
var states: Dictionary = {}
|
||||
|
||||
func _ready() -> void:
|
||||
for child in get_children():
|
||||
if child is EnemyState:
|
||||
states[child.name.to_lower()] = child
|
||||
child.Transitioned.connect(on_child_transition)
|
||||
child.enemy_ref = enemy_ref
|
||||
|
||||
if initial_state:
|
||||
initial_state.Enter()
|
||||
current_state = initial_state
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
if not is_multiplayer_authority(): return
|
||||
|
||||
if current_state:
|
||||
current_state.Update(delta)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not is_multiplayer_authority(): return
|
||||
|
||||
if current_state:
|
||||
current_state.Physics_Update(delta)
|
||||
|
||||
func on_child_transition(state: EnemyState, new_state_name: String):
|
||||
if state != current_state:
|
||||
return
|
||||
|
||||
var new_state = states.get(new_state_name.to_lower())
|
||||
if !new_state:
|
||||
return
|
||||
|
||||
if current_state:
|
||||
current_state.Exit()
|
||||
|
||||
new_state.Enter()
|
||||
|
||||
current_state = new_state
|
||||
@@ -0,0 +1 @@
|
||||
uid://biujgdpsjonmi
|
||||
24
actors/Enemies/Spider/SpiderFollowPlayer.gd
Normal file
24
actors/Enemies/Spider/SpiderFollowPlayer.gd
Normal file
@@ -0,0 +1,24 @@
|
||||
extends EnemyState
|
||||
|
||||
const maxFollowDistance: float = 12.5
|
||||
|
||||
func Enter():
|
||||
if enemy_ref.spiderLight:
|
||||
enemy_ref.spiderLight.visible = true
|
||||
if enemy_ref.hitBoxTeeth:
|
||||
enemy_ref.hitBoxTeeth.active = true
|
||||
|
||||
func Exit():
|
||||
enemy_ref.can_move = true
|
||||
if enemy_ref.spiderLight:
|
||||
enemy_ref.spiderLight.visible = false
|
||||
if enemy_ref.hitBoxTeeth:
|
||||
enemy_ref.hitBoxTeeth.active = false
|
||||
|
||||
func Update(_delta: float):
|
||||
if enemy_ref.closestPlayer:
|
||||
if enemy_ref.distanceClosestPlayer > maxFollowDistance:
|
||||
Transitioned.emit(self, "Wander")
|
||||
|
||||
enemy_ref.can_move = enemy_ref.distanceClosestPlayer > 2
|
||||
enemy_ref.pathfind(enemy_ref.closestPlayerGridPosition)
|
||||
1
actors/Enemies/Spider/SpiderFollowPlayer.gd.uid
Normal file
1
actors/Enemies/Spider/SpiderFollowPlayer.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dc8gd7klgokxu
|
||||
18
actors/Enemies/Spider/SpiderWander.gd
Normal file
18
actors/Enemies/Spider/SpiderWander.gd
Normal file
@@ -0,0 +1,18 @@
|
||||
extends EnemyState
|
||||
|
||||
var rng = RandomNumberGenerator.new()
|
||||
var arrived: bool = true
|
||||
var wanderGoal: Vector2
|
||||
const wanderSpeed := 2.3
|
||||
const wanderRange: float = 20
|
||||
const detectionRange: float = 8
|
||||
|
||||
func Update(_delta: float) -> void:
|
||||
if enemy_ref.distanceClosestPlayer < detectionRange:
|
||||
Transitioned.emit(self,"FollowPlayer")
|
||||
if arrived:
|
||||
wanderGoal = Vector2(rng.randf_range(-wanderRange,wanderRange),rng.randf_range(-wanderRange,wanderRange))
|
||||
arrived = false
|
||||
enemy_ref.pathfind(wanderGoal,wanderSpeed)
|
||||
if enemy_ref.pointPath.size() <= 2:
|
||||
arrived = true
|
||||
1
actors/Enemies/Spider/SpiderWander.gd.uid
Normal file
1
actors/Enemies/Spider/SpiderWander.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dyhvo1kt3kb5e
|
||||
36
actors/Enemies/Spider/ik_target.gd
Normal file
36
actors/Enemies/Spider/ik_target.gd
Normal file
@@ -0,0 +1,36 @@
|
||||
extends Marker3D
|
||||
class_name SpiderIKTarget
|
||||
|
||||
@export var step_target: Marker3D
|
||||
@export var step_distance: float = 1.75
|
||||
@export var tween_duration: float = 0.45
|
||||
|
||||
@export var adjacent_target: SpiderIKTarget
|
||||
@export var opposite_target: SpiderIKTarget
|
||||
|
||||
var spider_body: CharacterBody3D
|
||||
|
||||
var is_stepping := false
|
||||
var can_step : = false
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
top_level = true
|
||||
spider_body = get_parent()
|
||||
step_distance = step_distance * owner.scale.x
|
||||
tween_duration = tween_duration * owner.scale.x
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
if !is_stepping && !adjacent_target.is_stepping && abs(self.global_position.distance_to(step_target.global_position)) >= step_distance:
|
||||
step()
|
||||
opposite_target.step()
|
||||
|
||||
func step():
|
||||
var target_pos = step_target.global_position
|
||||
var half_way = (global_position + step_target.global_position) /2
|
||||
is_stepping = true
|
||||
|
||||
var t = create_tween()
|
||||
t.tween_property(self,"global_position",half_way + owner.basis.y-Vector3(0,0.45,0)*owner.scale.x,tween_duration / spider_body.velocity.length())
|
||||
t.tween_property(self,"global_position", target_pos,tween_duration / spider_body.velocity.length())
|
||||
t.tween_callback(func(): is_stepping = false)
|
||||
1
actors/Enemies/Spider/ik_target.gd.uid
Normal file
1
actors/Enemies/Spider/ik_target.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b7nx043bbja0u
|
||||
24
actors/Enemies/Spider/mech_spider_base.gd
Normal file
24
actors/Enemies/Spider/mech_spider_base.gd
Normal file
@@ -0,0 +1,24 @@
|
||||
extends BaseEnemy
|
||||
class_name SpiderEnemy
|
||||
|
||||
var closestPlayerGridPosition: Vector2
|
||||
var distanceClosestPlayer: float
|
||||
var closestPlayer: PlayerCharacter
|
||||
@onready var spiderLight := $SpiderLight
|
||||
@onready var hitBoxTeeth := $HitBox
|
||||
var attackTeeth: Attack = Attack.new()
|
||||
|
||||
func _ready() -> void:
|
||||
attackTeeth.damage = 25.0
|
||||
attackTeeth.trauma = 0.65
|
||||
hitBoxTeeth.attack = attackTeeth
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
closestPlayer = getClosestPlayerOnPathGrid()
|
||||
if !closestPlayer: return
|
||||
closestPlayerGridPosition = Vector2(closestPlayer.global_position.x,closestPlayer.global_position.z)
|
||||
distanceClosestPlayer = (closestPlayer.global_position - global_position).length()
|
||||
baseEnemyIdle(delta)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
baseEnemyPhysics(delta)
|
||||
1
actors/Enemies/Spider/mech_spider_base.gd.uid
Normal file
1
actors/Enemies/Spider/mech_spider_base.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://drdkwkfj4rnb8
|
||||
1427
actors/Enemies/Spider/mech_spider_base.tscn
Normal file
1427
actors/Enemies/Spider/mech_spider_base.tscn
Normal file
File diff suppressed because one or more lines are too long
1440
actors/Enemies/Spider/mech_spider_base.tscn9732395635.tmp
Normal file
1440
actors/Enemies/Spider/mech_spider_base.tscn9732395635.tmp
Normal file
File diff suppressed because one or more lines are too long
1440
actors/Enemies/Spider/mech_spider_base.tscn9745725999.tmp
Normal file
1440
actors/Enemies/Spider/mech_spider_base.tscn9745725999.tmp
Normal file
File diff suppressed because one or more lines are too long
14
actors/Enemies/Spider/rotationLock.gd
Normal file
14
actors/Enemies/Spider/rotationLock.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Skeleton3D
|
||||
|
||||
var bones: Array[int] = [6,11,16,21,26,31,36,41]
|
||||
var boneRotations: Array[Quaternion]
|
||||
|
||||
func _ready() -> void:
|
||||
for bone in bones:
|
||||
boneRotations.push_back(get_bone_pose_rotation(bone))
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var x = 0
|
||||
for bone in bones:
|
||||
set_bone_pose(bone, boneRotations[x])
|
||||
x += 1
|
||||
1
actors/Enemies/Spider/rotationLock.gd.uid
Normal file
1
actors/Enemies/Spider/rotationLock.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://by5f8425fuu8q
|
||||
12
actors/Enemies/Spider/step_ray.gd
Normal file
12
actors/Enemies/Spider/step_ray.gd
Normal file
@@ -0,0 +1,12 @@
|
||||
extends RayCast3D
|
||||
|
||||
@export var step_target: Marker3D
|
||||
|
||||
func _ready() -> void:
|
||||
step_target.top_level = true
|
||||
|
||||
|
||||
func _physics_process(_delta: float) -> void:
|
||||
var col_point = get_collision_point()
|
||||
if col_point:
|
||||
step_target.global_position = col_point + Vector3(0,0.78,0)*owner.scale.x
|
||||
1
actors/Enemies/Spider/step_ray.gd.uid
Normal file
1
actors/Enemies/Spider/step_ray.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bb8gorx3134vp
|
||||
14
actors/Enemies/Spider/step_targets_container.gd
Normal file
14
actors/Enemies/Spider/step_targets_container.gd
Normal file
@@ -0,0 +1,14 @@
|
||||
extends Node3D
|
||||
|
||||
@export var offset: float = 10
|
||||
|
||||
@onready var parent = get_parent_node_3d()
|
||||
@onready var previous_position = parent.global_position
|
||||
func _ready() -> void:
|
||||
offset = offset*owner.scale.x
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
var velovity : Vector3 = (owner.global_position - previous_position) * delta
|
||||
global_position = owner.global_position + velovity.normalized() * offset
|
||||
|
||||
previous_position = owner.global_position
|
||||
1
actors/Enemies/Spider/step_targets_container.gd.uid
Normal file
1
actors/Enemies/Spider/step_targets_container.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bodwd2ercb5e2
|
||||
104
actors/Enemies/base_enemy.gd
Normal file
104
actors/Enemies/base_enemy.gd
Normal file
@@ -0,0 +1,104 @@
|
||||
extends CharacterBody3D
|
||||
class_name BaseEnemy
|
||||
|
||||
@export var turn_speed: float = PI/2 ##how fast the enemy turns into the direction it is moving
|
||||
@export var turn_to_move := true ##Aktivates/ Deaktivates turn to move direction logic
|
||||
@export var can_move := true ##Controls weather move and slide gets executed on process
|
||||
|
||||
@export var base_speed := 3.5 ##Base movespeed of the enemy
|
||||
@export var decelleration := 0.5 ## How much the enemy decellerates each frame
|
||||
@export var max_speed := 10.0
|
||||
@export var min_speed := 0.05
|
||||
@export var pathfindLeniency := 0.25 ## How close this enemy needs to be to a pathfinding node to pathfind to the next node
|
||||
|
||||
var health: float = 100.0 ##If health reaches 0, the enemy dies
|
||||
var momentum := Vector3(0,0,0) ##Controlls the speed of the player
|
||||
var lastMoveDirection:= Vector3(0,0,0) ##Which direction the enemy moved last, used for rotation
|
||||
var directionMovePathfind: Vector2 ##
|
||||
|
||||
@export var mapLogicRef: MapLogic
|
||||
|
||||
var pointPath: PackedVector2Array ##Path used for Pathfinding
|
||||
var pathfindingGoalLocation: Vector2 = Vector2(0,0)
|
||||
|
||||
func _ready() -> void:
|
||||
mapLogicRef = get_parent_node_3d() # Might need to change
|
||||
|
||||
func baseEnemyIdle(delta: float) -> void:
|
||||
if health <= 0.0:
|
||||
die()
|
||||
|
||||
if turn_to_move:
|
||||
rotation.y = rotate_toward(rotation.y,atan2(lastMoveDirection.x,lastMoveDirection.z), turn_speed*delta)
|
||||
|
||||
if momentum.length() <= min_speed:
|
||||
momentum = Vector3(0,0,0)
|
||||
momentum -= momentum.normalized()*delta*decelleration*momentum.length() #decelerate
|
||||
|
||||
func baseEnemyPhysics(delta:float) -> void:
|
||||
if can_move:
|
||||
velocity = momentum
|
||||
move_and_slide()
|
||||
|
||||
func createPath(pos1: Vector2,pos2: Vector2) -> PackedVector2Array:
|
||||
if !mapLogicRef:
|
||||
return PackedVector2Array([])
|
||||
if !mapLogicRef.astar:
|
||||
return PackedVector2Array([])
|
||||
var closestPointPos1: int = mapLogicRef.astar.get_closest_point(pos1)
|
||||
var closestPointPos2: int = mapLogicRef.astar.get_closest_point(pos2)
|
||||
return mapLogicRef.astar.get_point_path(closestPointPos1,closestPointPos2)
|
||||
|
||||
func updatePointPath() -> void:
|
||||
pointPath = createPath(Vector2(global_position.x,global_position.z),pathfindingGoalLocation)
|
||||
|
||||
func pathfind(goal_pos: Vector2,speed: float = 0.0) -> void:
|
||||
pathfindingGoalLocation = goal_pos
|
||||
if (goal_pos - Vector2(global_position.x,global_position.z)).length() <= pathfindLeniency:
|
||||
return
|
||||
if pointPath.is_empty():
|
||||
updatePointPath()
|
||||
|
||||
if pointPath:
|
||||
directionMovePathfind = pointPath[0] - Vector2(global_position.x,global_position.z)
|
||||
move(Vector3(directionMovePathfind.x,0,directionMovePathfind.y),speed)
|
||||
|
||||
if directionMovePathfind.length() <= pathfindLeniency:
|
||||
updatePointPath()
|
||||
if !pointPath.is_empty():
|
||||
pointPath.remove_at(0)
|
||||
|
||||
func clampVectorLength(Vector: Vector3, minLength: float, maxLength: float) -> Vector3:
|
||||
#scales Vector up/ down to the max/ min length givin. If the Vector has a length of 0 it will be returned without being scaled.
|
||||
if Vector.length() == 0: return Vector
|
||||
if Vector.length() < minLength:
|
||||
return Vector * minLength / Vector.length()
|
||||
elif Vector.length() > maxLength:
|
||||
return Vector * maxLength / Vector.length()
|
||||
return Vector
|
||||
|
||||
func getClosestPlayerOnPathGrid() -> PlayerCharacter:
|
||||
if !Multiplayer.alivePlayerDict:
|
||||
return
|
||||
var shortestPath: PackedVector2Array
|
||||
var closestPlayer: PlayerCharacter
|
||||
for player in Multiplayer.alivePlayerDict.values():
|
||||
var path := createPath(Vector2(self.global_position.x,self.global_position.z),Vector2(player.global_position.x,player.global_position.z))
|
||||
if !shortestPath.size():
|
||||
shortestPath = path
|
||||
closestPlayer = player
|
||||
else:
|
||||
if shortestPath.size() > path.size():
|
||||
shortestPath = path
|
||||
closestPlayer = player
|
||||
return closestPlayer
|
||||
|
||||
func move(direction: Vector3, speed: float = 0.0) -> void: ##add momentum in direction, depending on speed, if speed parameter is left empty (or == 0) the function will use the base speed of the enemy
|
||||
if speed:
|
||||
momentum = clampVectorLength(direction.normalized()*speed,min_speed,max_speed)
|
||||
else:
|
||||
momentum = clampVectorLength(direction.normalized()*base_speed,min_speed,max_speed)
|
||||
lastMoveDirection = momentum
|
||||
|
||||
func die() -> void:
|
||||
queue_free()
|
||||
1
actors/Enemies/base_enemy.gd.uid
Normal file
1
actors/Enemies/base_enemy.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://clrqxvcw8k08m
|
||||
Reference in New Issue
Block a user