00:00
00:00
CrankyRabbit
Would-be DJ/Producer. Plays too many video games. Drew a webcomic once. Old fart.

Age 53, Male

Coordinator

New Zealand

Joined on 5/7/04

Level:
19
Exp Points:
3,637 / 4,010
Exp Rank:
15,326
Vote Power:
6.05 votes
Rank:
Safety Patrol
Global Rank:
30,532
Blams:
94
Saves:
224
B/P Bonus:
6%
Whistle:
Normal
Medals:
2,416
Supporter:
2y 1m 7d

CrankyRabbit's News

Posted by CrankyRabbit - November 12th, 2024


One of the goals I want to achieve is writing some games and sharing them on Newgrounds. Most likely I will set up a separate account for that. One should keep vices separate.


The weapon of choice is the MEG-4 fantasy console. This thing is a bit more flexible than the PICO-8, sports about 512KB of memory, and a classic resolution of 320x200 pixels. Basically, about the same resolution as the Commodore 64. Except that you can code your programs in a flavour of ANSI C, and you don't have to faff about in screen resolution modes that severely limit you choice of colours and make all your pixels wider.


This means some heavy limitations. No object oriented programming, no structs (I know from experimenting.) Everything is ANSI flavoured numbers and chars, in arrays and out.


Naturally I’ve tried making games before. What happened was that I ended up with a too-grand vision, got bogged down in details, couldn’t understand the workflow, and gave up for the easy rewards of playing someone else’s games. Not this time.


The games I intend making are basic copies of arcade classics: Breakout, Bezerk, Space Invaders, Joust, that sort of mid-1980s stuff.


But first I need to code up a framework.


States of Play

One feature of the framework I need is to be able to identify what state the game is in. For instance, there is an initial default state where the game sets itself up and sorts itself out. There may be a splash screen state which lasts until you press the start button. Then there is the game loop state proper, and finally a game over state. Each state has unique logic, and it makes sense to keep it all separate.


The easiest way is to set up a global variable, and change its value whenever we need a state change.


enum { _FALSE = 0, _TRUE = 1 };
 enum { S_ERROR = -1, S_INIT = 0, S_TITLE = 1, S_GAME = 2, S_GAMEOVER = 3 };
int32_t _STATE = S_INIT; // obviously if(_STATE < 0) do error stuff

This makes the loop() function a basic switch..case statement.

switch(_STATE) {
    case S_INIT:
        // set up everything for showtime
        if (setup() != _TRUE) {
            _STATE = S_ERROR;
        } else {
            _STATE = S_TITLE;
        }
    break;
    case S_TITLE:
        // splashy splashy insert coin
    break;
    // and so on until
    default:
        // do error stuff
 }

But it may be more complex than that. Theoretically we shouldn’t need thousands of distinct running states, but that is academic. If I understand correctly, enumerated values are 32-bit signed integers, so it’s best we keep compatibility.

You’ll also notice another pair of global constants, _TRUE and _FALSE. These can be used for answering the question, “did this function do what it’s supposed to?” or, as we’ll code later, “are these two objects colliding?” Having constants makes the code easier to read.


However, we don’t really need to compare like that. After all, states are defined as numbers! We can streamline loop() into this:

switch(_STATE) {
    case S_INIT:
        // set up everything for showtime
        _STATE = setup();
    break;
    case S_TITLE:
        _STATE = title();
    break;
    // and so on until
    default:
        // do error stuff
 }

This requires less processing overhead, and is simpler than constant comparisons; the functions just have to return the state for the next cycle. If everything got set up properly, we switch straight to the title state; a lot easier. Especially if we have multiple game over states (e.g. good and bad), and then need to circle back to the title screen.


Of course, every function returns an int32_t, so we declare them as int32_t setup() {}. If there are any child functions for these, we’ll need a naming system that helps identify what’s what.


There are two conventions: One is to capitaliseFirstLetters and prepend the scope of the function. So, a function that sets up, say, a prefab array of baddies could be called setupBaddiesArray. The capitals make it easy to spot the individual words. Another is to use underscores, which would make the function call setup_baddies_array. It’s basically a matter of taste and legibility. (Word doesn’t like either of them.)


Anyway! We have a state management skeleton designed. But... what am I going to use it on?


First Game: Bat and Ball, redone

One of the tutorial demos in the game is a simple keepy-uppy game with a ball and a bat. If the ball hits an obstacle, it changes direction appropriately. If it drops off the bottom of the screen, game over.


