[WIP] Ardunaut (previously Parallax rocket launch)

I’m going to advise against it.

I’ve recently been helping out/advising someone else with a game project that has a bit of overlap with this project (in terms of physics and using tile-based rendering) and something I found with the everyXFrame trick is that it can cause problems because of the timing.

What the everyXFrame trick is supposed to do is to simulate decimal numbers/fractions, but instead of accumulating the fractional part of the distance you’re just delaying until you can add a whole part.

I.e. if you had a ship travelling at 4 pixels per second (1 pixel every 1/4 of a second) then your movement is going to look like this:

Method \ Frames 1 2 14 15
Using float 0.0666 0.1333 0.9333 1.0
Using everyXFrames 0 0 0 1

I’m doubtful that it will be a problem, and I’ll explain why…

The error depends on the format.
Whether it’s going to affect you or not depends on what the smallest fraction speed you’ll have to represent is.

The smallest fractional value that a floating or fixed point type can repsresent is called its ‘epsilon’.
(The epsilon is also the smallest value larger than zero that the type can represent.)

float's epsilon on the Arduboy is:
0.000000000000000000000000000000000000011754944324493408203125

Which I think it’s safe to say is pretty tiny.

UQ8x8 and SQ7x8 have an epsilon of 0.00390625 (1 / pow(2, 8)).
It’s significantly larger than float's (more specifically ‘orders of magnitude’ larger),
but it might not be that much of an issue.

UQ16x16 and SQ15x16 have an epsilon of 0.000015258878 (1 / pow(2, 16)).
That’s still comfortably small.

What you have to ask is what sorts of values are you going to be handling.
If you wanted to move 1 pixel per second at 60 fps then you need to move 0.01666… pixels per second.
0.01666… is still over 4 times UQ8x8's epsilon and over 1092 times UQ16x16's epsilon.
With UQ8x8, theoretically you could go as slow as 1 pixel every 4 seconds before you’d encounter problems.


I’m not sure what you’ve done so far.
That was all a bit too much for me to process.
I’ll wait until I know that your GitHub is up to date and then I’ll have a peek.

Before I sink too much time into it, I think I need to know a bit more about what you want.

What’s your intention for the background?

Are you going to have the same 64x64 block repeated infinitely?
Are you just going to have stars in the background?
Stars and planets?
How much variation do you want in the star patterns?

While thinking about it I’ve had an idea that I think you might like, but I need a bit of time to test it.

Whne I have a better idea of what your intention is and how the background is going to be drawn, I’ll start discussing the movement of the background with you.

When it comes to tile games there are two approaches:

  • Move the camera and keep the world static
  • Keep the camera static and move the world

I think you might be better off with a static world and a moving camera, but we’ll see.

1 Like

Sorry about that, thats understandable. At first I found a bug, then fixed it, then got the background scrolling working so you could take off and scroll infinitely up, left, or right (or at least until the value became too large).

Im still kicking around ideas where to go next, though… Id like to make something bigger than may be possible so I might end up just using the different ideas for their own separate games, but im still hoping to make something that captures the adventurous spirit i was kind of shooting for when i started… I know i couldnt, but id like to make something you could take off and land on the moon and walk around (from a top down perspective), even if it was just in the same looping tile space (like I have set up for launch/space), but even making the most minimal player sprite and background i could takes up 6717 bytes of ROM and 1221 bytes of RAM (and i hadnt even tiled it yet), and this game takes up 14098 ROM and 1336 RAM (leaving me at 99% RAM), so ill probably take it a more simplistic route (maybe so you can get out but keep in the environment as is) or just remove the parallax.

While I think of it, here’s an example of a game that uses fixed points for its movement calculations:

(In fact I think it’s the first game that ever made use of my fixed points library.)

In theory the movement should be smoother than games that don’t use fixed points or floating points,
but I don’t really play enough Arduboy games to know if that’s the case.

1 Like

Actually, that’s kind of what my idea is about.

