Close

It's starting to feel like a game.

A project log for HTML5 Retro Game Engine(s)

A Side project where I try and build various scriptable retro game engines in the browser.

timescaleTimescale 04/30/2019 at 19:030 Comments

The little online adventure game engine that could has had some major improvements the last session I spend on her. I could list them all, but as I promised video (or it did not happen) last time, here is the current state of the project.

In this short video, you can see me demo'ing the masking feature first. With the crude cursor input I can move around Pitt Rivers in front or behind features in the scene. I an happily navigate around the stone pillar and you can see the (oddly transparent) rock being masked as well.

After that I use the cursor to demonstrate that this type of input does indeed move the object towards it target. This function checks the meta data file and if the red channel has a pixel at that point, it tries to navigate the object there. This function has room for improvement as the object can get kind of stuck at some angles and it now tries to go in a straight line, so when it encounters a zero in it's way, it stops. There is no a* path finding routine implemented (yet).

The final demonstration is picking up the bag and clicking the strange rock which then disappears. These are the first bits of game logic that are surfacing. At this point these are not really important and the implementation is nothing like the final product should work, but at one point it is nice to actually see something happening.

A major upgrade to the render engine also has been made. The obvious one is the ability to vertically mirror the graphic. So when I steer left, the figure looks left. A bit less noticeable is the re-sampling of the image. As this is 8-bit style, it is a simple near-neighbour algorithm. It isn't the prettiest, but it is period specific. Especially Sierra scaled their onscreen assets similarly like this for ages.

I would like to share this function now, but unfortunately it is a bit of a mess at the moment, but that is not a bad thing! Before doing the re-sampling, I was trying to implement basic frame animations. I decided that I do not want separate files for frames, so frames for an object exist in the same PNG, delimiting the boundaries either in the data structure or later via abusing the alpha channel.

The problem was that with opacity, masking, mirroring and scene offset build into the main pixel-wrangler, this function was becoming.. crowded? It started to look like the onset of spaghetti and I was trying to avoid that.

What I needed was a nice in-between function that would handle the frames and neatly deliver it to the drawing function. It struck me that I could roll the frame select function and the re-sample function into one, creating a single image for the main function to draw. So I started with the re-sample function that can be seen in the video and am now in the process of implementing the frame select code.

As you can imagine, the object data structure has grown a bit since its initial inception

objectData[objectData.length - 1]['name'] = "PittRivers"
objectData[objectData.length - 1]['asset'] = "PittRivers1"
objectData[objectData.length - 1]['type'] = "character"
objectData[objectData.length - 1]['frame'] = 0; // which animation frame to draw
objectData[objectData.length - 1]['hidden'] = false;
objectData[objectData.length - 1]['alphaMask'] = true; // use scene mask
objectData[objectData.length - 1]['opacity'] = 1;
objectData[objectData.length - 1]['drawClean'] = false; // subject to filters or not
objectData[objectData.length - 1]['x'] = 35;
objectData[objectData.length - 1]['y'] = 165;
objectData[objectData.length - 1]['Direction'] = -1;
objectData[objectData.length - 1]['zoom'] = 'map'; // map = use Y position
objectData[objectData.length - 1]['curZoom'];
objectData[objectData.length - 1]['action'] = 'none'; // For example "move"
objectData[objectData.length - 1]['targetX'] = 0;    // Move target
objectData[objectData.length - 1]['targetY'] = 0;
objectData[objectData.length - 1]['anchorX'] = 15;
objectData[objectData.length - 1]['anchorY'] = 45;
objectData[objectData.length - 1]['fixed'] = false;

And it will get longer! But eventually this structure will be generated in the asset loader. The movement of the object is very simple. When a targetX and targetY is set and the action attribute is set to move, every tick, the X and Y attributes are pushed a bit closer to the target by a set speed amount. This is handled in what are the beginnings of the state machine where the real action happens!

Plans for the next step will be the frame animation implementation.

Discussions