2D Sidescrolling Toolkit

I’ve been building a 2D sidescrolling “toolkit” - ie software that can be used to build a variety of sidescrolling games. It’s packed with animation, as you can see from this simple level

https://www.youtube.com/watch?v=Uzw3TJkayJM

For demonstration purposes, I’ve only used images provided with Codea. Level maps can be easily built in Codea as ASCII tables, using letter codes (as shown at the end of the video) to tell Codea what to put where.

I did this mainly to see what was involved, and how much Codea could do. 2D sidescrolling doesn’t sound hard, but it has taken me many dozens of hours over a couple of months, and I have probably rewritten it four times. However, I’ve satisfied myself that Codea can produce pretty awesome results.

I’m planning to ultimately share the code so people can use it as a template, and probably write an ebook around it as a guide to designing various parts of a sidescroller (and how not to design them, because I have made a lot of mistakes along the way!).

If anybody wants to get involved and help take it further, let me know, because I am not going to produce a complete game. However, following the code requires a pretty good understanding of Codea, and I’ve invested a lot of time in it, so at this stage, I’m going to share it very selectively indeed.

Hey, @Ignatz, I love the idea, and kudos to you for putting in so much work! It’s something codea has needed for a while, something I considered doing myself when I get skilled enough, and something I’m very glad to see that you’ve made! I hope this helps out a lot of beginners and makes sidescrollers so much easier to make (something that still poses a challenge to me). That said I’m having trouble viewing the demo though, so I have a couple of questions! Can the level editor be used standalone to make games that scroll along both the x and y axes? I am currently working on something big (well, big for me), and am stuck at the level editor stage. If your library can solve my issue, I would be ten billion more times interested than I already am.

@Monkeyman32123 - you can make game levels of any size with this project. So if by “scrolling” you mean the ability to go beyond the limits of the screen, definitely yes. The demo shows that.

Here is a direct link to the video above

very nice!

@Ignatz,

Looks amazing! Did you write a level editor to create the levels or have you crafted them by hand? If the former, how did you approach saving and loading? I looked at this but wasn’t overly pleased with my approach when looking at foggy bummer. How did you approach collision detection? Do you cross reference the player position with the “map” to establish whether there was ground present or did you implement in physics?

@West - I have a level editor. You provide a table of characters, one per tile, to define what goes in each tile, like this below - the entire level of the demo game. “g” stands for an earth block, “w” is water, “m” is a coin, “-” is blank, etc.

 local mapText={ 
    '-----------------------',
    '-----------------------',
    '-----------------------',
    '-----------------------',
    '-----------------------',
    '-----------------------',
    '----m-----cu-----------',
    '----m---m-r------------',
    'b---m---b-------kb----b',
    'b@-----bb-----t--bF--lb',
    'ggggggggggggglggggggglg',
    'ggggggggggggglggggggglg',
    'ggggggggggggglggggggglg',
    'ggggggggggggglggggggglg',
    'g-----------glggggggglg',
    'g-L---------glggggggglg',
    'g--m---h-f---lggggggglg',
    'g-------i----lggggggglg',
    'g-ggggggggggggggggggglg',
    'g--------------------lg',
    'g----------m-----m---lg',
    'g-------y----s-------lg',
    'ggggwwggggggggggggggggg',
    'ggggggggggggggggggggggg
}

This is compact and makes it very easy to define and edit levels. The levels can be any size you like. You can also easily redefine what the letters stand for, or add new ones. I put each object (other than simple blocks) in a class, to allow for maximum flexibility.

Background images are added by defining which tiles they cover, so that has to be done separately at this stage.

Collision detection was extremely difficult, not just for enemies, but also for walking, jumping, landing on blocks, moving on ladders etc. I ended up using a lookup table for the tiles containing blocks, to tell me which tiles couldn’t be entered, but for the enemy sprites, I used an AABB overlap test. I used a simple downward force for gravity, and an upward force for jumping. I turned gravity off while on the ladder.

Lighting is done with a shader, as you might imagine.

@Ignatz Codea can do a hell of a lot if done right, this is a good example of that. I imagine the collision took a lot of tweaking too, great work.

@Ignatz - That look amazing ! great work. On my side, I’m building a sprite (animated) editor. I’ll be glad to invest some time in your project if you think I can have some skill to help.

This is awesome!!! @Ignatz please be My master!!!

@llEmill - thank you, but I am nobody’s master…

@toffer - you certainly have great skill! I guess you are talking about how to create animated objects that can be used in projects like mine (and others like Fogbuzz etc).

