|
I'm a freelance 2d artist; My portfolio can be seen here.
Feel free to contact me if you have any questions.
|
| Wednesday, January 30, 2008 |
 Milestone 0.9 |
Posted - 1/30/2008 12:25:59 AM | It moves, but not as we know it.
(Pretend that it's moving in some direction you didn't click.)
I just gotta work out the details of the navigation function a bit. But hey, it works in a component based framework.
Let's see if we can't get some particles shooting out the back of there, then some asteroids floating around, some collision detection ... and the navigation working properly, of course.
I'm kinda fried on technical details, but at least I got the trig mostly figured out this evening with little trouble. It's much better than that one program I made with gravity inversions in certain quadrants of this space simulation.
Let's call it milestone 0.9
Due to popular demand, here's some code and a little explanation:
An example of the components in-use
Building the ship:
class Ship(Entity):
def __init__(self):
Entity.__init__(self)
self.addState( 'position' )
self.getStateByName('position').coords = [100,100]
self.getStateByName('position').rotation = 2.0
self.addStateObject( Sprite( 'ship64_redA' ) )
self.addStateObject( ShipHull() )
self.pushAction( 'move' )
Here're the states, which are stuck into things to contain info of various sorts. Entities are handled depending on which states they have and what's in said states.
class Position(State):
'' contains position coordinates, x/y velocity vectors, and rotation ''
name = 'position'
def __init__(self, coords=[0.0,0.0],velocity=0.0,angle=0.0,rotation=0.0):
self.coords = coords
self.velocity = velocity
self.rotation = rotation
self.angle = angle
self.noMove = False
class Sprite(State):
'' contains a graphic -- be it a texture? ''
name = 'sprite'
def __init__(self, imageName = 'testFiller'):
self.imageName = imageName
self.color = [1.0,1.0,1.0,1.0]
class NavInfo(State):
'' contains navigation infomartion ''
name = 'navinfo'
def __init__(self):
self.targets = []
from ..ship.components import componentCache
class ShipHull(State):
'' contains various components and stuff ''
name = 'shiphull'
def __init__(self):
self.engine = componentCache.get( 'engTest' )
Here are the actions which can be run on entities so far. "Move" is basically a physics movement updater, "Navigate" is a bit more complex (and is somewhat broken). Actions get called from action stacks held in entities and these repeating actions re-add themselves to the stack, usually. It's downright procedural, actually.
class Move(Action):
name = 'move'
id = False
def __call__(self,parent):
if parent.hasState( 'position'):
posObj = parent.getState('position')
posObj.angle += posObj.rotation
vectorX = posObj.velocity * math.cos( math.radians( posObj.angle ) )
vectorY = posObj.velocity * math.sin( math.radians( posObj.angle ) )
posObj.coords = add( (vectorX, vectorY), posObj.coords )
parent.setStateObject( posObj )
if self.id: parent.pushActionByID( self.id )
else: parent.pushAction( 'move' )
class Navigate(Action):
'' use NavInfo to move parent toward navinfo.targets[1:] ''
name = 'navigate'
id = False
def __call__(self,parent):
fullstop = False
position = parent.getState( STATE_POSITION )
shipHull = parent.getState( STATE_SHIPHULL )
navInfo = parent.getState( STATE_NAVINFO )
delta = timer.getDelta()
angleDif = angleBetween( position.coords, navInfo.targets[0] )
if not angleDif == 0.0:
turnRate = shipHull.engine['turnRate'] * delta
if angleDif <= turnRate:
position.angle = angleDif
position.rotation = 0.0
elif angleDif < 0.0:
position.rotation = -turnRate
else:
position.rotation = turnRate
distToTarget = distanceBetween( position.coords, navInfo.targets[0] )
if distToTarget < 1.0:
position.coords = navInfo.targets[0]
navInfo.targets = navInfo[:1]
if len( navInfo.targets ) == 0:
self.position.velocity = 0.0
fullstop = True
else:
pass
maxSpeed = shipHull.engine['maxSpeed']
thrust = shipHull.engine['thrust']
if distToTarget < maxSpeed / thrust:
maxSpeed = maxSpeed * 0.5
else:
if position.velocity < maxSpeed:
position.velocity += thrust
if position.velocity > maxSpeed:
position.velocity = maxSpeed
parent.setStateObject(navInfo)
parent.setStateObject(position)
if not fullstop:
if self.id:
parent.pushActionByID( self.id )
return
else:
parent.pushAction( 'navigate' )
return
And finally, the generic entity class. Basically it holds and handles States, and has an action queue that gets actions pushed to it which get executed upon update():
class Entity:
def __init__(self):
self.name = False
self.states = {}
self.actionQueue = []
self.children = []
def addState(self,stateName):
'' add new state by name w/ default settings ''
state = stateCache.getObject( stateName )
self.states[ stateCache.getID( stateName ) ] = state
def addStateObject(self,stateObject):
'' add new state by passing in the object itself ''
self.states[ stateCache.getID( stateObject.name ) ] = stateObject
def setStateObject(self,stateObject):
'' set current state to given state ''
self.states[ stateObject.id ] = stateObject
def removeState(self,stateName):
if self.hasState(stateName):
del self.states[stateName]
def hasState(self,nameOrID):
stateID = self.stateNameToID( nameOrID )
if self.states.has_key( stateID ):
return True
else:
return False
def getStateByName(self,stateName):
stateID = stateCache.getID(stateName)
if self.hasState( stateID ):
return self.states[ stateID ]
else:
return False
def getStateByID(self,stateID):
if self.hasState( stateID ):
return self.states[ stateID ]
else:
return False
def getState(self,nameOrID):
return self.getStateByID( self.stateNameToID( nameOrID ) )
def actionNameToID(self,nameOrID):
if type( nameOrID ) == IntType:
return nameOrID
elif type( nameOrID ) == StringType:
return actionCache.getID( nameOrID )
else:
return False
def stateNameToID(self,nameOrID):
if type( nameOrID ) == IntType:
return nameOrID
elif type( nameOrID ) == StringType:
return stateCache.getID( nameOrID )
else:
return False
def pushAction(self,nameOrID):
'' push action onto self.actionQueue ''
return self.pushActionByID( self.actionNameToID(nameOrID) )
def pushActionByID(self,actionID):
'' push action onto self.actionQueue by ID ''
self.actionQueue.append( actionID )
def update(self):
tempQueue = copy( self.actionQueue )
self.actionQueue = []
while( len(tempQueue) > 0 ):
actionID = tempQueue.pop(0)
actionCache.getByID( actionID )( self )
for child in self.children:
child.update()
| |
 Shoulda called in sick |
