My questions thread

Return to Scripting Issues

My questions thread

Postby Bradamante » Mon Jun 29, 2009 6:05 am

I have a scene where a spaceship travels through a warp tunnel, similar to a map in Quake III Team Arena:

http://s4b.directupload.net/images/090628/cfengvqs.jpg

I would like the texture to swirl and move towards the player. I guess one could do it via a shader, but I am not familiar with CG or GLSL.

(1)
I'd like to move a texture by a lerp interval. Pro pointed me at LerpTexOffsetInterval (btw, how is one supposed to find this stuff?). Why do I get an assertion error for:

Code: Select all
warpcolumn_movetexture_interval = LerpTexOffsetInterval(self.warpcolumn1, 4, texOffset = Vec2(-0.4,0), startTexOffset = None, other = None, blendType="noblend", textureStage=None, bakeInStart = 1, name = None, override = None)


(2)
There's an older thread on running PStats on a Mac. I don't want to mess with my system by installing all kinds of GUIs or fight with compiling anything myself. Is there some click&install solution?

(3)
I had no success in customizing the look of the DirectGrid class beyond stuff from the init function, like

Code: Select all
DG = DirectGrid(gridSize=5.0, gridSpacing=2, planeColor=(0, 0, 0, 0), parent=render)


To set parameters like line thickness or color and deactivating the center bubble I copy&paste'd the whole DirectGrid, renamed it, edited it and imported it. Works fine. That wouldn't get me into legal trouble, would it?

(4)
In the Infinite Tunnel sample, line 161, there is:

self.tunnel[0].setScale(.155, .155, .305)


I understand segment x-1 depends on x, starting with 3, going to 0. But where do these values come from? There must be some math behind it, instead of just trial&error?

(5)
In the Infinite Tunnel sample, fog was used to hide the end of the tunnel. I would need something similar, but in my scene the cam is off center. The manual says you cant specify where fog is spawned from, like in my case, the end of the tunnel. Furthermore, I use setShaderAuto on the spaceship and activating fog gives me a "fog and shader generator do not work together, yet" type error.

(6)
What is the stuff in lib/direct/controls/ for?

Well, that's it for now.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby LoneKiltedNinja » Mon Jun 29, 2009 9:12 am

(1) Check the Reference section. It's not 100% complete/accurate, but it has a bunch of stuff. What exactly is the assertion being violated?

(3) I don't think that would be a problem, as long as any authorship headers were also kept, but since parent parameters propagate to children unless the children have their own parameters set, I'd imagine there would be a way to force setColor(), setRenderModeThickness(), etc. on instances from the unmodified code.

(5) "Fog" is really a misleading term in computer graphics. It's not so much the concentrated volumetric fill that you see in the real world, just a function that multiplies the color of a piece of geometry with a fixed other color proportional to its distance from the camera. Hence, specifying the 'origin' or 'spawn point' of a fog is conceptually meaningless, and furthermore, fog can't really be defined as part of a scene, just part of the rendering process, which shaders by their nature override. Writing a fog effect into a shader is fairly trivial, but if you're using the autoshaders and they don't yet support Panda's fog declaration, you're SOL.
LoneKiltedNinja
 
Posts: 131
Joined: Tue Jun 16, 2009 10:38 am

Postby rdb » Mon Jun 29, 2009 9:24 am

Note that the reason why Fog is not implemented into the shader generator is that it's easier (and maybe even more efficient) to achieve per-pixel accurate fog in a postprocessing filter.
I prefer e-mail over PM
rdb
 
Posts: 8545
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby LoneKiltedNinja » Mon Jun 29, 2009 9:57 am

What would that be, basically? Render * depth buffer + fog * (1 - depth buffer)?
LoneKiltedNinja
 
Posts: 131
Joined: Tue Jun 16, 2009 10:38 am

Postby rdb » Mon Jun 29, 2009 10:02 am

Something like that, yes, you could do that with the combine mode CMInterpolate.

For more advanced fog control you can create a postprocessing shader that translates the depth values back to 3d space using the world projection matrix and colors accordingly.
I prefer e-mail over PM
rdb
 
Posts: 8545
Joined: Mon Dec 04, 2006 5:58 am
Location: Netherlands

Postby Bradamante » Mon Jun 29, 2009 11:06 am

Pro, your answer is a bit beyond me :) In the end all I want to do is hide the end of the tunnel. All that shader stuff would be just another thing to dig into and I've got other more core related things to learn.

LoneKiltedNinja wrote:(1) Check the Reference section. It's not 100% complete/accurate, but it has a bunch of stuff. What exactly is the assertion being violated?


Uh can't say, it always crashes as the whole line. If I distribute the variables over multiple lines, it indicates the last line crashing.

Like:

Code: Select all
warpcolumn_movetexture_interval = LerpTexOffsetInterval(
      self.warpcolumn1,
      duration = 4,
      texOffset = Vec2(-0.4,0),
      startTexOffset = None,
      other = None,
      blendType="noblend",
      textureStage=None,
      bakeInStart = 1,
      name = None,
      override = None
      )


Error report:

Code: Select all
 File "Panda3D-tpl-rw/Panda3D/1.6.2/lib/direct/interval/LerpInterval.py", line 667, in __init__
  File "Panda3D-tpl-rw/Panda3D/1.6.2/lib/direct/interval/LerpInterval.py", line 45, in __init__
AssertionError

Line 45 is the blend type, 667 the init.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby LoneKiltedNinja » Mon Jun 29, 2009 11:24 am

Ah. Sometimes the system is friendly and states, e.g., AssertCallable (usually meaning you passed in the returned value functionName() rather than the function functionName).
I'm guessing one of those None arguments is something the interval thinks it needs to function, or else it's a but in Panda itself, since I can't imagine too many people use lerpTexIntervals.

If your tunnel is a hollow tube, I'm not sure there's any compelling way to magically close off the end- even fog would fade out the rest of your scene unless you somehow applied it only to the tunnel, in which case, with no back geometry, there'd be nothing to blend the fog with at the end of the tunnel, and you'd just get a hole. I'd suggest tapering the back of the tunnel into a point and applying some sort of static gradient at the back end on another texture layer. Your swirl should be able to operate independently if you take advantage of the textureStage input to the tex lerp.
LoneKiltedNinja
 
Posts: 131
Joined: Tue Jun 16, 2009 10:38 am

Postby Bradamante » Mon Jun 29, 2009 11:36 am

Found it, it's

Code: Select all
blendType="noBlend",


instead of

Code: Select all
blendType="noblend",


Now I will experiment with the

Code: Select all
texOffset = Vec2(-1,0)


values. But what already strikes me is that it seems like the lerp is not looping:

Code: Select all
warpcolumn_movetexture_interval.loop()


Only a movement of the texture for 4 seconds, and then business as usual.

Alright, got it working with:

Code: Select all
warpcolumn_movetexture_interval = LerpTexOffsetInterval(
      self.warpcolumn1,
      duration = 4,
      texOffset = Vec2(0,-1),
      startTexOffset = Vec2(0,0),
      other = None,
      blendType="noBlend",
      textureStage=None,
      bakeInStart = 0,
      override = None
      )
warpcolumn_movetexture_interval.loop()


Problem is you have to set startTexOffset. bakeInStart 0 or 1 does not make a difference.
Also interesting that you cant do:

Code: Select all
warpcolumn_movetexture_interval = self.warpcolumn1.LerpTexOffsetInterval()


... like with all other intervals in my scene. You get:

Code: Select all
AttributeError: 'libpanda.NodePath' object has no attribute 'LerpTexOffsetInterval'


if you try.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby Bradamante » Thu Jul 02, 2009 5:50 pm

(7)
In my game I am using minimalist style buttons, i.e. no graphics, at least not if I can avoid it.
I like the look of DirectFrames filled with a solid dark color and DirectButtons above them for the clickable text.

Now I'd like to have a 1px or 2px solid color border around the frame, just like:
Image

Now the manual afair says a frame cant have a border? What else could I do to achieve the desired look?
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Thu Jul 02, 2009 5:56 pm

In your DirectFrame constructor, try passing pad = (px, py), where px, py are the amount of padding you want in x and y, respectively.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Thu Jul 02, 2009 7:19 pm

Thanks, will try that. Though I'm a bit sceptical, because where do I set what the padding should reveal underneath?

drwr wrote:In your DirectFrame constructor, try passing pad = (px, py), where px, py are the amount of padding you want in x and y, respectively.

David

Btw I got some strange (I guess Mac-related) behaviour today. Until now I had all my assets in
Applications/Panda/1.6.2/
along the usual Panda files.

After thing grew a little (still totally basic stuff), I left the Panda stuff there, but moved the game-related assets to
Applications/mygame/

I can still start scripts as usual, but quitting Panda causes the Python executable to hang up. It's not crashing, just hanging up (white window, but the window size from the prc file is correct, so it's definitely Panda). In Apple's activity utility the "nice" CPU usage (blue) turns to "system" (red), with way too much CPU used. The process is listed as not receiving inputs anymore.

- Some scripts are not affected, i.e. they dont hang up at all. The only non-Panda-Python script I have ever created. All DirectButton examples from the manual. My own menu script.
- Most scripts work fine, but hang up on quit. The default Panda samples. My own game script sometimes runs, sometimes hangs up immediately.