I was going to write a demo to make sure it would work before telling you because I didn’t want to get your hopes up, but I’ll tell you anyway.

Basically I remembered all that discussion we had about procedurally generated worlds and it suddenly occurred to me that if you generated the background tiles using a hash function then you should be able to achieve very large worlds (not infinite, but large).

When you were looking at the idea of a top-down world the hash function was a bit of a problem because it only generates noise rather than cohesive structures, which is why all the extra steps were needed.
But with a space setting, all you really need is patterns of stars,
so noise should be perfectly adequate for that.

So what I’m thinking of doing is basically:

const auto value = hash(tileX, tileY);
const uint8_t index = (value % 8);
Sprites::drawOverwrite(drawX, drawY, stars, index);

For each tile to be drawn.

Cheap. Cheerful. Incredibly large.

Is your GitHub code up to date?
I’m sure it’s possible to reduce that.

1 Like

My github code is up to date, although it isn’t organized into header files yet (doing that now) so it’s still a bit of a mess.

And I meant the program as it is on github plus a new program I wrote (for the top down perspective part as minimally as possible) equals 99% RAM, although I was hoping there might be a way to reduce that (like chunking) because I had to draw so many backgrounds in order for it to loop (which is why I was also thinking of doing away with the parallax, potentially), wasn’t sure if there might be a better way to do it.

And as for the hash function, I can somewhat follow (just generating noise for star placement), but how does it actually work? Also, what would the output look like (does it just populate the screen, does it populate a larger area outside, how large, etc), and what size tiles were you thinking? Sorry, just asking so I follow. Thanks!

1 Like

I modified Flappy Ball (one of the earliest games ported to the Arduboy) to use fixed point math for the gravity calculations. The fixed point code was done by myself, before @Pharap’s fixed point library existed.

1 Like

I’ll have a read of it tomorrow.

I won’t look right now because it’s late and I want a spin on Oblivion before the night is over.

There almost always is.

Ah, when I heard this I had to have a peek.

I’m not exactly sure what you’re doing with all the different backgrounds, but I’m almost certain there’s a better/easier way.

Which part? The hash function or the tiling?

Imagine 8-16 black rectangles.
Imagine those rectangles filled with a pattern of white dots.
Imagine those white-dotted rectangles tiled across the screen in a random order.

That’s what it will look like.

Probably 8x8, 16x16 or 32x32.

The world size limit will be determined by what type you use for coordinates because your ship’s coordinates will always be in pixels.

No worries, like I said it’s a bit of a mess, hopefully I’ll have it more cleaned up by the time you can get back to it.

And yeah, basically what I did was tile the background three more times, once more in x, once more in y, and once more diagonally (like quadrants of a rectangle) and when each respective background traveled the specified distance (so that it was offscreen) I moved it to wrap back around.

But since the parallax scrolling uses 3 layers I ended up with 12 backgrounds overall, hadn’t really planned ahead and didn’t realize til it was getting a little out of hand, just kinda went with the first method that came to mind :stuck_out_tongue:

Occurred to me after the fact that I probably could have even tried chunking, but I don’t mind burning rubber on this kind of stuff, helps me to sharpen my skills better using the information I learned more recently (so it’ll be less of a blunt force trauma :P), if anything.

And that definitely helps to clarify a bit, thanks! I’m just not so sure how it works under the hood yet but I’ll just sit with it a bit and digest and I should get a better idea. Thanks again!

I started the day intending to write an example of the stars demo but I’ve been sidetracked half a dozen times.


I saw your thread about memory usage (and made a few comments).

People are right that in general it does depend on the game and the context,
general tips are only useful if you know when and where to apply them.

I think that a large chunk of your RAM usage has been chewed up by the background drawing,
but I’m struggling to see a way to reduce it because I’m struggling to track what all the backgrounds are doing.

My instinct says that you could possibly just generate all the background coordinates on the fly using a single pair of x and y offsets as a base.

