Sub-Pixel-Walker v0.1: Testers not needed
Moderators: Bob the Hamster, marionline, SDHawk
Sub-Pixel-Walker v0.1: Testers not needed
This is a tech demo inspired by kylekrack's Pixel-Walker, but with the difference that all the calculations are done in fixed point arithmetic.
For the most part the idea is to have accurate Zelda-like controls but also Super Mario platform style controls and tank controls for vehicles. In this demo I've implemented only the first type but the other two can be obtained easily enough.
A generic slice (not the hero at least for now) is subject to inertia and it collides against the regular wall map. Acceleration and friction can be tuned from ice skating to mud and anything in between. The code itself turned out better than I though altough it's rather long because I had to type 8 collision cases (4 walls and 4 corners) individually, mostly due to limitations in the language.
So, if anybody's curious, here's is a precompiled demo and the source code. To modify the source code this compiler is needed, altough if you really want it shouln't be too hard to modify it to compile with the regular compiler.
For the most part the idea is to have accurate Zelda-like controls but also Super Mario platform style controls and tank controls for vehicles. In this demo I've implemented only the first type but the other two can be obtained easily enough.
A generic slice (not the hero at least for now) is subject to inertia and it collides against the regular wall map. Acceleration and friction can be tuned from ice skating to mud and anything in between. The code itself turned out better than I though altough it's rather long because I had to type 8 collision cases (4 walls and 4 corners) individually, mostly due to limitations in the language.
So, if anybody's curious, here's is a precompiled demo and the source code. To modify the source code this compiler is needed, altough if you really want it shouln't be too hard to modify it to compile with the regular compiler.
Last edited by lennyhome on Tue Apr 28, 2020 7:24 am, edited 2 times in total.
somebody who was curious
What's the advantage of fixed point arithmetic?
Tried the demo--seems like a lot of code for something so simple. Kylekrack's had a lot of extra features, were those in here as well or were you saying one could edit the scripts to include them??
breaking out of the tile grid sure does feel nice
Tried the demo--seems like a lot of code for something so simple. Kylekrack's had a lot of extra features, were those in here as well or were you saying one could edit the scripts to include them??
breaking out of the tile grid sure does feel nice
First of all, I don't mean to compete with kylekrack. The title of the thread is an homage more than anythinge else. This is something different.
Extra precision and fractional speeds. I guess you coud call it smoothness.What's the advantage of fixed point arithmetic
I had to replicate some functions that already are in the engine using scripting, so I could customize them.seems like a lot of code for something so simple
I'm never going to implement those. What I am probably going to do next are slopes and ice sheets just because those should be easy to do, but then again this is a very specific tech demo.lot of extra features
If you want to modify this script and re-compile it, you need a special compiler because it's not quite regular HSpeak.edit the scripts to include them
Cool! I think what would really benefit this as a tech demo is a HUD with controls to tweak the parameters of movement. For instance, displaying the current acceleration, and allowing 2 keys (+ and - perhaps) to increase or decrease that value. If this is meant to show off the benefits of sub-pixel movement, real-time comparisons are important to convey that. You mention the difference between ice and mud, etc. Post another build with those terrains on. I'd love to see that in action.
If you ever find a spot where a segment of the pixel-walker scripts are useful here, feel free to copy stuff. I'm not sure how likely that is to be the case, just wanted to give that green light explicitly.
If you ever find a spot where a segment of the pixel-walker scripts are useful here, feel free to copy stuff. I'm not sure how likely that is to be the case, just wanted to give that green light explicitly.
My pronouns are they/them
Ps. I love my wife
Ps. I love my wife
I didn't bother because this all about how the controls feel.It would be great if you posted screenshots
Certainly. Also the ability to switch from Zelda controls to Super Mario controls to tank controls. I've already tried the tank controls, which use the sin/cos tables. They're fun. I didn't include it because I didn't have a sprite in 16 rotations at hand and I wanted to put out something.a HUD with controls to tweak the parameters of movement
I'm still trying to shake off the 'rona, but I should have more experiments coming.
Likewise of course.just wanted to give that green light explicitly
----
I've added some patches to the right of the map where the physics are different. There's an attempt at ice and some slopes. It's based on zones. It checks which zone the player is in and adds a dummy acceleration (1-4) or reduces friction (5). But it could also be done by reading the tile.
Bouncing off walls is disabled at the moment, but it can be done. I may have enough to make a little top-down car racing game. We'll see.
Last edited by lennyhome on Tue Apr 28, 2020 12:29 am, edited 3 times in total.
- SwordPlay
- Chemical Slime
- Posts: 966
- Joined: Sun Jan 22, 2017 9:32 am
- Location: London, England
- Contact:
I tried it out and it feels really good.
You have to use an inverted wallmap? That's pretty crazy!
Can this work with other collision maps (other than wallmap) and different sizes for the player?
This could be really neat for extending the engine's capabilities to make new games. But you won't be able to take advantage of built-in A* or other commands
I guess it doesn't matter if you're making a platformer or top-down shooter or something.
You have to use an inverted wallmap? That's pretty crazy!
Can this work with other collision maps (other than wallmap) and different sizes for the player?
This could be really neat for extending the engine's capabilities to make new games. But you won't be able to take advantage of built-in A* or other commands
I guess it doesn't matter if you're making a platformer or top-down shooter or something.
"Imagination. Life is your creation."
Is it inverted? The walls have a direction in my implementation because I need to know which side is the "out" side. It could proably be implemented differently. I don't know. I've never written a game for this engine.You have to use an inverted wallmap?
Yes. With enough effort you can collide anything with anything.Can this work with other collision maps
In principle yes, but for simplicty right now I'm considering the player to be a 9 pixels radius circle placed at the bottom of the sprite, just because it works well with the tile size. Can be changed and made so certain characters are able to go through certain passages and others can't.different sizes for the player
Several features that are in the engine can't be used. This is a "forward looking" experiment and to some extent it's also an abuse because many story-driven games don't need anything like this.built-in A* or other commands
Last edited by lennyhome on Tue Apr 28, 2020 12:54 am, edited 1 time in total.
Aha, I didn't see the other patches of terrain. Those feel quite good. I also just realized I think this is running at the default FPS. I would recommend bumping that up to 60 fps. One of the big problems with using pixel-movement is that even 1-pixel/tick speed is quite fast at 60fps, and there's nothing slower. That's a big reason sub-pixel movement is such a big deal.
My pronouns are they/them
Ps. I love my wife
Ps. I love my wife
I've just tried it to run it at 60 fps and it works but it stretches the limits of the arithmetic a little bit. The units of measurement for the acceleration are "pixels per fps squared" or something like that, so eventually you run into trouble if you try to run it too fast.bumping that up to 60 fps
Last edited by lennyhome on Tue Apr 28, 2020 7:25 am, edited 2 times in total.
Oh, nice. Very smooth. Sub-pixel velocity really does help for physics, otherwise the minimum possible acceleration 1px/tick^2 is pretty high.
It would be possible to use the "check wall collision x/y" commands to do the wallchecking instead of having to script it, however that results in a square hitbox while you use a circular one, and also wrote it so that just nicking a wall pushes the player sideways around the obstacle, aligning the player with the wall grid. I can't immediately see how the scripts do that, I'll examine . Unfortunately "check wall collision x/y" can't do that, though it's something I want to add (I have also scripted such a system in the past, for Blood Ledger). Maybe someday circular hitboxes too.
It's possible to store acceleration in higher precision than position or velocity, either using an accumulation buffer, or much easier, using temporal dithering. E.g.:
The 3* results in the dither pattern [0, 3, 6, 1, 4, 7, 2, 5].
But I think you still have more than enough precision at 60fps... acceleration on ice would still be 9/256 px/tick^2?
Moogle's Sidescroller 101 scripts also use subpixel velocity/acceleration (the unit of measurement is a tenth of a pixel), and most OHR sidescrollers are based off those scripts. I vaguely remember at least one game adapting them for top-down movement too.
I actually soon want to make the engine use subpixel positioning of NPCs and heroes internally, to be used for fractional walk speeds. Nothing would change from the point of view of existing scripts, but I could add some new commands to get/set the fractional position.
However I don't want to also convert the whole slice system to support fractional pixel positions if I can avoid it. Too much of a headache. Well, fractional velocity is already possible with the "move slice to" and "move slice by" commands, which use X,Y accumulators for fractions of a pixel. (Which I think is ugly and inefficient compared to fixed point slice positions.) But it means we could add some script commands to get/set fractional slice positions and velocities which act on those accumulators, but not update any other slice code at all, meaning that translating a slice by half a pixel won't translate its children. That's probably better that way anyway: If you move a tree of slices across the screen, you want them to all move by an equal numbe of pixels without aliasing effects.
It would be possible to use the "check wall collision x/y" commands to do the wallchecking instead of having to script it, however that results in a square hitbox while you use a circular one, and also wrote it so that just nicking a wall pushes the player sideways around the obstacle, aligning the player with the wall grid. I can't immediately see how the scripts do that, I'll examine . Unfortunately "check wall collision x/y" can't do that, though it's something I want to add (I have also scripted such a system in the past, for Blood Ledger). Maybe someday circular hitboxes too.
It's possible to store acceleration in higher precision than position or velocity, either using an accumulation buffer, or much easier, using temporal dithering. E.g.:
Code: Select all
acceleration = (acceleration_times_8 + (3*tick % 8)) / 8)
But I think you still have more than enough precision at 60fps... acceleration on ice would still be 9/256 px/tick^2?
Moogle's Sidescroller 101 scripts also use subpixel velocity/acceleration (the unit of measurement is a tenth of a pixel), and most OHR sidescrollers are based off those scripts. I vaguely remember at least one game adapting them for top-down movement too.
I actually soon want to make the engine use subpixel positioning of NPCs and heroes internally, to be used for fractional walk speeds. Nothing would change from the point of view of existing scripts, but I could add some new commands to get/set the fractional position.
However I don't want to also convert the whole slice system to support fractional pixel positions if I can avoid it. Too much of a headache. Well, fractional velocity is already possible with the "move slice to" and "move slice by" commands, which use X,Y accumulators for fractions of a pixel. (Which I think is ugly and inefficient compared to fixed point slice positions.) But it means we could add some script commands to get/set fractional slice positions and velocities which act on those accumulators, but not update any other slice code at all, meaning that translating a slice by half a pixel won't translate its children. That's probably better that way anyway: If you move a tree of slices across the screen, you want them to all move by an equal numbe of pixels without aliasing effects.
Last edited by TMC on Tue Apr 28, 2020 3:56 pm, edited 1 time in total.
Looked up fixed point arithmetic, my bad. Assumed kyle would have used that, kinda surprised. For ohr scripts, seems trivial to do with planning— like x /100 to get two deep fraction, ie 1234 becomes 12.34, with consistent rounding is as smooth as real thing because pixels on screen can never be fractions, edit: so it’s really about timing which have to delta or set to a fixed fps
Last edited by charbile on Tue Apr 28, 2020 6:29 pm, edited 1 time in total.
We briefly touched on that at the end of kylekrack's thread. It's not enough to be able to tell if two shapes have an intersection. Long story short, you also need to know where the barycenter of the intersection is.use the "check wall collision x/y" commands to do the wallchecking instead of having to script it
You pretend that the playfield is much bigger than it is, you do your calculations and then you scale down the final results while leaving the partial results untouched. That's the idea. The rest is a forgotten art due to the fact that floating point numbers are supported everywhere now.Is there a good overview of how sub-pixel stuff works?
In my cult once we reach the 33rd level we are taught how to use the dark arts of convolution to blit sprites at fractional coordinates. If you're interested I can send you a brochure.pixels on screen can never be fractions
----
I hope this makes any sense. Initially I intended the corners to be circles but then I settled for that split-triangle geometry. As a consequece, the collision source is a diamond shape implicitly defined by (abs(x) + abs(y) < radius) and then split by (abs(x) > abs(y)). The red arrows represent the surface normals. The yellow lines represent the grid.
Last edited by lennyhome on Wed Apr 29, 2020 6:43 pm, edited 4 times in total.
OK, thanks. Sorry, this time I actually studied the code, needn't have bothered you for an explanation.
I'm surprised that you used the L_1 norm for the distance (diamond shaped hitbox) instead of circular. Did you do that just to justify diagonal normals/bounce/repulsion angles? I don't think there's anything wrong with pushing the slice away diagonally even if the hitbox is a circle, but calculating the correct normal is trivial anyway except for rounding problems.
But whoops, I missed the discussion at the end of that thread. The "check wall collision x/y" commands don't just tell if there is an intersection, they tell how far along the displacement vector it is, which is enough for any use case I can think of except sliding past a glance.
But this is very relevant to rotozooming too; I'd like to add optional filtering to fix up the result a little bit, like the well-known "rotsprite" algorithm, but in real time.
I'm surprised that you used the L_1 norm for the distance (diamond shaped hitbox) instead of circular. Did you do that just to justify diagonal normals/bounce/repulsion angles? I don't think there's anything wrong with pushing the slice away diagonally even if the hitbox is a circle, but calculating the correct normal is trivial anyway except for rounding problems.
This isn't something I've heard of before. I imagine you can use the barycenter to work backwards and get the point of collision, but beyond that, it might be useful for sliding past a glancing collision?We briefly touched on that at the end of kylekrack's thread. It's not enough to be able to tell if two shapes have an intersection. Long story short, you also need to know where the barycenter of the intersection is.
But whoops, I missed the discussion at the end of that thread. The "check wall collision x/y" commands don't just tell if there is an intersection, they tell how far along the displacement vector it is, which is enough for any use case I can think of except sliding past a glance.
Does the convolution incorporate a sharpening filter? Because sub-pixel shifting really wrecks pixel art with blur. ("Box" filtering looks 10x better than standard bilinear filtering for scaling pixel art, but I think it's equivalent for shifting.)In my cult once we reach the 33rd level we are taught how to use the dark arts of convolution to blit sprites at fractional coordinates. If you're interested I can send you a brochure.
But this is very relevant to rotozooming too; I'd like to add optional filtering to fix up the result a little bit, like the well-known "rotsprite" algorithm, but in real time.
Last edited by TMC on Thu Apr 30, 2020 4:48 am, edited 2 times in total.