This is all very annoying since scripts I develop are supposed to crash all the time for syntax errors or whatever, then they hang up and I have to force-quit Python.
I could post some error reports, but they are lengthy. Now I haven't done a restart yet and maybe it's just user file system rights. But just to already mention it ...

Now, is this a Python cache issue? Is there a way to flush those cache files out? Is this a path issue? Can't be?

EDIT:
Alright, a restart it seems fixed it. I guess a restart is required for a asset reorganisation :/
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby Bradamante » Sat Jul 04, 2009 7:36 am

(8)
In my main menu I got a lot of DirectFrames for button backgrounds, then DirectButtons over them.

Changing from the menu to the game I remove all nodes, but removing the buttons doesn't work.

Code: Select all
menuButtons1 = ["Play Pilot", "New Pilot", "Load Pilot"]
menuButtons2 = ["Help", "Settings", "About", "QUIT GAME"]


Backgrounds:

Code: Select all
for i in range(len(menuButtons1)):
   self.menuButtonBackgroundsLeft = DirectFrame(frameColor=(0,0,0,0.6),
   frameSize=(-0.4,0.4,0.055,-0.055), pos=(-0.8,0,-0.15-0.16*i), sortOrder=-1)

for i in range(len(menuButtons2)):
   self.menuButtonBackgroundsRight = DirectFrame(frameColor=(0,0,0,0.6),
   frameSize=(-0.4,0.4,0.055,-0.055), pos=(0.8,0,-0.15-0.16*i), sortOrder=-1)


The buttons:

Code: Select all
for i in range(len(menuButtons1)):
   self.menuButtonsLeft = DirectButton(
   text = str(menuButtons1[i]), pos=(-0.8,0,-0.165-0.16*i), scale=0.07, text_fg=(1,1,1,0.75), frameColor=(0,0,0,0),    command=self.printButtonInput, extraArgs=[str(menuButtons1[i])])

for i in range(len(menuButtons2)):
   self.menuButtonsRight = DirectButton(
   text = str(menuButtons2[i]), pos=(0.8,0,-0.165-0.16*i), scale=0.07, text_fg=(1,1,1,0.75), frameColor=(0,0,0,0), command=self.printButtonInput, extraArgs=[str(menuButtons2[i])])


The cleanup:

Code: Select all
def cleanup(self):
   self.spaceship.removeNode()
   self.warpcolumn1.removeNode()
   self.warpcolumn2.removeNode()
   self.menuButtonBackgroundsLeft.removeNode()
   self.menuButtonBackgroundsRight.removeNode()
   self.menuButtonsLeft.removeNode()
   self.menuButtonsRight.removeNode()
   render.clearLight(self.thatdirlight)
   render.clearLight(self.thatamblight)


No errors. Seems I am not addressing the backgrounds and buttons correctly.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Sat Jul 04, 2009 12:52 pm

First, you should call button.destroy() instead of just button.removeNode(), to clean up any DirectGui object.

But that's not your problem here. Your problem is the way you create your buttons:
Code: Select all
for i in range(len(menuButtons2)):
   self.menuButtonsRight = DirectButton( ... )

Each button you create, you assign it to self.menuButtonsRight, replacing what you had previously assigned to self.menuButtonsRight. Thus, at the end of your loop, you have stored only one button in self.menuButtonsRight, the last one you created. All of the other buttons have been lost, and do not ever get removeNode() called on them.

Instead of assigning them all to the same member, you can store them in a list or something.

Alternatively, set the parent of each of your buttons to your DirectFrame. Then, when you call directFrame.destroy(), it will automatically destroy all of your buttons as well. (Destroying a parent object automatically destroys all of its children.)

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Sat Jul 04, 2009 6:04 pm

Thx, I did not understand your suggestions though. Or I did unterstand them but could not translate that into code. If I append my stuff to a list, and then delete that list, how would that remove my buttons? Delete would be a Python method, would that even work? During creation I have 9 background frames and 9 buttons above them. So that list would contain 18 items.
And reparent to DirectFrame?

Anyway, I get the desired effect with:

Code: Select all
menuButtons1 = ["Play Pilot", "New Pilot", "Load Pilot"]
menuButtons2 = ["Help", "Settings", "About", "QUIT GAME"]
self.menuButtonsNode = aspect2d.attachNewNode("MenuButtonsNode")


Code: Select all
for i in range(len(menuButtons1)):
self.menuButtonBackgroundsLeft = DirectFrame()   self.menuButtonBackgroundsLeft.reparentTo(self.menuButtonsNode)

for i in range(len(menuButtons2)):
self.menuButtonBackgroundsRight = DirectFrame()   self.menuButtonBackgroundsRight.reparentTo(self.menuButtonsNode)

for i in range(len(menuButtons1)):
   self.menuButtonsLeft = DirectButton()
   self.menuButtonsLeft.reparentTo(self.menuButtonsNode)

