Switching camera on key press

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

First time caller…

I’m trying to write a simple script that will swap cameras in the scene.

Spatial + script
Cube
Camera1
Camera2

He’s what I mashed out on the keyboard:
extends Spatial

var cam1 = get_tree().get_root().get_node("camera1")
var cam2 = get_tree().get_root().get_node("camera2")

cam2.set_current(true)

func _ready():
	pass

func _input(event):
	if event.is_action_pressed("switch"):
		cam1.set_current(not cam1.current)
		cam1.set_current(not cam2.current)

This is my first stab at GDscript so go easy on me.

:bust_in_silhouette: Reply From: jgodfrey

Welcome to the community.

A few things here…

First, it’s hard to tell how your scene tree is organized based on your post (it looks “flat”). I’ll assume the last 3 nodes are simply 1st level children of the top-level Spatial. In that case, the easiest way to get references to the cameras would be this:

onready var cam1 = $Camera1
onready var cam2 = $Camera2

Next (and the main issue here) is that there’s some trickery going on behind the scenes that’s causing your logic to not work like you expect. That’s because (as documented here), in a scene with multiple cameras, one will ALWAYS be current. So, if the first line of your camera switch code makes cam1 not current, cam2 will automatically be made current by Godot. So, when you hit the second camera switch line, cam2 is already current, and your code makes it not current (automatically making cam1 current again. So, just a viscous cycle that actually changes nothing). That, and I assume you meant to (try to) set cam2 in that second line - though not sure.

With the above in mind, with only 2 cameras in the scene, you really only need to manage the current state of one and let the other one handle itself. So, with all of that, something like this should do what you want.

extends Spatial

onready var cam1 = $Camera1
onready var cam2 = $Camera2

func _ready() -> void:
	cam1.current = true

func _input(event):
	if event.is_action_pressed("ui_select"):
		cam1.current = not cam1.current

I would have added a screenshot to show the hierarchy, but the image button assumes that the image is already uploaded - which brings up the question: What is the usual/recommended method for adding images on the Godot forums

  • Some sites delete images after a time period, which might be frowned up.

ghoulfool | 2023-02-05 11:10

Thank. I eventually got it to work with my set up with the script attached to camera 2

onready var cam1 = get_node("/root/world/camera1")
onready var cam2 = get_node("/root/world/camera2")

The cameras weren’t given the right path so just came out as Nulls - but weren’t kicking up any errors- having a knock on effect.

ghoulfool | 2023-02-05 13:54

What is the usual/recommended method for adding images on the Godot forums

I’m not sure there’s any recommended way. However, the image does need to be uploaded to a web-accessible location and then linked in the forum.

jgodfrey | 2023-02-05 15:29

Thank. I eventually got it to work with my set up with the script attached to camera 2

Good to hear. For reference, if the script is attached to cam2, you can access that camera’s properties directly. So, just using current there (for example) will access the cam2 property.

The cameras weren’t given the right path so just came out as Nulls - but weren’t kicking up any errors- having a knock on effect.

You won’t get an error when you acquire an invalid reference, but you’ll definitely get one if you try to use that reference.

So (from your original code), this can return a null (with no error) if the node isn’t found.

var cam1 = get_tree().get_root().get_node("camera1")

But, if you try to use that null reference (like below), you’ll definitely get an error:

cam1.set_current(not cam1.current)

jgodfrey | 2023-02-05 15:39