Help with classes[solved]

Hi, I´m new to panda3D and to python. I have already made a working demo of my game before, but for better organization I started to use classes(which I learned recently), then, my game do not even starts now.

It appears it´s because I do not know how to read/set variables between classes. I have made a level class and a player avatar class:

#Player
class Avatar(DirectObject):
    def __init__(self):
        
        self.loadActor()
        self.eventCapture()
            
    def loadActor(self):
        self.player = render.attachNewNode("player")
        self.playerActor = Actor.Actor("models/player")
        self.playerActor.setScale(0.1,0.1,0.1)
        self.playerActor.reparentTo(self.player)
#Level
class Level():

    def __init__(self):
        self.loadScenario()

    def loadScenario(self):
        self.Level = loader.loadModel("models/peaks")
        self.Level.reparentTo(render)
        self.Level.setScale(10,10,10)
        self.Level.setPos(0,0,-9)
        playerStartPos = self.Level.find("**/start_point").getPos()
        player.setPos(playerStartPos) 

The level is failing to set the player position in class Avatar.I get this error:

DirectStart: Starting the game.
Known pipe types:
  wglGraphicsPipe
(all display modules loaded.)
Traceback (most recent call last):
  File "tsm.py", line 360, in <module>
    Levelobject = Level()
  File "tsm.py", line 254, in __init__
    self.loadScenario()
  File "tsm.py", line 263, in loadScenario
[b]    player.setPos(playerStartPos) 
NameError: global name 'player' is not defined[/b]

**** End of process output **** 

I would be gratefull for any help on this problem, I have switched from blitz3d, and I think panda3d(and python) is a very reasonable and powerfull tool for game development, if I know how to use it.

you have to say the program that it has to find “player” in class Avatar:

        playerStartPos = self.Level.find("**/start_point").getPos()
        Actor.player.setPos(playerStartPos) 

But, the best way is to pu it everything together:

Class World():
      def __init__:
        Main()
      def Main(self):
        self.player = render.attachNewNode("player")
        self.playerActor = Actor.Actor("models/player")
        self.playerActor.setScale(0.1,0.1,0.1)
        self.playerActor.reparentTo(self.player)
        self.Level = loader.loadModel("models/peaks")
        self.Level.reparentTo(render)
        self.Level.setScale(10,10,10)
        self.Level.setPos(0,0,-9)
        playerStartPos = self.Level.find("**/start_point").getPos()
        self.player.setPos(playerStartPos) 
run()

your sollution does indeed work. but it defeats the purpose of using classes and OOprogramming, thus its not the “best” way for huge projects.it’s fine for small stuff, i’d say for <1000lines of code.(from what i can tell,thought i’m not a big OO-programmer myself)

@felipemoraes:
the object “player” does not exist in your Level-instance so you cant access it. unless you pass it there.
since the code for creating instances of both, the level and the avatar is missing i cant paste the complete code. there are several sollutions for it.
either pass the entire player-class-instance to the Level-class during init

    def __init__(self,player):
        self.player=player
        self.loadScenario() 

.....
.....
        self.player.setPos(playerStartPos) 

or dont call the loadScenario on init but externally call it and pass the player-instance into the loadScenario(self,player)

if you go the first way. you need to have something like that in your main.code

avatar1 = Avatar()
level1 = Level(avatar1.player)

2ThomasEgi:
[size=75]
I’d like if you’d know one thing:

Do you know about last thing before complimation? No, it is NOT debugging. The last thing is finalizing, which is the last optimalization method.

The whole, nice&understandable code just puts into the smallest posible file, you become a LOoONG piece of code. But it takes up to 3/4 of the memory and is up to 20-30% faster!

There are types of applications where if you’ll finalize, it’d take long time and would produce only like 1% faster application, but in games, where you access the memory really much, finalizing means almost everything.(after optimizing) Why? Because even slower coputers could run it!(you’d need only a Geforce 6100 instead of 6200, for example. But don’t forget that without optimizing you’d need a, for example, 9800 GTX++ to run it)

The last example just to ensure that you did understand:

Take the instancing example:[/size]

for i in range(50):
  dancer = Actor.Actor("chorus-line-dancer.egg", {"kick":"kick.egg"})
  dancer.loop("kick")
  dancer.setPos(i*5,0,0)
  dancer.reparentTo(render)

[size=75]
Now I will change it a bit:
[/size]

