[WIP] Ardunaut (previously Parallax rocket launch)

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.

Alright, so Ive hit my first snag… luckily its something fairly minor, just something I hadnt quite understood the last time around.

I updated my code in the repo here, to reflect where I am since starting over: https://github.com/CatDadJynx/Ardunaut

Basically, my problem is that I have a function located in the Player.h file (playerAnimate) which I need to call in the Camera.h file under the button presses (so that the player sprite is animated on button press), but this would require the Camera.h file to #include “Player.h”, while Player.h also needs to #include “Camera.h”, and this is giving me errors… Ive tried using #pragma once, but am still a little confused where and how to use this, so I still havent had any luck. The code in the repository has the playerAnimate function included but does not use it anywhere (because thats as far as I got it working).

I didn’t see this topic revived the first time round so it must have been buried under other active topics.


Good plan.

As ever my advice is to list the things that need to be completed and steadily break them up into smaller steps.

Actually, I’ve since discovered that I didn’t create the hash function,
I stumbled upon it when researching hash algorithms and forgot to take note of the original author so for quite a while I was convinced I’d invented it by accident.

The truth is that it was invented by a man named George Marsaglia.
Originally it was actually intended to be used as the iteration function for a pseudo-random number generator,
and it’s actually one of many iteration functions following a similar pattern,
which are collectively known as xor-shift generators.

So there is an actual mathematical basis behind why/how it works,
but it’s easier to just accept that it works without questioning it than it is to understand the concept behind it.
If you really want to know you can read Marsaglia’s paper about it.

That’s what modulo is for.

So there’s a way, and it will involve the modulo operator (%) but the exact details of how it’s used will depend on the circumstances in which you intend to use it.

Probably.

I don’t really remember many details about the project (it was 8 months ago and I’ve had half a dozen projects enter and leave my mind since then),
but if the backgrounds are merely pseudo-randomly generated stars,
or some kind of planet surface on top of pseudo-randomly generated stars then parallax should be possible.


Ignoring suspension of disbelief for a moment,
a decent scientist would calculate whether they could reach the next planet before launching and decide not to launch when they realised they wouldn’t have enough fuel. :P

Variable gravity will complicate things slightly.
When you get to that point, have a read of this:

Make a list of features and prioritise them.
Ignoring the potential difficulty of having all these interacting components,
there’s the memory limitations to bear in mind,
so you may have to make some sacrifices.

You might not, but if you do it’s good to know ahead of time what you’re prepared to drop if you have to.


Ah, the classic cyclic reference scenario.
There are two ways to solve this.

The better solution is to not have to call playerAnimate from Camera.
My question to you is “why is the camera animating the player?”,
followed by “is there perhaps a better candidate for animating the player?”.

There is another solution, but I won’t go into that unless the better solution won’t work.
(It involves creating a .cpp file.)

#pragma once is needed at the top of all header (.h) files,
but not in source (.cpp) files.
It’s used to prevent the same header file being included more than once.

To understand #pragma once and .h vs .cpp files you need to understand the compilation process,
but I won’t explain that now because this comment is already quite large.


Without going too much into reviewing the code, my immediate reaction to Player.h is:
“Why is position part of Player but playerSprite and playerFrame aren’t?”

1 Like

Oh alright, thanks! That’s all super helpful. I’ll read more into that hash function/the resources you provided and see if it makes a bit more sense. I’ll look into the modulo as well, once I get to that point. I’ll look at your physix demo again as well. And as for space/memory limitations, I’ve had some details that are dependent on that, but I think I can fit a good portion of what I have planned, since it would reuse the camera code you provided (which already takes up very little space).

And yeah, it dawned on me last night as I was trying to fall asleep (naturally) that I should probably just move the input out of the camera header and into its own input file (because there will be additional input anyway). Thanks!

1 Like

If you actually manage to sit through Masaglia’s “Xorshift RNGs” paper and understand it,
could you do me a favour and explain it to me?

I have neither the patience nor (probably) the mathematical ability. :P

When you do, best compare it to some reading material about physics to see what’s what:
https://www.mathsisfun.com/physics/index.html

And as always, feel free to ask any questions.

More specifically, you may want to consider having some outer class that contains both the camera and your player and manipulates them based on user input.

(There are reasons as to why this tends to be the better architectural model, which I can go into if you’re interested, but I don’t want to overload you with information.)