Monday, August 5, 2013

Baby Steps

First Entry!!!  As this is the first entry some explanation is in order.

If you were redirected from my CV from an application somewhere in the internet you know who I am.  Else, check the about page if you must know.  As much as I would like a job I also value my privacy.  If my identity doesn't matter to you, for all intensive purposes I am Mikodite Yvette.

Intros aside let me tell you about my current project.

Its a 2D, birds-eye-view adventure game where the player is a priestess navigating dark catacombs in an undead-infested swamp.  Maybe not the most exciting idea for a game that you have ever heard, but the twist to justify it all is the fact that there will be a lighting mechanic that involves deciding between being able to see but notifying enemies of your location, and stumbling around in the dark undetected, or at least in much of the game one would be doing that.

Course, before I can even start building levels I would need a proof of concept... a little something that
  1. Test to make sure that the mechanics are properly drawn and coded.
  2. Prove that the idea has some merit.
So, of course, the first major hurtle: getting the game engine to actually draw something onto the screen.

The engine of choice is Pygame, a freeware engine for Python with the Lesser GNU license.  Its good for making 2D games (I've heard that it can make 3D games as well, but one thing at a time).  Python can be a nice little language that is at the forefront of rapid application development, course I have found that programming in it have its own, at times, bizarre challenges, which I will elaborate on in future entries.

Now, to a weird problem I was having, and how I solved it!

A design decision was to have a class that was responsible for storing and managing the level sprites.  This Level class would be the super class of other classes that would override it, populating the sprite groups with all the sprites of the level - you know, the enemies, the walls, doors, etc.

Part of this was a function I called 'fillSprite'.  I give it two cordinates and it fill draws the sprite of my choosing between those too points, because I am lazy and do not want to so much as copypasta every floor tile for a dungeon. The code at time of writing:

 def fillSprite(sprite_construct,topRight,leftBottom,group):
    sprite = sprite_objects[sprite_construct]()
    for x in range(topRight[0],leftBottom[0],sprite.rect.width):
         for y in range(topRight[1],leftBottom[1],sprite.rect.height):
            sprite.rect.center = (x,y)
            group.add(sprite)


Where topRight/leftBottom are tuples, and group is Group, a subclass of the Sprite class that comes with Pygame that acts as a container for other classes.

"Why is there a method call from a dict element?" asks the Python developers I keep running into on StackOverflow, "And the hell with nested statements!?  What are you, stupid?"

Well, the idea is that one loop iterates through the x coordinates while the other goes through the y.  If there is a way to do that without nesting loops I would love to hear it.

Next, the tiles in the game are subclasses of sprite, intending to make it easier to actually create the objects (I mean, typing StoneFloor() is easier than making a sprite like it), and the sprite was created at the function call.

Next, this came from an original implementation of this function, where I would give it a sprite and the function would create a deepcopy of the sprite to put on it.  The problem with that approach was that it produced the following runtime error:

Traceback (most recent call last):
  File "K:\The Undead Horde\level.py", line 79, in <module>
    level.draw(screen)
  File "K:\The Undead Horde\level.py", line 38, in draw
    self.floor.draw(screen)
  File "C:\Python32\lib\site-packages\pygame\sprite.py", line 475, in draw
    self.spritedict[spr] = surface_blit(spr.image, spr.rect)
pygame.error: display Surface quit


The hell?  I asked myself.  So, after playing around with the code I found out on StackOverflow that it does that if you deepcopy any pygame surface (and the sprite class uses the Surface class).  So I removed the deepcopies.  Course, anyone that understands object oriented programming understands why I would want a deep copy as opposed to a shallow one (that pointer = pointer provides), so a did some horror in the programming language.

Where the level tile classes were declared I put in a dict class that stored the... wait for it... constructors of the classes associated with a string key that would be provided to the function and would call the contructor.

How does that look you might ask?  With the following call:
fillSprite('StoneFloor',(0,0),(300,300),self.floor)

As I said: Baby steps.

No comments:

Post a Comment