for i in range(5000000):
  dancer = Actor.Actor("chorus-line-dancer.egg", {"kick":"kick.egg"})
  dancer.loop("kick")
  dancer.setPos(i*5,0,0)
  dancer.reparentTo(render)

[size=75]
Well, that’s pretty much(ehm). Now correct me if I’m wrong:

Every time the GPU calls the memory to send her the variable dancer. Dancer is a pretty long name. in ascii(which, I think, the gpu gets from the memory) it is:[/size]

011001000110000101101110011000110110010101110010

[size=75]
so everytime the memory has to send it.
but, if I will change the code a litlle:[/size]

for i in range(5000000):
  q = Actor.Actor("chorus-line-dancer.egg", {"kick":"kick.egg"})
  q.loop("kick")
  q.setPos(i*5,0,0)
  q.reparentTo(render)

[size=75]
now, instead of the long bin code above it will have to send only this:[/size]

01110001

[size=75]
Don’t forget that it has to send it 5.000.000 times, so it’s 5.000.000 times longer.

And don’t forget that the code above is not optimized at all. It’d not make any sense! :unamused:

Thank you.

P.S.:smiley:on’t do that! Seriously! I still haven’t seen a game in Panda3D that would need it.(except the fireflies demo, if you make the count of fireflies really big) Yes, maybe projects like Crysis, Far Cry 2 or Assains Creed have become faster thanks to finalizing(or absolute finalizing, don’t get confused) but not “my first game” or “MFG: 23000 LTH Star Racers OPENGL!!! [new version: 0.0.2!!!] absolutely amazing!!!” like I have seen :smiley:[/size]

I hope it was helpful information!

I was writing it pretty long, so don’t rate my english and don’t tell that it did not make sense. It makes sense, at least for me, and it was hard to correct the post, understoodea?

Admin, please ban him. This is not funny anymore, but misinformation and confusing others.
I hate to say it this way. You’ve really improved since the last time you came here, but not enough yet.

PS. No, the GPU has NO access over the variable names. It’s about the geometry, not the name. Both codes are entirely equivalent.

in one short sentence… it was NEITHER helpfull nor was it even technically correct.
learn about programming, how it works internally, how your computer works and how your gpu works… BEFORE you make missleading , confusing and wrong statements.

yes i quote your entire message as proof since you love to delete most of your nonsense after we point you to your mistakes.
everyone makes mistakes from time to time. thats not a problem.
but posting long articles which barely contain a grain of truth are off-limits.
i will no longer object if someone intends to ban you. ( i did for quite a while cause i hoped you improved).
admin please ban him and delete his post, including mine (since it wont make any sense anymore) from this thread.
enjoy your 4th ban, btw. you are the only real-person who ever got banned on this forum afaik. maybe you should spend some time and think about it.

PS:no further comments, sorry for the long and nasty post. i just had enough of cleaning up behind him. thx@admin in advance.

erm, i have a question.

lets say i have 2 classes:
myclass
hisclass

if in hisclass, i want to acces somethin in myclass, the code would be:
hisvar = myclass.myvar

am i correct or am i not clear?

MVG,

assainator

No, not unless its a static member.
Usually you would create an instance of that class and call “.myvar” on that.

like this:
classes:
myclass
hisclass

transfer = myclass()
hisvar = transfer.myvar

Yes. That is, if you’ve defined self.myvar to be anything in the init of myclass.

Hey, the first method ThomasEgi said worked. I´m still analysing to understand some things you explained.

Could you post an example of this other method? And in your oppinion, what method is better?

Here´s the working code, there are some imports it does not make use, but futurely they will be used of course:

import direct.directbase.DirectStart

from pandac.PandaModules import PandaNode, LightNode, TextNode, NodePath, Camera
from pandac.PandaModules import Filename, NodePath
from pandac.PandaModules import PointLight, AmbientLight
from pandac.PandaModules import LightRampAttrib, AuxBitplaneAttrib
from pandac.PandaModules import CardMaker
from pandac.PandaModules import Shader, Texture
from pandac.PandaModules import Point3,Vec2,Vec3,BitMask32
from pandac.PandaModules import *

from direct.task import Task
from direct.actor import Actor
from direct.interval.IntervalGlobal import *
from direct.showbase.BufferViewer import BufferViewer
from direct.showbase.DirectObject import DirectObject
from direct.filter.CommonFilters import CommonFilters
from direct.gui.OnscreenText import OnscreenText

import random, sys, os, math

render.setAntialias(AntialiasAttrib.MAuto)

