The core of the problem, I imagine, is that “centreNode” is defined in the separate file, and thus isn’t defined within the scope of the “main.py” file. Thus some means of referencing its location in the separate file is called for.
The exact means by which this might be done likely depends on the context: How are you importing that separate file? And is “centreNode” a member of some class or other?
That is a good point: when dealing with collisions, Python-tags can be a useful means of accessing related data.
There is a caveat, however: doing so can result in circular references, which can interfere with garbage collection and thus potentially cause memory leaks.
That isn’t to say that it shouldn’t be done–merely that caution and cleanup might be wise!
Of course, if the relationship between collider and “centerNode” is static–if, for example, the “centerNode” is always the parent or the parent-of-the-parent of the collider–then one can simply use that relationship to access it. This can be done via the “getParent” method of the “NodePath” class.
Hum. Perhaps a bit more information would be useful here, then–I was imagining that you were trying to access “centerNode” in a collision-response event, in which case you would have direct access to the collision-node.
So, in what context are you trying to access “centerNode”? What are you trying to do, and under what conditions (including, if applicable, in response to what)?
There’s likely a simple way of doing this, but without more information it’s hard to guess at what might work, I fear!
I am able to move it in the function where it’s defined, so that’s a good start.
However, I can’t move it outside of the function whatsoever, even in the same file.
Because I am going to use the centerNode down the line for movement, this could be a problem.
I might as well share my code here, if it helps.
from direct.showbase.ShowBase import ShowBase
from gameCode.characters_and_players.pcSharedFunctions import *
#this only disables the "model viewer" controls.
#Later, this should lead to a menu.
self.scene = self.loader.loadModel("models/environment")
self.scene.setPos(0, 42, 0)
#centerNode = camera.getParent()
#centerNode.setpos(0, 0, 4)
#moveToSpawn(0, 0, 3)
teGame = MyGame()
As you currently have it, “centerNode” is a local variable–while the node itself should persist, the variable that holds it, “centerNode”, will presumably be lost when “pcCollideSetup” is done.
Further, being a local variable, it is indeed only accessible from within “pcCollideSetup”.
Now, there are a few ways that you could address this:
You could give the node a unique name, and then search the scene-graph for it.
This might be a little cumbersome at times
You could create a global variable
This can become messy as more global variables are made
You could create a module-level variable. That should be available to be referenced via its module.
In short, a variable defined outside of the “pcCollideSetup” method.
You could store a reference to the node in something else that persists
Of course, you’d need such a something else first
Let me focus on that last possibility for a moment: If you were to create a class to hold your character-nodes, and any other character-specific data that you might have (e.g. health), then you could create instances of that class. These instances could then be instantiated and stored in the main script, and thus be accessible from it.
(If the design of your game becomes more complicated, you might end up with layers of this: your “Game” class instantiating a “Level” class, which in turn instantiates your “Character” class, for example.)
Hmm… Do I presume correctly that your main “game” class still inherits from ShowBase?
If so, then where does the line above get executed in the overall flow of the program–is it before or after the initialisation of ShowBase in your main “game” class?
That is, consider the following program:
from panda3d.core import PandaNode
from direct.showbase.ShowBase import ShowBase
from SomeOtherClass import SomeOtherClass
myOtherObj = SomeOtherClass()
game = MyGame()
In the above, follow the order in which things are executed: First our “MyGame” class is instantiated. Then our “SomeOtherClass” class is instantiated. Then the code within “SomeOtherClass”'s “__init__” method is run. Then ShowBase is initialised.
But there’s a problem there: If I’m not much mistaken, ShowBase sets up things like “render” and “loader” when it’s initialised. Thus, since the use of “render” occurs before ShowBase is initialised, it doesn’t yet exist.
However, if we were simply to swap the order of “myOtherObj = SomeOtherClass()” and “ShowBase.__init__(self)”, ShowBase will be initialised before SomeOtherClass, and thus before the use of “render”, and so the code should work!
Now, I am rather guessing at this being the problem in your case–perhaps I’m wrong! If so, perhaps you could post your code–that way we might be able to see where the problem lies and so hopefully help you better.
No, I don’t think that this will help at all, I’m afraid. ^^;
My advice to you is not to use attachNewNode this method breaks the logic.
from panda3d.core import CollisionNode
from panda3d.core import CollisionSegment
from panda3d.core import NodePath
centerNode = NodePath("charaCenter")
cn = CollisionNode("charaColHolder")
charaLine = CollisionSegment(0, 0, 0.25, 0, 0, -0.25)
charaColl = NodePath(cn)
By using NodePath, you will maintain a clear understanding of what you are doing. In your case, you are trying to set a method for the CollisionNode to the scene graph object. The way out is to use the node method.
However, this is a strange way. It is better to do it in the correct sequence.
I don’t really agree that the use of “attachNewNode” is an inherent problem, but do agree with serega regarding the core of the problem: “addSolid” is a method of the node, not the NodePath. That is, it’s to be added to the node held within the NodePath, and not to the NodePath.