Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

How to create a Platformer
Started by redninjacat Feb 19 2016 07:38 AM

* * * * - 2 votes
49 replies to this topic
platformer tiled tiles platform
[TOPIC CONTROLS]
Page 1 of 2 1 2
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

I am actively working on a puzzle game that will be released in the next month or two. I am already looking ahead to future games though and would really like to create a Metroidvania-style platformer. I have played with both MTE and Dusk a little. It seems to me that with enough work I could certainly create a decent platformer using either of these engines. The key words here are "enough work"! Neither of these engines seem well-suited to platformers and actually seem to be more suited for top-down dungeon-crawler kind of games.

 

Can someone please point me in the right direction to get up and running quickly with a simple platformer using Tiled or something like it? Is there a tutorial out there I have not seen? Does someone have a sample project they can share or point me to? Anything would help! Thank you!



[TOPIC: post.html]
#2

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

I am also a fan of the classic top-down Zelda games, which these engines do seem to be well suited for. So I would definitely appreciate being pointed toward a tutorial or working sample project for a Zelda style game too.

 

I am aware that Dusk and MTE both include demos, but none of them deal with things like dynamic enemy spawning, transitioning between "rooms" or levels, that kind of thing. They are very rudimentary, and frankly buggy, demos.



[TOPIC: post.html]
#3

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

Have any of you Windows users used Level Director? If so, would you recommend it for what I am wanting to do?

 

http://www.retrofitproductions.com/level-director/



[TOPIC: post.html]
#4

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

These types of games have several challanges - drawing the level is only one of them. MTE and Dusk will happily draw them, and in reality drawing it isn't hard (although drawing it *quickly* is more challenging and fun. MTE and Dusk aren't IMO particularly optimised, but then optimisation is something I really enjoy tinkering with so I'm likely more demanding than others).
 

So much for drawing :)

 

Other parts include things like game logic, enemies, pick-ups etc, but to be honest all of these are relatively trivial issues once you have the next (and in reality, the overall biggest) issue sorted well - collision detection.

 

It is in this area that I think far too many people (particularly in Corona, for reasons I will detail later) attempt to solve using the inbuilt physics engine. This, to me, is a huge mistake. Here's some of my reasoning:

 

- Physics engines are inherently unstable (they often take a few seconds to approach stability).

- Physics engines are usually non-deterministic (which means re-running a simulation several times from an identical start state which result in different outcomes).

- Physics engines, while easy to set-up crudely, require a lot of time tweaking to approach what you want.

- They are essentially a black-box - you don't get fine or total control (this may not be an issue for most people, but I *hate* this!).

- Physics engines do not scale well to a (potentially) infinitely large tiled-world (which is likely why you want to use a tile-based engine in the first place).

 

I will add that I in general *hate* physics engines, so take the above with a pinch of salt ;)

 

So, what is the solution? Write your own collision detection. This is almost certainly why many people go down the physics engine route. It can appear daunting, and since Corona is marketed as enabling easy creation, the idea that new coders would come in and then be told *not* to use what appears to be a helpful engine is naturally slightly counter-productive. However, I'm reaching out now to people what want to create something more professional, so I'll continue in this nature.

 

Why would you write your own collision engine (note I didn't say physics engine, for now)?

 

- Total control over all collisions

- Once it is set up, you don't need to worry about it again (with physics, every time you add something new, it requires more tweaking).

- The nature of tile-based engines means it is extremely well suited to home-brewed collision code.

- It *can* be faster than physics engines (depends on your coding abilities and complexity, naturally).

- Stability.

 

So, how would you go about it? There's varying degrees of complexity, so I'll start from the simplest and work my way up.

However, there are some choices to be made right from the start, namely what type of collisions do you intend to deal with?

A physics engine automatically deals with solids against solids (whether 2d polygons or 3d models).

In tile-based engines this is possible, but isn't necessarily the fastest nor the most satisfying solution.

Think about your player. Here are some of the more common possibilities:

 

- Player rectangle against level tiles

- Player point against level tiles

- Player raycasted against level tiles

 

Rectangles VS level tiles (or other rectangles) collisions is actually trivial in isolation, especially in a platformer where we almost certainly would use just AABB (axis-aligned bounding boxes). This means your rectangles won't rotate. This simple limitation makes this *very* simple to code. It is, however, more complicated in that it results in more collisions to process and is slower as a result.

 

Points VS level tiles (or other rectangles) is the simplest there is. However, it is often impossible to reduce larger objects like players and enemies down to a single point, meaning the collision results won't be very satisfactory.

 

Raycasts VS level tiles etc is what I use (a technique shamelessly stolen from Sonic the Hedgehog!). It is an extension of points VS level tiles, and allows for mimicking volumes. I personally am only allowing for AA rays (axis-aligned) for simplicity and accuracy, btw. It can get complicated with large volumes, so isn't recommended for everything.

 

It should also be noted that these engines generally don't handle arbitrary directions of movement. They would break each movement down into individual movements in the X and Y axis. This is more accurate and vastly simpler.

 

OK, so here's 2 approached of differing complexity.

 

1) The basics. Tiles are either solid or not.

 

