105 lines
4.0 KiB
Plaintext
105 lines
4.0 KiB
Plaintext
|
|
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()
|