Snowball update, random infinite runner

The game has not changed much looks wise since I last posted, but I've gotten some important functional changes done. The game now works with a randomly generated route, instead of a fixed one. What this means is the game can be truly infinite, and dynamic as I add more permutations and type of terrain.

To get into the technical changes for a bit, the original code uses a z position, which goes up in value each frame to move through the path. Now though once you pass a segment of the ground, it gets removed from the scene, and put back into the object pool. Once a full section is passed, such as a: hill, straight away, curve, or s curve, a new random section is added. This will go on indefinitely.

Originally each segment stored its index, in terms of where it is in relation to each other segment. I dropped this, in favour of using its array index instead. This allowed me to pull the first element of the array off easily, and add new ones to the end, without having to update a property. However, I did have to update the "world position" of each segment when a segment is removed. The world z position is based off of its array index, so when the array index changes, so must the world position. This is an extra O(n) operation I would really prefer to avoid, so it's something I'm going to have to continue to think on.

cleanupSegments() {
  const baseSegmentIndex = this.findSegmentIndex(position - SlopeBuilder.SEGMENT_LENGTH);
  const segment = this.children[baseSegmentIndex - 1];
  if (segment) {
    me.pool.push(segment);
    this.children.splice(baseSegmentIndex - 1, 1);
    this.setTrackLength();
    position -= SlopeBuilder.SEGMENT_LENGTH;

    // TODO: Think if there's a way to avoid looping through all segments
    for (let i = 0; i < this.children.length; i++) {
      this.children[i].resetWorldZ(i, SlopeBuilder.SEGMENT_LENGTH);
    }
  }
}

As you can see here, I find the segment behind the current camera position. Fetch the segment from that. If a segment is returned, it gets pushed to the pool, removed from the collection. The setTrackLength method takes the children.length by the SEGMENT_LENGTH to determine the current length of the track, and cache it accordingly. The camera position is then negated by the SEGMENT_LENGTH as well. While one solution is to increment the position forever, numbers do have maximum storage values. So I went for the route of subtracting the position, and update the world position on each segment in the game world.

While the route generation is mostly random, down hill has a higher weight, so it will spawn a majority of the time. This is to give the feeling of still going down a large slope. I re-implemented the fire pit hazard, along greatly increased the rate at which collidable objects spawn on the route. Something I'm going to do soon is replace the art assets of both objects. I'm planning to simplify them on detail and number of colours, make it look more stream lined with the rest of the game, and go back to vector art for one of the items. The downside right now is the firepits or objects you collide into spawn in 1 of 3 positions in the lane. It looks a little too static, or programmed in. I hope to play with some variance on this, make it look more organic. The frequency of the objects is really high too, so I might try to put in some more non man made hazards, such as rocks and trees.

Thanks for reading. This game has my focus outside of my fulltime job now, so I should be able to post fairly regular updates.

Snowball, rolling hills

I took a break from development on Snowball Effect for around a month. I participated in LibGDX Jam. You can check out my entry here if you wish.

Before the holidays I implemented hills into the generation system. This evening I finally got the sprites clipping properly, which you can see here!

This was accomplished by referencing a few tutorials on building an oldschool racer from the NES & SNES days: http://codeincomplete.com/posts/2012/6/30/javascriptracerv4_final/. The terrain is in segments. A segment has two pieces of data, each pertaining to the top & bottom sides of the segment. Each side contains an object storing the position, width and scale. It also stores a Vector3 for its original world starting position. This is never changed. The world Vector3 stores the z coordinate, an index of where it sits relative to other segments. It also stores a y coodinate, which is its z coordinate * height.

It then has a Vector3 called camera, which is used to cache the calculated starting values stored in world, and add them against the game's camera position. This is what makes them "move" along the screen.

These vectors are used to calculate the screen position & scale needed each frame. It uses set values I have making up the game world & height.

Segments are drawn from the bottom of the screen, up to the middle where they cap out. As it goes along in a given frame, it stores the lowest Y value achieved. This Y value is stored on each segment. This Y value is then used when the sprites are drawn, from top to bottom, so they draw over top of each other properly.

Drawing a sprite takes its segements top Y value, subtracting its scaled height. It then calculates the amount to clip off by doing:

let clipH = clipY ? Math.max(0, ypos + scaledHeight - clipY) : 0;