If your tiles are (say) 20 x 20 pixels, then this means any time a point or rectangle crosses a 20 pixel boundary (x % 20 == 0) either horizontally or vertically, you need to check for the new tile you are entering. Likely using a lookup table (eg tiles using frame 20 have a list of properties including solid or not), you'd check if all the newly entered tiles are solid, and if so, move whatever entered it back by precisely enough pixels so that it no longer is colliding. If you are doing rectangle VS rectangle collisions, don't forget to check the leading edge, so if moving right, check the right edge of the moving rectangle against the tiles, if moving down, check the bottom edge etc. So you might have something like (this is an example only for horizontal movement *to the right* - for movement to the left you'd swap the signs on some of the maths):

local x, y, dX = player.x, player.y, player.dX
local halfWidth = player.halfWidth
x = x + dX + halfWidth -- You check the right edge of the player, plus the amount you want to move

local tileX, tileY = math.floor( x / 20 ), math.floor( y / 20 ) -- Assuming tiles of 20 by 20 pixels
local offsetX = x % 20 -- This is how far into the given tile you have gone horizontally

local tileToCheck = map[ tileX + 1 ][ tileY + 1 ]
local thisTileProperties = allTilesProperties[ tileToCheck ]
if thisTileProperties.isSolid == true then
    x = x - offsetX -- There was a collision so we move you backwards to the edge
end

player.x = x - halfWidth -- Set the player x to this value (removing the half width from earlier)

2) Slopes etc.

 

This gets to be more fun. You need an additional data structure that represents the shape of the tile. I, for simplicity, simply have a linear table defining the height of the ground (or ceiling as well if you need that - I allow a tile to be either ceiling or floor, but not the same at the time). In this case the collision needs to look up which pixel you are referencing, for which you would use the offsetX value. In my case it'd be something like:

local thisTileProperties = allTilesProperties[ tileToCheck ]
local floorHeight = thisTileProperties.floorHeights[ offsetX + 1 ]

Now, you can respond to this by moving backwards out of the tile like in the first bit of code, but this wouldn't factor in if the floor is lower generally than the point checked. This is why I use raycasting rather than a simple 'is this point colliding?'.

 

If you start from X, and you move dX pixels right, I'd check *every* pixel from X + 1 to X + dX, so you find exactly where the collision is - pixel-perfect.

 

 

So how do you turn the above into a collision engine that handles psuedo-solids like sonic the hedgehog? Here's how:

 

The player X and Y are basically the center of the object. We also have the player's half width and half height. This enables us to find the edges. So, here's the fun part :)

 

1) Cast a ray horizontally in the direction of movement, and resolve that collision.

2) If jumping, cast a ray vertically up to see if your head hit anything - resolve that collsion.

3) If falling or simply not jumping up, cast a ray vertically down either by the rate of falling, or by your gravity strength + plus an amount equal to how well you want your player to move over uneven terrain. If there is a collision, resolve it and mark your player as standing on the ground. If there is no collision, then mark your player as falling if not already, and react accordingly.

 

That's pretty much it. I use a slightly more complicated method using two vertical down rays to enable me to make the player object respond to uneven terrain (his his feet follow it more accurately, and to find if you are balancing on the edge of a tile, for example).

 

Note you can mix and match. I do my more complicated check *only* for the player - enemies get a simpler check (only 1 horizontal and vertical ray each), to keep speed up.

 

 

OK, so why do I talk seperately of physics engines and collision engines? Because in general, people use physics engines for collision. Touching pickups / enemies and things like jumping with gravity are trivial problems to solve, but collision is not (although not as hard as you may fear!) So - the core issue for me is creating a solid collision engine, and you write your own simple physics over the top of that, and that really isn't as big a deal as you'd think, because it essentially boils down to how you move your player.

 

If you want acceleration in player speed, maintain an acceleration property and increase that every frame the player wants to move in the same direction, reducing it when not pressed. Add this to the speed, instead of doing something like speed = speed + 5.

 

