2009
11.15

Feasability

Well I’m just going to say it, big projects suck. A lot. And it’s amazing how a project that appeared simple in the beginning grew into an unmanageable beast. I’m referring to Lago and its engine, Hydrogen, which have been at a standstill ever since I attempted to rewrite the thing in C++ only to realize that hey, thats a million times harder. But I don’t want to go back to Python because I need to be a good C++ programmer. So I need a simplified project to begin with so that I can get used to writing a full, complete, albeit feature-sparse engine and game.

But I also still want it to be FUN. Which poses a problem, how can a game be both fun and feasible for one person to make, without being some kind of puzzle game? I want to make an adventure game, its the only kind I care about, but is this unrealistic?

2009
08.22

She lags.

The engine. Lags. With about 30 sprites.

Hydrogen is the engine that is written in Python on top of Pygame, and is the engine that Lago and its editor use. So I started working on the first level in the editor, adding background sprites and various decals. Lots of transparent sprites. I made a little black cloud sprite that was repeated a lot to add variation to the stone tiling and make the world seem like it was fading out at the edges. Well that killed the framerate to about 20 or 30, and bear in mind, its a 2D game. Maybe I should just throttle the graphics down, change styles. But come on, these days with big video cards and dual core processors, shouldn’t all 2D games fly?

So the decision is to be made: either tone the graphics down, optimize it somehow, or switch to C++ and DirectX or OpenGL. Either one would be blazingly fast compared to this. But of course that comes with the downside that development isn’t nearly as simple. C++ is a good language, but compared to Python, its tedious. Setting up libraries, long compile times, headers and implementations, the whole deal. No more Ctrl+F9 to and bam it’s there. But C++ is the industry standard, so I should probably get back in that game. I used to use it exclusively, and I was the best, the best.

Decisions.

2009
07.25

Level Editors and GUI’s

I never really appreciated level editors, until I realized placing object by hand in Notepad was less than intuitive. So now most of my projects usually start off with a brand new level editor. I’ve written about 5-ish editors now, and it would be really nice if I could make one editor to rule them all, but alas this is not the case.

In writing the editor I had to make a critical decision: a tile-based grid system of levels, or a free arbitrary object position type system. Tile based levels were used all over games in the 90’s and are still used a lot today for handheld games, because they’re incredibly memory efficient and rendering efficient. It’s easy to get only the tiles that are in the screen’s view. But these kinds of games tend to look repetitive, and it takes a lot of work on the part of the artist to get a lot of variation with this system.

The alternative is to allow the artist to place objects wherever he wants, with rotation and scaling, and let the engine sort out how to optimize the memory usage. This works well for hardware accelerated rendering, because OpenGL and DirectX can draw rotated and scaled sprites as easily and quickly as non scaled or rotated ones. But such rendering abilities are not as common on handheld devices like cell phones. Although more and more devices are getting graphics chips with OpenGL, their texture memory is still pretty limited, so sprites need to be either small or repeated frequently for these devices.

Another problem with the arbitrary sprite system is that it is much more difficult to get only the sprites that are in the screen’s view. This can be optimized with a QuadTree, but you can still end up with significant overdraw (drawing more sprites than you need to). It’s a tradeoff that modern computers can deal with, but maybe not so much for small devices.

Fortunately I’m not making a game for small devices, so I don’t have to worry about it. In fact I think if worse comes to worse, my game will take up maybe 100 megabytes of texture memory (if I try REALLY hard to be inefficient), so that’s not a problem. And rendering is fast enough in PyGame, even if it is just a software blit. So I decided to go with the free sprite positioning editor.

Then I decided to make the editor in-engine, rather than writing it in a separate library. All of the rendering,input, etc is handled by Hydrogen (my engine) and PyGame, instead of a GUI library like wxPython, like I have previously tried. In the future this will probably be better, but right now all this means is that I have to write a dinky basic GUI for the editor. Currently it relies on key presses to set the mode (like setting sprites or drawing rectangles) and changing the tool (like rotating, scaling or moving). The most GUI-esque thing I wrote was a text input box that would pop up whenever you needed it, like when it wanted to know where to save or load the file. I may come back to that, but for now the editor is functional enough to get sprite and rectangle data to and from a file, along with an optional script name and properties for each thing (for example, the player starts at the entity whose name is “player”). Works well enough.

Early Editor Screenshot

Early Editor Screenshot

2009
07.09

I’ve been programming Lago for a while now and got decently far. Since python isn’t really known for its speed, I decided to implement a QuadTree in it, used for drawing and colliding with static objects in the world. In the future I may decide to make it compatible with moving objects, but for now it’s not necessary.

#Ion's Superific QuadTree! Static for now.

LEAF_MAX = 1