Posted - 1/25/2008 11:14:15 PM | Down with the Sickness
My throat has been a veritable river of phlegmy pain, so I've mostly been moping and playing Jagged Alliance 2, which, though not an indie game, I did buy through Manifesto Games, which is nominally a source of indie games. What can I say, I have a soft spot for socialist kitsch. ...even if it is painfully ironic when used in the service of entrepreneurialism, or something. You know what I mean.
Point being, I've been taking some "sick days". So deal!
Pyglet and OpenGL
Use of Pyglet allows (requires?) occasional access to the low-level OpenGL commands we all know and love to do certain things (though one could get away with using the Pyglet blit for a while, I imagine). Rotation, for instance, which is what I've been concerned with. But I pretty well know how to do that .. and have access to code to steal learn from which already does it; The trick is implementing image handing and rendering into the previously mentioned component design.
So I find myself making an ImageCache again, treading some familiar ground in some slightly less familiar ways. It'll take a few iterations before it really makes sense, I think (but maybe that's because I'm not thinking straight due to my sinuses being annoying).
Obligatory dcosborn reference
I realize now that I haven't mentioned dcosborn yet, which I must do in every post. In short: I learned much from working with him, and I am still understanding tricks he used in the code of our shared projects. Just in the last week I realized how he was handling some file reading in just a few clever lines while I made up my own rather awkward format for use in IsoStrat which required some hundred lines of code to read in (and god help me if I wanted to read them out). At least I know now and all that effort on IsoStrat forced myself to learn all kinds of string manipulation.
I almost used lambda the other day, too, but thought better of it.
Joining the 21st Century
Oh yeah, re-installed my OS. Now on XP. As Laura said, "Welcome to the 21st century." The new Photoshop (CS3?) isn't bad either. They finally made the toolbar one column.
| |
| Tuesday, January 22, 2008 |
 Codename: Oort |