If you want jumping / falling, you need a property like isOnGround, gravity, fallingSpeed (negative for up, positive for down most likely) and fallingAcceleration. Let's say you are standing on the ground and want to jump, you'd first check if isOnGround == true, and then set fallingAcceleration to whatever negative value you want, and then add this to fallingSpeed, which you then add to the player's Y. Don't forget to mark isOnGround to false.

Then in subsequent frames, change fallingAcceleration by adding the gravity variable, so you curve in the air and begin to fall. As long as you remember to check below the falling player and set isOnGround when a collision occurs, all is good.

 

The two above cases will cover 99% of all player collisions with the level - just about everything can be broken down into either a horizontal or vertical movement, or both (one at a time).

 

It really doesn't require more.

 

OK so for now that's all I'll write, maybe later I can comment on things like enemies and pickups etc. If interested, let me know what you'd like to read about :)



[TOPIC: post.html]
#5

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

@jerejigga, I saw your comments above on what interests you, I'll cover some of that later on :)



[TOPIC: post.html]
#6

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

Wow! Thank you Rakoonic! This is a fascinating read! If you haven't already, you should seriously consider writing a book on this stuff!

 

From how I am interpreting what you are saying, I could use Tiled to create my levels and set custom properties on the various tiles that include physics and other data. I could then read in these tile maps using Dusk, MTE, or even a very simple Tiled file loader, but without enabling Physics. Instead, I would use code that behaves like you have described to implement my own collision detection and gravity and such. For pick ups and doors and such, that seems like that is just a matter of specialized collisions. Could bullets or other fast moving objects work using these methodologies? It seems that they might pass through their intended target at times.

 

Both MTE and Dusk have demos that use custom physics. Do you think these would be good places to start? Or would you recommend shying away from these engines altogether?

 

Again, thank you so much for any tips!



[TOPIC: post.html]
#7

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

I'm not aware of how custom their 'physics' is - I've not gone over them in depth myself, but if you have examples, I'm always curious :)
One thing I try not to do is label my collision engines as physics engines - these are generic and often overly complicated solutions that work in similar fashions. I'm a much bigger fan of simpler, quicker and above all more specific solutions. For example, in how many platformers do you need to collide 30 randomly moving / rotating objects at once? Pretty much none :)

 

So your main paragraph is correct - you could easily set up everything in Tiled, load it in and process it how you want. This is exactly my approach in fact. You still have the possibility of splitting things up - there's no reason you couldn't use MTE or Dusk for *drawing* the engine, but you handle the collision yourself.

 

Here's an overly complicated breakdown of a demo Tiled level of mine, for the demo located here: https://www.dropbox.com/s/uvj2881rrbo1jyg/platformer.apk?dl=0

Firstly I have two tilesets - the actual visual tiles, and a second never-drawn set of collision tiles. I keep the collision data seperate from the visuals purely for convenience - it allows me to do various things but this isn't a necessity.

 

Secondly, just the level shown has a whopping 17 layers (!). These are, in order from front to back:

 

1) Objects
2) Lifts collisions

3) Lifts

4) Parallax near

5) Collision

6) Platform objects

7) Foreground

8) Game objects

9) BG slow

10) BG near

11) BG far

12) Parallax middle collision

13) Parallax middle objects

14) Parallax middle

15) Parallax far collision

16) Parallax far objects

17) Parallax far

 

Screen Shot 2016-02-19 at 13.07.18.png

 

Now, this is massive overkill, as it is a test bed, but it shows several important things about setting up levels and Tiled:

 

- Not everything in Tiled has to be tiles. Many of these layers are object layers - it is here that you'd place enemies, power-ups, spawn points etc. I do use a *small* amount of shapes, but only ever rectangles (I use these to define doorways / exits and also tile-based objects such as the lifts) or lines (to define paths of special enemies or lifts etc).

- You don't have to draw all the layers. Any tile layer with 'collision' in the name is not drawn, but I use the data for collision purposes.

- Tiled is *really* good and flexible generally ;)

- Tiled essentially is a way of creating level *data*, not just how it looks.

 