I started out trying to use Simeon’s Juice effects library, which has jumps, spins, bulging, squashing etc, based on tweens, and I found it was too difficult, because (as I said to him):

"Suppose I have a continuous side scroller, and the character moves along smoothly along a level surface. If he comes to a hole, he should fall in, and if he comes to a wall, he should stop. If he jumps and hits the ceiling, he should fall down.

This means I need collision code that continuously checks whether there is a surface below and in front of the character (and above, if the character is jumping).

If I use an animation effect like Juice to (say) bounce up, I can use the getActualPosition function to get the true x,y position and test for collisions with the roof. If a collision occurs, I need to stop the animation and somehow get the character down to the floor again without the help of Juice.

If I use Juice to leap up and sideways, eg to jump up onto a higher block, Juice will not realise the block is in the way, and I will have to use collision testing to decide when to stop the animation. If the player collides with the side of the block, I will also have to interrupt that, and get the player down to the floor again.

If the player jumps sideways, and there is a hole, the player will need to keep falling in a convincing way after the animation ceases (ie once the player falls below his current level), in a continuing arc rather than straight down. This means my code has to integrate closely with Juice to produce a continuous movement.

A complication is where you include a spin animation. If the player collides with the roof while spinning and partly upside down, I don’t want to really have to think about how to get him back on the ground again, the right way up, having interrupted the animation.

Another problem is that several of the Juice animations start with a slight downward movement that pushes the character partly through the floor. This causes a collision which (in my code) cancels the animation before it starts, unless I make my collision code smart enough to ignore initial collisions, which gets messy. I think none of the animations should go below the current floor level, at any stage.

Finally, there is no function to tell the developer when an animation is finished. This is important."

All this is a pity, because Juice has some great effects.

So the main problem with custom animation effects is how to interrupt them if the player collides with something while the animation is running. I came to the conclusion that it is too hard to do this, but you may have a solution. If so, I’d be very happy to hear it.

@Ignatz - It’s a pixel editor. You draw frame by frame and exports a spritesheet from it.

From the the few 2D engines I’ve build, I’ve learned that moving and animating sprites with a separate tween system is a lot harder to manage. All your tween informations (velocity, size, mass, etc…) are separated from the engine itself, mean that is harder to predict / check for collisions, triggers…

As I don’t know how you use Juice and how your engine loop is done it’s harder to say if it’s better to rely on a tween lib or not.

But I can see that when you fire a tween, this one is predefined to go from A to B during a time T, so you must ‘break’ it if something have to cancel/adjust it. That is different when you have all your sprites properties (vel, acceleration…) adjusted from within the engine loop at each frame tick according to the game environment.

Hope it makes sense.

@toffer - I think a spritesheet would be very useful for "in place"animation, ie animations that don’t change the position of the player, eg animations that flap wings, or make legs walk, or make a smile. It’s when the animations change the player position that you get into trouble.

@Ignatz, when using Juice and colliding, can you not just call another juice to override the current one and react to the collision?

@JakAttak- short answer, no. If you look at all the scenarios I outlined above, it would be impossible (in my view) to do that.

@Ignatz - long(er) answer (after I looked into it), Juice lacks a way to stop the current action.

I played with it a bit, and added a method to Juice that halts all current actions and (smoothly) returns the object back to its position (or another specified position).

With this addition, I think it would be easy to just call that function when the player collides with something, and have it smoothly return to an allowed position.

@JakAttak - does it work even if you are upside down at the time of collision?

Does it work if you are jumping and hit the side of a block, and need to slide straight down?

It would be good to see a simple demo…

@Ignatz, yes, and yes - because you can provide new position, scale and angle for the end of the reaction.

Here is a basic demo:

https://www.dropbox.com/s/0imgbpywutg6wzl/Video%20Sep%2005%2C%207%2000%2012%20PM.mp4?dl=0

@JakAttak - if you share the code, I’ll try it out :slight_smile:

Here is the modified juice library: http://gist.github.com/JakAttak/21a3ad3027a6ac3e273e

The new function is used as follows: object:stopMoves(duration, tbl) duration being the time it takes and tbl being the end result (if you don’t want it to return to its original position, like so: tbl = { pos = vec2(10,10), scale = vec2(2, 0.5), angle = 120

Look in the touched function of main to see a basic example.

If you have any issues, let me know, I’m happy to keep working on it so that it works at its best in every scenario.

ok, it may take me a couple of days to get this included, but thanks