So if there's a clipY coordinate, it finds the bottom of the sprite, subtracts the coordinate. Then cap the clipH so it doesn't surpass the sprite's scaled height.

The source image coordinates are relative to the sprite sheet, but the height is then dependent on the clip value.

spriteHeight - (spriteHeight * clipH / scaledHeight)

Height in this case is the sprite's true height, not the scaled value. It subtracts itself, from the percentange that the clip amount takes off of the scaled height. This ensures the amount drawn from the image respects the projection scaling.

The destination height is then simply:

scaledHeight - clipH.

Initially I was drawing from the center of the sprite, so positioned in the middle instead of top left. This lead to a lot of calculation problems with the scaling.

Curves in snowball

It's been a busy week, but I found some time to get back to working on the game. I implemented the much needed curves to the terrain generation.

It feels pretty cool! I definitely need to get it working in random, so I can add a curve, chop off segments behind the player, and then generate new ones on the fly. After that, I will look at adding up & down slopes.

In addition to gamedev, i've been doing a fair bit of advent of code, which is a programmer challenge advent calendar. The problems do tend to align with mathematic challenges, but are more programmer-y than project euler. I've been using Rust to do them, but you can use any language. Check it out if you're looking for a nice break from the usual.

Projection in snowball fixed.

Pretty happy with this progress. I fixed the numnbers and managed to get the projection working correctly. Though a major problem i had was the original code I referred to for this style assumed an anchor point of being smack in the middle of the sprite. MelonJS like a lot of 2d game engines defaults to top left for the anchor point.

In MelonJS 3, a lot of work was done to fix the anchor point and improve it's capabilities. So once I updated from 2.1.3 to 3.0, and fixed my code to follow the changes, the projection essentially fixed itself. So now, it looks like this:

The updated game is playable here: http://projects.agmprojects.com/snowballeffect

Snowball v2

A little bit ago I decided to take a break from the stealth prototype, and revisit my snowball game to make it good.

I have a game out on ios already, and you can play it on in your browser here: http://agmcleod.itch.io/snowball-effect. I decided to re-visit it as I feel like I can make it a much better game. What i've done so far is got rid of the level system, and I'm going towards an infinite runner. Where instead of having a max length of a slope, you just keep going. Slowly getting bigger. As you collide into things, you fill up a skill bar. You can use this resource to have snowmen launch themselves at fire pits. I have other ideas as well for things like jumping, putting an ice shield on you, etc. The dev version is available here: http://projects.agmprojects.com/snowballeffect/

If you hit too many fire pits, or other traps and get to small, game over. The idea is to keep growing and stay alive as long as possible.

Another major flaw with the game is the fact the backdrop is not all that interesting. So something I am working on now is making it more dynamic. Instead of a static image, im going about implementing a 3d feel similar to retro car/racing games. What i have so far:

The trees still need to be redone. But i have the collidable objects rendering on the slope. The calculations still need some adjustment. Once I have that right, I can update the trees to render along side the slope properly, and add terrain to the side as well.

From there add things like curves, and and down hill, etc.

Stealth Prototype - The first hack, one of many i hope

As I mentioned in the last post the focus of this prototype is going to be sneaking, and hacking to avoid enemies as supposed to killing. So I wanted to add a hackable wall that allows you to circumvent the enemies. It's a vent duct of sorts that you can sneak into. The hacking for it is super simple, just a press button with a timer.

Note that nothing visually differs the wall to show it's an area. This is something i plan to change, but I still want to keep it a bit secret. You need to brush up against a small section, roughly two tiles high, and then you can press E like the UI says. Once you do, a bar starts filling up:

Due to the fact it takes time, you're at risk while standing there. As displayed before, an enemy will either chase you, or shoot you straight away. So you need to make sure to time it properly. This is one of the things I really enjoy about game development: tweaking and cleaning up the gameplay. Making it so it's challenging, but fair. It's hard to pull off in some cases, but feels great when it works. Planning is very important. I sketch out level ideas and type out design concepts, but you won't know what works out until you try.

Once the hack finishes, you can go through the wall:

As you can probably tell, the walls on each end still look like walls. Their needs to be a way to identify the wall tiles on both sides of the vent are now passable. Something along the lines of hide or change their image when the wall is hacked. Without that, it's hard to know what the hack actually did. For all the player knows, maybe the hack disabled a turret further down the path. That's the next thing I plan to work on.