So here in this file in layers (you can hide them as you wish of course in Tiled, it doesn't always look this complicated!) you'll find the level graphics, including all the layers of parallax, and all the 'entities' (IE objects both visible and invisible). Everything you need, once you have your code understanding how to import it and use it. And the importing is really simple - the LUA export from Tiled is excellent, and means you can just require() the file and not have to import or do any conversions (such as from JSON etc).



[TOPIC: post.html]
#8

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

I should also add that pixel collisions works just as well for platformers as it does for top-down zelda-type stuff (as indeed my APK demo above shows!).

 

To answer some of your specific questions:

 

- Fast moving bullets etc passing through objects.

 

This is a potential problem yes. There are several potential solutions. If you use rectangle VS rectangle you could expand the bullet to include its movement vector. For example if a bullet is a 10x10 collision rectangle and it moves 30 pixels right in a frame, you could make the rectangle be 40x10 instead, so it includes the 'sweep' of the movement. One major problem with this approach is it only really works on movement aligned to an axis. If the bullet moves 30 pixels up AND 30 pixels right, expanding its boundary to include this means you'll end up with a very big rectangle that actually includes a lot of space the bullet itself never touched.

 

Another solution (more a hack!) is simply never use anything that moves too quickly ;) But we'll ignore that because it is embarrassing!

 

A more reasonable solution is if you use rays, these check every intervening pixel in the movement, which means it will never miss a collision. If you expect to have a lot of stuff moving around though, this can add up very quickly.

 

Another solution is to have a maximum 'check' limit. If for example you have objects that are 10 pixels thickness minimum, then you'd break any movement down into sub-movements that are never more than this limit. So with a 10 pixel limit, if you want to move 35 pixels you'd move 10, 10, 10 and 5 (assuming all previous checks show no collision, naturally). This is a solid and easy solution to implement for things like bullets, and to be honest you'd be surprised at the tolerances you need. For a game running at 30 fps per second, something moving 10 pixels per frame is actually pretty damn quick :)

This does raise one interesting point, and that is that your collision / data representation of the level does *not* have to match the on-screen resolution. In the same way we are used to the concept of different scales (eg retina and non-retina - 2 sets of different resolution graphics being placed in the same virtual resolution), we can use a lower game / collision resolution to help speed things up.

 

For example, you might have visual tiles of 64x64 pixels each, but only have a game resolution of each tile being 8x8. This means fewer collision checks, and quicker ones to boot. I use this approach without problems. You do however need to be comfortable with the general concept of programming a game that works entirely in data structures, with the visuals being entirely seperately handled and purely an interpretation of what the data shows (this is a very different approach to physics-based games, where often the sprites and tiles *are* literally the things being collided against).



[TOPIC: post.html]
#9

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

The other topic, which is different from that of physics engines, is seperating out your actions.

For example, it is entirely normal to have 1 set of collision code for objects VS level, bullets VS level, another for objects VS other objects, and yet another for bullets VS everything. This allows you to tailor the code where needed, and in particular optimise massively in cases where you'll have a lot to check. Each of these could use entirely different methods of collision, eg:

 

- Objects VS level - the full collision as mentioned above using multiple rays

- Bullets VS level - simple check to see if the bullet ended up inside a tile or not

- objects VS objects - simple bounding rectangle checks

- bullets VS objects - points within bounding rectangle checks, likely with culling by splitting the screen up into another grid (so a bullet in the top left knows to only check against objects in the top left, reducing the number of more complicated checks).



[TOPIC: post.html]
#10

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

Another thing of interest is that for games such as this, you likely want to break away from the Corona way of doing things (with timer, events etc). Control everything strictly, then you know exactly what happens and when.

 

All my games now have the game engine and draw engines apart. The game engine is what processes input, updates the players, enemies, bullets etc, while the drawing part is completely seperate. I do this because I'm not a fan of tying the visuals into actual game actions - for me the visuals should only ever represent an (accurate) snapshot of what the game itself is doing, so having the visuals influence the game is not a good idea (I'd go as far as to say, bad practice in many instances).

 

What do you get from seperating it out? I mean, apart from simplifying code? :)

 

Well, of interest to me is multiplayer. If the visuals are just a look into what the game itself does, you can create multiple different copies of the visuals without affecting the game at all.

 

Another thing is that your game will run consistantly despite fluctuating frame-rates. That is *not* to say that visually it will look like it runs at the same speed regardless of framerates, far from it. What it means is if you play a game on an iphone 6, the end state will be identical to a game running on something rubbish, even though (for example) the framerate will be different. This is known as fixed time step - for every game frame you always run the same code, regardless of how long that frame takes to process. The physics engine in Corona can be used like that, but often it isn't, and the differences this introduces into games is subtle, but real.

When you combine this with the fact that physics engines aren't deterministic generally (deterministc means if you start from a given position and run the simulation various times, it will always play out the same), means physics engines are normally an exercise in variability *limitation* because it is inherently impossible to remove.



[TOPIC: post.html]
#11

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

Regarding Dusk and MTE non-Box2D physics:

 

