How to create a Platformer

@ spideri I figure the ideas in this thread need some renewed attention given the new canvas texture feature. One use case might be to use the latter to build a mipmap and then expand upon Caleb P’s technique to actually implement it. (Then again, I suppose this would exacerbate the dearth of inputs.) Are these meant as speed optimizations? Quality? Both?

An alternate approach I’m meaning to explore is to paint image sheet fill-based 2x2 rects into a texture to encode the corner texture coordinates, rather than indices, into a canvas, then look those up in-shader and do whatever. (I’m thinking animated cross-frame effects on sprites, for instance, but it might have implications for tile maps, too.) It remains to be seen if this can be done sanely in light of texture filtering.

@spideri - if the only actual difference between maps are the tile-sizes, you could probably get away with just swapping the tileset used at an appropriate distance. I guess it depends entirely on how quick the zoom is as to whether it is noticeable or not.

@starcrunch - stop coming up with interesting ideas I want to explore! But realistically, I’m not sure what benefits it would bring. One thing that you need to be careful of with shaders is pixelisation - this may or may not be a good thing depending on what you want, but unless you really want to slow things down in a shader, you are only going to ever have a single discrete pixel lookup which means no sub-pixel rendering.

I think for animated tiles I can see where you are going with your idea, but to be honest I’d probably rather just set up some special animation frames. I can’t think off-hand how to set this up in Tiled though (but I’m using their tile animation creation which works with discrete tiles just fine, so there *may* be a way to hack this - likely I’d set up the animation as a tile property (IE tile 345 has an anim property that defines how it changes over time, then at level load it uses this info to create the extra frames needed). It would be interesting to be able to paint tiles in differing resolutions all at once though, although frankly again, pixelisation could be a problem there.

@StarCrunch - Thanks for the links, we will check them out in more detail when we start doing some tests. We’re after quality and speed improvements: quality because when you’re zoomed all the way out the bilinear filtering doesn’t cut it and we get pixels flickering when it scrolls due to the super high source resolution, and speed because I’m sure it could be a lot faster with lower res textures when zoomed out. Cross-fading between the texture sets could be interesting as you pass the border between them (e.g. low to medium). Kinda like tri-linear filtering… but not. Still, it might help mitigate any visual jumps as it switches between sets.

@rakoonic - We run at 60 (where possible) so dropping frames when it swaps would not be ideal.

Thanks again guys, I think we just need to do some tests.

I should point out that many tile-engine-based games will fall foul of the horrible gap visual problem (or, if you’ve set up the tile image differently without gaps between tiles, tile-bleed). I’ve been attempting to use the new canvas texture feature to get around this, and while there’s still a few issues (an inexplicable delay in corona updating graphics which I’ll hopefully be able to prod Vlad into looking at once I’ve simplified my test case, some fighting with texture mag/min filters, and overriding content scaling without actually checking if  the files exist) it is working.

What this means is you don’t need to manually expand the borders of each tile graphics, which is a tedious and soul-crushing task, as it can be done automatically.

If you look here: https://www.dropbox.com/s/ir48kkh7an1si2u/RagnarRock.apk?dl=0

What you’ll see is some pixelation (that’s the mag/min problem from above), but what you won’t see are gaps between the tiles, despite the base 2x image normally showing them (controls aren’t 100%, this is just my platformer testbed - down in front of an open door to go through).

@rakoonic I have seen the gap issue in both MTE and Dusk! I was hoping that was just a Windows simulator issue! Are you saying that I should expect that to happen on devices too? How in the world could I create a Tiled based game if I can expect this horrible issue to occur?

Hi all,

I’ve had fairly big success sometimes by just scaling my tiles to 101 or 102 percent. Do check on different devices however, because sometimes one devices (e.g. iPhone) works best at one setting and another (e.g. iPad) works best at another setting - potentially fixed with clever device detection.

Not a magic fix mind you, but works well for some projects.

Yup, that’s the simplest solution, and I won’t knock it for its simplicity, but I’m after a more solid, pixel-perfect solution. If only I’d known the torture it would bring me while searching!

@jerejigga - there is a way to avoid it (I mean, apart from thomas6’s suggestion above).

Although the problem happens slightly when shrunk, this is most noticable when you zoom a tile image using “linear” filtering, so I’ll concentrate on explaining why that happens.

Linear filtering uses a nice blend between pixel colours. Say you have 2 pixels in the source image next to each other. White and black. Now, when you show that image zoomed, you’ll actually see a smooth fade from white to black. The GPU is linearly blending between pixels, so they don’t look all pixelated and silly up close (unless that is what you want!).

Now, with that in mind, what happens when you try to draw the edge of a tile sprite? Well, it depends on how you set up your source tile set image.

If each source tile touches the tiles next to it, when you try to draw your view, each sprite will have a border where the tile you want’s edge pixels blend into those of the tile next to it. Often not good.

The next possibility (and what I recommend) is that individual tile graphics don’t touch either other in the source tile set image. You leave ideally a 2 pixel or greater gap between them all, both horizontally and vertically. However, this now means that when you draw a tile sprite, the edge pixels are now blending from the actual graphic, into pure transparent. This is where the gaps come from.

So, the proper solution (and this is a known thing when working on this type of game), is to do your tile set graphics, then expand the edge pixels of each tile graphic by 1 - IE for each tile you duplicate its left edge one pixel to its left, its right edge one pixel to its right, and the same for up and down etc. This means edge pixels will be blended with a copy of themselves, so they’ll look 99% correct - hurrah!

However, this is a pain if you are still editing the tile set graphics. It is a tedious and frustrating task at the best of times. If you don’t do it though, your graphics in-game while testing look rubbish.

So, what I’ve been struggling to do, and with some degree of success, is using the new canvas object to automatically expand the borders.

Essentially what I do is load the tile set graphic into a canvas. Then I make it an image sheet, making sprite frames from the edge pixels of each tile that I need to expand. Then I :draw() a lot of sprites into the self-same canvas using these frames to offset the tile edges, finishing with an :invalidate(). Then I create another imagesheet from the canvas, which is the normal one I’d use for my tile sets as if I’d done none of this expansion stuff.

So what are my problems? Firstly you *must* do all this edge expansion stuff with the texture min and mag filters set to “nearest” or it just goes wrong. That alone isn’t bad, but it means that any use of the tile set canvas later on will use these filters, which is likely *not* what you want to happen.

Secondly, because you actually want the corner pixels expanded, I’m doing my edge expansion in 2 sets. Firstly horizontal, then vertical. The vertical ones will use the already horizontally expanded source, so they now have these corner things. The problem is that for some reason I can’t just update and invalidate() the canvas horizontally 1 frame after initialising it, then doing the same for vertical adjustments in the following frame after that. It *should* work, and indeed in the simulator it does. But on my device, I need to leave a delay of roughly 700 milliseconds between updates. This isn’t a huge deal, but it means something is going on I’m not aware of, and means you can’t start showing the level until approximately 1.5 seconds after you set it up. Not something I’d want in a publically released library :confused:

Hi Rakoonic,

Very good points. Might I suggest not to forget that you can create a Photoshop action to do the necessary duplicating of the edges - and I even believe that TexturePacker has an option for this, but I’m not sure.

@thomas6 You are correct about TexturePacker. It does have an option called “extrude” that behaves as you describe.

@thomas6 and @rakoonic I am glad to hear that there are workarounds for the gap issue! Presently I have been playing with tilesets created by other people so it seems I am stuck using the 101-102% zoom as suggested by thomas6. Rakoonic, once you get your solution working properly, I hope that you will be sharing it. :slight_smile:

I spent several days on trying to programatically fix the gaps between tiles, instead of requiring photoshop action etc.

I failed, but I did discover some interesting bugs which will be passed to the relevant people :slight_smile:

On the other hand, the splendiferous Vlad from Corona did pass me this gem which has flown completely under the radar until now:

display.setDefault( “isImageSheetSampledInsideFrame”, true )

This will likely fix most of your tile gap problems :smiley: Set it before you load any tile images and / or make sprite sheets from tiles (and don’t forget to reset it afterwards).

Now, it does still have some issues - in particular if you are running your app on a much higher res screen than you generally cater for, or if you zoom the tiles significantly, but those are specific cases (and in the case of high res screens, you should be running x2 or x3 assets to cater for it. For zoomed up pixel art, you’ll still need to manually extrude edges).

But, it helps a ton generally.

Try it, love it, thank Vlad!

Here’s a couple of links so you can see if it works for you or not:

APK: https://www.dropbox.com/s/ir48kkh7an1si2u/RagnarRock.apk?dl=0

OSX Build (no onscreen controls, use cursor keys to move): https://www.dropbox.com/s/jl2ynkuq43r61nm/RagnarRock.zip?dl=0

PS, let me know if it runs at 60fps nicely, and what you think of the slightly semi-trans near layer of parallax (I made it semi-trans because I got annoyed at it blocking the player entirely).

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.

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/

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 :slight_smile:

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 :wink:

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)
  1. 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 :slight_smile:

  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 :slight_smile:

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

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!

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 :slight_smile:
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 :slight_smile:

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

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 :wink:

  • 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).

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 :wink: 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 :slight_smile:

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).

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).

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? :slight_smile:

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.

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!!