Posted - 1/22/2008 9:35:51 PM | Component Based Game Design
So we read about how to design a game before starting coding the game. I know, I know, what!? We did a minimal amount of research and came upon a fascinating approach described here quite readably, here rather less clearly but in great depth... if you're into directX or something. I skimmed it. ... and here in powerpoint format or something.
Basically, instead of coding each game object's functionality individually, you make a bunch of generic States and a bunch of Actions that can be applied in any number and combination to any object within the game. To make a simple asteroid, say, we'd take an entity an apply a state.Position, state.Velocity, state.Rotation, state.Graphic, action.Move, and action.Render. Or something like that. Anyway, it's terribly clever and I can't imagine how I've lived my life up until this point without it.
Pyglet
I'm very impressed by Pyglet. Its like someone went and made all the bits and pieces of code that we were trying to figure out ... hold that, I mean all the code that we were trying to get dcosborn to figure out for us ... to make our game codename: ATTAS. What we wanted was essentially a Pygame-like interface that used OpenGL. Except someone's gone and done all the work now, I see. This is lovely! (And take note dcosborn: this is something to check out.)
Oort
This project is now codenamed: Oort, and we're working on it right now. It'd be easy to haxor pyglet to move a ship around, but it wouldn't be doing it within the super-extensible and dynamic system that we intend to use, so milestone #1 may take 'til the end of this week. Anyway, enough talk, more work. Pictures Friday.
One last thought...
... and this is a subtle one. I have been pretty disappointed with the major games I've bought in the last while (eg. Oblivion), so I really haven't been buying anything, just playing games from 10 years ago. As a nominal indie game developer, I should be playing and supporting indie games. I'd never really done this before because ... I don't know, it's just not something I do. So that's gonna change: I'll find an indie game that looks like fun and buy it (and hey, it'll be 1/3rd the cost of Oblivion was). This insight is incredible.
Perhaps you, dear reader, should consider it too, because it is probably in your self-interest to support a culture of buying independent games rather than blockbusters. This would be a great time to plug my own game that I'm selling except that I don't have one so this golden opportunity is lost.
| |
 Old project, New project |