Dusk has a demo in which the Box2D physics are not used at all. Instead, all of the collision detection is done using proximity checks.

https://github.com/GymbylCoding/Dusk-Engine/blob/master/Demos/spin/main.lua

 

MTE has a Sonic demo that uses a very similar, although more complex. technique.

 

Neither of these demos use raycasting. They both use objects bounds and proximities to determine when something is "touching" something else.

 

Regarding your sample Tiled map:

 

Dang! That is a crazy thick map. But hey, if it works for you... I think I could manage with easily under 10 layers. I think. Regarding the collision layers and other "objects" in that map, I have done enough experimenting with Tiled and MTE to know that that is how I will most likely handle that too. I really don't like the idea of putting physics bodies directly on the tile.

 

This is all for now. I have other thoughts but need to do some other things. Needless to say that, once again, you have presented some really amazing ideas, especially that last part about detaching the game data from the visuals! Fun stuff!

 

Thank you!!



[TOPIC: post.html]
#12

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

I tried that Dusk demo but it didn't work, an error in one of the functions. Probably not hard to fix but likely not worth it as you can see the code from the link you posted. It looks like it is just a check for crossing (vertically) a tile boundary - if you do and the tile below is solid, then it returns a collision and moves you back up out of it. Not actually very different from what I suggested above. But it is similar to raycasting in that it will detect a collision along a line rather than being a single point check (but his appears to be a general check, and since it is just line VS line (one line being the player line of movement, the other being the top of the tile), it doesn't translate to slopes and undulating terrain very well. Before I switched to a pixel-base collision routine I tried something similar using pure trig and stuff, but there are a few annoying gotchas and bugs that are hard to crush, and in the end it ended up being less flexible and harder to set up than my current system anyway :(

 

As for the thick map, as mentioned it is to test a lot of stuff. I'd envisage a real level probably containing maybe 6 layers max, although it does depend on how many graphical niceties you have (for example, parallax layers or not, and how many you use for the 'player' layer - I've used anywhere from 1 to 4 for that in the past). But the basics would be:

 

- Level graphics

- Collision tiles

- Object positions

 

That's far more reasonable I think :)



[TOPIC: post.html]
#13

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

Excellent responses @rakoonic. I've finally found another true custom-physics-engine enthusiast! :D

 

@jerejigga:

I am currently using Dusk to build a very large-scale metroidvania platformer RPG hybrid. I've rolled my highly flexible physics engine, and use a lot of Dusk's methods to implement complex functionality. Dusk is great for quickly getting a map loaded for prototyping, but is still extremely scalable and very fast.

 

Here's a little of what I'm using Dusk for:

- Physics. For this I query tiles based on the pixel position of the object and check for properties imported from Tiled to decide whether the player should collide. My physics engine even works offscreen seamlessly via some of Dusk's core methods.

- Custom objects. I've created an extensive registry of object types (custom objects that are built when their associated object comes onscreen) and mixins (modular code that adds functionality to object types) and can swap them around and combine them. I use Dusk's addObjectListener function to tell me when an object goes onscreen or offscreen and build and create the custom objects based on that. I can now do ridiculously random things like create a ladder (object type) which displays an icon when you move near it (mixin), moves on its own with AI capabilities (mixin), and damages you when you touch it (mixin).

- Camera movement and parallax. This is a big relief not to worry about. Dusk does all this internally. You just have to specify the parallax ratios and tell Dusk to track the player, and Dusk handles the position of the camera, tile, and object culling.

 

I find Dusk to be really useful for being a stable base on which to code the rest of my engine. Dusk lets me avoid worrying too much about the map and functionality related to it and worry more about getting the actual game to work how I want it.

 

(As I read over my post again, it sounds a lot like an ad - I am the developer of Dusk, after all - but believe me, it's not intended to be one. It's intended to be a post to detail some ways in which Dusk helps greatly with coding a metroidvania. I definitely wouldn't code a whole new tile engine because it might be better tooled to platformers - that's Dusk's point. It's not geared towards any particular type of game. It just provides the base on which any type of game can be built.)

 

- Caleb



[TOPIC: post.html]
#14

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

Heya Caleb :D Great work on the engine, but I didn't manage to get the examples that jerejigga posted earlier - is there a newer version I'm not aware of or something?

 

I do kinda re-iterate that I don't consider my own stuff a physic engine, just a collision engine. I think it is a useful distinction so people have an idea of the capabilities and don't go asking for angry-birds-in-a-platformer. Bluergh!

And don't worry about selling your own engine, and you can probably clear up any misrepresentation I did above as I'm not fully up to speed on your engine :)

 