for i in range(len(menuButtons2)):
   self.menuButtonsRight = DirectButton()
   self.menuButtonsRight.reparentTo(self.menuButtonsNode)


Code: Select all
def cleanup(self):
      self.menuButtonsNode.removeNode()


delete() is not possible here of course.

Good? Bad? Good enough?

(9)
I once had sounds in that menu, just defined them in the DirectButton field (rollover and click). I don't have the syntax anymore, but it was something totally simple. Now, I guess this is a common issue, the sounds played when the menu was first loaded (Class first instanced), but not on rollover or click. Now here on the bottom http://www.panda3d.org/wiki/index.php/Loading_and_Playing_Sounds_and_Music it says something pointing in that direction. Is that it?
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Sun Jul 05, 2009 9:42 am

I meant, after appending them to the list, you should then clean them up by iterating through the items of the list and calling destroy() on each one of them. (Then you may delete the list if you like.)

Your current solution is still not quite right, because you are only calling removeNode() and not destroy(). This makes the buttons disappear from the screen, but they are still listening for their button events--you have created a leak in the event handler table. It's true you cannot call destroy() on the plain PandaNode you are parenting the buttons to now. So you either have to go with the list approach, or parent them all to a DirectFrame instead. I believe it is possible to create an invisible DirectFrame for this purpose if the buttons really don't have any visible frame they're associated with, though the name "menuButtonsBackgroundLeft" and "menuButtonsBackgroundRight" gave me the idea that these frames are intended to be background frames for your buttons (meaning the buttons should be parented to them). Of course, the frames themselves still need to be parented to something else you can destroy, or retained in a list so you can destroy them explicitly.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Sun Jul 05, 2009 2:53 pm

Alright, parenting it to an invisible DirectFrame at 0,0,0 worked. The former solution - removing the Node - did not pose problems, the buttons where gone. No rollover sound when one moved the mouse to where the buttons where and no reaction on clicking blindly :) No difference now, but you are right of course.

Any ideas on that sound thing (9)?

I tried your pad=(x,y) thing, but that did not make any difference:

Code: Select all
self.backgroundwhite = DirectFrame(frameColor=(1,1,1,1), frameSize=(-0.8,0.8,0.45,-0.45), pos=(0,0,0), sortOrder=-3)
self.foregroundblack = DirectFrame(frameColor=(0,0,0,1),   frameSize=(-0.8,0.8,0.45,-0.45), pad=(2,2), pos=(0,0,0), sortOrder=-2)


Where supposedly the black foreground has the same size like the white background and the padding makes it visible.

(10)
Old issue ... In my game, the cam looks from above onto the scene and moves with the spaceship at the center. We had endless discussions on IRC about this ... Currently it's a thread that corrects the cam pos each frame, but then the movement of the ship/cam jitters.
Reparenting the cam to the ship smoothes things, but then my coords are of course no longer valid. More importantly, the cam turns with the ship, like in a typical shooter or the Ralph example. But, I want the cam fixed and the spaceship to turn underneath.
I know there is a syntax like
Code: Select all
cam.setPos(target,x,y,z)


but when I tried that something was ugly. Don't remember what. And I don't find the syntax anywhere.

Is there a solution for this? Suppressing certain values forced from target to cam?

drwr wrote:I meant, after appending them to the list, you should then clean them up by iterating through the items of the list and calling destroy() on each one of them. (Then you may delete the list if you like.)

Your current solution is still not quite right, because you are only calling removeNode() and not destroy(). This makes the buttons disappear from the screen, but they are still listening for their button events--you have created a leak in the event handler table. It's true you cannot call destroy() on the plain PandaNode you are parenting the buttons to now. So you either have to go with the list approach, or parent them all to a DirectFrame instead. I believe it is possible to create an invisible DirectFrame for this purpose if the buttons really don't have any visible frame they're associated with, though the name "menuButtonsBackgroundLeft" and "menuButtonsBackgroundRight" gave me the idea that these frames are intended to be background frames for your buttons (meaning the buttons should be parented to them). Of course, the frames themselves still need to be parented to something else you can destroy, or retained in a list so you can destroy them explicitly.

David
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby Bradamante » Wed Aug 12, 2009 5:05 pm

(11)
Are there some bugs in DirectScrolledFrame?

I've got a DirectScrolledFrame with:

Code: Select all
self.Starmap = DirectScrolledFrame(frameSize=(-329*0.8/480,329*0.8/480,221*0.45/270,-221*0.45/270),
      pos=(-135*0.8/480,0,32*0.45/270), canvasSize=(-658*0.8/480,658*0.8/480,221*0.45/270,-221*0.45/270)


As you can see, the canvas is wider then the frame, but of equal height. But it looks like this:
http://s4.directupload.net/images/090813/zzcbelr6.jpg
The horizontal scrolling works fine, but the vertical gets displayed too, where it wouldn't be necessary. I guess the auto manage thing does not distinguish between the horizontal and vertical bar?

Let's increase the height of the canvas, too:
Code: Select all
self.Starmap = DirectScrolledFrame(frameSize=(-329*0.8/480,329*0.8/480,221*0.45/270,-221*0.45/270),
      pos=(-135*0.8/480,0,32*0.45/270), canvasSize=(-658*0.8/480,658*0.8/480,442*0.45/270,-422*0.45/270)


Looks like:
http://s7.directupload.net/images/090813/ztthf9nq.jpg

And good bye to the lil' blue dots I came to know and love! Could it be there's some position bug on the vertical axis?
On the other hand, I can call

Code: Select all
self.Starmap.getCanvas().getPos()


for both a same-size and double-size canvas, the Pos of the canvas is always (0,0,0), as it should be. Also notice how the visuals of the horizontal bar changed, without me doing anything.
Is there maybe some align option I am missing?
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Wed Aug 12, 2009 5:36 pm

The DirectScrolledFrame is getting confused because you are creating an inside-out frame, specifying a "bottom" value that is larger than the "top" value. (Remember, in Panda, the coordinate system increases from the bottom to the top, unlike most 2-d coordinate systems.) Arguably, the code should handle this inside-out case more gracefully, but it doesn't.

If you correct these parameters, reversing the last two parameters of your frameSize and canvasSize, then both of your DirectScrolledFrame examples are well-behaved. Note that you still have a vertical scroll bar in the first example, because the horizontal scroll bar takes up some of the space within the frame.

You might also want to set something like borderWidth = (0.01, 0.01), so the bevels on the scroll bars make more sense.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Wed Aug 12, 2009 5:49 pm

You are right, that did it. This is actually an error I see in all my code, I define all DirectFrames by:
Code: Select all
frameSize=(-x,x,y,-y)


instead of

Code: Select all
frameSize=(-x,x,-y,y)


For naked DirectFrames that doesn't seem to be a problem, but here it get's me. Thanks for the help, I will get to formatting the bars later.

drwr wrote:The DirectScrolledFrame is getting confused because you are creating an inside-out frame, specifying a "bottom" value that is larger than the "top" value. (Remember, in Panda, the coordinate system increases from the bottom to the top, unlike most 2-d coordinate systems.) Arguably, the code should handle this inside-out case more gracefully, but it doesn't.

If you correct these parameters, reversing the last two parameters of your frameSize and canvasSize, then both of your DirectScrolledFrame examples are well-behaved. Note that you still have a vertical scroll bar in the first example, because the horizontal scroll bar takes up some of the space within the frame.

You might also want to set something like borderWidth = (0.01, 0.01), so the bevels on the scroll bars make more sense.

David
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby Bradamante » Sun Aug 16, 2009 9:50 am

(12)
My Player is a FSM with a state "Jumping", among others. The FSM works, but after I enter a state and request it again, I get a crash with

Code: Select all
direct.fsm.FSM.RequestDenied: Jumping (from state: Jumping)


That is to be expected, but can't I prevent that? Something like:

Code: Select all
If FSM.Jumping.isPlaying():
    pass
else:
    FSM.request("Jumping")


One way I am using right now is to unaccept the key that evokes the function that request that state (here: J for Jumping) while being in that state. But that's just not the real thing.

(13)
I've got a Starmap, a DirectScrolledFrame, as formerly mentioned. It looks like this (WIP):
Image

Works fine, problem is it takes 4-6 seconds to build it on my relatively decent machine. It would be too much to post the full code, but here's how it works.
I've got roughly 160 stellar systems, each represented by a dot on the map, which is a DirectRadioButton, each with a boxImage. The database is a dict looking like this:

Code: Select all
StarmapData = {
'DSN-901': [-184, -89, None, None, None, None, 0],
(... 160 entries like this ...) }


The numbers being pixel coordinates. I then build the buttons like:

Code: Select all
for Stob in self.StarmapData.keys():
    self.buildStobButton(Stob, self.StarmapData[Stob][0],
    self.StarmapData[Stob][1], StobButtonID, scalefactor)
    (...)
    StobButton.reparentTo(self.Starmap.getCanvas())


Right now I reparent all Buttons to the canvas upon creation - is that the problem?

The wrapper for the buttons contains stuff like:

Code: Select all
def buildStobButton(self, stobname, buttonposx, buttonposy, indexno, scalefactor):
return DirectRadioButton = (...)
pos=(buttonposx*0.8*scalefactor/480,0,buttonposy*0.45*scalefactor/270))


for a 16:9 960x540 window. Those calculations can't be the problem. The - and + you see in the screenshot do a scaling a la

Code: Select all
StarmapElement.setPos(StarmapElement.getPos()*1.25)


and that one is almost instant for all 160 elements.
Building the dot graphics (DirectRadioButton - boxImage) is not the problem either - when I comment those out, it does not speed up.

So things must get slow earlier. In the beginning, when my database contained only like 10 instead of 160 entries, thing where a lot faster. Should I first reparent the buttons to a node and then reparent that to the canvas?
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Sun Aug 16, 2009 11:59 am

(12)
If you're getting a RequestDenied, it follows you must be using a defaultTransitions table to list the allowed transitions (unless you're using your own custom filter func). Simply add a transition from 'Jumping' -> 'Jumping' to this table. Or, if you do have your own custom filter func, make it return None in response to the request for 'Jumping' -> 'Jumping'.