One thing I’d like to point out.
Instead of doing -= 1, -= 2, -= 3,
you could just store one set of coordinates,
and then when it comes time to draw it:

Sprites::drawSelfMasked(x + (background.x * 1), y - (background.y * 1) - 64, backgroundTile1, 0);
Sprites::drawSelfMasked(x + (background.x * 2), y - (background.y * 2) - 64, backgroundTile2, 0);
Sprites::drawSelfMasked(x + (background.x * 3), y - (background.y * 3) - 64, backgroundTile3, 0);

And if you were to pack your backgroundTiles into a single array with multiple frames, you could further reduce that to:

for(uint8_t index = 0; index < 3; ++index)
{
	const uint8_t scale = (index + 1);
	Sprites::drawSelfMasked(x + (background.x * scale), y - (background.y * scale) - 64, backgroundTiles, index);
}

I’m not sure that would help here.
It depends how you were thinking of using it.

Chunking is primarily for generating terrain dynamically (in bite-size chunks, so to speak).

1 Like

I finally found time to do it.
This is what I was talking about:

StarTerrain.hex (22.3 KB)

And here’s the code:


Basically the world is static and the camera moves around the world.
The rendering code decides which tiles are on screen and renders only those tiles.
The rendering loop takes the coordinates of the tiles,
feeds them into a hash function,
and then limits the output of that hash function to an index of one of following 4 images:

Star0 Star1 Star2 Star3

If that doesn’t make sense,
I’ll write a clearer explanation later.


I’m sure there’s a way to add parallax,
but it’s going to involve some maths so I’ll have to mull it over.
I know it will involve scaling coordinates at least, it’s just a question of how.

1 Like

Ah, thank you! Ill be away from the computer a bit but ill take a look as soon as I’m able

1 Like

Sorry, just to try to keep things from jumping around too much, back to this thread…

I can understand things up to the hash fuctions, then im lost, just because there are too many operators I dont know about or understand yet (more specifically the different bitwise operators). I looked into them each individually and have an idea of what each does on its own, just seeing it all together i get a bit lost as to whats going on. But Im just going to keep reading about what i dont get yet (to try and spare you too long an explaination) and hopefully things will make more sense.

Oh, you should have said so sooner.
I didn’t realise it was the operators you were having problems with.


^= is the compound form of ^, which is the xor operator.
<< and >> are the bit shifting operators.

To understand them you first need to understand binary.
https://www.mathsisfun.com/binary-number-system.html

Personally I find that thinking of binary numbers like this helps a lot with understanding them:
powers-of-2

(This way of looking at them is also fundamental to certain types of calculations where binary numbers are treated as polynomials. Polynomials still scare me slightly.)

<< shifts the binary digits left.
So for a single shift 0110 becomes 1100, and 0101 becomes 1010.

>> shifts the binary digits right.
So for a single shift 0110 becomes 0011, and 0101 becomes 0010.

(Note: ‘bit’ is actually short for ‘binary digit’.)

^ is a bit different, it takes two numbers and applies the outcome of a ‘truth table’ over every bit:

left right output
0 0 0
1 0 1
0 1 1
1 1 0

Or to put it another way, the output is 1 if only one of the two bits is 1.

So 0110 ^ 0101 would become 0011 because:
0 ^ 0 becomes 0
1 ^ 1 becomes 0
1 ^ 0 becomes 1
0 ^ 1 becomes 1


To help you understand what’s going on, here’s a version that only introduces new variables rather than modifying old ones:

uint32_t hash(uint32_t value)
{
	const uint32_t v0 = value;
	const uint32_t t0 = (v0 << 13);
	const uint32_t v1 = (v0 ^ t0);
	const uint32_t t1 = (v1 >> 17);
	const uint32_t v2 = (v1 ^ t1);
	const uint32_t t2 = (v2 << 5);
	const uint32_t v3 = (v2 ^ t2);
	return v3;
}