I do find your comment about Dusk having an addObjectListener function to be a bit odd, but then I never fully embraced the whole event-driven model for gaming, particularly simple games like these, as it seems clunky and imprecise. I much prefer a simple, linear game engine that handles everything in a specific, guaranteed order.

 

From what I gather, your ladder example is that it creates the icon *as part of the engine*. That also seems strange to me, as I'd have that abstracted away from the core engine. I guess I compartamentalise more than you. My set up is, from top to bottom, something like this (so the game engine sits on top of the seperate collision engine which sits on top of the seperate level data:

 

Core game:

 

- Game engine - including movement code (which uses the collision engine, but the collision engine does not handle actual movements itself)

- Collision engine

- Loading level 'engine' - really by this I mean the container for the level data

 

Visuals:

 

- Game-specific drawing 'engine'

- Level drawing engine

 

Note how the two things are entirely seperate. Things like the icons etc are dealt with in the game-specific drawing code. I myself have handled these sort of things in different ways (although the ladder for me has so far just been part of the normal movement code, there are ladder 'tiles', not a ladder entity). The icon could either be a normal sprite-based entity which, in its update code sets visibility based on proximity to the player entity, or (which I prefer) is a data-only entity based on rectangles set up in Tiled (I prefer this for accurate sizing, I use the same thing for doorways etc). The icon would appear when my 'zone' entity registers the player is inside it.

 

At the end of the day we may well have very similar set-ups, just with different names.

 

I'm curious though, do you generally have collision data tied into the *visual* tiles or, like me, have an entirely separate invisible collision layer?

 

Also, does your collision code support slopes etc?

 

One thing that is causing me headaches is proper lift behaviour. It is one thing to have a simple horizontal slab that moves around in a space where you don't touch anything, but I want lifts that are basically just a mobile sub-set of tiles (so can have slopes etc), and that can move across other parts of the normal level, resulting in you being pushed around and potentially crushed - I'm mean like that :)

I haven't quite found an optimal solution as it often requires recursing through the various collision layers :(

 

