Showing posts with label programming. Show all posts
Showing posts with label programming. Show all posts

Wednesday, 22 January 2014

New and improved "Sociales Santillana" (aka Minimcentric). First gameplay footage.


Here are some screenshots for an improved version of "Vacaciones Santillana", the game I did for LD #26 (I've renamed it to Minimcentric, but I'm not too sure about that name either). I found out it was quite fun to play, so I took notice of all the feedback and began polishing it. As gaming , writing and real life responsibilities interfere with programming at home as a hobby, I haven't devoted as much time as I should have, so I'm working at snail pace. Still, it's looking nice so far -and I managed to keep my non-gamer mother hooked for a couple of hours, which is a triumph of its own.




I'll upload a playable version as soon as I polish the sound and menu flow. Stay tuned!

Tuesday, 27 August 2013

LD#27 (10 seconds) - 10s Paparazzi

Time flies, and the 27th Ludum Dare took place this weekend. The theme? 10 seconds.
Play it here...

...or check the LD entry

Of course, here is the postmortem.

Also, take a look at some friends's Jam entry, Bloody Bob.
It looks this cool:

Monday, 29 April 2013

LD #26 (Minimalism) - Sociales Santillana

This is my entry for Ludum Dare 26 (Theme: Minimalism), Sociales Santillana

I couldn't come up with a good name, so in the end I chose the school books whose cover pic inspired me for the game.

You can play it here

Link to the Compo entry

And, of course, the mandatory post-mortem link

Monday, 17 December 2012

LD #25 - You are the villain

This is my entry for Ludum Dare 25 (Theme: You are the Villain).

Behold...Conquer all the castles!!



Link to the entry

Tuesday, 28 August 2012

It's evolution, baby! Ludum Dare #24




Long time no see!

I've come back to life to....eat your braaaaainz!!!.

Well, not really.

I could start with the prototype I've been coding at a ridiculously irregular rate, but I'll restrain for now until I have something that I can show or talk about. Instead, I want to talk about the Ludum Dare.

This weekend was the 24th edition, and I contributed with my first submission. For those who don't know what I'm talking about, it is a speed game development jam. There are two modes: the competition, where you have 48 hours to develop a game by yourself, and the jam. In the jam you can work in teams and have one more day to do stuff.

I've always liked  the idea, and the challenge a game jam represents, so I was considering to join one sooner or later. Since the theme for this edition was Evolution, which is a topic I've been interested in for some time, I couldn't let it go. My choice was to make a god game where you could control an evolving ecosystem sim of sorts, based in an overly simplistic implementation of genetic algorithms.



I won't delve in much detail. Instead, I'll just link to the submission and post-mortem posts, stating what went right (a couple of lessons that could be valuable for life), and what went wrong (almost everything else).

Despite this, I'm thinking that the idea is interesting, so I might give it a go and develop it in the future (once I'm done with the prototype and a full version of Wall Chaos, of course).

And, of course, the direct link. Don't dig too much into the code, please... it is embarrassing :P
Dropbox link here. Uncompress and enjoy (Windows only, sorry :S)

Wednesday, 27 October 2010

Quick and dirty scripting with Python

Quick and dirty scripting with Python


I came home from work today and, instead of taking a nap (something that would have come in really handy) or playing Mass Effect 2, I started coding a couple of scripts to help me organising some files that I've got in several Micro SD cards.

Keep in mind that I've omitted the imports, "const-like" vars declarations and the if __name__=="__main__" statement for the sake of brevity.

The first one just lists the files and subdirectories from a given path, and then it saves it to a text file. Python also provides the function os.walk (or the deprecated os.path.walk), but I got it into my head that I wanted to indent the files according to the depth from the root path and the easiest way to accomplish this was using os.listdir, which worked as a charm =)

def extract_dir_files(arg, dirname):

    dir_str= "%s/%s/\n" % (" "*arg[0],os.path.split(dirname)[1])

    arg[1].write(dir_str)

#os.listdir just returns a list containing all files and directories #contained within the path 'dirname'
    for item in os.listdir(dirname):
        new_path = os.path.join(dirname,item)
        args = [arg[0]+1,arg[1]]
        if os.path.isdir(new_path):

#The child directories will make recursive calls
#until the root_path directory has been completely #parsed
            extract_dir_files(args,new_path)
        else:
            name,ext = os.path.splitext(item)
            #do not write out the files having one of the
#extensions specified in IGNORE_EXT
            if ext not in IGNORE_EXT:
                file_str = "%s-%s\n" % (" "*(arg[0]+1),item)
                arg[1].write(file_str)
                print(file_str)    


