Methods of level loading in Panda3d (Solved)

Text file stores information of any level. This is something like a database. You can store whatever you want, but it’s worth noting that you first ensure the logical use of data in your classes.
Can you tell us more about the special code?

I have no special code, sorry, I attempted to understand your first post and was asking if you were suggesting the use of a normal txt file containing code readable only by the script, which I assumed your first post said.

In fact, the data in the file are not code. This is a data set for building a level, it contains transformations and other information. I think I will make a sample code.

“serega-kkz”: instructions for code to play out like a sequence or set of events, right?


“rdb” and “Thaumaturge”: your method was working up to the point where I got the “AttributeError: Room’ object has no attribute ‘loader’”, “Room” being the level script and “loader” being load model function and I figured out why I got it.

But here is the issue, problem seems to stem on the fact that function has the attribute “self” in front of it, and from I can get is, the program is trying to access the self attribute of it’s own namespace rather then one from my main code, I would just get rid of it, but there are some dependencies on it, so I ask, is there way to pass the self attribute from the main code’s namespace to my level scripts’s?

I’m not quite sure of what you’re trying to do that might be a problem for classes. Classes can be instantiated multiple times without trouble–something like this, given a class named “MyClass”:

def someFunction():
    myInstance1 = MyClass(<parameters, if any>)
    myInstance2 = MyClass(<parameters, if any>)

We then have two instances of the same class.

(They’ll be lost once the function exits, of course, but you already know about that. I’m just giving a very simple example of instantiating two instances of a class.)

You don’t need to, if I’m not much mistaken: “loader” is a global variable, and should be available without a reference like “self”.

However, in general, “self” is in essence just another parameter, like any other passed to a function or method. It doesn’t even have to be named “self”, if I’m not much mistaken. It just happens to be one that’s (usually) automatically filled in by Python for you, providing a reference to the class to which the method belongs.

As to getting access to the main object that you’re using, you can just pass in a reference to it like any other parameter.

For example, let’s say that your “main class” is called “Game”, and we’ll stick to the name of your “Room” class. Then we might have something like this:

class Game():
    def __init__(self, <other parameters, if called for):
        # Initialisation here

    def someFunctionThatAccessesRoom(self, <parameters, if called for>):
        # Perhaps this is your task, perhaps it's something else; it shouldn't matter
        # Since this method belongs to "Game", "self" here will refer to the
        # instance of "Game" to which it belongs
        someRoomObject.someRoomFunction(self)

class Room():
    def __init__(self, <parameters, if called for>):
        # Initialisation here

    def someRoomFunction(self, game):
        # Note that the game is the >second< parameter here. As always, the first
        # parameter to an instance function, here called "self", is automatically
        # filled in by Python with a reference to the instance--in this case a reference
        # to the instance of the "Room" class associated with this call. Any parameters
        # passed in manually, as the "Game" instance was above, follow after that.
        self.someVariable = game.someOtherVariable

All of that said, you may find this a little awkward at times. In that case, you may find it worthwhile to create a “common” object or file that can be included in any other, and give access to frequently-used objects, like the game, or the current level.

My example of the control level, which I came to gradually. However, I note that this approach is classic. I use the task manager to make the download bar work. I store all the data in INI text format, simply using it in a non-standard way, using value separation. This allows you to put more information in one line. Or it also allows using named access to a string, this is useful for developing a third-party level editor.

Demo_Level_Load.zip (89.5 KB)

“Thaumaturge”: what I mean is I’m under the impression that the class only runs once, but after having a look at the ShowBase section of the manual, I may be the one confused, since I learned that the “run” command is panda3d’s loop. but it does not explain some things I seen happen in the game if the class was repeated, I,m going to try your code example for a “update function” that I will make.

With the loader issue, I actually used the “from main import *” line I got from someone at “stackoverflow” and it worked for the global variables, but I concerned because there are others like the "self.taskMgr.add:, “self.accept(“fr-again-in”, self.function)”, “self.render”, “self.camera” and so on, your suggestion seems to focus on functions, but I also have code in the sub-class itself that needs the main class’s self.