I should add, your final comment about creating a new engine per game-type simply shows why making the visuals seperate from other modules (particularly the collision code) is the way to go. In the demo link I posted above, the drawing engine is exactly the same regardless of whether it is the side-on or top-down part of the demo, only the control and collision changes (there's just a seperate module for side-on and top-down collision).



[TOPIC: post.html]
#15

Caleb P

[GLOBAL: userInfoPane.html]
Caleb P
  • Corona Geek

  • 1,424 posts
  • Corona SDK

My game engine is completely separate from Dusk. Object types and mixins are abstracted away from the actual map code. I really sort of have two engines - one is Dusk, for the map loading, culling, properties, etc., and the other is the actual game, for the movement, behaviors, objects, etc. All the object type code is part of my secondary game engine, not part of Dusk. Dusk only handles drawing the tiles and telling me when events like object drawing or erasing happen. I then hook into the Dusk base to do what I like with my code.

 

I do add collision bodies straight to tiles - it makes for a much cleaner result IMO, and it's easier to build maps with. For example, I might have a wall tile which the player should collide with. I set the "has a solid on the left side" property in Tiled, then I'm assured because of my physics engine that every time there's a wall tile, the player should collide with the left side. My physics engine even handles flipped tiles, so you can use say that objects collide with the left side a tile, flip it, and objects will automatically collide with the right side. I understand that everyone will have their own approach to things like this (and I have used separated collision and display layers before), but for me, automatic physics tiles that I can just paint onto the map and be assured that will work every time is my personal favorite approach. My collision code doesn't currently support slopes, but only because I haven't needed them so far. The capability is there, though, as I use a pseudo-raycasting kind of technique.

 

I think your statement about similar setups may be correct. Your 7th paragraph (about your approach to what I call object types and mixins) is just about exactly what I'm doing, just instead of using separate objects for added functionality (like your data-only "zone" object), I have object types to create the basic object (the graphic, for example) and mixins which add added functionality. Mixins add directly on to my objects (so, say, a doorway with added "zone" functionality to tell when the player is near) and work in a "stacked functionality" way. So as I mentioned, I can have a ladder (which is an object type for flexibility - "ladder" is a bit of a misnomer; a "ladder" in my game engine just means something the player can climb vertically, so vines, grating, etc. It was the simplest word for what I was looking for) with a lot of added functionality that may not even be related to the object. Though that seems useless, it makes complex objects easy to make. For a real example, my context-sensitive-sign object uses the "sign" object type combined with a proximity icon [displays "press context sensitive button now" prompt], the dialog mixin [add a method to the object to display a dialog on demand], and the context-sensitive-action mixin [call a method on the object when the player is near and the context-sensitive button is pressed]. The result is a nice context-sensitive sign which displays a floating icon and displays a dialog when the context-sensitive button is pressed. By separating the code like this, the engine remains modular and really quite awesome.

 

- Caleb

 

P.S.

and don't go asking for angry-birds-in-a-platformer. Bluergh!

 

Oh... man... nightmares will haunt me now. :blink:

 

P.P.S.: Having read a couple of posts above again, I think we may be using the same approach to physics... I ripped my approach directly from this Sonic guide!



[TOPIC: post.html]
#16

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

Yeah I think we are both on the same wavelength really, it was just terminology differences.

 

I don't know if that is the exact sonic article I read, but I'm guessing it could be, there can't be that many detailed docs about our favourite blue hedgehog!



[TOPIC: post.html]
#17

StarCrunch

[GLOBAL: userInfoPane.html]
StarCrunch
  • Contributor

  • 829 posts
  • Corona SDK

Lots of good stuff here.

 

To speak briefly to mixins, these also go by the name "components". A good (and influential, I believe) article on the same can be found here: Evolve Your Hierarchy

 

(There was a question elsewhere on the forums about components in Corona, looking for examples, though I forget where...)



[TOPIC: post.html]
#18

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

That was a nice article, thanks StarCrunch. The only area I think components breaks down, and this is mentioned in the article itself, is that when components require access to others, there's no point in going through the component manager as it causes slow down, so in the end components end up having direct access to each other.

 

This suggests to me one of two approaches:

 

A generic 'properties' component, that is simply a container for all object values (naturally you only add in values as needed), so each component can reach in and find what it needs, or (and?) a dependency list of components, should it be necessary.

 

I do like the idea, and I already tend to break my code up much more than having a lumbering set of heirarchies, so I'm going to see how closely my own mess approaches this, and if I can move to it. I'm a big lover of libraries, so having more just for entities etc seems like the kind of thing I'm down with.



[TOPIC: post.html]
#19

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

I have been following this thread all weekend. Wow! This is a whole lot of great reading material and food for thought!
 
Rakoonic, I love your ideas about separating the game UI from the game world such that the game world is actually a fraction of the size of the corresponding UI. The first several games I developed were all written for TI graphing calculators, specifically the TI-80, TI-85, and TI-92. They were limited in both speed and memory but by leveraging matrices, basic math, and pre-rendered graphs I made the UI so fast that the kids playing my games never knew there were performance limitations. I spent over four years, though, fine-tuning my skills. I didn't start out doing things so fancy and so I was limited initially to a dice game and a simple maze game. My final TI game was a top-down dungeon crawler / RPG that included lots of fancy animations.
 
I am still in the process of writing my first Corona SDK game, a puzzle game, and although it's coming along very well I still have a lot to learn. That said, here is what I am thinking now in regards to the first platformer that I will make (eventually). Although I have been playing with MTE more than Dusk, I will now switch to Dusk since it's obviously working well for Caleb. I plan to use Tiled to define my worlds/levels and store the physics data in object layers. I plan to draw the "physics bodies" in Tiled so I can see them (like how Rakoonic does it), as opposed to storing them as tile properties (like Caleb does it). As a long-time Java developer I am very familiar with event-driven programming, so I really like and plan to use Caleb's method of creating and destroying objects (e.g. enemies, ladders, doors, etc.) as they enter and exit the viewable area (or near the viewable area). Here is a screenshot of a POC I did using MTE a while back. The player and the physics bodies were generated by my code based on placeholders in the Tiled map.
 
tiled.png
 
That covers a lot of things but I am still unsettled about the collision handling. I read a good chunk of the Sonic article and looked at the Sonic demo in MTE that uses the techniques described in the article (for the most part). I think I would have to do a lot of research and trial and error to create a "collision engine" that behaves the way I want/need. Caleb, would you be willing to share your platformer framework code? I watched your CoronaGeek interview from a while back so I know you don't want to be stuck maintaining your work for the public. I would be totally okay, though, getting an archive file that provides just enough functionality for me to get going. I have no problems digging into the code and making changes myself as needed. (In fact, I have made some changes to my local version of your awesome CBE library to better meet my needs.) I am just looking for a jump start.
 
Rakoonic, at some point in the future, it is highly likely that I will use the approach you described. In fact, at some point I plan/hope to create a multi-player game and I will absolutely need to use an approach that is at least similar. I am just going to need to work my way there. ;-)