Naturally I want to complicate this demo and turn it into the base for a Breakout clone. I want variable velocities, more generalised collision code, scoring etc. BUT! Before I can start that, I need to get it a) into the state framework, and b) sort out collision coding.


Variable Velocities

In its vanilla state, the ball moves in diagonal lines. While it has velocities dx and dy, these just change sign when it hits the bat or edges of the screen. Whether you crawl the bat, or just fling it from side to side with gay abandon, it doesn’t matter a damn. I want it to matter.


Generalised collision code

The collision detection for the two objects is hard coded into the loop. I want a method that can be generalised to an arbitrary number of objects. For instance, adding blocks, or bumpers, or pickups. This is going to be tricky. I’ll discuss implementation in another blog post.


But first, let’s see about getting bat and ball into a state-based frame of mind:

#!c
 
 int x, y, dx, dy, px;
 str_t msg = "GAME OVER!";
 
 void setup()
 {
  /* Things to do on startup */
  x = 156;
  y = 96;
  dx = dy = 1;
 }
 
 void loop()
 {
  /* Things to run for every frame, at 60 FPS */
  cls(0);
  spr(x, y, 0, 1, 1, 1, 0);
  px = inw(0x16);
  if(px > 296) px = 296;
  spr(px, 191, 1, 3, 1, 1, 0);
  x = x + dx;
  y = y + dy;
  if(x == 0 || x == 311) dx = -dx;
  if(y == 0 || (y == 183 && x >= px && x <= px + 24)) dy = -dy;
  if(y > 199) {
    dx = dy = 0;
    text(184, (320 - width(2, msg)) / 2, 90, 2, 112, 128, msg);
    if(getclk(BTN_L)) setup();
  }
 }

So currently it exists in one state. The ball launches as soon as the game starts. We need to fix that:

#!c
 
 enum {S_ERROR = -1, S_INIT = 0, S_TITLE = 1, S_GAME = 2, S_GAMEOVER = 3};
 int32_t _STATE = S_INIT;
 
 int x, y, dx, dy, px;
 str_t msg = "GAME OVER!";
 
 void setup() {
 }
 
 void loop() {
  switch (_STATE) {
    S_INIT:
      _STATE = initSetup();
    break;
    S_TITLE:
      // placeholder
    break;
    S_GAME:
      _STATE = gameLoop();
    break;
    S_GAMEOVER:
      // placeholder
    break;
    default:
      // an error occurred, which with a game this simple shouldn’t happen
    break;
  }
 }
 
 int32_t initSetup () {
  /* Things to do on startup */
  x = 156;
  y = 96;
  dx = dy = 1;
  return S_GAME;
 }
 
 int32_t gameLoop()
 {
  /* Things to run for every frame, at 60 FPS */
  cls(0);
  spr(x, y, 0, 1, 1, 1, 0);
  px = inw(0x16);
  if(px > 296) px = 296;
  spr(px, 191, 1, 3, 1, 1, 0);
  x = x + dx;
  y = y + dy;
  if(x == 0 || x == 311) dx = -dx;
  if(y == 0 || (y == 183 && x >= px && x <= px + 24)) dy = -dy;
  if(y > 199) {
    dx = dy = 0;
    text(184, (320 - width(2, msg)) / 2, 90, 2, 112, 128, msg);
    if(getclk(BTN_L)) { return S_INIT} else {return S_GAME};
  }
 }

So what has happened here is that we have made some function prototypes, and pushed both the setup and game logic into state-specific functions. This should run. So, what do we want to do now?


Well, first off, we want a start screen, preferably one with a “click to start” message and bat plus ball showing. So what’ll that look like?

int32_t titleLoop()
 {
  str_t startMsg = "Click to Start";
  /* Things to run for every frame, at 60 FPS */
  cls(0);
  spr(x, y, 0, 1, 1, 1, 0);
  spr(px, 191, 1, 3, 1, 1, 0);
  text(184, (320 - width(2, startMsg)) / 2, 90, 2, 112, 128, startMsg);
    if(getclk(BTN_L)) {return S_GAME} else {return S_TITLE};
  }
 }

Now notice that this is just a stripped down copy of gameLoop(), since the only thing we need to know is whether or not the player clicked to start. Once they do, the _STATE changes and the message will poof. It’s keepy-uppy time!


(Also, there are some semicolons missing, as well as a default return call! Oops.)


But wait! We now need a game-over state!