Hacking needs to be more interesting than this. Nothing coded yet, but did a sketch on the UI I'm thinking of:

The first sketch is a bit messy due to edits. But the left section is meant to be a metallic keypad of values 1 through 9. The second device attached by a cable scans the code over time. Filling the numbers, similar to the green numbers filling in at the start of The Matrix. Type in the number wrong and click the confirm button, the alarm goes and guards will come to your position.

The second sketch involves a metal plate that has a screen on it. The attachment takes a few seconds, and scans the unlock pattern. A similar unlock mechanism to that of android phones. You join the dots together to unlock it. 2-3 failed attempts will cause it to fail, and guards will come after you.

The Start of a Stealth Prototype

For the past month I've been working on a top down 2D stealth prototype. The game itself will evolve into much more than a stealth game I hope. I have bigger ideas for it, but for now I want to explore some of the concepts and ensure they will work.

So like most prototypes you start off drawing simple shapes, or using very little art, much like below:

As you can see the walls have boxes around them which are collidable bodies. The first level here is static. It's broken up into individual parts, and placed relative to each level. Using libgdx this process was actually fairly straight forward. What took some more doing was getting the camera to clamp to the edges of the level, while still following the player.

Movement with box2d, even arcade movement is pretty straight forward. Just have to set linear velocity accordingly. I've read from others in the past "don't use a physics engine for a platformer!". Honestly, I disagree. While you can point to funny examples like Box2D tetris, using it correctly can yield a lot of benefits. AABB collision & correction can be simple, but once you want to use polygon shapes, or triangles. I have 45 degree angle walls for example. It gets much harder on the math. I'm not very good at physics stuff, so I leverage Box2D.

Once the level got layed out, it needed some guards:

The guards have a cone vision, very similar to that of metal gear solid. The AI is super simple right now. There's two modes: chase or shoot. Both types start off patrolling from one point to another. If they catch you in their cone, they switch to their designated mode. The Chase one is pretty straight forward:

The red signifies you've been spotted, and the npc will chase you. If the npc catches you, you're done. If you get away, the NPC goes to your last position and looks around for a second:

It's pretty neat, but I have to say i'm not finding it compelling enough. I'm going to explore more group mentality with the NPCs in the near future. The AI in a stealth game needs to be perfect. For the shoot npc, if you get caught you die. They are very unforgiving, and will shoot you quickly and deadly.

The general view for the character at this time is completely non violent. They will use cunning and technical skills to hack around their enemies. Once I get the AI the way I want it, hacking puzzles and work arounds in the level is what I will explore next.

Thoughts on multi platform solutions

A couple days ago, I was at a JavaScript hacknight here in Toronto. I know the organizer (Dann) reasonably well, as i've been going to these events and other ones like it for a few years now.

I myself have been diving into cross platform solutions for a while, typically involving the JavaScript stack. I've messed around with nwjs a bit for desktop html5 games. I've used cordova for a couple projects at work to create android & iOS apps. I've written HTML5 games with various web libraries that are bundled in cocoonJS for the mobile app stores.

More recently for web content, I've been learning ReactJS. I have also watched the recent talks on React Native. All of these tools I find tend to serve two main purposes that the native frameworks do not:

  1. You can write the applications in a language you're familiar with
  2. Have more transferable code.

Obviously these vary from framework to framework. I'm sure we'll be using different components in iOS vs android environments with React Native.

I started talking with Dann about building native mac & windows apps with html+css+js and using NWJS, and how it almost feels wrong. Like we are clinging to the stack almost too much. No doubt it can be done, and can be done well. Atom is a good example of this. But I think there are limits.

Now let's say I wanted to build a markdown editor, as I'm picky and don't care much for the ones that exist already. The abstraction to native APIs that I would need would be writing to the file system. NodeJS makes this pretty simple, so an application like this is quite practical to build using a JavaScript stack.

