>
posts/2024_06_13_checklists
Lately i've been playing a lot of flight simulators, specifically X-Plane 11 and more recently Microsoft Flight Simulator 2020.
Some of these sims are very in-depth, what some people like to call 'study-level' sims. So i started taking notes on a paper, with a pen.
After a while, i organized my notes, into something that started resembling the checklists that pilots use in real life, but still, more related to the sim.
And after looking for about 5 minutes on google, i couldn't find a simple app to build checklists and go through them with my phone as a side screen to the sim.
So, what did i decided to do? i decided to write something myself, because it is good practice, because its something that i'll use it myself and because why not?
and thus SimChecklists were born, as a small project to entertain myself, during lunchbreak, while i was trying to understand how to program the onboard computer on a Boeing 737-800.
I used PHP for most of the backend stuff, so sorting, parsing and delivering the checklists to the screen in a readable manner. With Vanilla Javascript for the frontend, interfacing with the user,
i wanted to avoid using anything heavy, so no images (only SVG icons dynamically loaded with PHP) and no 'javascript frameworks' (remember: no
russian jquery). My main idea
was to keep everything as simple as possible, meaning its something lightweight, fast, easy to load, simple to use, and as barebones as it can be, just a way for me to keep track of a list while
also playing a flight simulator.
The main thing is that the checklists themselves are simple text files, i used a simple structure, using double dashs (--Foobar--) to denote a new sublist and foo=bar to denote items to do.
A simple js script to cross and mark the items as done once i clicked them and after less than 1 hour, i had a version 1 ready to upload, which i did.
I uploaded the app for myself, to use it on my own (this) domain. And i also uploaded the code to github, both to increase my portfolio and if anyone else wants to host it, modify or whatever, can
feel free to.
I also showed a friend, which gave a few suggestions. So i started implementing them, and this is actually a good reminder, for me, of how much i prefer working with vanilla js over jquery, it
as easy, but much faster and lighter weight and if'm honest, i think i did a good job.
At this moment i have a webapp that while not fully featured is really not that bad:
- Theme support through appropriated .thm files.
- Auto detection and theme switching between light and dark modes.
- Hability for the user to upload their own checklists, files gets verified in both extension and mime type formats.
- Auto-scroll the checklist on the screen as the items are clicked.
- Hability to swipe left on a checked item to uncheck it.
- User can choose a theme and the result is saved on a php_session (i wanted to avoid saving anything and i wanted to do something simple with no database.
The live app is here:
http://checklist.classicgames.com.br/
And you can check the code @
http://github.com/jflores82/simchecklists
This has been fun to do. And i've actually been using it. It reminds me of when i did Retroamp, so many years ago, but nowdays the core of the app isn't 'outsourced' to a library i haven't wrote,
all the lines of the code are 100% written by me. :)
>
posts/2024_05_25_raposa
Late january 2024, i remember that the SMS Power (www.smspower.org) anniversary competition is happening in march,
since i usually try to enter on the music competition, i thought to myself, what if i tried my hand at the coding competition instead?
might be cool to try and code something for my favorite console, for a change.
-- Part I: The Toolset --
I remember that there's a C devkit, appropriately named "devkitSMS", so i googled that and found the github for the devkit.
So i started reading what i'd need to install to make it work. There's SDCC (small devices c compiler) and the devkit itself. Ok seems simple enough.
Installed everything, run a test following the manual and it seems correct.
Went to the examples folder and there's something there to test.
Try to build the examples and it managed to get them both to run, nice, time to learn.
Or is it? Just realized i have no tools to make graphics or sounds.
devkitSMS seems to like files converted with Maxim's BMP2Tile, so downloaded that, but apparentely, it also needs another plugin, time to search for that.
Installed that, managed to get a very simple demo running.
Its just my logo, basically, graphics tools, check.
What i'll be using: Libresprite to draw, BMP2Tile to convert to SMS, seems good enough.
Its been a while that i've been wanting to learn Furnace, to write tracker music for the SMS, instead of using my 'usual' method of recording midi in the my daw,
converting to vgm, editing the vgm in mod2psg2, so i went to try and get, install and get a basic tutorial going.
Managed the very basic, so i guess its time to try my hand at adding sound to my logo demo.
Thanks to the PSGlib included in the devkitSMS, it was easy enough, a couple of minutes and lines of codes and i had my old western_sms.vgm song playing the same.
NOW it's time to learn.
-- Part II: First tests and coming up with an idea --
Next step, testing controllers.
Added a very badly made sprite over my logo background and made it move with the controller. Realized the sprite wraps around the screen when
going off-screen, might be easy to implement something like Asteroids, then? But i really wanted something a bit more involved and less cliché than
Asteroids. Maybe i should do Space Invaders? But there's already a good Space Invaders for the SMS, i'm sure.
So, time to start searching the web, 'best fixed screen games', 'famous arcade games' and so on. Nothing really grabs my attention. So i decided that i might
just convert an Atari2600 game, seems simple enough, but... which one? I know haroldoop did a very cool version of Turmoil, so that's out of question.
Kaboom might require more skills than i currently have, Enduro
definitely requires more skills than i currently have and the SMS already has Outrun,
Keystone Cappers requires more graphical skills than i have, Beamrider seems cool, might try to do that... but i realized that animating the background grid
with tile based graphics and my current skill set would take more time than i had (a little under two months before the SMSComp deadline).
Then, browsing youtube, i saw a game that might be a good fit, Solar Fox, an arcade game originally, with a slightly tweaked VCS port, that might be it.
Watched about 2hrs of gameplay, of both the original arcade and the VCS port, my feeling after it was: "i can do this", 100%.
But, i didn't want to do a port, i just want to inspire and get ideas and build my own game, so it begins, the coding of the Sega Master System "port" of Solar Fox.
-- Part III: SMS_setTileatXY ---
First things first, i start with a routine to draw walls on the 4 limits of the screen.
My very first initial idea was to use sprites for the walls, but it turned out to be a very bad idea, very quickly, since the walls won't move, there's no
reason to use them as sprites, instead of background tiles, so, that's what i did.
// Vertical Walls //
for(y = 0; y < 22; y++) {
SMS_setTileatXY(1,y,108);
SMS_setTileatXY(31,y,108);
}
// Horizontal Walls //
for(x = 0; x < 32; x++) {
SMS_setTileatXY(x,0,107);
SMS_setTileatXY(x,21,107);
}
// Corners //
SMS_setTileatXY(1,0,105);
SMS_setTileatXY(1,21,105);
SMS_setTileatXY(31,0,106);
SMS_setTileatXY(31,21,106);
That does it, pretty simple, two columns (vertical walls) and two lines (horizontal walls), with 4 decorative corner tiles, the beginning of a playfield.
And for the walls inside the playfield, i wrote a very simple routine to draw them, grabbing the location from the arrays, so i could design a proper level.
void walls_draw(void) {
for(int i = 0; i < level_walls_num; i++) {
SMS_setTileatXY(walls_x_y[i][0] / 8, walls_x_y[i][1] / 8, 100);
}
}
A very simple routine, but you might notice that i divided the value by 8, that's because, there's a difference between tile position and pixel position,
since i didn't realized that in the beginning, my arrays are storing pixel position for the X/Y of the walls, instead of tile position, and since each tile is 8x8 pixels, a very quick and dirty fix.
Now i had already had a ship, controlled by the player, and bound inside a playfield, with a couple of walls drawn in, time to write a collision detection routine.
That was the first 'obstacle' i encountered, because i knew, due to previous experiences writing other small games in other languages that collision detection could make the game craw to a halt,
specially since it is a routine that you need to check at least every other frame, in most cases of action games.
And since my wall locations were written inside arrays, that also meant i needed to loop the arrays.
Luckly for me, the little z80 could handle it like a champ.
This is what i came up with:
for(int i = 0; i < level_walls_num; i++) {
wall_x = walls_x_y[i][0];
wall_y = walls_x_y[i][1];
// collision bounderies //
if( pl_x < wall_x + 8 &&
pl_x + 16 > wall_x &&
pl_y < wall_y + 8 &&
pl_y + 16 > wall_y) {
...
It ssems to work, i can even call it up every single frame and since i'm not really re-drawing anything at the moment, it seems that i still have cpu cycles to spare.
And since it works, i used a similar collision check for the shots and the little 'satellites' which are called 'pellets' in the code, because i still wasn't sure what
to call them. :)
-- Part IV: random number is random --
One of the things that i've realized its very difficult to do on the SMS is random numbers, this is because the random seed for the rand() function in C
is generated at compile-time and not at run-time, which means that everytime, the rand() returns the same things, unless you re-compile the program, which is not
exactly viable, especially in a system like the SMS. But if you change the seed, you can simulate randomness, other way to simulate randomness is to generate a
random LUT and use that either as the seed or as the numbers themselves.
I took the first approach, basically i created an unsigned int and add to it every frame, until it reaches the int limit (no need to be a long, in this case, i think).
// For the random_level_generator //
unsigned int randomseed = 30; // Used to seed the rand command, 30 just being whatever to avoid starting at zero //
randomseed++;
if(randomseed == 25600) { randomseed = 0; } // unsigned int limit, no need to go over it.
That allows me to re-seed the rand() command, which different values, and since there's hardly a chance of someone taking the exact same number of frames in a menu or to complete a level,
it kinda makes the random seems really random.
Next step is to write a simple function to generate a random number between two values:
int rand_num(int lb, int ub) {
srand(seed); // re-seed the random number generator each time //
int ret;
ret = rand() % (ub - lb + 1) + lb;
return ret;
}
With that simple trick, i can now generate 'random levels', based on some parameters i designed, to avoid getting levels that were too easy or even worse,
impossible to complete, which is never what you want.
// Level Random //
if(level == 0) {
srand(seed); // re-seed the random number generator each time //
int r_pellet_x = 0;
int r_pellet_y = 0;
level_pellet_num = rand_num(5,20);
level_walls_num = rand_num(5,15);
en_l_y = rand_num(en_lim_top, en_lim_bot);
en_l_dir = 0;
en_r_y = rand_num(en_lim_top+10, en_lim_bot-10);
en_r_dir = 1;
level_pellet_collected = 0;
// Pellets //
for(int i = 0; i < level_pellet_num; i++ ) {
r_pellet_x = rand_num(pl_lim_left, pl_lim_right);
r_pellet_y = rand_num(pl_lim_top, pl_lim_bottom);
pellets_x_y[i][0] = r_pellet_x;
pellets_x_y[i][1] = r_pellet_y;
r_pellets_x_y[i][0] = pellets_x_y[i][0];
r_pellets_x_y[i][1] = pellets_x_y[i][1];
}
// Walls //
while(i < level_walls_num) {
w_x = rand_num(pl_lim_left, pl_lim_right);
w_y = rand_num(pl_lim_top, pl_lim_bottom);
wall_pellet_collision(w_x, w_y);
if(wall_pellet_col == 0) {
walls_x_y[i][0] = w_x;
walls_x_y[i][1] = w_y;
r_walls_x_y[i][0] = w_x;
r_walls_x_y[i][1] = w_y;
}
i++;
}
}
walls_draw();
gamestate = 1; // goto gameplay //
Its really not overly complicated, en_l_ variables set where the left turret will start, and en_r_ variables set where the right turret will start.
Then we get random numbers for how much satellites there will be on the screen (level_pellet_num) and we place that inside the playfield which is
determined by pl_lim_left, right, top and bottom, that is to avoid generating an unreachable sattelite.
Next step we generate a random number for how much wall (blocking) tiles there will be on the level.
For each new wall, we also check if its colliding with a already placed sattelite, you can't have overlap between them, to avoid generating an
'unsolvable' level, so if, and only if, there's no sattelite on that spot, we can place the wall, otherwise, we try a new random location, until
we fulfill the required number of walls.
Then we call for the routine that draws the wall tiles on the screen and move to the gameplay.
This 'random world' is imho, the best thing about the game, because the gameplay is really simple and designing a bunch of levels that are interesting enough to keep the gameplay interesting
even after the player have finished them would be above my skill level, so with the random world sequence, we can at least add a real re-playability factor to the game.
-- Part V : conclusion --
In the end of the day, Raposa do Sol was a learning experience for me, which is why i ended up adding things like SRAM and even voice samples, they
were added more for me than for the improvement of the game experience itself, because saving hi-scores on this game is not something that really
makes or break the same and the same about anyone hearing my voice very muffled saying 'raposa do sol' or 'game over, yeah" (because Sega Rally references are *tight*).
This was very fun to make and i've learned a lot, so i consider this project worth of the time i've invested into it and if anyone can also benefit from this, even better.
Which is why the code is avaiable:
github.com/jflores82/raposadosol feel free to explore it and if you have any questions
just hit the contact button, maybe you too will have fun making little games for the old Sega Master System.