“serega-kkz”: from your demo, yes I got the impression that you mean using a algorithm to read text from a txt file, sorry I worded it badly earlier, but that is what I was trying to say, but this demo is impressive, it has concepts that I was going to implement later, like the load bar and menu, not to mention, your text method, it’s good, and I may actually implement it in my save functions later.

I could also imagine rewriting my code to utilize algorithms, to use it like you suggested, but then I have look at my functions and plan them out carefully, as I add and customize them on the fly, it is something for me to think about, thank you for the demo, it is programming treasure trove, and something I will be looking more into.

Ah, I see. Yeah, “run” in this context is just a method of the ShowBase class, which is called to start Panda’s main loop, I believe.

Well, show us an example of your code, and tell us what odd behaviour you’re seeing, and we may be able to tell you what the problem is. I will say that I make extensive use of classes, and they can work, I do believe.

Ah, yeah… I’m not sure that I’m a fan of that idea. That will import everything from the “main” module. If you really want to have some globally-accessible elements, I’d suggest separating them out into a “Common” file, and importing “*” from that.

Indeed, the “self” variable is local to a given method; it’s not globally available. Indeed, it’s not all that special–it’s really just a parameter to the method, albeit one that Python fills in for you (generally).

In this specific case, much of what you’re looking to have access to is already made globally available by Panda without the use of “self”.
To start with, you can generally access “render” just like that. As to the others, if you’re using the “run” method of “ShowBase” to start your game, then you should have access to a global variable (provided by Panda, that is) named “base”, which allows access to the methods of ShowBase–i.e. you should be able to write “base.cam”, “base.accept”, etc.

I think that I see what you mean. But remember: “self” is just a local variable that stores a reference to the class to which the function or method in question belongs. That’s all. What you want is access to a reference to the main class.

Now, if the main class is calling some method or function of the other class, then it can just pass in a reference to itself, as I showed above.

However, if there’s no such clear connection, then it might be worth storing a reference to your main class in a global variable, and using that. (I know that I’ve done so.)

(Come to think of it, if your “main” class is a sub-class of ShowBase, and you’re using its “run” method, then you may already have global access to it via Panda’s automatically-provided global variable “base”.)

However, I advise that you use such global variables sparingly: having lots of global variables could become a pain to manage, I fear. Where reasonable, I recommend passing references in as parameters.

Again, perhaps it would help if you showed us some of your code–that might make it easier for us to give more-specific advice,

He may have a problem with the code examples. The fact is, if your class is used:

from direct.showbase.ShowBase import ShowBase

Obliges to use self.

import direct.directbase.DirectStart

Obliges to use base

Examples of using code in DirectStart or using ShowBase. Leads to a dead end when you need to combine several code demonstrations with different implementations. Using global variables is not necessary with ShowBase. Although DirectStart imposes the use of global.

I think DirectStart should be excluded from the textbooks.

I’m pretty sure that you can use “base” if your main class is a sub-class of “ShowBase”–in fact, a quick check indicates that I’m doing so myself in at least two projects.

Yeah, the presence of two approaches in the samples could well lead to some confusion, I fear.:/

For the main class, you’re probably correct–but it can still be useful elsewhere. For example, I sometimes use it as a quick way to gain access to the current level.

You could probably get away with not using globals by passing in references to the game just about everywhere–but that would likely become rather tiresome!

I think that the current recommended method is sub-classing ShowBase. If so, then it would probably help indeed for the various resources to stick consistently to that one method.

I just wanted to say in my post that newcomers are constantly stumbling over this.
Although I like to use import direct.directbase.DirectStart :slight_smile:

Fair enough, on both counts!

Myself, I don’t think that I use “DirectStart” at all these days–a quick search suggests that the only place that I have it is in old projects, made before I moved over to sub-classing from “ShowBase”. :slight_smile:

For the record, importing DirectStart is exactly equivalent to:

from direct.showbase.ShowBase import ShowBase
ShowBase()

The ShowBase constructor writes base to the built-in scope.

Far be it from me to criticise anyone for their approach to programming, but I do personally avoid the use of globals as much as possible; I think it’s perfectly possible to avoid them by structuring your classes well. For example, you can pass in a reference to a World class to your WorldObject class, so that they can do operations with respect to the world they are in, parent themselves to the World’s root, etc.