Posted - 1/18/2008 10:27:32 PM | I'm going number two: Isostrat on hold (until I make another Isostrat, and I totally will), have some fun completing some smaller projects.
What becomes of ye, Isostrat?
I'm going to clean up any exceptionally rough edges for a release, then release it like last time. If anyone wants to view/copy the code for educational purposes (Taking note of the advice: "don't read source code" ), then they're welcome to it. I could probably let all the graphics go free too because they're nothing that I couldn't do again given a few minutes.
Upgrading
Whether I can haxor things to get Pyglet going on Windows 2000 or not, I suppose it is indeed about time to upgrade, so I'm getting Windows XP and a new drive to install it on.
It's a big step, I know. I clung to Windows 98, for instance, for far too long as well because I was worried about bloat -- ha! Look at Vista for bloat, it makes XP look like a laser. Anyway, you can't even buy hard drives in the size that my current installation is on (40 gigs) (and ok, maybe you can, but it's uncommon) -- and my largest drive is 60 gigs. I've been keeping it powered down most of the time because it was starting to become flakey but I had nowhere else to put everything (though I did back everything up on Laura's computer). This is, you shall note, a rather ridiculous thing to be doing when 160 gigs costs only 60 bucks.
I'm going to have to drop some cash and get the latest Photoshop too, methinks; I'm more or less "in the industry", so it's time to be all current and stuff.
A New Project
As we all know, every aspiring game developer has a million super cool awesome unique ideas, so Laura and I sat down and prepared an outline for our next game -- yeah, we're going to work together on this one. I'll have more time to work on it, of course, because she has a real job.
So imagine Asteroids where you collect gems and stuff from the asteroids you blow up and sell them to buy upgrades for your ship and a home-base space station. It's like a compulsive grinding action-lite game, but the grinding should be fun and all interactions with the game should feel good, like in Diablo with its clanks and clunks that reward interaction with objects in a small way. That's the plan. Nothing radical, just good clean fun. And if we want to make it insanely complex later, we'll have a solid and working foundation to screw up on.
Milestones
#1:
- Ship flys around under mouse control
#2:
- Ship goes "pew pew" and shoots lasers
- Asteroids spawn
- Asteroids blow up when shot
#3:
- Asteroids spawn loot when blowed up real good
- Ship can collect loot with tractor beam
- Loot is stored in inventory
- Can throw loot back out the airlock
4:
- Home base Space Station exists
- Can dock at base
- Can enter "base mode" to buy/sell stuff
5:
- ???
6:
- Profit!
| |
| Thursday, January 17, 2008 |
 Puny Human Emotions |
Posted - 1/17/2008 8:10:54 PM | This is an off-schedule post dealing with
Feelings
Let me share an anecdote:
I made Quake maps for many years. In fact, I made Duke3d maps, then Quake 1 maps, then Quake 2 maps, then Half-life 1 and Quake 3 maps, then Half-life 2 maps. I was quite good at it, if I may be so bold, but I only ever really released one map that ended up in a random Half-life: Opposing Forces deathmatch map pack under some other name. I made that map by joining some fellows server and somehow we went through loading single player map sections and seeing how suitable for deathmatch they were. We found a particularly fun section of Opposing Forces that was an open arena with a mortar shooting down on it -- in Deathmatch the mortar, which shouldn't have been around, would target the first player in the server exclusively forcing them to move around. Still, this map wasn't made for deathmatch, so players would spawn in one place and it was kinda dumb so I offered to re-make the map, send it to him, then he'd run it. So I did and he did, but it didn't quite work. So he went around the map pointing out things by shooting them with a pistol, like "put a tunnel there" and "put the rocket launcher there", and I went and re-iterated the map. We did this five times and came out with a fairly enjoyable map -- the only map I made that ever got out into the public.
I found a couple shots of stuff I made like 7 years ago; It was going to be some single player maps for Half-life 1 revolving around a research station on Xen:

So really it's a bit presumptuous to claim that I was "good at making maps", because I wasn't. I was good at map architecture, lighting, placing things, all the small level skills, but I was not good at overall project management it took to finish a map and release it. People who were simply mediocre at the small skills but good at project management were far more successful than I ever was.
What's my point?
So glad you asked!
I'm feeling a bit down about this project and I haven't been doing enough on it, for sure. If I had a progress chart it'd be going into exponential decay or something (well, not that bad, but you know). And I've been thinking about where I have to go with this project and it's pretty overwhelming. Yes, I'm pretty good at making graphics and implementing little things, but I'm having trouble with project management. The project is too big. I've been making progress through sheer cussedness (as it were) and taking little pieces as they come, but it's getting difficult to manage. I was thinking today about how I have to implement entities, their interaction with each other, and their interaction with the map itself, and it's looking frighteningly complex -- I see now why other games don't implement my "super cool unique" ideas. They demand a -lot- from the map and a lot of interacting logic. And add to this the development of my own GUI and resource handling systems, it's crazy! Damn I love it, but it's crazy.
What do I do?
1: I can recognize that I'm just in the low end of an emotional sine wave, push through and keep working at this as I go along. I mean I was feeling pretty good only a week and a half ago, and really, the current problems are nothing that couldn't be solved with a few days thought and some planning, right?
2: I can "take a break" from this code and do something simpler, something I can accomplish. (Something with Pyglet). I've certainly learned a ton that could be applied to making (and completing) a smaller game. Even an asteroids-type game would be a pile of fun and in my hands would probably *look* pretty sweet. Or I could make a simple Roguelike RPG (as much as I despise Goblin Genocide ideologically, they are fun). Or a simple sim game that involves building things, I love building things. Maybe like SimTower except not a damn elevator scheduling simulator (what a bizzare game that was!).
I just fear that Isostrat would die, and this would be another corpse on the pile of 4 to 12 (depending on how you count) iterations of this game. I should have enough perspective to realize that this is what tends to happen to projects that get "left for a while".
I'm not really sure what to do.
I think I'm leaning toward option #2. I need to start having fun again.
Edit: Seems like I need Windows XP to use Pyglet. It's about time I upgraded.
| |
| Wednesday, January 16, 2008 |
 Meta-Progress and Portfolio |
Posted - 1/16/2008 1:26:18 AM | Edit: Damn, I posted too late and the clock for GameDev went to Wednesday -- But really, I posted on Tuesday at around 10:30pm PST, so I kept to the schedule! Really! This is going to bug me all month.
Provoking Development
I want everything in my code to be perfect and beautiful, but this is no way to make any sort of progress on a project. So I need to provoke progress from myself. I've decided to randomly and poorly implement new features. This will, in turn, force my obsessive perfectionism to integrate and polish them.
It can't fail!
Random new classes to fill out:
- GameData
- Polity
- HumanPolity
- ComputerPolity
- FlagMaker
- MapGen
Ok, the last two aren't new, I just never did anything with them before.
New terrain types:
- Glacier
- Snow
Unfortunately it'll take one or two more before the list of terrains exceeds the size of the of the TerrainPalette which would force me to implement some kind of scrolling. After the whole scrollbar fiasco from the end of November I was kinda turned off to the whole idea, but it's probably been long enough that I can look at the problem with a fresh perspective. Surely. And I made a little chart of wetness versus temperature for all my terrain types, so there are like 16 or so total to have done, see here:

And this isn't accounting for TerrainEffects or IsoFeatures, of course.
New GUI Element:
- Next Turn Button
Sure, it doesn't do anything yet, but it exerts a subtle teleological imperative. How can I but live in despair under such a force?
Actual development?
I very nearly implemented toggle buttons. The codes all there, I just haven't cleaned it up or, ahem, tested it. But it should work with a few rounds of debugging, I'm excited! I should mention, this was prompted by the realization that writing out the current Editor mode (see last post's screenshot) should be unnecessary because the button selected should show what mode the Editor is in. Yeah!
Game Art Portfolio
See, the way to get people to pay you for things is to look like you're expensive. So I'm moving my portfolio away from 1993 and more toward a design that at least acknowledges something beyond the most basic HTML. Yes, it goes against my anti-aesthetic sensibilities, but this damn Web2.0 thing with it's bells, whistles, and faux-glossy buttons is making me look bad.
Not quite done, but check it out.
This whole freelance graphics thing is interesting, really, but I'm not yet making the equivalent of any kind of fulltime job. And I don't really care for piles of cash mind you, though they'd make life easier. I'd just like to live on doing something I enjoy, ya'know? It's as much as anyone reasonable asks, I know, and I'd be privileged to attain it.
I'm nervous about posting in the help wanted section because I worry that I'm not good enough, but damn, I know I'm good enough -- people are indeed paying me to do art! And it isn't just $5 from the guy who sat in front of me in chemistry class to draw a picture of robots shooting guys armed with muskets. I've got quite an ego enough besides, so this shouldn't be a problem.
We'll see.
| |
 Just small things |
Posted - 1/11/2008 10:03:55 PM | Nothing major this post, just working on a lot of small things and thinking about big things.
GUI work
Here's the shot, not much new, just some work on the interface.

I removed the 6-button panel I was once so proud of and replaced it with the new 5-button topbar. I'm working on transforming the other clunky panels into a similar style that is both compact and able to get across enough information to be useful.
What more interesting, perhaps, is what you can't see. Panels within GUIs can now be 'deactivated' which makes them invisible and unclickable, so in use-terms, they're gone. This allows me to have "layouts within layouts", which is what the three buttons in the upper-left Mode Panel are for: Select, Paint, and Generate mode. I'll explain Select and Generate when they start to do anything, for now they just cause the map-painting palettes and palette chooser to disappear.
Icons
These are just fun:

My stupid paint icon first looked like a broom, then I added paint but it was blue paint, so it looked like a mop or something, so I made the paint purple. So there!
And I couldn't think of something that could represent "game mode" (as the hammer represents "edit mode"), so I just made a hand because ... you play using your hand. Brilliant, yes, thank you.
Dragging
On O-san's suggestion, I implemented drag-scrolling with the right mouse button. It works, nothing much to say.
Hmm, and I started implementing a more 'advanced' drag-painting implementation. Basically, when you left-click drag the mouse, a series of points are created between the current and last "frame" of input, then these points are collided against the Isomap and all tiles thus hit are painted. My function to create these intermediate points is rather half-baked though, so painting is quite erratic. In other words the work is done, it just needs fine-tuning.
And Other Things...
I've been poking at a flag-maker and have decided that I probably won't create flag animations on-the-fly. As cool as it'd be, it'd be too much trouble for something kinda silly. Maybe in IsoStrat: The Expansion Pack. In any case, I want the flags to be fun, and I think they will be because they will be so open-ended and will allow the player to make their Polity very much their own. In many games you can only choose your color, but I want to have the Player choose a major and minor color in one of any number of (moddable) flag patterns with the option of having a (moddable) crest. Want a flag that's half pink half-black with a skull in the center? It's yours!
Of course flags are a bit irrelevant without gameplay. Yes, I've been thinking about how to start implementing it now that the Game class is nicely gutted. I really do need the GUI to do all the things I planned for it to do, though. The Minimap will be clickable once I figure out how to do subclasses in Python again. Ugh. And perhaps I should make it a goal to get horrible, horrible text-input working. Perhaps.
I forget what else. Hmm...
| |
 Optimization and Worlds of Fun |
Posted - 1/8/2008 8:17:02 PM | Note that my new posting schedule is Tuesday-Friday.
As ever, I'll try to have something new and interesting to talk about for every post rather than ranting about how everything sucks.
And a hearty thanks to everyone who tried out Isostrat last week, such feedback is invaluable.
Issues brought up, Answers to them
- Save/Load buttons don't work
I haven't implemented this yet. I've been working on getting the map into a savable state by moving all the rendering functions from the map class to the video class (where they should have been anyway). So: unimplemented.
- The "????" button doesn't do anything
I'm removing it now in a re-work of the editor interface: fixed.
- Far ends of the map sometimes don't work
It turns out that parts of the map were thought to be 'off map' by the game. I found a place where I was comparing an X coord to a Y coord and a Y coord to an X coord -- ridiculous! But now fixed.
- Clicks on Minimap don't recenter GameView
I've been putting this one off because it requires me to code some unique behaviour into a GUI component. But why not? It's my game, after all, I can make something with unique functionality. I'll get around to it as I expand the functionality of the GUI (which is going to have to happen a lot more to get gameplay working properly): unimplemented.
- Mouse-drag tile-painting in the editor is sporadic
As in, a few tiles show up painted, but there isn't a swath of, say, green grass between the start and end point of a mousedrag. As David O suggests, I'd do well to draw a line between points of mousedragging and paint every tile that collides with it -- and improve framerate generally: in-progress?
- Needs better scrolling
Yeah, the map needs to scroll on right-click drag (rather than kinda painting random tiles, if in edit mode). This should be very easy to do: unimplemented.
- Editor needs an eraser tool
I didn't even think of this. Or I did a long time ago, but forgot with all the other stuff to do. It took no time to implement because I had code to do most of this already done: fixed.
- Major slowdown at startup
Turned out this was due to blitting Borderstyle pieces tens of thousands of times.
- General slowness
...was due to the previous, and a horribly inefficient FindVisibleTiles function that was called on every render.
These both deserve their own sections, so:
Blit less, Blit bigger
Now this was interesting.
I'll talk more about how I found out that Borderstyle drawing was taking so long in the next section, so suffice to say: Borderstyle drawing was what was taking so long. And it makes sense, really, because to make the border for the Gameview I'd be blitting a little 4x4 image across the top and bottom, and down the left and right to make all the sides. Worst of all was blitting a 4x4 image of pure colorkey across a 796x596 field: 29651 (or so) blit calls for nothing that couldn't be done with a single fill.
The problem here is not necessary blitting for nothing but, rather, a process that increases quadratically -- in very rough terms, as the dimensions of a panel grew by x, I'd have to do x^2 blits. I solved my blit calls growing quadratically by increasing my blitting image quadratically as well to fit the area to-be-blitted by calling this function:
def makeSurfQuad(surf):
'' Make a new surface from four of given surf, in a square''
surfquad = pygame.Surface( (surf.get_width() * 2, surf.get_height() * 2 ) )
for x in range(2):
for y in range(2):
surfquad.blit( surf, (x * surf.get_width(), y * surf.get_height() ) )
return surfquad
... which takes a surface and returns that surface squared, and the Borderstyle does this until the surface could be blitted across the width of the panel in 2 blit calls. By doing this, about 30,000 blit calls are reduced to about 30 blit calls. I made one for linear blits as well with less dramatic but still valuable savings in blit calls.
The lesson: A blit call has much more overhead than a hell of a lot of pixels in a blit call , so: Blit less, Blit bigger. Now I need to do this with terrain rendering.
And if a problem increases exponentially, increase the answer exponentially.
(Not that you can for all situations, but it sure sounds clever.)
Finding bottlenecks and FindVisibleTiles
First the bottlenecks.
A million thanks to Oluseyi for pointing out Python Call Graph to me. By giving me a tool that can bring my attention to processing bottlenecks, he has, well, indirectly lead to me learning a hell of a lot about programming (or so it feels over the last few days).
So: Python Call Graph makes graphs of Python programs and tells the number of calls and time spent for each function. Now this is very interesting. When I first ran this three places stood out as taking the most time. In order they were Borderstyles, which I've discussed, FindVisibleTiles, which I will discuss, and a far third was David O's vector.add function, which I'm going to let slide because it gets called a few ten thousands of times more than any other function. Oh, and tile.update is up there too I suppose, but that too is called like a hundred thousand times in a short period of time, and it doesn't really do anything yet except make sure that animation is working. Maybe I could only call that update on tiles which are visible.
Here's a shot of FindVisibleTiles being slow:

At first I tried re-arranging the deck chairs on the Titantic and got this:

Which was even slower than before. What I was doing was calling updateDrawPos, which found the absolute pixel position the tile was to be drawn at for every tile, then filtering out tiles that didn't fall within the Gameview area (plus a little). While making up new functions to obfuscate the problem I found myself only pulling tiles from those rows in the map matrix that the Gameview could possibly see, then I thought -- why not clip columns too? Why not just take a slice out of the map matrix of the tiles I know I will be able to see based on transforming the Gameview offset from (0,0) to an offset in the map matrix, and the size of the Gameview to a size in tile rows/cols in the matrix, so then:
for n in range(viewtop,viewrows):
viewTiles.extend( self.isomatrix[n][viewleft:viewcols] )
return viewTiles

3500 times faster. And I only call updateDrawPos in the renderer where, you know, it's actually needed.
In conclusion:
Optimizing was fun. I get this thrill from making things faster and more efficient. And I was only doing it to avoid thinking to hard about what to do next.
Here's the full program chart of the more or less current build for those who want their brains to explode:

| |
 Sweet release |
Posted - 1/4/2008 5:21:17 PM | I got everything working for this release after breaking all my code with a radical change in where everything goes. It should suffice to say that this won't be a verbose post.
Try my game-so-far!
You must have Python 2.5 installed.
You must have Pygame 1.7.1 for Python 2.5 installed.
I have not tried to make this work on anything but Windows, and I'm using Windows 2000, so be warned.
There is no gameplay, just a GUI and map editor. In game mode, select with left clicks, re-center the map with right clicks. In edit mode paint with left clicks and dragging with the left mouse button. Re-center the map with right clicks. Hit an "exit" button or your escape key to quit at any time.
I don't think there's anything (straightforward) that will go wrong, so let that be the challenge: If you can find a cool error and tell me what you did, you win!
If you have undertaken and understand the above, or even if you manage to stumble through on sheer cussedness, you may now download Isostrat v0.05.
Tell me what you think and how it goes, if ya like. If you're particularly adventurous, go ahead and look at the sourcecode.
| |
| Wednesday, January 2, 2008 |
 Changes, large and small |
Posted - 1/2/2008 10:40:05 PM | Big changes
The perspective of a week or so off convinced me of the need for a major change in how everything is organized, as mentioned, to facilitate the saving of maps and gamestates as well as the implementation of novel rendering methods. I found that I was doing a number of ridiculous things, like handing render everywhere except in the Video class itself and doing everything in the Game (instance) class that I should be doing in the Main (meta) function/class. I could go on.
To get a handle on what was going on, I booted up OpenOffice and made some flow-charts that follow no meaningful scheme. Do appreciate that these are by no means comprehensive or terribly meaningful; I never did learn to do flow charts properly.
Isostrat Fork 4:
This is my attempt at expressing what I think was going on:

Isostrat Fork 5:
This is my attempt at expressing what I am now implementing:

It should be much more sane.
A Release!
... but not yet. Due to heckling by besomegames I'm going to release a working version for everyone to play with for themselves once I get the code stable and operating again. There will be no gameplay, just menu-clicking and map-making. So check back on Friday.
Updating Schedule
Under consideration of my greater freelancin' workload, I think that I may do updates on Tuesdays/Fridays starting next week instead of Monday/Wednesday/Friday.
| |
|
| S | M | T | W | T | F | S | | | 1 | | 3 | | 5 | 6 | 7 | | 9 | 10 | | 12 | 13 | 14 | 15 | | | | 19 | 20 | 21 | | 23 | 24 | | 26 | 27 | 28 | | 30 | 31 | | |
OPTIONS
Track this Journal
ARCHIVES
October, 2009
July, 2009
June, 2009
May, 2009
April, 2009
March, 2009
January, 2009
December, 2008
November, 2008
October, 2008
September, 2008
August, 2008
July, 2008
June, 2008
May, 2008
April, 2008
March, 2008
February, 2008
January, 2008
December, 2007
November, 2007
|