Similar to the multiplayer course for Godot, I was spawning in 4 players for a coop game. I worked on the code to have a scene just containing the camera that will be instantiated in each of the local player’s games. The current bit of confusion I am having is that I would like to have the camera instantiated as a child of the player character. After a few attempts and some research, I keep coming away more confused. This is probably a simple fix. however, I am dyslexic and I may need someone to point out my mistake or nudge me toward the right solution. Otherwise I tend to overthink it. I would appreciate if anyone could give me a nudge.
Ok - what exactly is happening vs what you want to have happen? This is called “gap analysis” btw, just in case you’re interested! The more clearly you can define both sides of the gap for yourself, the better-positioned you are to cross it. The far side’s pretty good, but I don’t have any idea what the near side looks like.
Mostly I’m trying to figure out why the standard approach taught in the courses isn’t working for you, and whether that’s even been attempted or not vs. some other approach I’m not thinking of. For a normal game, in the player script, you would:
- build a reference to the camera scene tscn. That can be done explicitly with a filepath to the scene, or you can use an
@exportvariable like Nathan does - each approach has its pros and cons. - instantiate it with
instantiate(), - and then add it to the SceneTree as a child of the player with
add_child(instance). If this is being done somewhere other than the player script, you will need to identify which node you are callingadd_child()as a member of (meaning, if you’re doing this in the game script, you’ll need to do something likeplayer_1.add_child()orplayer[i].add_child(), etc. - bullets 2 and 3 can be done in the same line if you want; if not, you will need to
instantiate()as the value of an instance variable so that you have an argument to pass toadd_child().
However, I’m assuming the fact that [this is a co-op game and requires configuring multiplayer authority] is the primary obstacle here. I can’t go way outside the course material, but hopefully this is already starting to give you that nudge you’re looking for. Let us know if and what doesn’t make sense and we can expand from there =)
My approach is similar to Nathan’s approach. Currently with the instantiated approach, the camera is sitting in the scene not connected to anyone.If the player moves the camera does not move with the player. The camera remains stationary. I know there are ways to have the camera move with the player by instantiating it. My goal was to have the camera instantiated as a child of the player character. I was aware this might be an issue as the course is for a 2D platformer and I am working on a 3D first person coop game. I was debating about adding an option for the player to choose third person view.
I think I have configured the multiplayer authority properly.
Would I be able to use the add_child() method effectively inside an if statement? The If statement would verify that the camera only spawns for the local player. My previous issue was that the camera was spawning for all players. I was able to fix that issue.
Also, thank you for all of the quick responses. I really appreciate your advice.
Cheers, I do what I can =)
I would’ve thought using an if-statement is exactly how that issue gets solved in the first place: “if this player has authority, spawn the camera [else do nothing].” Unless I’m misunderstanding what you’re asking, you can definitely use add_child() in an if-statement. From the course, it would look something like this (can’t check for the exact syntax at the moment):
#pseudocode
for p in players:
if [p is local player]:
p.add_child(camera_instance)
break
It looks like you’re doing this in the game script (and not the player script itself), so you’ll need to call player.add_child() and not just add_child(). This is how the engine knows what to add it as a child of. add_child() belongs to the Node class (as in the white Node that everything inherits from), so everything when you call the function as a member of player, it’s a lot like navigating to a particular folder instead of dumping something straight onto the desktop (like I’m frequently guilty of).
I could see that being done in two different ways: you can have multiple cameras per player and set which one will be active (this is probably the cleaner way to do it); or you could reparent() the existing camera to some sort of invisible anchor above the player, as if they’re holding a bindle. reparent() does exactly the same thing as add_child(), but for something that already exists in the SceneTree.
If the camera is a child of the player, it will move with the player automatically because its Transform will be relative to the player’s Transform. Because this happens automatically, if you currently have code that makes the camera follow the player in some way, you probably need to disable it.
The way to make this not happen is to make the camera Top Level in its Inspector, which causes its Transform to behave independently despite the camera’s place in the SceneTree.
I’m sort of just info-dumping whatever relevant stuff comes to mind in the hopes that something triggers the a-ha moment you’re looking for =)
Thank you againf for your help. I have been working through it but I am also in the middle of moving houses. Sorry for the late response.
I have been experimenting with a few fixes and I have a hypothetical question.
Once again from the course, An easy way of not having to set up multiple cameras is to have the camera in a separate scene and then each camera is instantiated for each player locally. My background is in Unity. I was wondering if there is a way to mark the camera so that if there is already one in the scene, no other cameras would be created. While it may sound similar to creating a separate scene for the camera, I would like to have the camera to already be with the player to begin with rather than having to instantiate the camera.
What was confusing me when I asked the first question, is that this doesn’t seem to have anything to do with parenting. I have the code for adding the camera as a child to the player. I thought the problem I was having was there, but I am no longer sure of that. I already had some code to switch between the 3rd person view and the first person view. Anytime I spawn in the cameras, only the 3rd person camera works. The first person camera will function as normal except that it will not move with the player. I have gone down many rabbit holes trying to refactor the code and separate everything into separate scenes to instantiate when needed. I am still willing to do that but I want to confirm that this would be the most ideal way. I feel like it may be easier to create an If check and delete any extra cameras that spawn in when the players join.
I for got to mention. At one point,I tried removing the 3rd person camera completely because I thought I might be making the game too complex. However, even with the 3rd person camera code gone, the first person camera would not move.
No worries, life happens =)
Well, there isn’t really a built-in flag to handle this, but you could achieve the same thing with something like this:
- Case A: if you’re instantiating all cameras, instantiate one
- Case B: if a starting camera exists at designtime already (and therefore does not need to be instantiated), use that one
- Assign this first camera to a variable (or a Group, which you probably know is basically equivalent to Unity’s tag system)
- From this point on, any time a camera is to be instantiated, check if this variable is null first (or if the Group is empty). If not,
returnand don’t instantiate another camera.
It’s a good idea to modularize things, but if you know ahead of time that an object must have exactly x of a given module active at any one time (usually x = 1, but the point is, x isn’t 0), then there probably isn’t any point in instantiating those modules separately. That’s a bit like going to a car dealership and coming home with a giant crate that says “some assembly required.” In this case, the Player isn’t considered functional without both a 1st-person camera and a 3rd-person camera, so you might as well include these as children on the Player from designtime instead of instantiating them separately. That should be your default approach; if you have a good reason not to do this, such as some sort of multiplayer authority quirk I’m not aware of, then that’s justification enough to do it differently.
Based on what you’ve said here, you’ve done some divide-and-conquer testing already (that’s worth researching btw - very useful technique to have a good understanding of). Your results are that your 3rd-person camera works fine regardless, and your 1st-person camera doesn’t work fine regardless, so these modules strongly appear to be independent of each other. That’s useful! What’s different about how you’ve implemented the 3rd-person camera from the 1st-person one, and what obstacles exist that prevent you from taking the same approach? You don’t have to answer these directly for me; they’re more to show you how you can use the implications you build from your test results.
Once again, I appreciate your advice. It is giving me some direction.
As I am sitting here working, I have 1 more question. Is there any way of getting info between scenes without instantiating? One of the current issues is that despite having references in the player script, it doesn’t seem to be finding any nodes in the camera. As an example, I wanted to put the 3D camera s a child of the first person view. In code, even if I replicate the exact same steps for the first person camera, it does not find it. Hopefully I am being clear. Sometimes it is hard for me to write this out with my dyslexia.
In my reserach , I saw a few people say that it was impossible to have reference between scenes without instantiating.
I’m glad this is helping you =)
I’m pretty sure what they mean is that there needs to be an instance of the scene somewhere in the SceneTree in order to pick up any live data from it, because otherwise, all you have is a blueprint and an empty lot - not the actual house, if you will. Is the front door open, or closed? Well, there’s simply no door at all yet. For the same reason, you can build a reference to the blueprint, but you can’t build a reference to a house that doesn’t exist, since it doesn’t exist!
One of the most reliable ways I’ve found to “get” a disparate node is to assign that node its own Group, and then search that Group for its members (of which there is only one in most cases). This works exactly the same as Unity’s tags: tag an object, search for stuff with that tag, and away you go. It may be slightly more complicated in your case since you’ll have multiple players, multiple cameras, and multiplayer authority to think about, but Group search is a good approach if you find that nothing else is working.
Although get_tree().get_first_node_in_group() works for this, make sure that if you’re changing/reloading the level scene anywhere, don’t forget to use call_deferred() - otherwise, what I’ve found is that a reference built using get_first_node_in_group() is likely to break after the reload. For whatever reason, I’ve had no problems with looping through the group and manually breaking after the first valid child, which is essentially the same as what that function does. You’d probably want to do this anyway to check multiplayer authority and avoid referencing the wrong player’s camera.
In the projects where I’ve done this, my syntax was as simple as this:
for node in get_tree().get_nodes_in_group("Camera"):
cam_reference = node
You’ll notice there’s nothing terminating this loop - if there were 3 members of this Group, each would overwrite the last, but you can get away with that since you know the Group only has one child in it. In your case, since that may not be true, you can instead do whatever other checks are needed here, and it will end up looking more like what you saw Nathan doing in the Multiplayer course.
I think I have fixed most of the problems. However, two oddities are ocurring. I want to verify whether I am misudnerstanding something or maybe I have found a bug. first, I was able to figure out that the camera no moving instantiated happens every time regardless of what type of node. I experimented with several nodes to see if they would spawn in and follow the player. As far as I can tell, thye all sit there. Another interesting detail is that if I drag and drop the scene with the camera without running the project, it will only load in the camera. If I add any other nodes to that camera, the nodes are not brought in. It loads in all the player details fine whether I choose to drag and drop or to run the program and spawn in the camera. I am not sure why both would behave differently which leads me to beleive I have missed something or there is a bug.
Ok, I’ll address those directly then.
While it’s not clear to me what nodes you would be talking about besides a camera, the node type shouldn’t usually make a difference here; its position in the SceneTree is what will matter (that, and whether one of the nodes involved has TopLevel turned on). Additionally, if the node in question has no Transform, such as a white Node, this will break any transform inheritance that the children would otherwise pick up from their ancestors.
This set will all follow parents as expected:
- CharacterBody2D
- Node2D
- Camera2D
- Node2D
This set will not; the Node has no way to follow because it has no Transform with which to pass location data to its child, so the Camera2D won’t follow either:
- CharacterBody2D
- Node
- Camera2D
- Node
What exactly are you clicking on for the drag-and-drop, and where exactly are you dropping it? If what you’re dragging is not the scene root, this isn’t going to work anyway, but in either case, it would be greatly preferable to use the link-shaped button at the top-left of the SceneTree (right of the + button) to Instantiate Child Scene. Done on the Player, that will make an instance of the entire camera scene for you, at designtime.
What I can say for sure is that if your Camera2D has children before you drag-and-drop, and these children are not appearing in the full SceneTree after the drag-and-drop, the camera scene is not being instantiated correctly.
The problem with drag-and-drop operations is that as convenient as they are, there’s less visual feedback to confirm you did what you intended. It’s very easy to make a mistake without even realizing something is wrong. There are a number of questions across the forum and course Q&As in which students ended up attaching the wrong script to a node, and a bad drag-and-drop is often how that happens.
Using the Instantiate Child Scene button is a lot safer, especially when it’s been a long day and your focus is starting to go. We’ve all had nights when we stayed up writing/editing code longer than we should have! XD
Thank you for the help. I have been able to fix most of my issues. I am down to 1 issue that is stumping me.
I get an "Invalid assignment of property or key ‘fov’ with value of type float on a base object of type ‘null instance’ "
I know what the error means and I know how to fix it. I just need to pass in a float. However, in my script I can not find exactly where the error is originating. It lists 2 variables as coming back null. The variables are @group_3_camera and @group_8_third person. I don’t remember creating these variables. I have a feeling that this might be leftover code from earlier in the project. After looking through all of my code, I can not find the variables. They only appear in the stack when I run the project and go to switch the camera view. Or if I run multiple players. Other than this, the projects runs fine.
I am frustrated because this is an easy solution if only I could find where in the code to make the changes. I am probably missing something simple. Is there a way to find where the variable is located?
Great! Sounds like this has been a real journey =)
In a case like this when you don’t know where to look, I suggest using breakpoints to figure out exactly what line the crash happens at. If you’ve identified that it’s triggered by a specific event (switching the camera view), then place your breakpoint at the start of that code and see where it leads.
While this isn’t absolutely guaranteed to point directly at the problem when it crashes, there’s a very good chance that it will. If not (ie the crash is an indirect effect of something else), it’ll still give you a better idea of what might be causing the issue. Breakpoints are a very powerful debugging tool when used well, and you have a good use-case for them here. Best of luck tracking it down!
I tried using breakpoints but wasn’t able to discover the issue or find new information. Thank you again for your advice. It has been helpful for me. I will keep working at the issue. If you have any other ideas, let me know. If you need to close the topic, I understand.
The topic will close on its own 20 days after the latest reply. I’ll just let it close on its own. If you find anything else in the meantime, you can update it =)
This topic was automatically closed 20 days after the last reply. New replies are no longer allowed.