Switching active cams

Godot Version

func _ready() → void:
LevelGenerator.generate(self, map_Width, map_Height, minRoomSize, maxRoomSize)
match current_cam_state:
cam_state.FIRST:
$level_Cam.make_current()

Question

I’m testing my level generator and want to change to a more zoomed out cam. I keep getting “attempt to call function ‘make_current’ in base ‘null instance’ on a null instance”. Is this because it should be ‘.set_current’ or is not old way?

make_current() is a perfectly fine working method found in the Camera3D node type.

The error says something else - it says that you are trying to call this method on a “null instance”. This means that your $level_Cam reference is null at the time this code is running.
Check if this reference is correct, that it has no typos (capitalization is important too), and the node of this name is a child of the node that you are running this code on.

the reference is correct and enabled and this a 2d camera would that change anything?

You can also save your cameras as variables, then use camera_var_name.current = true.

Some pseudocode (You can use the general idea of this code for your needs):

var camera_ref = $YourNodePathHere

func your_func():
       camera_ref.current = true

Well, something must be incorrect if you’re getting this error :slight_smile:
Please share a screenshot of your scene structure.
Camera2D has the same method.

Screenshot 2025-01-16 161834

I see you’re using LevelGenerator autoload to generate the levels - can you share its code?

1 Like

If you only ever need 1 camera at a time you could replace the cameras with anchor nodes and anchor one camera to a node with a @tool script. Then instead of switching between active cameras you can switch the active anchor node.

1 Like

I don’t understand what you mean by the anchor nodes and switching between active anchor nodes, could you explain? And how is this gonna be easier than using multiple cameras and switching between them with make_current()?
I don’t want to be rude, I’m just confused and interested in what you actually mean as that’s the first time I hear about such an approach :slight_smile:

extends Node

enum Tiles {EMPTY, SOLID}

class Room:
var position:Vector2
var dimensions:Vector2
var centerpoint:Vector2

var dugRooms =
var rng = RandomNumberGenerator.new()

func _ready():
rng.randomize()

func generate(map:TileMap, map_Width, map_Height, minRoomSize, maxRoomSize):

var potentialRooms:int = (map_Width / maxRoomSize) * (map_Height / maxRoomSize)#figuring out max number of rooms by checking how many max size rooms can fit
var rooms:Dictionary
var room:Room
var position:Vector2

var start:Vector2
var end:Vector2

var modifier:int

var key:String


# Fill map with solid tiles, adding a border of solid tiles around the map
for r in range(-1, map_Height + 1):
	for c in range (-1, map_Width + 1):
		map.set_cell(0, Vector2i(c, r), 0, Vector2i(Tiles.SOLID, 0))

#making the rooms
for r in potentialRooms:
	position = Vector2(rng.randi_range(1, map_Width - maxRoomSize), rng.randi_range(1, map_Height - maxRoomSize))

	key = str(position.x) + " " + str(position.y)

	if (!rooms.has(key)):
		room = Room.new()

		room.position = position
		room.dimensions = Vector2(rng.randi_range(minRoomSize, maxRoomSize), rng.randi_range(minRoomSize, maxRoomSize))
		room.centerpoint = room.position + Vector2(room.dimensions.x / 2, room.dimensions.y / 2)
		print("room center point:"+str(room.centerpoint))
		print("room left edge:"+str(room.centerpoint-Vector2(room.dimensions.x / 2 , 0)))
		var leftSide = Vector2(room.centerpoint-Vector2(room.dimensions.x / 2, 0))
		rooms[key] = room

		digRoom(map, room, map_Width, map_Height, leftSide)

func digRoom(map, room, map_Width, map_Height, leftSide):
for x in range(room.position.x, room.position.x + room.dimensions.x - 1):
for y in range(room.position.y, room.position.y + room.dimensions.y - 1):
digCell(map, Vector2(x, y), map_Width, map_Height, leftSide)
#undigCell(map, Vector2(x, y), map_Width, map_Height, leftSide)

func digCell(map, pos, map_Width, map_Height, leftSide):
if ((pos.x < map_Width) and (pos.y < map_Height)):
map.set_cell(0, Vector2i(pos.x, pos.y), 0, Vector2i(Tiles.EMPTY, 0))
print("left side x value: "+str(leftSide.x))
print("left side y value: "+str(leftSide.y))
map.set_cell(0, Vector2i(leftSide.x, leftSide.y), 0, Vector2i(Tiles.SOLID, 0))

func undigCell(map, pos, map_Width, map_Height, leftSide):
if ((pos.x < map_Width) and (pos.y < map_Height)):
map.set_cell(0, Vector2i(leftSide.x, leftSide.y), 0, Vector2i(Tiles.SOLID, 0))

I don’t see anything obviously incorrect here, but please use preformatted text with ``` for code snippets, otherwise it’s very hard to read.

What I assume is happening here is that during runtime your scene structure changes, so that your $level_Cam node is no longer a child of the level node, or your are duplicating the level node without its child structure.
You can put a breakpoint in your _ready() method to stop the execution when the $level_Cam reference is null.

func _ready() → void:
	if $level_Cam == null:
		breakpoint

	LevelGenerator.generate(self, map_Width, map_Height, minRoomSize, maxRoomSize)
	match current_cam_state:
		cam_state.FIRST:
			$level_Cam.make_current()

Then you can investigate in the Remote tab what is the actual structure of the scene at that point of time.
obraz

This cannot be the correct script/scene then, your script is attached to a Node2D named level, but you are calling generate(map: TileMap, etc....) with self which is the incorrect type Node2D != TileMap.

Can you paste/screenshot your exact error message?

1 Like

No problem!

What I’ve done is create an ‘anchor node’ which is just an empty node that points at something the same way a camera does. I program the anchor node instead of the camera and then attach a script to the camera so it mirrors the anchor nodes position and rotation, or use one node for the position and another as a ‘target’ that the camera will point at. Then I add a function to switch between anchor nodes if I need it to move. I think it’s a better system just because it’s more obvious what’s happening if something doesn’t work. The limitation is in previewing camera views, which is why I recommend using a tool script for the camera. I don’t actually know how to do this part myself but in theory that would make it much easier to preview camera views in advance.

I think this is a common way to use cameras. I got the idea from the Phantom Camera add-on. It definitely makes it easier to smooth the camera movements if you want to, which is a big part of the add-ons functionality.