23 January 2008

January Update

Unfortunately I don't have much to tell regarding Opioid2D, even though it's been several months again. There have been small patches and adjustments since the last release, but most of my coding time has been spent on the game project I'm doing at work. The game is nearing its release deadline and the crunch is on, so I really haven't had that much energy for personal projects.


There are a couple of Opioi2D related things I've been thinking about, but haven't yet started implementing. The biggest is the rethinking of the node hierarchy system and sprite drawing order. The current design just isn't flexible enough in all use cases, and also isn't as efficient as it could be. Another important thing is the drawing system (lines, triangles, rects etc.) and how to tie that neatly into the action system and rest of Opioid2D. I also happened to come upon a really promising looking 2D physics library called Box2D, which would be a perfect fit for Opioi2D. I've browsed through the API, and I don't think it would be all that difficult to integrate it, giving Opioid2D true physics support.


When thinking about how to integrate drawing primitive shapes with the action system, I've built a prototype for a more generalized action API. This is something that will be released both as a part of Opioid2D and as a standalone action library that can be used with any Python program (pygame games etc.). The API currently looks like this:


@action
def example():
size = interval(10, 15, time=0.5, mode=pingpong)
for x,y in interval(start=(50,0), end=(70,100), time=2):
draw.color = (255,0,0)
draw.circle(x, y, size.value)
yield
for alpha in interval(255, 0, time=0.5):
draw.color = (255,0,0,alpha)
draw.circle(70, 100, size.value)
yield

How does that look? My goal was to design the API so that it would be somewhat clear what the code does, even for someone not familiar with the API beforehand. interval objects give a value based on the current time and their initial parameters, so for example interval(0, 10, time=10) will increase its value by 1 per second until it reaches 10. yield is used to suspend the action until the next frame update.

4 Comments:

Blogger Zorbicon Heptis said...

Sounds good. Good to know you are alive :).

I used to have a class similar to this called 'aGrad', as it was utilizing time in a 'gradient' fashion. The only issue is that there must be a supporting system that ticks these objects, and so they (end users) should be able to use their own game loop to update the ticks manually.

I've tried to get the svn but I get this:

"D:\svn>svn co svn://svn.opioid-interactive.com/shang/opi2d/trunk/
svn: Can't connect to host 'svn.opioid-interactive.com': No connection could be
made because the target machine actively refused it. "

As for the ordering of Sprites and the like, there are several options that come to mind:

-indexes. Lists of sprites are ordered according to their index in a dict and then put in that order ( dict[index] = Sprite() ) for drawing. Leaving gaps in the indexes would allow for sprites to be inserted between pre-existing ones (eg: [..,100,200,..] -> [..,100,101,200,..] )

-position. This would be helpful for the isometric engine, etc in that it creates a pseudo plane wherein the top of the screen is furthest away, unless someone would want to do the opposite (for a sky maybe). An object at (30,40) would overlap one at (30,39). You could incorporate a 'z' value as well, which would be added to y when drawing the image. This allows the sprite to be sorted correctly but not be stuck at the same y as its map location. The positions on the map 'plane' would be used for game logic as well, so this is why the z is added to the y.

-improve attach_to/detach functionality. If the damn sprites would attach in order, there wouldn't be a problem. However, it would be very good if you include the ability to dynamically alter the ordering of sprites so sprites attached_to a parent sprite don't have to detach themselves and re-attach to influence the ordering of the whole.

This would open up new capabilities to your project. Particles being able to orbit around an object (horizontally) is one idea that comes to mind.

The 1kb a second bug is probably the quietest but biggest issue concerning the usability of your software. After a few minutes of continued operation, the program has accumulated a sizable load of memory that eventually slows it down from 80-90 ticks/sec to <40. I am in the process of reviewing my code to see whats going on, as far as my own personal oversights.

Another strange thing is that for some reason the screenshot functionality has stopped working on later versions of some prototypes. The error says that PyOpenGL is missing, but I assume that O2D uses it, so how is that true? The screenshot function is:

def screenShot(file='d:/temp/scrnsht.bmp'):
tmpSurf = pygame.display.get_surface()
pygame.image.save(tmpSurf, file)

26 January, 2008 01:29  
Blogger Zorbicon Heptis said...

Some other issues that come to mind:

-disabling blending on scaled images. This would be useful in some situations for an '8-bit' effect.

-image 'skew'. The ability to warp images by sliding one side of an image on an axis.

-Also, pickling seems like it will be a problem, as I've read that pickle can't handle images. An easy way to 'switch off' the image and convert it back to a pathname could be a solution to this.

Another bug that pops up is what seems to be an error in the precision of the rotation actions. They don't often end up back at the original location:

obj.do(RotateDelta(-30, .2) + Delay(.2) + RotateDelta(30, .2))

Anyway, thanks for everything.

29 January, 2008 00:23  
Blogger shang said...

The problem with ordering sprites according to e.g. their position is that you have to re-sort the sprite list each frame, which might be too big of a performance hit. I'll have to run some benchmarks to see how feasible this is.

Changing the attach_to functionality so that it maintains the order of attachment sounds a lot better, as it would not affect rendering efficiency at all. It would make attaching and detaching a bit slower, but probably not too bad as long as the number of child nodes stays reasonable. I'll try this out today.

As for the "1kb bug", have you tried the example games that come in the Opioid2D source distribution? Does the bug manifest in them on your machine? I've tested the invaders example game myself, and don't notice any continuous memory increase beyond what is expected when the number of enemies and particles increases. Can you email me the program you are seeing this in to shang@iki.fi?

As for PyOpenGL, Opioid2D does not use it, so it's possible your current installation is in fact missing it. Opioid2D calls OpenGL directly from the C++ code, so it doesn't require the Python wrapper. However, pygame.display.get_surface probably requires PyOpenGL when the surface is in OpenGL mode.

Pickling: it's not easy to pickle sprites automatically, because images can be manipulated or even created at runtime. The bigger problem is that lot of the sprite and action data is in the C++ side and completely invisible to the Python code. I'll have to think about how to enable pickling of whole scene state reliably, but I don't think a 100% automatic solution is even possible.

02 February, 2008 12:24  
Blogger Zorbicon Heptis said...

I guess as far as the pickling thing goes, I am gonna try and just implement that myself. The intent is to be able to move objects that exist on a large map onto disk, thus freeing up memory when they are an arbitrary distance off-screen from the focal point (eg player). My idea is to use your sprite/scene architecture for rendering and events, but have the actual object attributes that interface with my system in a separate object which can then be initialized into Sprites.

I will email you the code.

02 February, 2008 23:58  

Post a Comment

<< Home