def main():
    root_path = os.path.join(DRIVE_LETTER,ROOT_PATH)
    with open(OUTPUT_FILE, 'a') as f:
        f.write("*"*PAD_NUM+"\n")
#args[0] will hold the value of the current depth in the dir. #hierarchy; args[1], the file object
        args = [0,f]
        extract_dir_files(args,root_path)
        f.write("*"*PAD_NUM+"\n")




The second one gets the HTML contents of a given URL which are parsed to a DOM-like object. After that, all that it's left is to extract the data of interest and do whatever you want. In my case, I decided to write them to a *.CSV file for future use. I used the library available at http://www.boddie.org.uk/python/libxml2dom.html

It was pretty easy to use, and it allowed for DOM-like processing of HTML pages, which aren't generally well-formed. This causes complaints and exceptions when using better known Python DOM libraries.

def main():
#URL returns a list of links, of which I'll only be
#interested in their text values.
#FROM and TO are the
values I want to pass to the query
#as GET parameters.

    with contextlib.closing(urllib.urlopen(URL%(FROM,TO))) as url:
        encoding = url.headers['Content-type'].split('charset=')[1]
        contents = url.read().decode(encoding).encode('utf-8')
    doc = libxml2dom.parseString(contents,html=1)
    links = doc.getElementsByTagName("a")
    results = []
    for l in links:
        release = l.childNodes[0].nodeValue
        #...then do whatever you want with it :P



Tuesday, 12 October 2010

Once upon a night

First, I believe that apologies are in order for the delay in updating. I finally got a job in a Barcelona-based studio, and I've been happily working there as a junior programmer since August :)

The rest of my daytime (and, more often than not, night time as well T_T) up until last Tuesday has been devoted to our master's final project delivery, which was presented that day on Caixaforum. 