[TOPIC: post.html]
#20

d.mach

[GLOBAL: userInfoPane.html]
d.mach
  • Contributor

  • 918 posts
  • Corona SDK

haven't followed and read everything here, but here are my two cents: Do not work with existing physics! Write your own movement, collision detection instead. This will save you a lot of trouble and you have 100% control over all aspects regarding movement and collisions.



[TOPIC: post.html]
#21

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

@d.mach That seems to be the prevailing advice. Thank you for contributing to that!

 

I have been asking around the forum in other places and some people have pointed me to the following two non-Corona tutorials on creating platformers. I haven't been able to sink my teeth into them yet but I wanted to share them with the rest of y'all so you have them. The Youtube link is to a complete series on creating a platformer using Java. The developer who provided the link says he used it as the basis for his Corona SDK collision engine.

http://www.wildbunny.co.uk/blog/2011/12/20/how-to-make-a-2d-platform-game-part-3-ladders-and-ai/

https://www.youtube.com/playlist?list=PL-2t7SM0vDfcIedoMIghzzgQqZq45jYGv



[TOPIC: post.html]
#22

redninjacat

[GLOBAL: userInfoPane.html]
redninjacat
  • Contributor

  • 196 posts
  • Corona SDK

@rakoonic Correct me if I am wrong, but don't you need Corona physics bodies in order to use Corona raycasting? Does that mean you do use the bodies but just don't use them for collision detection?



[TOPIC: post.html]
#23

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

@jerejigga - I do my own raycasting. Basically if you have a single pixel-perfect collision detection routine, you just run it in a line (ray!) until it either reaches the end of its distance, or at the first (solid) collision it detects. It isn't massively fast to do this, which is why you limit using it a lot for the player character (which requires 3 or more for decent effects).

 

Enemies just use a couple - left / right and down. You could probably even limit this to one, by having them alternate their rays between frames, although naturally you lose accuracy. Actually you'd probably always want a down ray, otherwise it'd look funny going over slopes, but you could cycle the horizontal rays between all enemies, as left and right values don't change really (although you'd need to make sure you check far enough ahead for the missed frames so it can't go through walls, and also with any biggish vertical height change you'd have to do a fresh horizontal check).

 

So say you have 20 enemies, and you check horizontal and vertical each frame - that's 40 rays per frame just for the enemies. Might be a lot, dunno :)

 

But now say you have 20 enemies, they always check down, but each enemy only checks horizontally every 5 frames, cycled accordingly (so only 4 enemies check each game frame) - now you've dropped from 40 rays to 24 - almost a 50% drop.

 

Mostly though, I'd just get a game up and running, and then work out what (if anything) needs to be optimised.



[TOPIC: post.html]
#24

rakoonic

[GLOBAL: userInfoPane.html]
rakoonic
  • Contributor

  • 112 posts
  • Corona SDK

Regarding collision detection - if you are just going to use squares, IE a tile is either fully solid or not, then the collision detection becomes extremely quick and trivial to write - you can make a loooot of assumptions and shortcuts.

 

I'd probably start with that, as at its most basic it differs somewhat from collision detection using slopes:

 

- Tiles are solid / nonsolid completely. Apart from the assumptions, the collision code works with rectangles / squares (IE the player is a rectangle, colliding against square tiles).

 

- With slopes, it makes more sense that you move to a simple axis-aligned raycasting model. This method often does have certain anomolies for collision detection, and certain cases you'll want to avoid, unless you want to end up with super bloaty/slow collision detection.

 

However, nearly all of these odd situations are easily avoidable by level design, and in fact most of these odd situations won't actually crop up under normal design situations, as they represent extremely bizarre set ups (one common example is a flat floor, and a ceiling that slopes down gradually to the ground - you'd likely never want *collision* data set up like this, although visuals is entirely seperate of course, because once you get to the part where the ceiling is closer to the ground than the height of the player, you wouldn't be able to enter it anyway. Essentially you should never be able to crush yourself to death simply by walking along the ground into a narrowing corridor).



[TOPIC: post.html]
#25

thomas6

[GLOBAL: userInfoPane.html]
thomas6
  • Contributor

  • 982 posts
  • Corona SDK

Hi there!

 

I'm going to be brief: everything you need to know when programming your own tile based platformer (without Box 2D) is in the attached pdf!

 

Happy reading! :)

 

 

Attached Files

  • Attached File  tbg.pdf   993.79KB   538 downloads



[topic_controls]
Page 1 of 2 1 2
 
[/topic_controls]