(13)
I don't know specifically where the slowdown is occurring; you might find it valuable to run your setup code in the Python profiler to look for obvious bottlenecks. My suspicion is that the cost is in the setup time for each of the DirectRadioButtons, though. In general, one of Python's biggest weaknesses is the time it takes to call constructors on complex objects, and the DirectGui objects are fairly complex. To reduce this time, you might need to go with a more custom solution; rather than creating a bunch of DirectRadioButtons, just create standalone geometry and then listen for mouse clicks and handle them explicitly by looking at the (x, y) click position and figuring out which star system was clicked.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Fri Aug 21, 2009 8:22 am

(12)
I kinda solved this by simply removing the FSM from the player, since it simply isn't one.
I guess a solution is to simply use a "isEnabled" attribute that at class creation is 0, during Jumping is 1, and at the end of Jumping goes back to 0. I use that pattern now in other places.

(13)
You're right, it is simply the setup time of the DirectRadioButtons. I brought the time down from 5-6 seconds to 3-4 seconds by using only DirectButtons. I guess I will have to come back to that later.
I know how to create a bunch of geoms via CardMaker for example. I know how to get the x,y coords of the mouse on click. But to be honest I don't know how to connect the two.

(14)
I've got a problem it seems with class attributes.

I've got a HUD that is in it's own class in a file, like:
Code: Select all
class MCHUD(DirectObject):
   def __init__(self):
      pass
   
   # the build function only sets background images and empty text fields
   def buildHUD(self):
      self.hudpictures = []
      self.hudtexts = []
      
      self.targetBackgrd = OnscreenImage( bla )
      self.targetBackgrd.reparentTo(base.a2dTopRight)
      self.hudpictures.append(self.targetBackgrd)

      (...)

   def deleteHUD(self):
      for hudpicture in self.hudpictures:
         hudpicture.destroy()
      self.hudpictures = []
      for hudtext in self.hudtexts:
         hudtext.destroy()
      self.hudtexts = []


At start of the game or when I jump from system to system the Environment AKA World class gets (re-)created. This is where the HUD initially becomes visible:

Code: Select all
from mchud import MCHUD   

class MCEnvironment(DirectObject): # AKA the World class
   def __init__(self, ..., ...):

      self.hud = MCHUD()
      self.hud.buildHUD()
      # now fill the empty fields with current data
      self.FreeCargoSpace = int(self.mcdbships.ShipList[self.PlayerShipIdentifier][8])
      self.hud.incargoText.setText('In Hold: '+str(sum(self.CargoContent.values()))+"t ("+str(self.CargoContent.keys())+")")
      self.hud.creditsText.setText('Credits: '+str(self.PlayerCredits))
      self.hud.freecargoText.setText('Free: '+str(self.FreeCargoSpace - sum(self.CargoContent.values())))
      self.hud.starsystemText.setText(self.StobIdentifier)
      self.hud.stellarnavGoal.setText("- none selected -")


Now upgrading the HUD content from the Environment works fine. But there are other elements in the game that also update the HUD. For example, the Starmap, where the HUD reflects some button clicks:

Code: Select all
from mchud import MCHUD

class MCStarmap(DirectObject):
   def __init__(self, ...):

      self.hud = MCHUD()
      # on some button click
      self.hud.hudtexts[1].setText(chosenStob[0])
      self.hud.stellarnavGoal.setText(chosenStob[0])


Another entity manipulating the HUD is some ingame menus. I think I see what is going on. The HUD class get's thrown into several namespaces over time.

The __init__ of the HUD is a pass to avoid multiple builds of the HUD when the classes import the HUD class. If I put the setup code from def buildHUD(self) to the __init__ I get three or four HUDs over each other, and only one of them gets changed with setText() commands.
What helped historically is to do something like:

Code: Select all
class MCIngameMenu(DirectObject):
   def __init__(self, ..., ...):

      self.hud = MCHUD()
      self.hud.deleteHUD()
      self.hud.buildHUD()
      # now fill the empty fields with current data
      self.hud.incargoText.setText('In Hold: '+str(sum(self.CargoContent.values()))+"t ("+str(self.CargoContent.keys())+")")