int32_t gameLoop()
 {
  /* Things to run for every frame, at 60 FPS */
  cls(0);
  spr(x, y, 0, 1, 1, 1, 0);
  px = inw(0x16);
  if(px > 296) px = 296;
  spr(px, 191, 1, 3, 1, 1, 0);
  x = x + dx;
  y = y + dy;
  if(x == 0 || x == 311) dx = -dx;
  if(y == 0 || (y == 183 && x >= px && x <= px + 24)) dy = -dy;
  if(y > 199) {
    return S_GAMEOVER;
  }
  return S_GAME;
 }
 
 int32_t gameOver() {
  dx = dy = 0;
  text(184, (320 - width(2, msg)) / 2, 90, 2, 112, 128, msg);
  if(getclk(BTN_L)) { return S_INIT;} else {return S_GAME;};
 }

So putting all these parts into the code, this should all run. Then I can start working on the next essential step: How to deal with all the objects?


The outcome(s)

Upon testing, the answer is a resounding no. For some reason, the switch call keeps breaking with a totally unhelpful 'syntax error' message. This could be due to a flawed implementation, or perhaps from me being a dill and writing this code while brainstorming in Word. However once replaced with if .. else if .. else statements, the code works properly. While annoying, I can work around this.


Also, I forgot to draw sprites, a lack quickly corrected.


Nevertheless, the state implementation works as expected, now all I need is to add a title state, so that you have to click the mouse to start the ball... not rolling, that's the wrong descriptor...


Tags:

Posted by CrankyRabbit - November 9th, 2024


iu_1298231_836446.webp

I have made some zines. One of them - "Frog Salad" - won a Special Mention Award at this year's Wellington Zinefest. And therefore, I feel you should know how to enjoy them.



I mean, special mention isn't all that, but I won an award, and that's more important.


Oh - these zines are not a foodstuff. But I'm not your mother. I'm a grumpy old fart who wants you to either buy something or get out of my goddamn shop.


Tags:

1

Posted by CrankyRabbit - January 30th, 2024


OK, I've already started preparing for the RPM Challenge 2024. An omnichord app is on my phone (since my Galaxy Tab won't upgrade to Android 11). I have found a nice synth sample bank. Lo-fi shenanigans loom!


You can follow the journey on my brand spanking new daily podcast tracking my progress.


Basically I'm spamming this because it keeps me responsible for pushing onwards. Ten tracks by March or bust!


Tags:

Posted by CrankyRabbit - August 11th, 2023


So you may have noticed that I published a song... a rather glum one. Screw EDM, I'm going lo-fi for Zinefest.


Wellington Zinefest is taking place on the first weekend in October (7-8 Oct), so I'm working on a fresh zine for it, as well as working sporadically on a couple of CDs I'll make zines for, and flog them too. Of course I need to keep eyes open for when registrations come available, and actually get on and finish the darn things.


Now I've tried my hand and other body parts at making dance music, but really I started with ideas of emulating Chris Knox, solo and in Tall Dwarfs, with a touch of Wendyhouse, a good twenty years ago. For some reason I find doing so hard. This though... it feels fun and I intend doing more of it. The same cannot be said of the weeks-long Lung Oyster Season I suffered through in July though.


Currently I'm working on the instruments for the second track "Lubberland".Then I'll get the gitbox and ukelele recordings for "Playtime!"


If I manage to finish this EP project (provisional title The Next Small Thing) in time, I'll release it on Bandcamp after the event's over.Depending on how things go, I might even offer physical copies for sale.


Well. Better get on with it. There's a lot to do.


Posted by CrankyRabbit - November 14th, 2022


According to this site, I've had an account here for over twenty years. High time I put ol' cb_boxeddobbs.jpg and the whole SubGenius thing to bed.


So you know, I DJ. A Lot. Weekly, actually. In a club in Second Life. And I have an debut EP on Bandcamp.


Well, there's that.


Posted by CrankyRabbit - October 23rd, 2020


You know, reading this, it's a good thing I didn't pursue this idea any further. Read my older posts and you'll see where this came from.


https://docs.google.com/document/d/1bXvXjzwvllQyK0gMRUqRgILfzKRDtYkWgJwxaxZbZQ4/edit?usp=sharing


Posted by CrankyRabbit - August 15th, 2019


So, with the power of Automatonism, Ableton, and a desperate need to make something, anything, I've been doing sort of dark ambient stuff under the name invisibl nudist.


  1. say hello to heaven
  2. choke points in biography
  3. next stop godot
  4. every sky its own limit

Tags:

Posted by CrankyRabbit - March 4th, 2017


