Godot Version
4.4.1.stable
Question
On my game I am working on, I have a map, player and enemy. I tried to figure this out by myself and look it up, but I couldn’t find a solution. This is also my first post, so if you need more information, ask me.
When the enemy goes within a player’s area, it teleports to the player position and turns it’s collision off. It also triggers the HUD to show a timer and a “clicks left” label, which you have to press the space a couple times to shake the enemy off, but occasionally, the enemy stays on the player. In this scenario, everything but the enemy’s position and collision does it’s normal thing. The HUD goes back to as if there was no enemy on you, and the player moves normally. I narrowed it down and think that the reason is that the global variable “Free” (Not as in “Queue_free”, just a variable called that) updates for everything but that enemy. I also noticed that the first enemy that spawns works fine, and any others with it (Multiple can be on you at once) work fine. But if the first is not there, instead of the enemies going in a random direction away from you, they stay. Using the print method, I figured out that if the first-spawned enemy is not on you, the enemies that are on you don’t recognize that the global variable has been updated. I have no idea why, but please help. Also, the globals are defined in project settings > globals.
Here is the Global code:
extends Node
var player : Vector3
var slugs := 2
var slug_speed := 50.0
var keys := 3
var clicks := 10
var timer := 5
var collected_keys = 0
var unlocked_locks = 0
var captured = false
var free = false
var clicks_left = 0
var time_left = 10
var dead = false
This is the enemy code:
extends CharacterBody3D
var SPEED = Global.slug_speed
var offset : Vector3
const offset_range = 2
var found = false
var capturing = false
var flying = 0
@onready var slime = preload("res://Slugs/slime.tscn")
@onready var nav_agent := $NavigationAgent3D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
SPEED += randi_range(-25, 25)
if SPEED < 10:
SPEED = 10
offset = Vector3(randf_range(-offset_range, offset_range),
randf_range(-offset_range, offset_range), randf_range(-offset_range, offset_range))
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
#face_at(self, Global.player, delta*(Global.slug_speed / 25))
#var y_velocity = velocity.y
#velocity = -global_transform.basis.z.normalized() * SPEED * delta #Constantly move forward
#velocity.y = y_velocity
#if Engine.get_frames_per_second() < 10:
#Global.lag = true
#else:
#Global.lag = false
var new_slime = slime.instantiate()
get_parent().add_child(new_slime)
new_slime.global_position = global_position + Vector3(0, 0.05, 0)
##Other test stuff
##var material = preload("res://Slugs/slime.tres")
##var newMaterial = material.duplicate()
##new_slime.find_child("MeshInstance3D").set_surface_override_material(0, newMaterial)
##$MeshInstance3D.set_surface_override_material(0, preload("res://Slugs/slime.tres"))
if not is_on_floor():
velocity += get_gravity() * delta
#var current_location = global_transform.origin
#var next_location = nav_agent.get_next_location()
#var new_velocity = (next_location - current_location).normalized * SPEED * delta
if global_position.distance_to(Global.player) < 5:
found = true
nav_agent.set_target_position(Global.player)
else:
if found:
found = false
offset = Vector3(randf_range(-offset_range, offset_range),
randf_range(-offset_range, offset_range), randf_range(-offset_range, offset_range))
nav_agent.set_target_position(Global.player + offset)
#velocity = new_velocity
var destination = nav_agent.get_next_path_position()
if Global.player.distance_to(global_position) > 1 and flying == 0:
var local_destination = destination - global_position
var direction = local_destination.normalized()
velocity = direction * SPEED * delta
Global.free = false
rotation.y = lerp_angle(rotation.y, atan2(-velocity.x, -velocity.z), delta * 10)
elif flying == 0:
#velocity.move_toward(Vector3.ZERO, 25)
velocity = Vector3.ZERO
if flying > 0:
var direction = (global_position - Global.player).normalized()
var movement = direction * SPEED * 3 * delta
velocity.x = movement.x
velocity.z = movement.z
#offset = Vector3(-10, 0, 0)
#velocity *= -1
flying -= 1
if capturing:
$CollisionShape3D.disabled = true
global_position = Global.player
else:
$CollisionShape3D.disabled = false
if Global.free:
print("Free")
print(flying)
print(capturing)
if capturing and flying == 0:
capturing = false
flying = 20
#velocity *= -3
if capturing:
print(Global.free)
print(flying)
print(name)
move_and_slide()
print("Slug Free: " + str(Global.free))
func face_at(object : Node, Position : Vector3, Speed):
var pos2d := Vector2(object.global_position.x, object.global_position.z)
var target_pos2d := Vector2(Position.x, Position.z)
var direction = (pos2d - target_pos2d)
object.rotation.y = lerp_angle(object.rotation.y, atan2(direction.x, direction.y), Speed)
func capture(): #When the slug gets the player,
capturing = true
print("Capture")
func get_flying():
return flying
Player code:
extends CharacterBody3D
var SPEED = 300.0
const JUMP_VELOCITY = 300.0
const FRICTION = 25
const GRAVITY = 0
var sensitivity := 0.002
var dead = false
@onready var twist_pivot := $TwistPivot
@onready var pitch_pivot := $TwistPivot/PitchPivot
@onready var raycast := $TwistPivot/PitchPivot/RayCast
func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_pressed("Jump") and is_on_floor() and not Global.captured:
velocity.y = JUMP_VELOCITY * delta
# Get the input direction and handle the movement/deceleration.
var input_dir := Input.get_vector("Move left", "Move right", "Move forward", "Move backward")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if Input.is_action_just_pressed("ui_cancel"):
if Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
else:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
#$RayCast.global_rotation_degrees.x = pitch_pivot.global_rotation_degrees.x
#$RayCast.global_rotation_degrees.y = twist_pivot.global_rotation_degrees.y
if direction:
var y_velcocity = velocity.y
var movement = direction.x * twist_pivot.basis.x.normalized() * SPEED
movement += direction.z * twist_pivot.basis.z.normalized() * SPEED
velocity.x = movement.x * delta
velocity.z = movement.z * delta
if velocity.length() > SPEED:
velocity = velocity.normalized() * SPEED
velocity.y = y_velcocity
else:
#velocity = -twist_pivot.basis.z.normalized() * SPEED #Makes it constantly move forward in the
#direction you are looking
velocity.x = move_toward(velocity.x, 0, FRICTION * delta)
velocity.z = move_toward(velocity.z, 0, FRICTION * delta)
Global.player = global_position
if Global.captured:
SPEED = 100.0
else:
SPEED = 300.0
if Input.is_action_just_pressed("Interact"):
if raycast.is_colliding():
var collider : Node = raycast.get_collider()
if collider.is_in_group("Key"):
collider.queue_free()
Global.collected_keys += 1
elif collider.is_in_group("Door"):
if Global.collected_keys > 0:
Global.collected_keys -= 1
Global.unlocked_locks += 1
collider.get_child(4).queue_free() #Delete the 5th child (The first lock)
if not Global.dead:
move_and_slide()
elif not dead:
dead = true
$AnimationPlayer.play("Death")
func _input(event: InputEvent) -> void:
if not Global.dead:
if event is InputEventMouseMotion:
twist_pivot.rotate_y(-event.relative.x * sensitivity)
pitch_pivot.rotate_x(-event.relative.y * sensitivity)
pitch_pivot.rotation.x = clamp(pitch_pivot.rotation.x, deg_to_rad(-90), deg_to_rad(90))
func _on_area_body_entered(body: Node3D) -> void:
if body.is_in_group("Slug"):
if body.get_flying() == 0:
if Global.clicks_left < 1:
Global.time_left = Global.timer
Global.clicks_left += Global.clicks
body.capture()
Global.captured = true
HUD code:
extends CanvasLayer
var previous_lag = false
var time_running = false
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
$Death.modulate.a8 = 0
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
$Game/Collected_keys_panel/Collected_keys.text = str(Global.collected_keys)
if Global.lag and not previous_lag:
previous_lag = true
$Game/Lag.visible = true
else:
$Game/Lag.visible = false
if Global.captured:
if not time_running:
time_running = true
$Game/Captured/Time.start()
$Game/Captured.visible = true
if Input.is_action_just_pressed("Jump") and Global.time_left > 0 and Global.clicks_left > 0:
Global.clicks_left -= 1
$Game/Captured/Clicks.text = str(Global.clicks_left)
$Game/Captured/Timer.text = str(Global.time_left)
if Global.clicks_left < 1:
Global.free = true
Global.captured = false
else:
$Game/Captured.visible = false
if Global.dead:
if $Game.modulate.a8 > 0:
$Game.modulate.a8 -= 10
elif $Death.modulate.a8 < 255:
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
$Death.modulate.a8 += 10
if Global.free:
print("Free: True hhhhhhhhhhhhhhhhhhhhhhhhhhhhhhiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiii")
else:
print("Free: False")
func _on_time_timeout() -> void:
Global.time_left -= 1
if Global.time_left < 1 and Global.clicks_left > 0:
Global.dead = true
func _on_replay_pressed() -> void:
Global.dead = false
Global.captured = false
Global.collected_keys = 0
Global.unlocked_locks = 0
Global.time_left = 10
Global.clicks_left = 0
get_tree().change_scene_to_file("res://Maps/map_1.tscn")
func _on_home_pressed() -> void:
get_tree().change_scene_to_file("res://Menus/start_screen.tscn")
Sorry, my code is kind of messy (I think)
Output (When the Global.free variable is updated):