So basically I’m just mixing up all the bits and making a real hash of them.


But frankly, the hash function could have just used arithmetic operators.
Some hash functions do.

Ultimately unless you’re a particularly good mathematician, all you can do with hash functions is either borrow someone else’s function or do trial and error until you get some nice output.

In the cases of generating backgrounds/terrain you don’t need to worry too much about the quality of the function because of the way it’s being used.

This page has some examples of some hash functions (all operating on arrays of characters, but don’t worry too much about that, the point is the mish-mash of operations being used):
http://www.partow.net/programming/hashfunctions/#AvailableHashFunctions


Usually I end up getting sidetracked because I end up clicking on many different links or doing something else part way through an explanation.
(Or just getting lost in thought.)

1 Like

Well, to be fair there’s still a bit more i dont understand yet, its also just a matter of identifying what all that is too… partly being as much a beginner as I am and it also doesnt help I have ADHD so i can just get a bit overwhelmed looking at a lot of new information at once, can just be a lot to take in at first, but i just wanted to try to break it down and identify what each part was before asking too many questions (so i could do as much of my own homework first).

But that is incredibly helpful, thanks a lot! I sort of understood the concept of bit shifting, didnt really understand anything about the xor operator and didnt really know anything about binary at all though… knew what 8 bit meant but didnt even know what bit was short for. But that helps clarify a lot, and between the explanation and reference material i can see theres a sort of pattern to the counting/numerical values, thanks a lot!

And I definitely understand more about the concept of hash values, just as for whats actually going on under the hood its a little beyond me at the moment, but like i said, i still have my own homework to do yet to get a better idea just where im lacking and what i can get some idea of on my own, then ill have some more questions. Thanks again!

Which things?

If you think you’re overwhelmed,
imagine what it must be like in my head. :P

A worked example of XOR

The truth table for XOR is as thus:

left right output
0 0 0
1 0 1
0 1 1
1 1 0

Assume you want to apply xor to two 4-bit values:
0110 and 0101.

The right most bit (the ‘least significant bit’) is the 0th bit.
The left most bit (the ‘most significant bit’) is the 3rd bit.

So you start with the 0th bit.
The 0th bit of 0110 is 0.
The 0th bit of 0101 is 1.

So your ‘left’ bit is 0 and your ‘right’ bit is 1.
Looking at the truth table, a ‘left’ bit of 0 and a ‘right’ bit of 1 gives an output of 1.

Then you move on to the next bit and repeat that process,
so you end up with the following steps:

index left right output
0th 0 1 1
1st 1 0 1
2nd 1 1 0
3rd 0 0 0

Thus 0110 ^ 0101 == 0011.

An alternative approach

An alternative way to look at it is to think of each bit as representing a boolean value.
Think of any 0 bit as false and any 1 bit as true.

Then you can express XOR in terms of logic:

If either a or b is true, then the output is true
If both a and b are true, then the output is false
If neither a nor b is true, then the output is false

(Which is exactly what the ‘truth table’ says.)

This way of viewing it is closer to XOR’s origins in boolean logic.

It’s the same pattern in any number system with any base.

How bases work

Base ‘X’ means that the system has ‘X’ symbols that it can use to represent its digits.

  • Binary is base 2, so there are 2 symbols:
    • 0 1
  • Decimal is base 10, so there are 10 symbols:
    • 0 1 2 3 4 5 6 7 8 9
  • Hexadecimal is base 16, so there are 16 symbols:
    • 0 1 2 3 4 5 6 7 8 9 A B C D E F

It starts to get complicated when you need a second digit though:

  • In base 10, the value ‘10’ means you have cycled through all 10 symbols once, thus is has a value of 10 (in decimal)
  • In base 2, the value ‘10’ means you have cycled through all 2 symbols once, thus it has a value of 2 (in decimal)
  • In base 16, the value ‘10’ means you have cycled through all 16 symbols once, thus is has a value of 16 (in decimal)