# Discovers in which directory this progam is
MYDIR=os.path.abspath(sys.path[0])
MYDIR=Filename.fromOsSpecific(MYDIR).getFullpath()
               
#Player
class Avatar(DirectObject):
    def __init__(self):
        self.loadActor()
        
    def loadActor(self):
        self.player = render.attachNewNode("player")
        self.playerActor = Actor.Actor("models/player")
        self.playerActor.setScale(0.1,0.1,0.1)
        self.playerActor.reparentTo(self.player)        

#Level
class Level():
    def __init__(self,player):
        self.player=player
        self.loadScenario()
        
    def loadScenario(self):
        self.Level = loader.loadModel("models/peaks")
        self.Level.reparentTo(render)
        self.Level.setScale(10,10,10)
        self.Level.setPos(0,0,-9)
        playerStartPos = self.Level.find("**/start_point").getPos()
        self.player.setPos(playerStartPos) 

Avatarobject = Avatar()
Levelobject = Level(Avatarobject.player)

run()

the other way would be to pass the argument “player” to your loadScene() function instad to init(). in the end both works the same.
i prefer to pass things to functions other than init() cause it makesk the order in which you can initialize your classes less dependant.
like right now you always have to create a player-instance before you can create a scene.
if this summs up you end with a quite long chain and in the end you dont know which class has to be instanced before which other.

that’s why i prefer to do things the following way (just a personal preference)

class Level():
    def __init__(self):
        self.player=player
        self.loadScenario()
       
    def loadScenario(self,player):
        self.Level = loader.loadModel("models/peaks")
        self.Level.reparentTo(render)
        self.Level.setScale(10,10,10)
        self.Level.setPos(0,0,-9)
        playerStartPos = self.Level.find("**/start_point").getPos()
        player.setPos(playerStartPos) 



Avatarobject = Avatar()
Levelobject = Level()
Levelobject.loadScenario(Avatarobject.player)

Neat tip, that’s a useful way of organizing things!

Here’s how I generally organize things, I’m curious if people think this is a good approach or horribly flawed. Basically, I create an overall game object that contains every object within the game, and I always pass an instance of the overall game to every object within the game so that they can see each other that way:

class Game():
    def __init__(self):
        self.player = Player(self)
        self.level = Level(self)

        # Test this setup.
        self.player.print_level()
        self.level.print_player()


class Player():
    def __init__(self, game):
        self.game = game
        self.name = "Joe"

    def print_level(self):
        print "The level is " + self.game.level.name


class Level():
    def __init__(self, game):
        self.game = game
        self.name = "Desert"

    def print_player(self):
        print "The player is " + self.game.player.name


# Set things in motion.
game_object = Game()

By the way, thanks a lot ThomasEgi, your help was very important

So no comments on my coding methodology? It’s not important, I’m just curious to hear the opinions of better trained programmers since I’m no software engineer.

well you as you say yourself. it works.
but i dont wanna keep track of things if you throw everything on a big pile. i can only guess but i’d say it has the potential of getting quite crowded for more complex games.

ok, my question is somewhere between felipemoraes’ and jhocking’s posts…i think…

It has to do with class instance scope in other modules. Essentially, I have several controller/manager classes, all created in one file. Later in the program, I have other classes (defined in another file) that need direct access to the controller class (usually its just a method call, but the data is “administrative” level and I have to manipulate only one set of data).
here’s a concatenated concept of what I am trying to do…and thus is probably useless ^^

file: test.py
import SpawnController
import FloorController
  class main():
    def __init__(self):
      SPAWNMGR = SpawnController()
      FLOORMGR = FloorController()
    ...

file: FloorController.py
import Floor
  class FloorController():
    ...
    def newLevel(self):
      self.currentFloor = Floor()
    ...

file: Floor.py
  class Floor():
    def __init__(self):
      self.createSpawnPoints()
      ...
    def createSpawnPoints():
      SPAWNMGR.createSP()
    ...

its the same concept as the factory design pattern…except anyone and everyone needs to have access to the factories. Also, there is kinda also some circular dependencies (at least thats what i get from asking other people…).

Passing as a parameter isn’t working because when I pass it in and change it, the data changes don’t…stay. I’ve also tried jhocking’s methodology (since that used to be how i did things to since I hate access issues) and its a mess (my program is kinda big…and unorganized). I was wondering if there was a way to declare these upper level classes so the other classes have access…like the c++ equivelant to global, extern, and static jumbled together?

thanks,
~Silver~