Godot Version
4.5.1
Question
I have tried 10 videos but it never works, i just need help please
Need more information, what methods have you tried? What about your current attempts do that doesn’t work? What does the feature your making trying to achieve?
I found this very simple video that works for 2D and should easily translate into 3D if you remove the Y axis
I’ve used that tutorial and word of advice, make a variable that is the subtracted positions then take that variable and set the velocity to that variable then use .normalize on it and multiply it by a speed variable
Eg:
var speed = 5
func process(delta) -> void:
var direction = global_position - player.global_position # you'd need a reference to the player
velocity = direction.normalized * speed
move_and_slide()
Global position removes some weirdness where it targets the player’s position with an offset and normalizing the vector makes it so that it isn’t faster the further away or is from the player.
Ok i will try the one that you suggested.
Ive tried most of the ones when you search “how to make a enemy ai in godot 4 3d” as well as the one on here but it kept on coming up with erorrs and when i searched in online i couldnt find anything to do with what i was doing, however i did do the gd quest one but i really wanted to focus on my game instead of doing tutorials
ok so it does work but how do i remove the y axis so i don’t go up into the heavens
Can you post you current code implementation?
Sure one sec
extends CharacterBody3D
var speed = 25
var player_chase = false
var player = null
func _physics_process(_delta: float) -> void:
if player_chase:
position += (player.position - position)
@warning_ignore("unused_parameter")
func _on_detection_area_body_entered(body: Node3D) -> void:
player = body
player_chase = true
@warning_ignore("unused_parameter")
func _on_detection_area_body_exited(body: Node3D) -> void:
player = null
player_chase = false
Some things that will confuse you if you ever expand you code:
the name detection area for your area3D is a okay node name but a bad name for the function as there is also area_entered/area_exited and if you ever make a signal for those it will be named _on_detection_area_area_entered which is a bit confusing (maybe detection range would be better)
I also implemented the suggestion from @istubbdmytoe as so you don’t encounter any weirdness later on
extends CharacterBody3D
var speed: float = 5 #lowered speed to account for physics (adjust as needed)
var player_chase: bool #initializes as false
var player: Node3D #this is good to know how data is going through your code
func _physics_process(_delta: float) -> void:
if player_chase:
#removed position
var direction: Vector3 = self.global_position - player.global_position #direction
self.velocity = -direction.normalized() * speed #calculate
move_and_slide() #physics application
#suggestion to add a check in the _on_detection_area_body_entered/exited to see if
#the body is the player either through class_name or checking to see if it is a CharacterBody3D
#like this- if body is CharacterBody3D:
#or this if you have a class_name on the player- if body is player:
#removed not needed @warning_ignore
func _on_detection_area_body_entered(body: Node3D) -> void:
player = body
player_chase = true
#removed @warning_ignore
func _on_detection_area_body_exited(_body: Node3D) -> void: #changed to _body
player = null
player_chase = false
Below is how to remove the Y axis (if still needed)
extends CharacterBody3D
var speed: float = 5
var player_chase: bool
var player: Node3D
func _physics_process(_delta: float) -> void:
if player_chase:
var direction_z: float = self.global_position.z - player.global_position.z#added
var direction_x: float = self.global_position.z - player.global_position.z#added
var direction: Vector3 = Vector3(direction_x,0,direction_z)#changed
self.velocity = -direction.normalized() * speed#same
move_and_slide()#same
#removing the y axis does cause some weirdness when the player is above the enemy
func _on_detection_area_body_entered(body: Node3D) -> void:
player = body
player_chase = true
func _on_detection_area_body_exited(_body: Node3D) -> void:
player = null
player_chase = false
thank you so much
How can i make it jump and stuff like that
You could think of it like this:
when the player is above my current y value I will apply the same jump mechanic the player has to myself to try to get to the player ( so if direction_y of player compared to me is different, jump )
I don’t have time right now to make a code block but I will later in my day, try to do it yourself I think I provided all the information needed in the code blocks above to be able to figure it out
ok i will, its fine that you don’t have time.
Have you got it figured out?
If you had time to get something somewhat working, you can post it and I can help with it.
If not it’s all good I have time now.
ive try to but it wasnt working so i took a brake and havent touched it since but heres what i was thinking
var y_axis = player.global_position
and
if player.global_position = y_axis and is_on_floor():
velocity.y = JUMP_VELOCITY
I went a bit crazy with adding jumping as its been a while since I coded in 3D but here is something that is an upgrade to before with jumping.
extends CharacterBody3D
var speed: float = 5.0 #(adjust as needed)
var acceleration: float = 10.0 #added acceleration for cooler movement (adjust as needed)
var friction: float = 10.0 #added friction for cooler movement (adjust as needed)
var jump_strength: float = 10.0 #changed your jump velocity from a CONST to a var (adjust as needed)
var player_chase: bool
var player: Node3D
var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") #added the gravity value from godot project settings
func _physics_process(delta: float) -> void: #changed _delta to delta since we use it for gravty
if not is_on_floor(): #gravity logic
self.velocity.y -= gravity * delta
#there is a bug in virtual input where the enemy resets to 0,0 if you leave the area while its jumping, you could change this value to target a return point for when the enemy is done chasing
var virtual_input: Vector3 = Vector3.ZERO
if player_chase and player: #added a saftey check (maybe when the player dies it could throw an error)
var direction: Vector3 = player.global_position - self.global_position #redid calculation cleaner
direction.y = 0#code cleanup
if direction.length_squared() > 0.01: #added this for enemy looking
virtual_input = direction.normalized() #for better movement
var target_angle = atan2(direction.x, direction.z)
self.rotation.y = lerp_angle(self.rotation.y, target_angle, delta * 10.0)#added rotation to the enemy mesh (not needed)
#this is for the enemy jumping added a +0.5 deadzone so the enemy doesn't jump to slight changes in elevation
if is_on_floor() and player.global_position.y > self.global_position.y + 0.5: #jumping logic
self.velocity.y = jump_strength
#made the enemy movement more like what a player script would look like
if virtual_input != Vector3.ZERO:
self.velocity.x = move_toward(self.velocity.x, virtual_input.x * speed, acceleration * delta) #added acceleration (not needed)
self.velocity.z = move_toward(self.velocity.z, virtual_input.z * speed, acceleration * delta)
else:
self.velocity.x = move_toward(self.velocity.x, 0, friction * delta) #added friction (not needed)
self.velocity.z = move_toward(self.velocity.z, 0, friction * delta)
move_and_slide() #physics application
func _on_detection_area_body_entered(body: Node3D) -> void:
player = body
player_chase = true
func _on_detection_area_body_exited(_body: Node3D) -> void:
player = null
player_chase = false
thanks man, i will make sure i your credited in script
No problem!
No need to credit I was just trying to give you a good place to start and building from here will add a lot more than the bare bones I provided