First, a Konami exec came and gave a talk about the upcoming release of Castlevania: Lords of Shadow, developed by Mercury Steam, a Madrid-based studio, and then the 5 teams showcased their projects.

  • The creature. A full 2.5d platformer game, featuring 20 levels. Your mission will be to help a creature being complete again by getting back some parts of its body, scattered around several areas.
  • Wyverns Assault. A funny, retro-style beat 'em up game where you're a huge dragon fighting hordes of soldiers and destructing everything :-D
  • Undertown. A graphically amazing action game a la God of War, made by just an artist and a programmer. The main character must fight the Disgusting (Asquerosos, in Spanish: that's their real name) and other monsters so he can have his girlfriend back.
  • Ghosty Town. This game has a truly original concept where you're put in the place of a ghost that must scare the hell out of all the villagers of a small town in order to conquer it.

You should check them all (although some of them still lack a proper downloadable release, ours being one of them -_-U), there's a lot of work put into each and everyone of them, and the results have been really good imho.

And yes...I mentioned there were 5 teams, but only 4 projects are listed above.

So now, enter Once upon a night!



The game puts you in the place of Any, a girl (it wasn't always like that, though ^_^U) that's been trapped in her dreams by a malfunctioning magical clock. To escape and wake up again, she must find a set of gears, springs and other pieces to make it work properly again. These gears are supposed to be similar gameplay-wise to the stars on Mario 64, to name a very obvious example, as it was one of the most important references we took. To retrieve them, she'll have to solve the puzzles scattered throughout the two parallel worlds of dreams and nightmares that shape a level.

I performed tasks as a designer (well, the whole team was, actually, which is something that I now deem a terrible mistake) and, mainly, as a programmer.

Since our work tends to slip unnoticed, I'll compensate by listing the main features I wrote as a programmer. I might talk a bit more about some specific features in the future if I'm in the mood or anyone is interested. I'm sure that lots of stupid errors will be found, but that will allow everybody, specially myself, to learn from those mistakes.

- Base application engine skeleton. It consisted of a main Application class that would contain the remaining subsystems, encapsulated as independent (or that was the goal) modules to handle audio, graphics, AI, etc. After initialization, it just starts the game loop and handles input and state management, the game's subsystems being the ones in charge for updating the world and their attributes.
       
- A stack-based FSM for the game state manager. I had previously used a simpler approach for my previous games, based on IDs and an abstract factory to provide concrete implementations of the states. The stack approach has worked quite well despite an embarrassing error I detected not much time ago concerning state changes -_-U

- Event manager. A template-based approach that allowed any subsystem or the game world itself to subscribe/unsubscribe and react to specific events triggered by the animation engine, the physics subsystem, etc. Events were posted to a priority queue and dispatched at a fixed point of the game update call.

- Game entities management...partially (it was more of a joint task). This is kind of a long story: during preproduction and the earlier parts of the production stage, I had been reading several books and articles on the internet about component-based architectures and data driven design, and thought it could be nice, as it would allow to avoid deeply nested class hierarchies, deadly diamonds, and such. More importantly, we would have a flexible architecture to make it possible to define new entities without changing much code, or modifying their attributes' values without recompiling the whole project.

However, I was unable to communicate the concepts and new philosophy to my fellow programmers, and besides there were conflicts with the level loading module, so we came up with an alternate, middle-of-the-road approach that, honestly, could have been much better.

I still won't desist, though, and sooner or later I'll come up with some tests to compare the implementation, usage and ease to understand that type of architecture as opposed to the classical inheritance-based ones.

- Scripting engine. We used LUA and luabind as an interface between that scripting language and C++ to implement the following features:
* FSM-based AI-controlled entities. I believe we could have made entities a lot more script dependent, allowing them to react to state changes (for instance, playing sounds, changing animations and such) inside LUA code instead of delegating to the main C++ code, but it was
decided to leave it at that.

* Triggers. We had some entities that could act as triggers when another entity (typically, Any, but it wasn't the only one) entered/exit/was at the volume defined by the trigger. Through LUA, we could define a pair of functions condition/action, so that the logic subsystem could check if a set of additional conditions had been fulfilled (besides the enter/exit/presence checks, of course) and, in that case, execute the action function. This provided triggers with some interesting flexibility.

* Cutscenes. The in-game cutscenes in our game were also coded in LUA, taking advantage of the coroutine feature LUA provides (this was a bit difficult to understand at first). We had made available a set of exported functions (move an entity, change an animation, show a message box, etc), and then all we had to do was define the script to launch the different actions sequentially.

- Audio engine. It was based on FMOD and a specialisation of Ogre3D's ResourceManager, that made it possible to define sound resources as scripts that could configure several properties: looping, 3D, intensity thresholds, etc.


- User interface: To tell the truth, the user interface is actually split into three different components:
- The actual GUI subsystem, used for good old buttons, combos, etc., widgets. For these ones I went with CEGUI, an open source GUI library that already came bundled with the Ogre release we used (1.6.5). The more familiar that I got with it, the more powerful I've been finding it, so we could have used it instead of overlays in some other places, but then it was too late ^^U

Skinning a GUI layout, however, has been hell (well, I managed to come with a new skin on two days under a lot of time pressure, but still, it was a nightmare)

- Ogre's overlays. Mainly used for the HUD, and for almost the whole development cycle, the pause and game over screens (they got replaced with the third approach in the end). Ogre provides a specification for overlay scripts, but I find it a bit messy when you want to do some more complex positioning.

- Ogre's Rectangle2D class. Even simpler approach, consisting on creating a quad and applying a material to it. The intro, game over and loading screens are examples of this.


- Several graphical features.
- Animation engine. We adapted some code of an animation blender found on Ogre3D's wiki, adding the possibility to incorporate partial blending using an array of weighted bones. Unfortunately, it wasn't used at it fullest, due to time constraints and bugs.

- Initial approach to incorporating soft shadows, that unfortunately didn't make the cut. They were working, but then, when the change world functionality you've seen on the video was incorporated, it stopped functioning. The world change being a key feature of the game, it took precedence and dynamic shadows were removed until a later stage in the game.

- Some special effects. Nothing fancy, though. Some of them were reused from existing open source code, and then incorporated to the game:
    - The intermittent tint effect shown every time Any gets hit. This one was pretty easy to implement by using a pixel shader that would apply a tint whose intensity would vary according to a sine-like function.
    - The flashlight halo effect, combining texture and node animation  with a projective decal. The particles were incorporated at a later stage by another fellow programmer.
    - A lens flare, but it triggered on very rigid constraints, so it had to be tweaked a bit.

- Gameplay programming. I implemented the behaviours for several entities in our game.
- Any.
- The tripollos in the world of dreams.
- The scared plants (those weird plants that hide when Any gets close).
- The diamond trees. They work like the multiple-coin boxes from the Mario platformers: you may hit them for a set amount of time and obtain diamonds.
- Egg nests: These ones could drop an item -or a tripollo- from a varying choice of weighted.
- The story book item.
- An initial version of the world change item.
- Signposts.


As you can see, there were quite a few things to do @_@. Despite all this,  to be completely honest, I'm not entirely satisfied with the end result, despite the efforts the whole team has put onto it. Maybe it's just that I'm too hard on myself, but I believe that some degree of ambition and self-criticism should be a must for anybody that aims at developing games professionally, and I think that our game still has a long way to go until it can reach the status of 'acceptable'. The experience, however, has been really valuable, either as an example or as a counterexample.

Last, I would like to recommend a book that I found particularly useful during all this time (it's not the only one at all, but it was the one I've enjoyed the most):

Game Engine Programming, by Jason Gregory. I discovered it while I was looking for some algorithms on game loop synchronization, or maybe for entity managers and event handling. This book is amazing: exhaustive (it covers such things as animation engine programming, physics or entity management) and at the time I found it quite easy to read.

Saturday, 10 July 2010

Strategy pattern applied

  
Yesterday I started thinking about how to improve the behaviour of one of the enemies on our Master's final project game, Once Upon a Night. At some point, I found myself thinking how the enemy might have to choose among a variety of available attacks once the main character enters the attack range for more than one attack types (obviously, if there is only one kind of attack it may launch, there is no problem). The easiest way would be to stick with a common selection policy (for instance "pick the first one", or "pick randomly"), but it wouldn't be very flexible. Then, almost immediately, one of the GoF patterns sprung to my mind. Of course, I mean the Strategy Pattern. According to their book, the pattern's intent is to define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.

To make the concept clearer, I'll show you a simple implementation that I sketched last night applied to the attack selection policy for enemies. It should be correct (save for missing includes, which I've omitted) aside from a few typos.

First, some macros and typedefs...

// Attack selection strategies using the same-name design pattern.

// Let's say we have an enemy currently chasing the player.
// At some point,their distance gets close enough for
// the enemy to launch one or several possible attacks.
// If more than one attack is available, which one would it select?

// This code shows how several selection choices may be
// available at once by using the well-known strategy pattern.

#define SAFEDELETE(x) if (x) {delete x; x=NULL;}
#define SAFEDELETEARRAY(x) if (x) {delete[] x; x=NULL;}

// Struct containing a hypothetic attack type data
struct TAttackData
{
std::string name;
int damage;
int attackRange;
int cooldown;
int energy;
};

// A collection of available attacks, indexed by their name
typedef std::map<std::string, TAttackData*> TAttackCollection;

// Functor-like struct used to fetch the vector of values of a map
struct getValue
{
template <typename T>
typename T::second_type operator()(T keyValuePair) const
{
return keyValuePair.second;
}
};

// Return the vector of attacks from an attacks map.
std::vector<TAttackData*> getValues(const TAttackCollection&

 availableAttacks)
{
//BEWARE! This is inefficient, it'll copy the vector to return it.
//Passing the vector as a parameter might be a better option

std::vector<TAttackData*> attacksVector;
std::transform(availableAttacks.begin(),availableAttacks.end(),
std::back_inserter(attacksVector), getValue());
return attacksVector;
}


And now, let's define our base strategy class, and a couple of concrete implementations.

// Base strategy class.
class AttackSelectionStrategy
{
public:
virtual TAttackData* selectAttack(const TAttackCollection&
availableAttacks)=0;
};

// Concrete strategy: an enemy using this strategy will always choose
// the highest-damage
class HighestDamageStrategy: public AttackSelectionStrategy
{
public:
bool compareHighestDamage(TAttackData* one, TAttackData* other)
{
return one->cooldown>other->cooldown;
}
virtual TAttackData* selectAttack(const TAttackCollection&
     availableAttacks)

{
if (!availableAttacks.empty())
{
std::vector<TAttackData*> attacks = getValues(availableAttacks);
std::sort(attacks.begin(),attacks.end(),
  compareHighestDamage);
return attacks[0];
}
return NULL;
}
};


// Another concrete strategy: this time, an enemy using it
// will choose the available attack that has a lowest cooldown,
// so it may attack again as quickly as possible.
class LowestCooldownStrategy: public AttackSelectionStrategy
{
public:
bool compareCooldown(TAttackData* one, TAttackData* other)
{
return one->cooldown<other->cooldown;
}
virtual TAttackData* selectAttack(const TAttackCollection&
    availableAttacks)

{
if (!availableAttacks.empty())
{
std::vector<TAttackData*> attacks = getValues(availableAttacks);
std::sort(attacks.begin(),attacks.end(),compareCooldown);
return attacks[0];
}
return NULL;
}
};




Next is some sample client code using strategies:


void AnEnemy::selectAvailableAttack()
{
AttackSelectionStrategy* myStrategy = new HighestDamageStrategy();
setCurrentAttack(myStrategy->selectAttack(mAvailableAttacks));
SAFEDELETE(myStrategy);
}


However, this is quite rigid, which defeats the purpose of the pattern. I then thought of a way to select specific strategies. Two different alternatives came to my mind, in both cases using an enumerated type as a discriminant.

//Strategy selector enumerated type
enum TStrategyPolicy
{
HIGHEST_DAMAGE,
RANDOM,
FIRST,
LOWEST_COOLDOWN,
LOWEST_ENERGY,
WEIGHTED
//..etc
};



// Now, to implement the strategy selector I have thought of two
// different alternatives:
// I could use a factory function that had a switch statement
// on a TStrategyPolicy value, instancing one
// or the other strategy on demand.
// The second possibility consists on defining a
// map <TStrategyPolicy, AttackSelectionStrategy*>
// and initializing the map at the beginning.
// When the time comes to select a strategy,
// the selector function/class would just access the map.
// While simpler, it has a bit of overhead since an
// instance of all strategies has to be created regardless of if
// it is used or not. However, if
// a getStrategy() method is used frequently, it may actually turn
// out being more efficient, since
// every strategy will only be instanced once.

//OPTION 1: FACTORY FUNCTION
AttackSelectionStrategy* createStrategy(TStrategyPolicy selector)
{
// Ensure that this function's client frees the
// dynamic memory, or memory leaks are bound to appear.
switch(selector)
{
     case HIGHEST_DAMAGE: return new HighestDamageStrategy();
     case LOWEST_COOLDOWN: return new LowestCooldownStrategy();
     //...remaining cases
       default: return NULL;
}
}

//OPTION 2: USE A MAP OF STRATEGIES AND RETRIEVE AN INSTANCE WHENEVER //YOU WANT

typedef std::map<TStrategyPolicy,AttackSelectionStrategy*> TStrategyCollection;

class StrategySelector
{
private:
TStrategyCollection mStrategies;
public:

// The initialization is hardcoded, which would require to
// recompile 
any time a new strategy was added
// (this will also happen using 
a factory function), but without
// any reflection-like device that'd

// allow us to dynamically load on runtime a particular subclass

// (I'll have to research more on RTTI or some libraries)
// there's little else to do.
// If I'm mistaken, which is really likely, I'm open to
// corrections :)
void initStrategies()
{
cleanupStrategies();
mStrategies[HIGHEST_DAMAGE]= new HighestDamageStrategy();
mStrategies[LOWEST_COOLDOWN]= new LowestCooldownStrategy();
//...
}

// Free memory
void cleanupStrategies()
{
if (!mStrategies.empty())
{
for (TStrategyCollection::iterator it=mStrategies.begin();
     it!=mStrategies.end();++it)
{
     SAFEDELETE(it->second);
}
mStrategies.clear();
}
}

// Retrieve a given strategy.
AttackSelectionStrategy* getStrategy(TStrategyPolicy index)
{
if (!mStrategies.empty() &&
mStrategies.find(index)!=mStrategies.end())
{
return mStrategies[index];
}
return NULL;
}
};


Any of these two alternatives would allow for some interesting results. For instance, you might script behaviours for enemies, such as 'Aggressive', 'Defensive', 'Ranged', etc, and the attack selection policy might be a behaviour-dependent parameter.

The client method I presented before would be rewritten to this (of course, myStrategy can be refactored to an AnEnemy class member, which would require at least a setter method allowing changes on the strategy selection algorithm to apply):


//Using option 1

void AnEnemy::selectAvailableAttack(TStrategyPolicy strategyId)
{
AttackSelectionStrategy* myStrategy = createStrategy(strategyId);
if (myStrategy)
{
setCurrentAttack(myStrategy->selectAttack(mAvailableAttacks));
SAFEDELETE(myStrategy);
}
// else throw exception, or do something to notify the strategyId
// wasn't valid
}

// Using option 2: assume StrategySelector is a Singleton
// (http://en.wikipedia.org/wiki/Singleton_pattern).
void AnEnemy::selectAvailableAttack(TStrategyPolicy strategyId)
{
AttackSelectionStrategy* myStrategy =
StrategySelector::getInstance()->getStrategy(strategyId);
if (myStrategy)
{
setCurrentAttack(myStrategy->selectAttack(availableAttacks));
myStrategy=NULL;

// Don't delete the strategy here: that'll be handled by
// the StrategySelector when it invokes its cleanup method
}
// else throw exception, or do something to notify the strategyId
// wasn't valid
}


Now, we can define as many strategies as we want, and the code for the class AnEnemy won't have to be changed to do that. We may provide the strategy selection policy externally through the value of an int that would be cast to a TStrategyPolicy.

In fact, using LUA and luabind, which allows exposing C++ enums to LUA, we wouldn't even need to care about casting between enums and ints.

Unfortunately, due to tight time constraints, we've been trimming the variety of attacks that enemies can launch on our game, so this code will never see the light beyond this modest blog post.


LARGELY UNRELATED RANT: I've been a happy user of the Opera browser for close to 8 years now. However, after the 10.60 release some Google services, such as Google Calendar, Gmail or Google Docs, are screwed up in varying degrees of severity. My biggest annoyance is at the moment Docs. Besides being close to unusable when using their new version, I've been crashing every time it auto-saves, or when I manually save my work. Restarting the browser and logging back in every two minutes is a real pain in the a#se, so I've ended up switching to Firefox so that I could finish this post without fear of having to restart again.

People in Opera Software, PLEASE, can you fix that???

Tuesday, 6 July 2010

Wall Chaos (II) - Technical stuff (Run for your lives!!)

After the first post, focused on design issues, this second one will show the dirty implementation details behind the 2D version of Wall Chaos.

The language of choice was C++. Firstly, because that way I had the chance to reuse some code from the theory classes, and also because it's the language I feel most comfortable programming in excluding Python. 

If you remember, the assignment included a constraint that restricted the game to be isometric. Getting this done was probably the most challenging part, and I ended up mixing theory concepts learned in class with some ideas I got from Ernest Pazera's Isometric Game Programming with DirectX 7.0.

As you probably know, there are several subtypes of isometric maps. The most widely used ones are probably the staggered map(for example, the one used throughout the Civilization series) or the diamond map (The Age of Empires maps have this kind of layout). I was pretty sure from the beginning that I'd go with the second approach, as it seemed to fit better with the shape of the rooms.  Both types are pretty similar, but they differ in the way the map is traversed. 

This is how the x and y coordinates range in a diamond map:
This setup makes it a bit more difficult to blit a tile, since two consecutive cells aren't blitted in rows as in a typical rectangular 2d map. Besides, the cell sprites (which are rectangular) will overlap, so the traverse order matters.

This is the blitting loop (there is an outer loop for further layers, as the tiles are stackable, but for brevity's sake I will omit it)

for (int y=0;y<SCENE_HEIGHT;y++)
{
for (int x=0;x<SCENE_WIDTH;x++)
{
TTile* tile = &(gameData.scene->map[y][x][z]);
//Read the tiles' sprite sheet to get the clip rectangle
tileRect=gameData.scene->getTileRect(tile);
int tileIndex=tile->index;
if (tileIndex!=NOTILE)
g_pSprite->Draw(textures[TILESET_INDEX],&tileRect,NULL,
&D3DXVECTOR3( float((x-y-1)*(TILE_WIDTH>>1)-baseX), float((x+y)*(TILE_HEIGHT>>1)-baseY-z*TILE_HEIGHT), 0.0f),
 inkColor); 
}
}

The x,y screen coordinates are computed as follows;
x_screen = ((x_map-y_map-1)*TILE_WIDTH/2)-baseX;
y_screen = ((x_map+y_map)*TILE_HEIGHT/2 - baseY-(z_map*TILE_HEIGHT);

baseX, baseY define the offset from the screen position (0,0). This ensures that the map is rendered at the right location (at the beginning of the game, it will typically start next to the top edge and horizontally centered).

Another issue was to retrieve the cell in the map from a set of screen coordinates. One of the main uses for this is to find out which cell the player has clicked on with the mouse. As Wall Chaos was basically controlled through the keyboard -save for the GUI menus-, I used this method to quickly convert between screen and cell coordinates instead.

The algorithm consists of two parts. This time I'll just describe it:

First, get the cell's rectangle (The diamond cell and its surroundings).
To do this, from the screen coordinates we'll first get the world coordinates, taking into account the scene's offset. This means that if the mouse click resolved to position (100,200), and there is a (400,64) scene offset, the world coordinates would be, respectively, (500,264).

Then, the tentative coarse (per-cell) and fine (per-pixel) coordinates are to be retrieved. This is done in the same way as with common 2D tiled maps:

coarse = (worldX/TILE_WIDTH, worldY/TILE_HEIGHT)
fine = (worldX%TILE_WIDTH, worldY%TILE_HEIGHT)

On those maps we'd probably end the whole process here. However, there are still some more steps involved in this case. Due to the scene's offset position, there is a chance than the fine coordinates are negative and we need to adjust them, adding the tile width or height to the modulo operation result.

Then, depending on the value of the coarse coordinates, we need to adjust the pre-final map coordinates. That's achieved like this:

int mapX=0,mapY=0; //Candidate map coordinates
while(coarseY<0)//Move north
{
mapX--;
mapY--;
coarseY++;
}
while(coarseY>0)//Move south
{
mapX++;
mapY++;
coarseY--;
}
while(coarseX<0)//Move west
{
mapX--;
mapY++;
coarseX++;
}
while(coarseX>0)//...and finally, east
{
mapX++;
mapY--;
coarseX--;
}


After iterating through these loops, the first part of the procedure ends. We have a pair of coordinates corresponding to a rectangular cell (x,y). However, depending on the fine coordinates, the actual diamond cell might be one of the 4 depicted adjacent cells.



The second part's objective is, therefore, to retrieve the actual cell. Taking advantage of the fact that  the ratio width:height of the tiles was 2:1 we can use the following property:

if(fineX<(TILE_WIDTH>>1))//32
{
//Left
if(fineY<(TILE_HEIGHT>>1))//16
{
//Up
if( (TILE_HEIGHT-fineX)>>1 > fineY ) { mapX-=1;}
}
else
{
//Down
if( (TILE_HEIGHT+fineX)>>1 < fineY ) {mapY+=1; }
}
}
else
{
fineX-=(TILE_WIDTH>>1);

//Right
if(fineY<(TILE_HEIGHT>>1))
{
//Up
if( (fineX>>1) > fineY ) mapY-=1;
}
else
{
//Down
if( (TILE_WIDTH-fineX)>>1 < fineY ) mapX+=1;
}
}

After this, mapX and mapY will hold the final map coordinates.

Last, this game featured music and sound. One of the assignment requirements asked us to implement an interface to abstract and encapsulate the concrete sound library used. This was relatively simple to do. I used the old API of FMOD, which seemed good enough for my purposes, and abstracted the three kinds of supported sounds (Streams, Sounds and Samples -midis, basically) into three subclasses of a base class CSoundItem. At the resource loading time, the layer parsed the filename and, depending on the extension (*.wav, *.mid, *.mp3,...), it instanced a particular subclass.
The sound layer had an STL map indexed by an ID string containing all the loaded sounds (the load was done on a per-game-state basis), and then the application just had to keep track of the IDs to play any sound of music track. 

I could dwelve a bit more on the game's architecture (For instance, for managing the game states I defined a couple of variables to keep the current and next state IDs and then a factory to resolve and instance the particular GameState subclass to switch to next. For Once Upon a Night, the Master's final project, I opted for using a stack-based game state machine instead, which turned out to be much more flexible), but I guess I've bored you enough already. If you feel like diving a bit more into the code, you may download the sources from here.

Tuesday, 15 June 2010

Tools in Python

There's been some time since my last update, so I've decided to write a new post to prove I am still alive and kicking.

However, the second post about Wall Chaos will have to wait a bit more, as I haven't finished writing it yet. Instead, I will show you some tools developed in Python that I have coded to assist me in the development of TINC (the first two scripts), and while I was playing Harvest Moon: Island of Happiness on my DS (the third one). The link to get the source code for the three of them is at the end of this post.

The reasons why I chose Python were that I wanted to get better at it, and mainly because it is a language I feel comfortable programming in. Besides, it is widely used in the games industry for tools or scripting, which is always a plus.
The first one is a simple level editor. If you remember TINC from previous episodes, it is just a clone of the Columns puzzle game. While I was designing test cases for it (yeah, I know...a bit over-engineered for a puzzle game) I got bored of editing text files by hand, so I came up with a GUI application. It may seem a little counter-intuitive at first sight, but it is quite easy to use in fact:
Select the checkboxes under the cell(s) you want to set and then pick a colour on the right combo box(you can choose "EMPTY" to clear the cells). The left-most checkboxes will toggle selection on a full row. Likewise, the top-most checkboxes will select/deselect full columns. Last, the checkbox at the top left corner will toggle selection on the full board.

I used wxPython as the library of choice for the graphical user interface. The main frame consists of two separate panels, the left one displaying the board and a grid of checkboxes to select cells, rows, columns or the entire board, and the second one displaying further functionality, such as colour selection, board clearing and exporting the board to a text file. 

Aside from the usual tasks related to GUI programming (layout, event binding, etc.), the most challenging part of the application, to name any, was the test for valid boards, since the program won't allow the user to export an invalid board.
A board is considered valid when there are no gaps left below a coloured block. For instance, the first screenshot corresponded to a valid state.

...whereas this one does not:
If an attempt is done to export the layout when the board in in an invalid state, the application will complain:
The validity check is quite straightforward. The board, initially assumed empty, is considered valid. After that, we'll start going through the columns as long as the current column is valid. To ensure that, the algorithm will start on the top-most row, and then it'll go down until the first coloured block has been found. If the column is empty, it'll be OK. If we find a coloured block, then every other block located in the rows below it must be coloured as well, otherwise the column, and therefore, the whole board, is considered to be invalid.
On the application, this check is performed when clicking on the "Export" button.
You may find the full code  under the "editor" subdirectory in the linked archive at the end of the post.
The second script that I coded while developing TINC is a bit more complex despite the fact that it does not come with a fancy user interface, as it is a command line tool.
You may find the full code  under the "editor" subdirectory in the linked archive at the end of the post.
Sometimes, when you're using enums in C++ (and other languages) you may need a text translation of the value. For instance, when logging messages, a string is more human-friendly than the enum's integer value, hence the need for this script (again, I didn't feel like browsing through all the enums and then writing the string arrays by hand, so I did some coding to automate the process).
It parses a specific header file where I keep type redefinitions, constants and others, searching for enumerated type definitions. Then, it creates a second header file, now containing several arrays of strings (one array for each enumerated type), and a set of matching inline functions, to translate a value of a certain enum to its matching string value. This screenshot depicts on the left side the source file, and on the right a portion of the generated translations file:



The script source code is now a bit more complex, specially on the parser side, relying on regular expressions to find enum declarations and such. The code relies on two classes: Context, which is actually the class in charge for parsing the source header file, and Generator, responsible for creating the enum translations header file.
Check the code under "enum_names.py".

My last tool is actually a lookup application I did to avoid checking the WWW when I was playing Harvest Moon: Island of Happiness, a game by Natsume and Marvelous for the DS. 
In case you don't know the HM series, these games put you in the place of a boy (or girl, depending on the game: the most recent instalments let you choose) that accepts a position as a farmer on a certain town. You'll get to develop the farm by growing crops, tending cattle, chopping trees, mining, fishing, cooking and flirting among several other tasks (if you've ever played Facebook's Farmville, it is a bit similar, but WAY MORE complex and a lot funnier).
It turns out that there are lots of recipes you can make by using several ingredients: the crops you've grown, the fish you've caught, and many others. At some point during my play-through I decided to fill my 'discovered/delivered recipes' (you can get a grasp of your progression throughout the game by checking the list of delivered crops, animal raw materials, gems, recipes, etc.), and I needed some quick reference about the ingredients I might need. As I said before, I wasn't in the mood for keeping an Opera tab constantly open to check every now and then, so I decided to develop a query application.
The GUI lists the set of recipes matching the criterion filter (you may search by the ingredient you need to deliver to unlock the recipe, or by one of the ingredients the recipe consists of), together with some additional information (name, description, stamina recovery, etcetera). The rows on the grid may be selected, and the text area below will display a list containing all the ingredients the recipe needs.
Again, I used Python and wxPython for the GUI. In addition, the application uses an sqlite embedded database where the recipes, ingredients and related data are stored. One of the python modules of the application contains the SQL code to create and fill the tables. I suggest using sqliteadmin, too, to manage the database. 
I intended to make the application multilingual, hence the initial language selection dialog, but it isn't functional, so at the moment Spanish is the only available language, sorry.
And, finally, here is the Dropbox link to the *.7z file containing the code for the three tools. Feel free to modify them at will. Credit will be nice, of course ;P
http://db.tt/YwdUywWD

Thursday, 18 March 2010

TINC v0.1

This is my first game, coded at irregular intervals on my free time during 2008. To be honest, I'd already done one at the Computer Graphics subject while at university, but I lost the floppy disks where I kept the last copy -_-U
But that's enough talk about the past. Behold TINC!!
As you can see, it is totally not a shameless ripoff of Columns. Many people start by coding a Tetris clone, but being the spirit of contradiction that I am (well, that's what my parents like to say), I chose Columns instead.
It is coded in C++ using SDL, with some Boost to add some flavour here and there. Although I started coding it on Linux, in the end I switched to Windows and Code::Blocks, to finish with Visual Studio Express.
This means the game is for Windows systems only, I'm sorry (it might work on Wine, but I haven't tested it myself; if somebody is willing to give it a try, please tell me and I'll put it here as well).
Attached are the MU links to the binary files (most of the space it takes is caused by the VS2005 and VS2008 redistributable packages), and the source code. Since I haven't touched it again since last year, it is quite messy (not even mentioning the graphical interface, which I did in a rush and never got to refactor it again).
For those who never read README files, these are the in-game controls:
  • Arrow keys: move or drop the falling column.
  • Z/X: Rotate the pieces of the falling column up/down
  • P: Pause/Unpause the game
Oh, and if it crashes before starting the game, you may have to install the two VC redistributable packages I mentioned before.
Enjoy!