class Rect:
	def __init__( self, x, y, width, height):
		self.x = x
		self.y = y
		self.width = width
		self.height = height

		self.right = self.x + self.width
		self.bottom = self.y + self.height

		self.centerx = self.x + (self.width/2)
		self.centery = self.y + (self.height/2)
	def testIntersect( self, other ):
		self.right = self.x + self.width
		self.bottom = self.y + self.height

		if self.right < other.x: return False 		if self.x > other.right: return False
		if self.y > other.bottom: return False
		if self.bottom < other.y: return False 		 		return True 		 	def testContains( self, other ): 		self.right = self.x + self.width 		self.bottom = self.y + self.height 		 		if other.right > self.right: return False
		if other.x < self.x: return False
		if other.y < self.y: return False 		if other.bottom > self.bottom: return False

		return True
	def colliderect( self, rect ): #pygame compatibility
		return self.testIntersect( rect )
	def contains( self, rect ): #pygame compatibility
		return self.testContains( rect )
	def getTuple( self ):
		return (self.x, self.y, self.width, self.height)

class QuadTree:
	def __init__( self, x, y, width, height ):
		self.rect = Rect( x, y, width, height )
		self.oblist = []

		self.subnode = []
	def addObject( self, ob ):
		self.oblist.append( ob )
		if len( self.oblist ) > LEAF_MAX:
			halfwidth = self.rect.width/2
			halfheight = self.rect.height/2

			if len( self.subnode ) == 0:
				self.subnode.append( QuadTree( self.rect.x            , self.rect.y,               halfwidth, halfheight) ) # upper left
				self.subnode.append( QuadTree( self.rect.x + halfwidth, self.rect.y,               halfwidth, halfheight) ) #upper right
				self.subnode.append( QuadTree( self.rect.x            , self.rect.y + halfheight,  halfwidth, halfheight) ) # lower left
				self.subnode.append( QuadTree( self.rect.x + halfwidth, self.rect.y + halfheight,  halfwidth, halfheight) ) #lower right

			kill = []
			for ob in self.oblist:
				for sub in self.subnode:
					if sub.rect.contains( ob.rect ): #object is contained in that node
						sub.addObject( ob )
						kill.append( ob )
						break
			for ob in kill:
				self.oblist.remove( ob )
	def getInBounds( self, rect ):
		total = []
		for ob in self.oblist:
			total.append( ob )
		for sub in self.subnode:
			if rect.colliderect( sub.rect ):
				total += sub.getInBounds( rect )
		return total

	def getAll( self ):
		total = []
		for ob in self.oblist:
			total.append( ob )
		for sub in self.subnode:
			total += sub.getAll( )
		return total

It’s compatible with PyGame’s rect class if you want to use that. Simply make a quadtree and give it a size, then call addObject() on objects that have a rect attribute. It provides some optimization at least. Then you call getInBounds( ) to get all of the objects that are mostly in the rectangle you give it (more than what’s in the bounds, but never less).

Now I’m going to learn you some basic AABB collision. AABB stands for Axis Aligned Bounding Box, which is the simplest collision you can ask for. So think 2D rectangles. The first thing you need to is detect the collision between two rectangles. Perhaps surprisingly, its easier try and detect whether they’re not colliding. For example, if the right side of the first rectangle is less than the left side of the second rectangle, then they must not be colliding. The same with the other 3 sides.

So once you see if they’re colliding, you have to see how deep the rectangle is in the other rectangle. This depends on the first rectangles velocity. If its moving right, then you have to consider how deep the rectangle is in from its right side. And then the same with the other 3 sides.

Finally, you move the object along the smaller of the two depths (not both). But the thing is, if that depth is bigger than the velocity on that axis, then you want to move it along the other depth. Anyways the code probably explains it better than I can.

class CollisionMan:
	def __init__( self ):
		self.bodylist = []
	def addBody( self, body ):
		self.bodylist.append( body )
	def collideBody( self, a ):
		#simple collision detection
		a.rect.x += a.velx
		a.rect.y += a.vely

		for b in self.bodylist:
			if a != b:
				if a.rect.colliderect(b.rect):
					dx = 0
					dy = 0

					#find the intersection depth for each axis x and y
					if a.velx > 0: #moving right
						dx = -( a.rect.right - b.rect.left )
					elif a.velx < 0: # moving left
						dx =  ( b.rect.right - a.rect.left  )
					if a.vely > 0: #moving down
						dy = -( a.rect.bottom - b.rect.top )
					elif a.vely < 0: #moving up
						dy =  ( b.rect.bottom - a.rect.top )

					# I'm a genius! Kinda. The basic algorithm here is to use to find the smallest
					# intersection depth, but with a twist: you never want to move the object passed its original position,
					# that is, the interesection depth must be less than (or equal to) the velocity on that axis.
					# So, at worst, an object can end up back in its original position, before the velocity shifted it.
					if dy == 0:
						a.rect.x += dx
					elif dx == 0:
						a.rect.y += dy
					elif abs(dx) < abs( dy ):
						if abs( dx ) <= abs( a.velx ):
							a.rect.x += dx
						else:
							a.rect.y += dy
					else:
						if abs( dy ) <= abs( a.vely ):
							a.rect.y += dy
						else:
							a.rect.x += dx

That’ll do. Add objects with a rect attribute via addObject, then call collideBody on an object in order to move it out of collision for every object in it. It’ll probably need to be modified for moving objects, but seems to work well for now. Hope this helps somebody.

2009
06.28

Game maybe

Lago, a game in its way too early stages

Lago, a game in its way too early stages

Feeling fine.