Then things get even trickier as more digits come into play.
The best way to understand what happens then (though not the easiest way is to understand how the relationship between the digit’s position and the number’s base.
That relationship is exponentiation.

The value of any digit in any numeral system is the numbers’ base raised to the power of the digit’s position.

So the Nth digit (using 0-indexing) in a base M system is a multiple of MN.
Some examples:

  • The 4th digit in a base 10 system represents multiples of 104, i.e. multiples of 10000
  • The 4th digit in a base 2 system represents multiples of 24, i.e. multiples of 16
  • The 4th digit in a base 16 system represents multiples of 164, i.e. multiples of 65536

If it didn’t make sense before then perhaps this will make sense now:

powers-of-2

If that still doesn’t make sense…
You could try counting on your fingers:
https://www.mathsisfun.com/numbers/binary-count-fingers.html

That’s not really a problem.
It’s very rare to need to write your own hash function.

1 Like

Well like I said, I’m still trying to determine just what it is i don’t understand, can just tend to bled together a bit at first :stuck_out_tongue:

I can definitely follow those parts now though, thanks! I also didn’t quite know what msb and lsb were- knew what they meant but didn’t know how to identify them, so that was helpful for that too, thanks again!

1 Like

Terminology

For the record, I made this image last year in november.
You’re not the first person to have that problem and you won’t be the last.

1 Like

Alright, sorry for the delay, had another computer die on me (among plenty of other frustrations x_x) but I’ve finally gotten all that’s taken care of and wanted to get back to it. I’ve been thinking of rewriting (most of) this game, partly to refresh my memory by implementing more things from the beginning (use of structs, user defined functions, better organization, etc.), and partly because I have a fairly realistic end goal in mind, and both are falling into place more as I’m taking better steps to outline.

That being said, I definitely want to keep the parts you did last (the camera and random background) because it can be used elsewhere in the game as well so it helps a lot with resources down the road too, I just have a couple questions/concerns yet…

Now that’ I’ve given the hash function another look i understand what you’re doing now, and I see in the code there’s a comment saying it was largely trial and error… I think that’s where I was getting hung up before, not being sure why you were using >>, <<, specifically, but I can settle with trial and error.

But where I do have questions… is there still a way to loop the map? For the flight part I just want the map to be finite, which is easy enough to implement using boundaries, but I was thinking a secondary game state where the player is on a planet walking around and the map coordinates themselves looped around.

And also, is there a way to implement the parallax for the flight parts? If not I can settle without, it’s just a nice effect :stuck_out_tongue:

And I can start rewriting the game before i potentially implement these things, certainly doesn’t hold me up any, just figured I might as well ask

1 Like

I like the name Ardunaut!

Good luck with the development. As questions as needed - as you know someone will jump in with some help.

2 Likes

Thanks! I’m just gonna go ahead and get started on it, can’t imagine I’ll have too much difficulty this time around (other than the couple things I mentioned above)… everything else seems like it should be fairly straightforward.

The main end goal of the game is for the player to collect objects to increase the fuel reserve for their ship (one object per planet), which will enable them to travel to the next planet (otherwise the next planet will be too far and they’ll run out of fuel and die on the way). Each planet will have its own gravity and the player will have to finesse the landing a bit (maybe with a bit of acceleration involved and a bar/meter for them to land with their speed in the right spot). Upon landing your fuel reserve will get refilled, and on each planet you can exit your ship and fight enemies (which will increase in difficulty as you progress)… I’m also thinking to include random powerup drops too, to increase things like player attack power, defense, and health, though I will also have to cap this so the player can’t just grind and get OP. And lastly I’d like to implement a save state at some point so the player doesn’t have to do it all in one go.

I have this outlined and organized better on paper, but that’s the idea at least… and I should be able to get the bulk of it done on my own. There are also a few places I may have to change some things (such as the perspective when out of the ship) in order to save memory, but these details can be figured out once I get further along. I’ll get started on it this weekend though.