• Advertisement
Sign in to follow this  
  • entries
    18
  • comments
    15
  • views
    46007

Entries in this blog

A little "postmortem" on my GDnet Community Challenge entry.

You can download the entry here: Download (Windows EXE - 5.05 MB)

The only requirement to run the game is to have the MS Visual C++ 2010 Runtime DLLs.

There is a known bug when attempting to run the game from a standard user account in Win7/Vista -- if the game crashes on startup, try running it as an administrator. (EDIT: On machines with the issue, setting the compatibility setting to "Windows 95" in the file properties of the .exe can fix the problem. I haven't identified the bug yet, but I found a way to reproduce it in a virtual machine, so I should be able to work it out eventually. Note that you may have to close the program from task manager if you run it this way... Not very convenient, I know, but I suppose it's better than nothing!)

We had three days (72 hours) to create a game more-or-less from scratch. I used version 3 of my "EDBJ framework" as a base, it's the 2D/audio/input/GUI framework I've been working on lately.

This latest iteration, EDBJ3, was actually a partial recode of the framework I used to prototype my classic Blackjack game. It lacked functionality such as gamestate management and scripted actions (as you can see in the game, even the title screen is a level), but it added OpenGL support, replaced all homemade GUI code with CEGUI wrappers (unused in the game) and SDL_mixer for sound.

In the rush to get the game out, I quickly hacked together some missing functionality:

- Music (MOD files; easy thanks to SDL_mixer)
- Trig and math functions
- Arbitrary keyboard bindings and input "passthroughs"
- Collision / "Physics"


I lost about 8 hours over 2 days to a silly issue involving header files and compilation settings... A real nightmare! It's a competition though... Gotta suck it up! Besides, I only put in about 30 hours into the project in total, when 72 were available, minus sleep :P

Here's a little description:

Your player is a little guy driving a small, round, red spaceship. To move, you have to choose an angle (by pressing UP/DOWN or clicking with the mouse to set a direction) and can charge up a jump by holding down space. The goal of the game is to get to the end of each level (the purple platform) by jumping from safe spot to safe spot, correctly estimating the angle and power needed each time, without touching any walls.


Levels are actually PNG files that you can create with any image editing software. Some pixel colors have special meanings:

RED (#FF0000) : "Safe spot" -- if you touch it, you'll respawn there next time you die
GREEN (#00FF00) : Player starting position (1 pixel)
BLUE (#0000FF) : Bouncer (horizontal) - doubles your vertical speed
BLUE (#0000C0) : Bouncer (vertical) - doubles your horizontal speed
BLACK (#000000) : Obstacle (die on touch)
PURPLE (#FF00FF) : Goal! (touch to win level)

All other colors are ignored - the player can pass through them.

Valid levels are PNG files with a width and height that are multiples of 256, with at least one green (#00FF00) pixel for the starting position. You can substitute any of the provided level PNG files for your own as long as they respect these conditions.

The game begins with a tutorial level, which also doubles as a title screen, and only has 3 levels:

ZUFdh.png

Title screen


6GkQo.png


Star level


tC40T.png

Colored dots and black grass level



n0CBp.png

Vertical level




Sadly, I ran out of time to create the ending I wanted, which was going to feature a crappy animation of MC Hammer dancing, so the closing screen just says "YOU WIN" in white on a black background :)

The game is functional, but the levels could use some editing; they were for the most part created and playtested in the 4 hours that preceded the deadline, so some parts are unnecessarily hard, and there's not as many levels as I would have hoped. Since this is a "guesstimating game," it's not good that making some jumps (especially with bouncing involved) requires up to 20, 30 tries, each time changing the angle or power by a pixel until you somehow manage to make the jump. This is the kind of stuff that makes people punch their computer, or stop playing a game out of utter frustration. :P

Possible improvements could include:

- Adding a title screen and proper ending
- High scores? Saving? Online leaderboards? User-submitted-level-browser? :D
- Make scrolling more obvious (with arrows when you move the mouse near the edge of the screen); possibly add a scrolling function when you right click the background
- Minimap and/or pointer that shows the location of the player if he's off-screen
- Overall graphic/sound/level improvements
- Additional block types: Booster, slowdown, "sticky walls," etc.
- Add license / copyright info, remove dependencies on included-but-unused third-party libraries

I will most likely take a fresh look at the project later on this week and post a "cleaned up" version. I'll wait until judging for the contest is over...
Last week, I announced the creation of the Pestering Squad. Here's what's up after 2 weeks.

The first thing I did was create a top-secret, password protected website, which I dubbed PesterPanel. It's a really simple interface where I post news for the pesterers to read, along with polls or questions for them to answer. When actively developing, I try to update the "P-Squad" daily.

Although only 23 of the original 72 pesterers ticked the "receive e-mail updates" checkbox, 55 answered the first poll.

In the poll, I asked my newfound faithful followers which project I should work on first. The choices were:

- Hardkore Blackjack (HB), the fast-paced arcade puzzle casino game I was working on before I began losing focus.
- Chemical Mayhem (CM), a lemmings-like puzzle game inspired from my cellular automaton experiments and high school chemistry.
- Super Penny Thrower (SPT), a physics game where you cause accidents and crush pedestrians by chucking pennies off the top of a tall building.

The poll was "blind" in the sense that it was impossible to see the results before you cast your vote. I took care to add a "TLDR" answer, which is selected by default, to make sure answers were carefully considered. A comment box was also provided, but not shared with the other pesterers.

HB won in the end, with over 38% of the vote, 31% for SPT and 29% for CM. Some complained that I hadn't given enough info about CM and SPT, while others said they would have voted for CM or SPT if HB didn't already have some assets and code finished. It's too bad I didn't think things through -- I did notice that the way I presented the projects was very uneven. When we vote on the next project, I'll try to offer an equal amount of details about all the projects I have to propose.

And so Hardkore Blackjack it is. Hopefully, the P-Squad will continue to follow my progress!

This week was an exercise for me. I set out to create a little demo application, mainly to see if things run on the beta testers' machines. I implemented some changes into my "EDBJ" framework; I phased out all my GUI code and all my SDL graphics code and replaced it with OpenGL. + CEGUI. I think this change will come in very handy to procedurally animate cards and add some visual appeal to the game.

Yesterday, I uploaded the first Pesterer-exclusive download, "Ballin Demo." The demo is basically a 640x480 window with a picture of an alarmed "rage face" in the center and a small dialog box at the top left. One button is labeled "Ball!" and the other is labeled "Boom!" If you press "Ball!," a ball appears out of thin air and starts bouncing around the screen. You can keep adding thousands of balls this way -- I've only tried up to 10,000. If you press "Boom!," all the balls start blowing up at random intervals. Since the mixer is very basic and all the sounds are identical, they add up to generate monster noise.

I got good performance on both of my systems; around 100 FPS with 10,000 balls bouncing around on my desktop (>2000 FPS with reasonable balls), and around 400 FPS on my netbook (10% single core CPU usage @ 60 FPS). That leaves plenty of processing strength for the meatier stuff.

All this talk about balls has made me tired... Which is pretty bad, because I'm supposed to upload a new Week 2 page for my pesterers to tell me about their totally ballin' experience and eventual hardware issues, and tomorrow's theoretically Week 3!

Once the demo runs for everyone (who has reasonable hardware), I'll resume work on Hardkore Blackjack. Hopefully, week 3 will be sufficient for me to finish up the Classic Blackjack play mode, which is already 90% finished (the last 10% are actually the other 90%, though).

Until next time...
Last week, I had an idea. One of my biggest problems is focus, and I noticed I was usually much more motivated to code when I had an actual audience, as opposed to just working on my own.

So I posted the following to Reddit's /r/gaming section, a "subreddit" for gamers with nearly 500,000 subscribers:


[quote]Hi Reddit.

I'm a hobbyist programmer and aspiring game developer... I've been programming for over 15 years, but for various reasons, life kept getting in the way and I just gave up on project after project. Never did manage to release anything, except for that little unfinished tetris clone and a handful of crap demos that don't really do anything. That's right, I'm THAT GUY. Plenty of talk, zero walk, or whatever the expression is.

Today, things are different. Today, I'm running a successful business out of my home and I have plenty of free time and money to dedicate to my programming hobby/lifelong dream. I want to move forward and release stuff; simple free stuff at first, and stuff people will want to pay for later on.

I've seen the world of difference an audience makes for personal motivation, so I'd like to try something new. I'm recruiting you. What I need is human capital, a "pestering squad."

Your job as a "pesterer" would be pretty simple:
1. Receive an e-mail newsletter from time to time about my ongoing projects, my progress, etc.
2. Play the sneak peeks/demos I put out -- you will get them before anyone else.
3. Provide feedback/vote on everything, from design decisions to business decisions.
4. If ever you feel that I'm moving too slowly, losing focus, etc... PESTER me. Call me out. I need honest feedback and motivation.

Note that I'm targeting desktop Windows PCs primarily, so make sure you've got one of those.

What you get:
1. Your name in the credits of all games I release.
2. Free copies of all the software I develop, for life.
3. A voice.

Note that I expect to live at least 30 more years, so I would ask you to avoid dying for at least that long. If you die, I'll have to kick you out of the squad; nothing personal.

Upcoming projects slated for release this year include an experimental fast-paced arcade version of the casino game Blackjack, a lemmings-inspired puzzle game where you guide bacteria through mazes and mix chemicals to trigger chain reactions, and a physics game where you cause mayhem in a city by throwing pennies off a skyscraper, among other things. Projects must always be within my means, so I'm starting small.

If you'd like to be a part of this experiment, shoot me an e-mail at my reddit username @gmail.com with subject line "I want in", and you're in. I'll accept the first 50 people and update here if the target is reached.

Thanks for reading, and please feel free to ask questions in the comments.[/quote]


To my amazement, over 60 people responded before the time limit, and I ended up accepting 72 pesterers into the squad in total -- very cool, because I was only expecting about 10 people to actually sign up!

I sent out the first "newsletter" earlier this week, where I laid out some of the rules and asked my pesterers to give me more information about themselves and tell me about their computer specs.

Right now, I'm hard at work on a little private website to track my progress and gather feedback from the pesterers. It'll serve as a top-secret interface where they can see updates on my progress, download games/demos, provide bug reports and input, etc.

To give the pesterers a run for their money, I'm trying to make this little website into a sort of game; mimicking a control panel for a secret organization. I already have a couple easter eggs in there for them to discover. I also thought it would be funny to do a little role-playing and assign each of them a number, as if they were secret agents. I hope I'll be able to entertain them even when there are no new betas to play.

So that's the official announcement: I now have a little army, a "Pestering Squad" that will make sure I remain committed and properly directed. As beta-testers, they will be my first fans, and my first critics. No more straying off and screwing around with irrelevant stuff; from now on, it's productivity, productivity, productivity!

I set a deadline of Sunday, April 24th to complete the little website, and I'm almost there... Just putting in a few final touches and generating account/password pairs for everyone. If I don't make it, my inbox will be flooded with complaints. :)

I'll be updating here to let you know how this little experiment pans out. If anyone who reads my journal wants in, feel free to shoot me an e-mail at my gamedev account name @gmail.com, and I'll add you to the list when I get a second!
So I'm supposed to be writing a GLSL shader/GPGPU version of my rock-paper-scissors cellular automata. Unfortunately, I got sidetracked again.

I decided to begin by implementing Conway's Game of Life in a shader before I move on to rock-paper-scissors. I'm running a Geforce GTX 260 with 216 shader cores, so even though it's a very naive and slow algorithm (plainly does 8 texel lookups/cell/generation), I'm getting about 2000 FPS @ 1024x1024. That's about 2 billion cells processed per second, and if my calculations are correct, 30% of each frame is overhead.

The r-pentomino:
011
110
010



For a few hours, I thought I had a bug, because I just couldn't get a pattern to last... I had read that the "r-pentomino" was a well-known pattern that takes many iterations to complete. So I created a "brush" that would allow me to place r-pentominos with the mouse. It didn't seem to work -- this is supposed to be a notable "methuselah," as A-life scientists like to call them, a small pattern that's famous for the number of iterations it takes for it to stabilize, and the amount of "life forms" it generates -- but it just created this short-lived pattern...

After reading further, I discovered that the r-pentomino actually stabilizes after 1109 iterations -- at 2000 FPS, that completes in a little over half a second! No wonder. My program was working just fine.

Once I understood this, I went on a google quest to find some of the larger methuselah... At some point, I was playing around randomly placing cells, and I saw this amazing thing appear on my screen -- like a diagonal laser beam that went straight towards a group of cells, "ate through" them, then got reflected and continued until it hit another group of pixels and finally died.

I have no idea what that thing was. All I know is I've never seen it before, and I might never see it again... For hours, I tried to find what I did that caused that laser beam to appear... It clearly wasn't an artifact... I just added some pixels to a random area and the beam shot out of there.

So I'm basically playing mad scientist now... Splicing, building, looking for new undiscovered patterns... But it's not what I'm supposed to do!

I'm trying to find reasons to quit playing around with the Game of Life now... Here's a list:

[quote]People with PhDs already discovered anything you might discover in your lifetime!
The only reason patterns look like little animals is because the algorithm is symmetrical! Don't be fooled, the faces and spaceships are actually uninteresting jumbles of pixels!
Markus Persson has over 40 million dollars by now; are you seriously sitting on your ass watching little black and white pixels eat each other?
For every glider gun you assemble, your wife is this much closer to leaving you.
You know what's more productive than playing the Game of Life? Masturbating.
[/quote]

Okay... I think this little auto-pep talk's motivated me.

Moving on. I need to get my rock paper scissors algorithm into a shader. I hadn't really foreseen the difficulties, to be honest. The way I have things set up in my C++ CPU version is simply not compatible with GPGPU concepts. I have to go back to the drawing board and completely rethink most of my optimizations...

Looking into paletted modes right now... To be continued.
[media]
[/media]

Automata, automaton... Is each cell considered an automaton? Or is the whole thing the automaton? I really have no clue.

How it works:

Similarly to a naive implementation of the Game of Life, the program iterates through every cell in the grid one by one every generation.

For each cell, one neighboring cell is selected at random (uniform 1 in 8 chance of picking any given neighbor).

The behavior that will be executed depends on the current cell being considered. In this demo, there's just 4 cell types: white space and the 3 colors.

Each color has 10 different gradient levels. When I click with the mouse, I insert a cell of level 0. If a whitespace picks a colored cell, and that cell's level is < 9, the whitespace gets replaced with the current color + 1, as if the cell was producing a slightly weaker-colored offspring. That means cells grow randomly outwards until the outer "shell" of a given colored blob cannot divide anymore.

The "feeding" rule follows a rock-paper-scissors principle -- red eats blue, green eats red, and blue eats green. A cell is "upgraded" towards level 0 when it eats another cell, and is "downgraded" or killed if it gets eaten. What that means is that mobility is observed when a blob of cells eats another.

The really fun thing, though, is when 3 colors meet -- this begins an endless feedback loop that produces surprisingly stable, ever-growing spiral patterns.

And there you have it. :)

EDIT: Heh... Usually, when you post a link to reddit, it's your website that dies... Looks like this time around, reddit's the one dying.

Pixels, pixels

It's the game of life:

l8vlm.png

My attempt at adding new rules to it:

nMgvb.png


(Nailed it)

And a colorful life simulation:

z8l4N.png


Colored pixels move randomly, spawn lower intensity pixels randomly, and regain their intensity by touching stationary white pixels. Looks kind of cool for a minute or two.

Monkey Mind

Lots and lots of IRL work lately... I don't know what I'm doing up at 6 AM on a Sunday morning. Maybe I shouldn't be bloggin'.

Nevertheless, very little progress since my last post. I think I'm starting to feel compassion for the news media when they have to resort to talking about Hollywood gossip to fill up their time slots. I really don't have all that much to report. So if you made it this far, thanks for reading, and prepare to be bored.

The monkey mind is hard at work. Sometimes, it feels like I'm climbing Mt. Everest and the only thing I can think about is when I'll finally be able to sign up for snorkeling lessons.

My Blackjack game works perfectly -- you can do pretty much everything you'd be able to do at a casino table -- but there's so much polishing to do... First, I keep running out of screen space. In Blackjack, you can split hands if you get dealt two cards of the same value; for instance, if you get two aces, you can divide that hand into two hands consisting of one ace each, and then additional cards are dealt on top of those. And if you get more pairs (in some variants, including mine), you can split those indefinitely as well... If you're lucky, you can turn your 5 initial hands into a whole lot more. So none of what I coded is adequate -- no matter what happens, you can never have enough screen space to accommodate all possible plays, which means a complete rehaul of the UI.

Speaking of UI, I keep running into stupid "didn't think things through" mistakes. For instance, when betting, I made it so you have to first click the hand (area on the table) that you want to bet on, and then, you have to click chips in your chip box at the bottom to deal them to the selected hand. That really isn't convenient -- what makes more sense is to select the chip denomination, and then click the hand you want to bet on, or even drag and drop chips to the appropriate location. And that pretty much changes the way the entire betting phase UI works.

I also can't decide where to put my buttons for different actions. Putting the buttons near the currently active hand makes it easy to see which hand you're making decisions for, but then there's still the screen space issue, and buttons have to be shifted away from the edge of the window in case they're out of bounds. So naturally, I'm whining to myself about how I don't want to hardcode this and would have preferred to create a grid/layout container that comes with this feature built-in.

I spent a lot of time working on a large pixel "arcade font," but it doesn't fit the theme at all, and it's actually too big. I have to make a new font.

And I still haven't touched sound or music. I don't even have speakers on this computer... Which is silly, because if you recall, I'm kind of loaded.

As if all this stalling wasn't enough, I'm "thinking of snorkeling," in my own way. I've been scribbling lots of stuff in my notebook lately about a game that I'm only supposed to start coding about 2-3 finished games from now, according to the plan.

You know that game idea that's driving you to learn, so you can hopefully pull it off sometime in your lifetime? Well, that's the one. Mine is a game that's heavily inspired from Starflight. If you don't know Starflight, it's basically this: you have a spaceship, you upgrade it, you venture out into the open-ended universe and discover planets, you mine for resources and capture lifeforms, and you communicate with other intelligent life, all while trying to gather clues that will ultimately lead you to save the universe from massive destruction. If you must try it, try the Sega Genesis version; the PC one is in 16 colors and plays horrid, loud music from the PC speakers.

I've got this interesting idea for the mining aspect, which would involve worms/lemmings-like destructible terrain, along with "sand physics." I think a 2D representation would be particularly fitting; you could mine down and see the different layers of the ground as you dig down. Buying more equipment means more fuel to venture deeper towards the core. You'll have to balance the equipment you take with you, sacrificing armor and weapons for more storage space, or more effective mining and scanning tools. And of course, make sure you have enough fuel to come back, remembering that more cargo means higher fuel consumption, just like what made the original Starflight so freaking engaging.

Am I rambling? No. Couldn't possibly be.

Either way... I need to figure out this whole Blackjack situation. It helps to write about it, because now I see I'm just stalling on something very simple. Time to pick up those tools and do something about it.

Sequencers

Lots of bug hunting today.

Just finished the code to deal cards from a deck to an arbitrary hand. I don't know if anyone else will understand it, but here goes:

void BJDeck::giveCard(BJHand* hand)
{
// Create new sequencer object
Sequencer* cardgiver = new Sequencer();
cardgiver->attach(this); // attach it to the deck

// Create new card's sprite, face down
Sprite* s = new Sprite("Card back vertical"); // new sprite using "card back" graphic
s->relativeAttach(hand->cards); // attach with relative positioning to the target hand's "cards" actor group
s->setPosition(position); // spawn it at the position of the deck

s->hide(); // hide it for now

// 1. Add a sequence message to unhide the card sprite when the sequence starts
SeqMessage* sm = new SeqMessage();
sm->setCommand(&ScreenObj::unhide); // universal functor in action here
sm->attach(s);
cardgiver->sequenceQueue.addRelationship(sm); // we add the message to the sequence

// 2. Flush: move the card sprite in a straight line to a given position on the table
Flush* f = new Flush();
f->setCourse(hand->nextCardDest(),10); // here we ask the hand where to put the new card, and set it to get there in 10 frames
f->attach(s);
cardgiver->sequenceQueue.addRelationship(f);

// 3. Sequence message to change the graphics resource used by the card sprite
sm = new SeqMessage();
sm->setCommand(&Sprite::changeResource,buildArgSet("Card Grid")); // 13 x 4 grid of card tiles
sm->attach(s);
cardgiver->sequenceQueue.addRelationship(sm);

// 4. Sequence message to set the correct tile index on the card sprite
sm = new SeqMessage();
sm->setCommand(&Sprite::setTileIndex,buildArgSet(getNextCard())); // getNextCard gives you the next card number (0-52) in the shuffled deck (6 x 52 cards)
sm->attach(s);
cardgiver->sequenceQueue.addRelationship(sm);

// 5. Add a 20 frame delay after the card has moved
SeqCountdown* sc = new SeqCountdown(20);
sc->attach(s);
cardgiver->sequenceQueue.addRelationship(sc);

// Add this "cardgiver" sequence to the Scene Manager's sequence list
SceneMgr::getInstance()->sequenceListeners.addRelationship(cardgiver);
}


Spawns a new card, moves it, flips it over, and dies gracefully... Which reminds me, I'm supposed to create an actual card object class that can be flipped instead of manipulating sprites directly.

Well, back to work.

Introducing... Hardk

Welcome to Hardkore Blackjack, a fast-paced "arcade" twist on a popular casino classic.

F0ULq.png



It's Blackjack, except before each round starts, you get to see the upcoming cards in the deck and rearrange them as you see fit to produce the best possible outcome. Once you're done rearranging (or if you hit the time limit), the cards are hidden from view and the game proceeds like a normal Blackjack game.

The order of play can always be determined in advance -- it's just you vs. the house:

1. 2 cards are dealt to the dealer
2. 2 cards are dealt to the player
3. The player performs simple actions (hit, double, split, stand) -- repeat sequentially for each hand if playing multiple hands or splitting hands
4. The dealer draws as necessary

The initial difficulty comes from remembering this sequence and ensuring that cards get distributed as intended -- just like a classic mistake in Tennis is to hit the ball into the net, a classic mistake in Hardkore is to set up the cards in the wrong order!

Also, as the level increases ("level" as in "Tetris"), some cards will be locked, hidden, or even worse; force you to pay before you can move them!

A simple way to win is to give yourself a Blackjack, or get the dealer to bust... But naturally, that will not yield a whole lot of points. What you want to do is bet on multiple hands, split hands several times to acquire "combos," etc. The more combos you try to make, the harder it is to figure out the order of the cards -- and of course, you have to remember what actions you had planned once the cards are hidden from view!

Special bonuses occur in some instances -- multipliers if all cards within a given hand have matching colors, if multiple hands have the same values, or if you manage to draw 4 cards or more on a given hand. The higher the dealer's hand, the higher the payout -- giving the dealer a 20 and getting a Blackjack is considered a nice move, while making him bust or making him stand at 17 is an easy way out.

Some possible game modes:

1. Classic mode

Plain old game of Blackjack -- nothing special. This is the mode I'm working on first, and the only one with a classic "casino" theme:

aTsNH.png




2. Hardkore

The "regular mode" -- can be compared to Tetris's infinite play mode. Every few rounds, the level increases, your time limit decreases, the base price of rearranging cards increases, and the number of randomly locked/hidden cards increases. How far can you go without losing all your money? How hardkore can you get?

3. Race

How many rounds will it take to transform $1000 into $1,000,000?

4. VS mode

Player VS player or Player VS AI -- all players are given $,1000 and the same deck each round. The winner of a round is the person who makes the most money. Play instant, best of 3, best of 5, etc... Also the basis for a possible campaign/career mode, and perhaps online multiplayer.

5. Puzzle mode

Haven't tried this yet, but it would consist in decks with many locked cards, a pre-set number of hands/bets, and a target earning minimum. i.e. earn 5x from this deck, moving only 3 cards.

The big issue with this concept is that game balance can be hard to achieve -- sometimes, it's way too easy to win, and sometimes, it's all about luck.

So... What do you think?

Oh yes they will. Here's what I've been doing instead of programming a game:

A typical game object class, before:


#define MSG_ONMOUSEOVER 1
#define MSG_ONMOUSEOUT 2
#define MSG_ONCLICK 3
#define MSG_ONUNCLICK 4

class ClickRect : public ScreenObj
{
public:

// ...

void processMessage(ActorMsg* msg);

void hoverCheck(int x, int y);
void clickCheck(int x, int y);
void unClickCheck(int x, int y);
};


A typical implementation of processMessage, before:


void ClickRect::processMessage(ActorMsg* msg)
{
switch(msg->type)
{
case MSG_TYPE_INPUT:
switch(msg->intData[0])
{
case MSG_MOUSE_POSITION:
hoverCheck(msg->intData[1],msg->intData[2]);
break;
case MSG_MOUSE_CLICK:
clickCheck(msg->intData[1],msg->intData[2]);
break;
case MSG_MOUSE_UNCLICK:
unClickCheck(msg->intData[1],msg->intData[2]);
break;
}
break;
}
}


Sending and receiving messages typically used to involve writing #defines for the different types of specific messages an object can send and receive (with no real distinction between the two), and a bunch of nested switches.

Well, it served its purpose quite well. The issue, of course, is that it simply was not elegant, especially when the only use for it was to call member functions of the target object.

So I needed a way to "store function calls" instead of messages. I couldn't just have this big message struct with all sorts of different containers that may or may not get used. I couldn't ask the programmer to come up with and remember all these macro names either, just so he would be able to delay calls to functions.

Enter member function pointers and templates.

A typical object class now:


class ClickRect : public ScreenObj
{
public:

// ...

MAKE_MESSAGEABLE2(hoverCheck,int,int);
void hoverCheck(int x, int y);

MAKE_MESSAGEABLE2(clickCheck,int,int);
void clickCheck(int x, int y);

MAKE_MESSAGEABLE2(unClickCheck,int,int);
void unClickCheck(int x, int y);
};


And code for sending a message to it:


ArgFunctorPair command(&ClickRect::hoverCheck, buildArgSet(50,-50));

command.executeOn(myClickRect); // calls myClickRect->ClickRect::hoverCheck(50,-50);


Isn't that much nicer? Just plug the MAKE_MESSAGEABLEn(function_name, arg_type1, arg_type2, ..., arg_typen) macro into your class's definition, and you now have a "messageable" member function.

MAKE_MESSAGEABLEn actually expands to an overloaded version of the function that takes a single argument; this ensures that all member function pointers have the same kind of signature, namely void(some_type::*)(ArgSet*), where ArgSet is the base class for a collection of templated "tuple" classes -- similar to std::pair.

The expanded function automatically casts the argument container to the proper type (i.e. the proper number of arguments).

So no more defines, no more switch statements, only arbitrary function calls.

One issue is that there's not really any runtime checks, so if you enter the wrong number of arguments, it crashes... Other than that, it's pretty much impossible to make a mistake; unlike in the previous implementation, you can't issue a command that doesn't exist, and you get all the benefits of autocomplete. It's also compatible with virtual functions.

(Official Template Wizard status acquired)

When writing a (genre), you often have to make sure that (some abstract concept) is properly (synonym of handled), but you want to make sure you don't lose (performance/flexibility). Have a look at the following diagram:

Exactly the way your current project is organized

There's several reasons you DON'T want to do it that way:

(list of reasons)

Over the next 25 pages, I will (explain why you're wrong/propose something you were too stupid to come up with on your own/slowly destroy your soul).

[size="5"]Chapter 1: A story about the time I, like you, used to do dumb things

[...]

Anatomy

So I'm hard at work on my object composition-driven rapid development framework. I reached a significant milestone in my career as a hobbyist developer today: I actually backed up the solution to another hard drive. It may seem like a normal thing to do for most people, but I've deleted dozens of projects throughout my life; projects that seemed like they could be redone better, projects that were erased through time and reformats...

I'm not entirely satisfied with the project in its current state, but I'm definitely satisfied enough that I probably won't be doing another full rewrite, and I think that's worth celebrating. Hooray, or something.

In an effort to collect my thoughts and perhaps provide something of value, here's a description of the system.

[size="5"]EDBJ: An introduction

First of all, EDBJ stands for "Event-Driven BlackJack" -- I decided to get back into game programming by chance, when I became interested in the mechanics of the casino game BlackJack. I created a quick and dirty console version, but I wanted more -- so I embarked on this journey, to create a rapid development framework specifically tailored to facilitate common game tasks, providing simple interfaces and functionality that can be extended and combined into complex behaviors, all while taking the requirements of a little (polished) BlackJack game into account.

EDBJ is all about composition -- Absolutely everything is a node on a hierarchical scene tree, from the game state manager to something as simple as a sprite. Parent nodes implement game logic and behaviors, while more basic things, such as their ability to receive input and their graphical representation, are attached to them as child nodes.

For instance, a "Spinner" is made up of a TextLabel with two PushButtons (up and down). TextLabel is the on-screen graphical representation of the spinner's current value and refers to a font resource for rendering. PushButton itself is made up of several things: an optional TextLabel (for button text), a Sprite (for the button background), and a ClickRect that informs the button of mouse activity. The ClickRect itself has a MouseListener child that is part of a special list/map in the Scene Manager, specifically designed to propagate mouse input. Likewise, Sprite has a RenderListener child, a component that is referenced in the SceneManager's list of renderables.

cMuJW.png

[size="5"]1. The Actor class

Most, if not all, objects in the game extend from the base class Actor.

Actor provides for simple tree functionality -- parent item A to item B, detach A from B, recursively delete all children, etc.

It also provides the interface for 3 virtual functions that must be extended by all derived classes:

render() -- called on all renderables every frame
processTick() -- called on all items that implement some form of logic every frame
processMessage() -- used to receive messages from any other actor, either directly or through a global manager

[size="5"]2. The Scene Manager

The Scene Manager is the root of a given scene. It is responsible for a lot of things. Its main loop, which is run every frame, looks like this:

tick() -- makes all actors tick (execute behaviors they implement every frame)
runSequences() -- a bit obsolete now, as I pointed out in my previous blog post, but it executes sequential and times actions from a simple stack
readInput() -- reads and dispatches input from mouse and keyboard to the relevant objects
dispatchMessages() -- dispatches indirect/global messages to their relevant recipients
cleanup() -- destroys any objects marked for deletion
render() -- sorts the render list and draws all renderables to the screen

It basically does anything that objects cannot (or should not) do themselves.

[size="5"]3. State Manager

The state manager is an actor that defines an additional layer of hierarchy -- stackable game states. Each game state is responsible for the objects it contains. For instance, my BlackJack game's GameState_Opening has a Sprite child for a background image of a Casino scene. You stack GameState_TitleScreen on top of it to show the game's logo and buttons such as "New Game" "Options" and "Quit." New Game and Options are linked to StateSwitchers; little utility nodes that pop the game state stack and replace the "tip" state with a new one. So, to go from the Title Screen to the Options Screen, which both share that same Casino scene background, you pop the Title screen (remove the game logo and main screen buttons) and push the GameState_Options state to the StateManager -- the background remains, but the options screen is now shown.

This allows you to use sub-states that run concurrently -- for instance, you would push a state containing objects like the BlackJack table, the player's chips, etc... And then an additional state on top of that depending on what's happening -- a state for dealing/animating cards, a state for presenting the player with options (hit, stand, etc), a state when the Dealer's cards are revealed and the game concludes...

Game states must be stacked in a linear fashion, but nothing stops you from adding several state managers as children of game states... And that's what I like about the system -- while there's relatively few safeguards and few of the "rules" are enforced by the compiler/language, unexpectedly useful features keep popping up (although I'll admit they're far outnumbered by the myriad of predictably useless features).

[size="5"]4. The Resource Manager

[size="2"]The Resource manager is a monolithic singleton class that can load different formats and keeps a simple table of resources. All game resources - for now, just fonts and (optionally tiled) images, later, sounds, config files, game levels, etc - are derived classes of ResPtr, the interface for resource pointers. They all implement file-format-specific loading and rendering code that game nodes can use. When you create a new instance of a node, you usually feed the constructor a string (an arbitrary name for the resource that you set when you load), the resource manager will then do a (quite slow, at the moment) search and return the relevant resource. It's also possible to refer to resources by ID#, or even just keep a raw pointer to the resource.

[size="2"]Each resource type is heavily dependent on the API used - in my case, FontPtrs handle TTF_Fonts from SDL_ttf, and ImgPtrs handle SDL_Surfaces. If a different rendering subsystem is to be used, different resource types will have to be defined. The good thing, though, is that resources of a similar type come with the same interfaces -- for instance, both bitmap fonts and TTF fonts have a "drawText" function that behaves the same, derived from a more generic Font resource interface.

[size="5"]5. The GUI

[size="2"]GUI nodes benefit greatly from the object composition approach, as illustrated in the Spinner diagram above. It's still relatively incomplete at this point, but it's relatively easy to do simple things -- draw text to the screen, implement clickable and draggable items, change the mouse pointer, assign hotkeys...

[size="5"]6. The Future

At the moment, the goal is to finish the little BlackJack game. I'm working on content now -- graphics for the cards and chips, cohesive GUI elements, bitmap fonts. I still have to implement some game logic and sound code. Hopefully, next blog post will be a playable demo :-D

Once that's done, I can move on to bigger things. The next project is "Super Penny Thrower" -- the game I failed to present at Ludum Dare 12 a few years ago, where you throw pennies from a skyscraper just to see what'll happen (hint: stuff blows up). I will be switching to OpenGL for rendering, implementing "viewports" (for scrollable game worlds and GUI elements), and of course work on more realtime-game-specific stuff, such as physics.
So lately I've been investing significant amounts of time into a "sequence listener" class that enables sequential and timed actions.

This is useful in the little BlackJack demo game I'm coding alongside the framework; for instance, when the cards are dealt, I can simply string together a bunch of countdowns, animators, etc. to spawn and move cards to the relevant areas, one by one.

The way I implemented this was with a "relationship descriptor" class that I really like -- it attaches a tiny object to one of the game elements on the scene tree, and if ever that game element is deleted, so does the little relationship object, and its destructor informs the relationship descriptor of deletion... It's a way of keeping lists of specific items without having to iterate through the tree, searching for specific objects (such as renderables, objects that respond to user input, etc). So waiting to be notified of the end of a sequential event amounts to waiting for it to die, which is pretty convenient.

But very quickly, this introduced an issue: if I set up a sequence in that system to be executed later, I had to attach the sequence's behavior to the relevant objects before I could push it to the sequence string... So what happens when I need a sequence object to spawn a new object with its own sequences to run? I can't, because I can't attach my sequence objects to something that hasn't been created yet.

In the card dealing example, I want to attach 4 "spawn card" commands to the card deck (2 for the dealer, 2 for the player). Those spawn card commands should then spawn the cards, and then add a sequence object and countdown to the cards so that they can be moved to their destination (the player hands) one after the other...

The problem with the monolithic sequence processor I coded is that if I do use it that way, 4 cards will get spawned in one shot, and then they'll travel to their destination one by one... But I don't want that -- I want each card to be spawned, then moved, before the next card is spawned.

So I got to work on a class that acts as a "group of sequences" -- i.e. a class that acts as a subsequence, so that my "spawn card" commands are actually "spawn+move subsequence" commands.

And that's the story of how I invented "fake threading." Meanwhile, ghosts of programmers past are looking over my shoulder as their bodies turn in their graves.

Derp

*click click click* Damn it. It's not doing anything. *click click click click click* Oh well... Guess it's time for some debugging.

Ladies and gentlemen, I give you... My mouse input handler:

switch(msg->intData[0])
{
case MSG_MOUSE_POSITION:
// TODO: hover check
break;
case MSG_MOUSE_CLICK:
// TODO: click check
break;
case MSG_MOUSE_UNCLICK:
// TODO: unclick check
break;
}


1YnO9.png

Very bloggy

Talking about my life to justify how little has been accomplished in the past week, programming-wise. [...]

Big big "IRL job" projects right now... Clients like to hold onto stuff until mid-January before they send off work to translators. So naturally, after almost a month of nearly complete silence and shivering at the idea that maybe my clients found new, cheaper, better translators, enough work has come in in the past week for me to survive until summer!! Did I mention working from home is "da bomb?"

Anyway... Since the last post, I began implementing a fixed-point coordinate system with a 2D vector class made up of interesting, but nevertheless shamelessly stolen bit-twiddling hacks. Still struggling a bit with complete avoidance of floats, and also wondering if it's even worth it. That's about it.

I also entered business talks with ... my sister. She wants to create a simple iPhone/iPad game starring dragons. She's in the middle of her second arts degree, and her boyfriend is a skilled pixel artist for an actual game studio in Montreal, so I'm pretty excited to see what they'll come up with.

My brother will also be joining the team. He's in his second semester of Computer Science, and still hasn't had a single programming class... So he won't be able to help me much with the coding yet, but I think he'll make a pretty good level designer and music guy in the meantime.

Official first meeting is set for next week!

They said they weren't in it for the money -- they "just want something to put in their portfolio" ... Hah! Reading that made me angry. You have pure, unlimited artistic talent at your fingertips. You work a minimum wage part-time job while studying full time... And you want to pay Apple a license to distribute an App Store game ... NOT FOR THE MONEY? WHAT IS WRONG WITH YOU!?

That game better sell zillions of copies. I don't care if you're my sister, my brother... I will SLAP you in your face if you even suggest distributing it for free. But not my brother-in-law-to-be. That guy could probably kick my ass.
Well, this is exciting. I think I'll use this and pipe the RSS into my website or something. (more)

A little introduction: My name is Ben and I'm a Computer Science dropout. I work from home as a freelance translator and recently resumed my programming activities. I've been learning C++ for about 14 years now, and the only thing I've released so far is an unfinished clone of Tetris that runs in the Win32 console. Yes, I'm "that guy who sure likes to start a lot of projects but never actually accomplished anything of significance."

I'm currently developing a 2D GUI/Game framework in C++ that works on top of SDL. Fifth rewrite so far, but I think this is the one!

I entered Ludum Dare about 3 or 4 years ago. I'm creating this framework because I want to go back and make the game I had planned but never actually managed to code. It's called Super Penny Thrower, and the goal is to drop pennies from a skyscraper to kill people and make cars explode. In this case, the 48 in LD48 will be months, not hours.

I plan on eventually publishing the framework, specifically to enable rapid game development for 24/48h compos.

If you stumble upon this blog and it's been more than 2 weeks since the last update, please do me a favor and post a comment; I need to be nagged!
Sign in to follow this  
  • Advertisement