If I don't do something like that, I draw the HUD originally in Environment, then I do self.hud.incargoText.setText() in the Starmap and get "self.hud has no attribute incargoText".
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Fri Aug 21, 2009 8:54 am

(14) Why are you creating a new instance of your HUD class every time you want to access it? Don't you really want to have only one instance, and have all accessors share that same instance?

Each time you call:
Code: Select all
self.hud = MCHUD()

that creates a brand new instance of MCHUD. So, do this only once. In other classes that want to access the hud, you can get a pointer to the instance you've already created, instead of creating a new one:
Code: Select all
self.hud = world.hud


Now that you're only creating one instance, you can put the initializers back into __init__(), where they belong.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Fri Aug 21, 2009 9:40 am

Oh, I thought stuff like that would get me circular imports. But I guess it won't now that I think about it ... thanks!

EDIT ... circular imports, like:

Code: Select all
player.py

from environment import Environment
from map import Map
class Player() # entry into the game
    self.environment = Environment() # initial init of the environment
    self.map = Map()
    self.hud = self.environment.hud
    self.hud.element.setText()

environment.py

from ingamemenu import IngameMenu
from hud import HUD
class Environment() # called from Player
    self.ingamemenu = IngameMenu()
    self.hud = HUD()
    self.hud.element.setText()

ingamemenu.py

from environment import Environment
class IngameMenu() # called from Environment
    self.environment = Environment()
    self.hud = self.environment.hud
    self.hud.element.setText()

map.py

from environment import Environment
class Map() # called from Player
    self.environment = Environment()
    self.hud = self.environment.hud
    self.hud.element.setText()


EDIT 2:
On the IRC channel Hypnos suggested using a globals file, I assume like:

Code: Select all
### player.py

from globals import Globals
self.globals = Globals()
self.hud = self.globals.hud

   self.hud.element.setText()


### environment.py

from globals import Globals
self.globals = Globals()
self.hud = self.globals.hud

   self.hud.element.setText()


### ingamemenu.py

from globals import Globals
self.globals = Globals()
self.hud = self.globals.hud

   self.hud.element.setText()

### map.py

from globals import Globals
self.globals = Globals()
self.hud = self.globals.hud

   self.hud.element.setText()

### globals.py

from hud import HUD
self.hud = HUD()


### hud.py

class HUD():
   def __init__():
      self.buildHUD()


But I often read globals are bad.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby Hypnos » Fri Aug 21, 2009 2:38 pm

rather something like this: :-)

Code: Select all
### player.py
import GLOBALS
### GLOBALS.py
# i'm empty

### player.py
class Player:
  def __init__(self):
    self.x = 1
GLOBALS.player = Player()

### main.py

import GLOBALS
import player

class Main():
  def __init__(self):
    print GLOBALS.player.x
    GLOBALS.test = player.Player()
m = Main()
Hypnos
 
Posts: 585
Joined: Sat Sep 11, 2004 8:07 am
Location: Zürich, Switzerland

Postby Bradamante » Fri Aug 21, 2009 4:05 pm

(14)
Following Hypnos' advice on the IRC channel this is pretty much solved via the globals thing, even though I don't like it.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Fri Aug 21, 2009 4:20 pm

You don't need to use a global module if you don't like it. If you use the "import environment" syntax instead of "from environment import Environment", you will be largely safe from circular imports.

BTW, it looks like you are creating multiple different instances of your Environment class in the pseudo-code above. I suspect you only want one Environment instance instead of several. Fixing this will also remove the need to import Environment everywhere, so this may also solve your circular-import problem.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Sat Sep 05, 2009 9:21 am

(15)
Got a new problem with class instances and intervals it seems.

I've got a base class for spaceships now, it has some attributes (which are present), one of them being the model node ".ShipModel". Attached to the model node are: nodes for exhaust graphics; nodes for running lights; nodes for rotating parts.The player ship is based on that as well as some NPC ships that I throw in every some seconds. The exhaust appears only when I hit the UP button, so the NPC ships don't have that effect, they have the nodes though for later use. So currently on the NPC ships you got two effect: blinking lights and rotating parts, while on the player ship you got those two + the exhaust when UP is pressed.

Adding the player:

Code: Select all
def addPlayerShip(self):
    self.PlayerShip = MCShipBase(self.PlayerShipIdentifier)


Adding NPC ships:

Code: Select all
def addSceneryShipByJumpIn(self):
    self.addShipObject(MCShipBase("Commando Ship"))
    # this adds it to a dictionary


The ship base class, just the important parts:

Code: Select all
class MCShipBase(object): # object
    def __init__(self, ShipIdentifier): # ShipIdentifier
        self.ship_exhaustlist = [] # holds the
        self.ship_runlightlist = [] # exhaust and runlight nodes

    def loadShipModel(self):
        self.ShipModel = loader.loadModel("../mcships/bla")
        self.ShipModel.reparentTo(render)
        return self.ShipModel

### rotating parts

    def buildShipModelRot(self):
        self.shiprotmodel = loader.loadModel("../mcships/")
        self.shiprotmodel.reparentTo(self.ShipModel)
        self.shiprotint = self.shiprotmodel.hprInterval(bla)
        self.shiprotint.loop()

### runlights

    def buildShipRunlights(self):
        for i in range(bla):
        self.ship_runlightlist.append(self.createShipRunlights(self.ShipIdentifier, i))

        self.ship_runlights_seq = Sequence(Func(self.showShipRunlights), Wait(0.05), Func(self.hideShipRunlights), Wait(bla), name="spaceship_runlight_seq")
        self.ship_runlights_seq.loop()

    def createShipRunlights(self, ShipIdentifier, indexno):
        runlgt = CardMaker("runlight")
        runlight = runlgt.generate()
        self.runlgtnode = self.ShipModel.attachNewNode(runlight)
        self.runlgtnode.reparentTo(self.ShipModel)

    def showShipRunlights(self):
        for runninglight in self.ship_runlightlist:
            runninglight.show()


The problem here is that as soon as I throw in a new instance of the class (here: a new NPC ship), the runlights disappear. If only the player is present and no NPC ships, all continues to work, the exhaust, the runlights and the rotating part (the latter two using intervals). As soon as the first NPC ship comes in, the rotating node on the player ship continues rotating, the exhaust appears when pressing UP, but the runlights disappear. On the NPC ship things rotate and blink ... until the next NPC ship comes in, then the runlights go off while the rotation continues. So the runlight effect only appears on the most recent ship.

I thought this comes from losing the class attributes at the creation of a new instance, here: the runlights and/or the intervals. But checking with getChildren() the nodes are still there. I thought the intervals would go, but checking with isPlaying() it says all intervals are still playing.

A screenshot to illustrate things: http://s5.directupload.net/images/090902/44zact9z.jpg

In the middle the player ship. The satellite dish rotates. Every some seconds a blinking light shows (not in picture). As soon as the NPC ships come in (here: every 5 seconds a new one), the satellite dish keeps rotating, but the blinking lights appear only on the most recent ship, even though the rotation interval continues.

I am using a dictionary to store stuff, but I don't think that has to do with anything, like: {0: instance adress, 1: instance adress, ...}

Then the main loop looks like:
Code: Select all
def updateShipModels(self, task):
    for ID in self.ShipObjects.keys():
        self.positionObject(self.ShipObjects[ID].ShipModel)
        return Task.cont


All effects use nodes and reparentTo(bla.ShipModel), all effects use intervals. One thing I notice is that for the rotating part I use the shortcut:
Code: Select all
self.shiprotint = self.shiprotmodel.hprInterval( ... ).loop()


For the exhaust I use no interval (since they appear on key press), the runlight effect uses a function sequence. There are no console errors.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Postby drwr » Sat Sep 05, 2009 9:33 am

Question: what happens if you don't assign a specific name to your intervals? In that case it will give each interval a unique name.

For legacy purposes, I think we still have the rule that each interval must have a unique name, and that when you start a new interval with the same name as another interval, the previous one is implicitly stopped. Don't know for sure that's true, but I seem to remember that; and for that reason we generally give all of our intervals unique names. And I don't know why your intervals would still report isPlaying() when they have been overridden in this way, but it's worth a try.

I wouldn't recommend relying on this rule, by the way, because I'd like to be able to phase it out--it's a terrible rule.

David
drwr
 
Posts: 11253
Joined: Fri Feb 13, 2004 12:42 pm
Location: Glendale, CA

Postby Bradamante » Sat Sep 05, 2009 4:28 pm

Wow you're right, it works now, thanks!
What you're saying sounds familar. In my environment I got blinking lights too, assigned to the space stations. There can be multiple of them, and that caused problems when deleting the environment elements. I had unique names assigned, but I did not derive the stations from a base class, so it caused no problems upon creation. But it did cause problems when I want to delete all environment elements, including those intervals.
The solution was to append all intervals in the environment to a list and then delete the elements of that list.

How is it with those intervals anyway ... Does an interval assigned to a node finish when the node is removed? Sometimes it seems to me yes, sometimes not.
User avatar
Bradamante
 
Posts: 303
Joined: Tue Nov 25, 2008 10:58 am
Location: Leipzig, Germany

Next

Return to Scripting Issues

Who is online

Users browsing this forum: No registered users and 0 guests