What if I wanted to do something more complicated than that? What if I wanted to do a garage band type application? Where I'm able to record from an audio input device, split up a track, adjust volume levels, and export an mp3. This really steps up the difficulty. I'm sure it's doable with our beloved JS stack, but it's going to be much more practical using Cocoa APIs, and likewise the newer APIs in windows 8. Obviously that kind of application is much larger and vastly more complicated than the markdown editor. However, as I've worked on Cordova apps at work, it's easy to run into little problems here and there that an existing plugin doesn't solve. So you either end up writing your own plugin, or doing a bunch of hacky solutions JavaScript side, or you just leave it as a bad experience.

Over the last couple days, I have been doing some eesearch at work. The goal is to take 4 photos with an iOS app, and turn them into an animated gif. This gif would also require a client logo watermark on top, and it to be grayscaled. My tech lead found a pretty decent JavaScript plugin for putting images or video together to make a gif. However, the only way I could make it work with pure Javascript code, was to take 4 photos individually. Four calls to the camera plugin:

html_button.click ->
  launch camera plugin ->
    take photo ->
      confirm/retake ->

That was for each of the four pictures, so around 12 button presses. That's no good. My tech lead managed to find a tutorial on doing a custom camera plugin. We figured might as well try it for a couple hours, and see if it's practical. So I got started on it from the tutorial. I added some minor changes to it, as it had a couple bugs. Once I could take a single photo, I modified the Objective-C code a little bit to add an array of photo urls. Applied the resize & grayscale, then passed the array to the webview. This only took a few hours of work total. If I were to just pass the raw images to the web view, I'd have to then using multiple async calls to the file system. Resizing them with the canvas and grayscaling them would be so much more work, especially due to memory limitations of the webview. The simple & synchronous code on the iOS side made it this process much easier.

Now granted, if this project was going on android, windows phone and other devices, it becomes a bigger task to maintain the code base. But I felt quite pleased on the results when building a feature in the native side. At least this way, we can still leverage our design team on HTML & CSS. I know from now on that with Cordova, if we need more than the plugins provide us, there is a way.

I brought these kind of examples to Dann's attention. He responded, which I'm paraphrasing "It is quite silly that we have to use different languages for these platforms. Android runs Java, and iOS runs Objective C/Swift, this just adds friction for developers that want to build applications. It's these greivances that causes us to explore solutions that can work for each device. We create a common API that invokes the proper specific calls based on the platform."

He's absolute right about that. Frameworks like Titanium and Cordova do go for the write once, run everywher approach. However, with the speed that android & iOS move at, it's hard to keep up with all the native APIs. With Titanium, you can't write native components, you're stuffed if their API doesn't do something you need it to. This could very well apply to React Native.

That said, I do think it's worth it. I think with enough brains behind it all, and push for good practices, we can make these cross platform solutions work. Looking back in our history of hardware and cross platform support, very smart people worked on compilers that could work with various CPU architectures, so we could write things like C code on various computers. The web browser gives us a JavaScript run time that works fairly reliably across platforms. In the gaming world we have transpilers of HLSL to GLSL. Blizzard Entertainment has supported Mac & Windows games for years, signifying they must have tools for writing D3D code and OpenGL code with a native API.

But of course, we still have platform detection code. In game code I sometimes see #if windows, #if osx type calls. We will write different versions of shaders depending on the OpenGL version supported. Older code we wrote platform specific stuff, with the cordova app I wrote platform specific stuff. We all need to be smart on when we use certain tools. At the end of the day, use the right tools to deliver the experience you want to deliver.

Working on art, level design, it's tricky stuff

Kudos to all you artists and designers out there. I know it's a tricky skill and takes years to develop, but I have even more respect for you after trying to make my own assets for Search For Hope. A short, 2D platformer that I am working on.

I haven't published my latest changes to my site because I like my deploys of games to be somewhat stable. But here are some visual updates that I've done.

The background for the intro now has some smoke/dark clouds above to hopefully give a more eerie atmosphere. I also added the cracks to the buildings/windows to show more destruction. I find this kind of challenging, as one really needs solid imagery to go with when they don't have the practice.

I updated some of the existing tiles, and added a few new ones. Mainly the dark gray rock tiles to have different shapes & edges to give it that more organic look for the underground. Again pretty simple art here, just trying to get by until I really get the game fledget out.

You'll notice a few lighter pieces in the middle. Those haven't been updated yet, but the theme of them is still accurate. The overall idea is that the further down you go, the better and more positive the scenery gets. And it keeps improving that way until you find the character a new home.