Godot Version
4.4
Question
hello i am making a 3d game like the old Resident evil in the way the camaras work, when you enter a new room the camara changes to that room’s camara i wanted the player to move forward the mouse with the “wasd” but i dont know how to set the Var camara for the rooms since they are children of the map and not the player. i tried to put all camaras in a group.
in the video i show a bit of how it works the blue area of the player is the front
extends CharacterBody3D
var camara
var ray_origin = Vector3()
var ray_end = Vector3()
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir := Input.get_vector("izquierda", "derecha", "adelante", "atras")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
look_at_mouse()
func look_at_mouse():
var mouse_position = get_viewport().get_mouse_position()
ray_origin = camara.project_ray_origin(mouse_position)
ray_end = ray_origin + camara.project_ray_normal(mouse_position)*2000
var space_state = get_world_3d().direct_space_state
var params = PhysicsRayQueryParameters3D.new()
params.form=ray_origin
params.to = ray_end
var intersection = space_state.intersect_ray(params)
For the sake of convenience, let’s make a name for the idea of a camera looking at an area, and the area the camera looks at. Maybe a “stage”.
So you have multiple stages in your game; presumably the player is always on one stage or another, perhaps they overlap. Only one stage is active at a time.
I think you probably want to have one Camera3D
, and give each stage a Transform3D
that corresponds to where the camera should be and where it should look. Perhaps other metadata as well; whatever you need for that particular stage.
When the player enters/activates a stage, you set the camera’s transform
to the Transform3D
for that stage. That should view the player properly, and it gives you two positions (the player, the camera) that you can use to do camera-relative WASD movement using direction_to()
, angle_to()
and the like.
If you want to incorporate the mouse pointer as well, you can project that into the scene through your camera to get a point in the world and use that instead of the camera when calculating angles/directions.
1 Like
i think i got the first thing you say to me but im confused as if this camara should be a child of the player or the map.
also, the last thing if i understood correctly like if i put a camara above the map looking down and calculate from that camara could that camara look through walls or roofs or it would work only on open areas
How are you changing the current camera? Seems like it’s based on where the player is, so if it’s a Area3D you may have the player from collision data, and I assume you have the camera because you are making it current.
Maybe you have a script like this for each Area3D/Camera pair?
extends Area3D
@export var camera: Camera3D
func _on_body_entered(body: Node3D) -> void:
if body is Player: # must add `class_name Player` to your player's script
body.camera = camera # assign current camera to player
camera.make_current()
the area 3d has a colsion shape and detects when the body player is on it, when it happens the corresponding camara becomes active
extends Camera3D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func _on_node_3d_2_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
self.make_current()
Awesome, so similarly you can set body.camara = self
extends Camera3D
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
pass
func _on_node_3d_2_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
body.camara = self()
so like this and i add a camara to the player as a child of the player scene?
yes-ish
self
is not a function, self
is the camera this script is attached to; so remove the parenthesis ()
.
- the
camara
is already a variable on the player script, you do not need to add anything to the player.
- do not remove
make_current()
from your script
so in total this is the changed script:
extends Camera3D
# - other functions were not used
func _on_node_3d_2_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
self.make_current()
body.camara = self # + the addition
the code now is giving me a problem with lines 41 and 33
extends CharacterBody3D
@onready var model: MeshInstance3D = $MeshInstance3D
@onready var camara: Camera3D = $Camera3D
var ray_origin = Vector3()
var ray_end = Vector3()
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir := Input.get_vector("izquierda", "derecha", "adelante", "atras")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
look_at_mouse()
func look_at_mouse():
var mouse_position = get_viewport().get_mouse_position()
ray_origin = camara.project_ray_origin(mouse_position)
ray_end = ray_origin + camara.project_ray_normal(mouse_position)*2000
var space_state = get_world_3d().direct_space_state
var params = PhysicsRayQueryParameters3D.new()
params.form = ray_origin
params.to = ray_end
var intersection = space_state.intersect_ray(params)
if intersection.is_empty():
var pos= intersection.position
var look_at_me= Vector3(pos.x,position.y,pos.z)
model.look_at(look_at_me,Vector3.UP)
What is error? Do you mean the line with space_state.intersect_ray
?
what do you meant by " + the addition"
and the error is this one
func _on_node_3d_2_body_entered(body: Node3D) -> void:
if body.is_in_group("player"):
self.make_current()
body.camara = self # + the addition
the # + the addition
starts with a hashtag, which means the rest is a comment and ignored by code. I meant that is the single line I would add to the script.
This error means you misspelled params.from
in your player script, line 41 should be:
params.from = ray_origin
extends CharacterBody3D
@onready var model: MeshInstance3D = $MeshInstance3D
@onready var camara: Camera3D = $Camera3D
var ray_origin = Vector3()
var ray_end = Vector3()
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir := Input.get_vector("izquierda", "derecha", "adelante", "atras")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
look_at_mouse()
func look_at_mouse():
var mouse_position = get_viewport().get_mouse_position()
ray_origin = camara.project_ray_origin(mouse_position)
ray_end = ray_origin + camara.project_ray_normal(mouse_position)*2000
var space_state = get_world_3d().direct_space_state
var params = PhysicsRayQueryParameters3D.new()
params.from = ray_origin
params.to = ray_end
var intersection = space_state.intersect_ray(params)
if intersection.is_empty():
var pos = intersection.position
var look_at_me = Vector3(pos.x,position.y,pos.z)
model.look_at(look_at_me,Vector3.UP)
now it crashes at the 33 and 47
You have to post the errors or I have no idea what is wrong
this 2 in specific
if intersection.is_empty():
var pos = intersection.position
var look_at_me = Vector3(pos.x,position.y,pos.z)
model.look_at(look_at_me,Vector3.UP)
look_at_mouse()
Ok. What is the error for those lines?
i think they detect the mouse and make the player look at it
doesn’t it crash with an error? what is that error?
It does seem like the if condition isn’t correct, it should be checking if the intersection isn’t empty
if not intersection.is_empty():
var pos = intersection.position
var look_at_me = Vector3(pos.x,position.y,pos.z)
model.look_at(look_at_me,Vector3.UP)
1 Like