I prefer to use functions, and it is not clear to me why it is necessary to create classes in Panda3D, at a time when this is not necessary. And the transfer of constantly referencing, sooner or later leads to a tangled tangle of threads. Sometimes it is easier to create a new code than to understand :slight_smile:

Using the built-in scope reduces many access problems and reduces the number of lines of code.

It’s possible, and I do prefer doing so in general, but it can become unwieldy at times, in my experience. That was why I started using a “Common” object that provides sort-of global access to a few commonly-used things.

I think that it really is a matter of what you prefer, and what works better for you. For myself, I find that classes fit well with the way that I think, and so make it easier for me to keep everything organised and (relatively) neat.

Thaumaturge: You may have to wait on your request for a example, because my script is mess right now as I,m still implementing the multiple scene function, but I will post it after I,m done though. though I think you may be right for separating functions into files. though, I,m worried about compiling, may I ask? how does panda compile games?

Do the python scripts retain their code form or are they compiled into machine code like C++, because from research, I found out that C++ does not retain it’s original form, and is compiled into machine code like assembly, so if I separated them into multiple files would the import functions fail because it is no longer python script?

So self, would need to be replaced with base then, thanks, I will use this in the future.


serega-kkz: I used showbase because I copied a lot of the roaming ralph demo’s code to jumpstart my game, I have seen some demo use Directstart, but from I can get of what you are saying is, showbase is more automatic? because you don’t have to add a method in front and just use self?


rdb: so showBase is automatic? I use global variables because they can be altered by functions, but also because they are referenced first for code needing to check for a variable before it is declared, I keep getting a “store your variables in a class” vibe, and it sounds I like a good idea, but I need to test out the class if it repeats or not first.

Hahah, fair enough! Of course, you could always put together a small script to demonstrate a specific issue–such as the example that I intend to request further down this post.

You don’t need to worry about that: your imports should continue to work perfectly well, I believe. (Again, I’ve made and distributed multi-file projects myself, and so speak from experience.)

As to whether it’s compiled… I’m a little shaky on the specifics of this myself, but ultimately it’s not something that you’re likely to have to worry about. Python deals with everything below the “source code” level, and it seems to work well.

I’ll leave a more-detailed description to someone who knows the internals better than I!

Note also, by the way, that while C++ is compiled into a much lower level, multi-file C++ programs still work after being compiled.

Class instances and local variables can be altered by functions, too–it just calls for giving the function a reference to the variable in question.

This really confuses me. What is it that you do with functions and global variables that you’re concerned that you can’t do with classes? Could you show us a bit of example code–even if it’s not a whole program–that demonstrates what you mean?

[edit]

Honestly, if functional programming works better for you, then stick with it!

Myself, I find that classes work very well for me–but that may not be the case for you.

I’m not sure of how you might keep your variables organised in a functional approach to programming–I’m not as familiar with it.

I do encourage you to try out classes (i.e. “object-oriented programming”) if you haven’t previously, because you might find that they work for you. But if you have tried them, and they don’t fit well with the way that you think, then I daresay that you can stick with functional programming.

(With the minor caveat that you will encounter classes in using Panda, as Panda’s various elements are generally classes that you’re intended to create instances of.)

I think you expects the panda to create classes at each iteration of the loop. The answer will be negative if you did not explicitly specify this using the task manager or the for loop. It’s also easy to check use print.

But… the same would be true of a call to a function, would it not? The computer won’t do something that it’s not told to do, after all.

Unless they’re thinking of a function passed in to the task manager, being “repeated” by the task system–in which case one could just pass in a method belonging to the relevant class.

I’m very hesitant to speculate further, because I really don’t know what’s meant, and so fear that advice given under the wrong assumptions may mislead, or miss the point.

Thaumaturge: heh heh heh, well, I actually don’t fully remember why I went with global variables and why I think classes don’t repeat themselves, since I have been working on this 3 months straight, but it is notion I got somewhere, that is why it is untested (I test it tomorrow though, just been vary busy adding features)

I guess you can chalk it up to laziness on my part as I have been just going forward, I do apologize for confusion though, but classes do sound better for organization though. So should I just post some code bits in my posts? or do you want a script file?

serega-kkz: no, I mean the “return Task.cont” function that allows a task manger function to repeat endlessly.