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()