Weeping Angel AI

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Laegh

Hi, I’m trying to make a simple 3D horror game. The problem is I can’t figure out how to move “Angels” towards the “Player” when they’re out of the screen or after a blink animation is finished. I tried Visibility Notifier camera exited signal for the desired effect but I couldn’t make the “Angels” move towards “Player” and I didn’t understand how to get the "Player"s position on my “Angel” script. I’m a beginner, so be kind with me. :slight_smile:

:bust_in_silhouette: Reply From: fpicoral

You need to get the player on the Angel script, get its position (object.position), get the angel position, calculate where the angel should move and make him move.

The laziest and fastest (faster to you do, the performance is the same) way to get the player’s position on the angel’s script would be using get_parent() and get_node() on the angel’s script but if you do that, you can’t rename the player node or change the player and angel parent.

The other way would be creating a singleton (global script), then creating a variable in the singleton like player_positon then in the player script, in _ready(), you would need to do (assuming that the name of the singleton is “Global”) Global.player_position = self.position.

Ok. Now you have the player position in the desired script. Now you need to calculate where the angel should go. I don’t work on 3D right now, so I can’t help you with that, but I think that you would need to turn the angel so he is “aiming” at the player. If there are walls or something like that between them, I really don’t know how to help you with that.

Then you will have to move the angel. As I said, I don’t work with 3D, so I’m not sure how you will do that but I think that move_and_slide() will do the job.

It’s probably a little confusing, sorry about that, I kinda that lost myself in the middle.
If you have more doubts, let me know.

Good Luck!

Thank you for the reply, it actually helped me a lot to understand things. But I’m stuck again :smiley: so here’s my Mannequin(Angel) code:

extends KinematicBody

var speed
var mannequin = self
onready var target = get_parent().get_node("Player")

func _ready():
	pass

func _physics_process(delta):
	pass

func _on_VisibilityNotifier_camera_entered(Player):
	speed = 0
	print("Entered")

func _on_VisibilityNotifier_camera_exited(Player):
	speed = 2
	var direction = (target.get_translation() - mannequin.get_translation().normalized()) * speed
	move_and_slide(direction*speed)
	print("Exited")

In 3D to get a objects position you use(thanks to reddit):
If you want local position:

node.get_transform().get_translation()

If you want global position:

node.get_global_transform().get_translation()

But it still doesn’t work. When I put the “_on_VisibilityNotifier_camera_exited” on physics_process function the “Mannequin” moves at my starting position and stops. It doesn’t even check for Visibility Notifier.

Laegh | 2019-01-16 08:44

You need to define the speed using a Vector3. What is direction returning? Try print int and print the typeof() of it just to make sure. If it’s a Vector3, then you need to multiply the direction.x and direction.y by speed. Then you need to put move_and_slide in _physics_process(delta). To it only moves when it’s off the screen, create a global variable on this script lix canMove and set it to false. On the visibility notifier camera exited, set it to true, on the other visibility, set it to false, then, put the code below on the _physics_proccess(delta)`:

if canMove:
    move_and_slide(direction)

Also, I don’t know how is in 3D, but in 2D the speed is in pixels/second, so I belive that in 3D shouldn’t be a much higher thing, might be meters/second. You may want to set it to a hiegher number.

Obs: If direction isn’t a Vector3, you will need to create a vector and change its X, Y and, if you want, Z.

fpicoral | 2019-01-16 11:03

Thanks to your help and Godot documentation I figure it out. So here’s the code, I hope it will help others too.

extends KinematicBody

var speed
onready var target = get_parent().get_node("Player")
var mannequin = self
var direction = Vector3()
var canMove = false

func _ready():
    pass

func _physics_process(delta):
    if canMove:
        direction = (target.transform.origin - mannequin.transform.origin) * speed
        move_and_slide(direction)
        print(direction)

func _on_VisibilityNotifier_camera_entered(Player):
    speed = 0
    canMove = false
    print("Entered")

func _on_VisibilityNotifier_camera_exited(Player):
    speed = 0.2
    canMove = true
    print("Exited")

Laegh | 2019-01-16 17:58

Nice! There is no need to keep that _ready() sinc it has no code, only pass. You also don’t need to set the speed to 0, only set the canMove to false. Now it won’t male any difference but if your game gets bigger it’s nice to have everything organized and with less lines as possible!
Good luck on your project!

fpicoral | 2019-01-16 19:30