Some quick snaps of sketches for this game. The first three or so are back from when it was called Totally Unoriginal Roguelike Dungeon (I know, juvenile acronym). That was maybe about two or three years ago. However, I already had the basic concept - even the design of the playfield! What was bogging me down was the level progression: where the player and his eventually unlockable companions (who unlock special attacks, power-ups etc.) end up going.

The initial playfield design (for combat)

The core of the game is combat on what I now intend to be a 9x9 grid of tiles. So the big stumbling block is writing AI that can be set from "thick as two short planks" to "cunning b'stard".

Token token design and equally token map design

Each tile (token) on the board fills up your score, inflicts damage, or fills up charge bars to do things that are either a) very good for you (if you do them) or b) very bad for you (if the enemy does them). I was also considering the possibility of using a similar mechanic for looting a treasure chest (limited moves, I expect), dodging traps, and navigating the dungeon. After all, back then I called it Totally Unoriginal Roguelike Dungeon.

Early character designs

Early character designs. Already I had the notion that each companion would be uniquely shaped, and Roger Ramjet's influence is already showing in the hero at left.

The Handsome Hero meets the Kindly King

Years later, and I drew up this concept for the throne room, the location of the first gag-filled and gag-inducing cutscene and gameplay introduction.

KING: Now, oh Handsome Hero, you know why you are here.

HERO: Yes, these two guardsmen marched me here at spear-point.

The idea is that cutscenes are like Roger Ramjet: very limited animation cut to quick-fire dialogue.

Your first enemy: Guard #1

Meet Guard #1. He's the dumber of the two guards who marched you in at sp - er, halberd-point. And he won't let you leave because he wasn't told at the start you were allowed to leave when finished, so up comes the playfield and fight!

If you're all very good, I'll stop right here and not threaten to continue working on this, i.e. scripting, writing the cutscenes, drawing art assets etc. Otherwise expect even more concept arts, cutscene excerpts, and getting sent off to rescue the lovely Princess Andertits (all three of her) from the wicked Count Whocares.


Posted by CrankyRabbit - February 7th, 2017


Yesterday managed to succeed at three things with the framework.

  1. Include support for cursor keys as well as WASD for movement (or indeed anything).
  2. Load MP3 files for music and have one loop. Turns out the loop runs outside of a state if you declare its handle as part of the main game object, I think.
  3. Progress bar! Finally worked the damn thing out.

This might not sound like much, but for me it's quite a lot. I now know I can implement two out of three input methods - the third will be clicking in the general region of where you want the player to go (left, right, up and down). That's a central conceit to bringing this game together.

To celebrate, I think I'll plug the tablet in and draw up some basic art resources, and redo that splash graphic. Maybe it's time to get serious about prototyping.

And come up with a better plotline than I currently have.

Incidentally, I was going to upload my first release under the title Invisibl Nudist, Centipede, until I read the conditions. I'm a little too reliant on prefab samples and lightly mauled MIDI clips, to say nothing of sampling a 20-year-old audio of young Billy Burroughs. So I decided against it. It's on Soundcloud anyway.


Posted by CrankyRabbit - January 21st, 2017


Six years ago I was attempting to learn enough Flixel code to make a game, but that fell through. I just didn't have the time and energy. Phaser came to the rescue.

Currently I'm slowly poking along building a framework for the game to reside in out of Phaser's state system. I like it. It makes me think of Second Life's states, just without a default{} one. The step I'm at is working out how to make a basic preloader animation - I'm just thinking a background image, some text and a loading bar.

Also I'm rereading some very old C++ code. You see, I once went down to a small games startup in in the late 90s, floppy in hand and a head full of Aspergers assurance that I'd land a job and it would be fun and easy.

The floppy held a simple demo of my game concept: You move your player piece around a tiled playfield and swap places with other tiles. When you match three in a group, scoring happens, new tiles fall out of the sky, rinse and repeat. (I did have a theme for the finished game, revolving around "cute anime kitteh inflicts horrific violence on monsters and other people and things" but it never got that far.

Some of the code I'm seeing boggles me. The playfield updating function has a switch(step){} logic that is empty for the majority of the case: branches. On second glance I get it though - I was thinking of making the player and destination tile "hop" rather than just slide straight, and any sideways motion would have been put in there.

Frankly, I'm beginning to wonder if I could make an object for tiles with their relevant properties and just send calls to that. It might make actually programming the important part easier than calling every damn thing from the main game loop like I did twenty-odd years ago.

It's good for me to look at this stuff. Otherwise I'll get caught up in contemplating canvas sizes, art styles, sound and music assets, and shopping for cheapo drawing tablets on Trade Me.

Well... I might make some simple assets again. Just for testing purposes.