[WIP] Ardunaut (previously Parallax rocket launch)

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

:laughing: Fair enough. If you dont understand it then chances are I wont, but certainly wouldnt hurt to take a look at it anyway.

Thanks, will do!

Thanks, Ill definitely keep that in mind! I was worried if I made another header file for user input that i might start to clutter things up too much that way, so Ill see if i can find a sensible way to organize/balance between the three (player input, camera, and player header files). Thanks!

1 Like

I understand how it works (xor-ing and shifting),
but I don’t understand why it works.

I’ve looked at the ‘Theory’, but I lose the will to continue reading at:

Because f is 1-1 over Z, the random variable f(z) is itself uniform over Z, as is f2(z); indeed, each element of the sequence f(z),f2(z),... is uniformly distributed over the seed set Z, but they are not independent.

So until I can find the patience I’m happy to accept that it’s magical voodoo that just works.

Mini rant...

I love how it says “indeed” as if what’s being said is some innately natural conclusion that a 5-year old ought to understand. It’s this kind of publication that lead me to refuse to deem anything as being “obvious” - one man’s “obvious” is another man’s arcane jargon.

Don’t be afraid to have one header file per class,
the more important thing is that each class is a clearly defined logical unit.
(I.e. each class has a single job/responsibility, you aren’t mixing different roles into the same class.)

Remember: the player playing the game/providing the input is not the same thing as the character that the player controls.
It’s often lost in casual/user-end discussion of games,
but it’s an important semantic distinction when actually writing a game.

1 Like

Ahh probability theory, (sarcasm) my favorite (/sarcasm). All that is saying roughly is that the for each and every input to the random variable function will output a unique output (so no two inputs can give the same output or no two outputs will have the same input). However in the case of xor+shifting the output is pseudo-random and deterministic in that the same seed will always yield the same sequence which can be calculated. Creating a truly random function is very difficult and often hinges on using a random enough seed based on some measured random physical phenomena.

1 Like

This is precisely why I hate mathematicians and formal papers and why I like the website mathsisfun.
If it can be explained in plain English like that, why avoid doing so?

And in this case, why not just say “it’s a bijective/injective function”?
(Preferably accompanied with a plain English explanation of what those terms mean.)


Unfortunately I already knew everything else you mentioned,
so it doesn’t get me any closer to the why.

1 Like

Hmm… so i moved the input to its own header file and moved a few other things around to reflect these changes… and it compiles and uploads fine, but for some doesnt animate my sprite. Updated the repo as well.

Looking only at the PlayerInput.h I’ve already got an inkling as to what the problem might be.
I’m betting your player has 4 frames of animation…


I was half right.

I think the main problem is that the animation is so difficult to see,
but the other problem is that you forgot the need for braces when you have more than one statement to pair to an if.

You have:

void cameraInput(){
    if(arduboy.pressed(LEFT_BUTTON) && camera.position.x > -300)
    --camera.position.x;
    playerAnimate();
  
  if(arduboy.pressed(RIGHT_BUTTON) && camera.position.x < 300)
    ++camera.position.x;
    playerAnimate();
  
  if(arduboy.pressed(UP_BUTTON) && camera.position.y > -300)
    --camera.position.y;
    playerAnimate();
  
  if(arduboy.pressed(DOWN_BUTTON) && camera.position.y < 300)
    ++camera.position.y;
    playerAnimate();
}

Which is equivalent to:

void cameraInput()
{
	if(arduboy.pressed(LEFT_BUTTON) && camera.position.x > -300)
	{
		--camera.position.x;
	}

	playerAnimate();
 
	if(arduboy.pressed(RIGHT_BUTTON) && camera.position.x < 300)
	{
		++camera.position.x;
	}

	playerAnimate();

	if(arduboy.pressed(UP_BUTTON) && camera.position.y > -300)
	{
		--camera.position.y;
	}

	playerAnimate();

	if(arduboy.pressed(DOWN_BUTTON) && camera.position.y < 300)
	{
		++camera.position.y;
	}

	playerAnimate();
}

Thus playerAnimate(); is called 4 times in a row.

I’m suspecting the intent was to call playerAnimate(); only if the button was pressed?

1 Like

Yeah, the sprite has 4 frames, which I thought were frames 0-3, if I’m not mistaken?

And that makes sense. I should have just added the curly braces when I copy and pasted out of your code, didn’t realize that would happen with more than one statement involved. Thanks!

1 Like

Don’t get me started on obfuscation in academia, I spent years and years struggling against it (and as a TA I spent too much time rewriting/explaining lab documentation in a way normal undergrads could reasonable digest). As to your question of why, there really isn’t a good answer other than classically linear feedback shift registers have long been used in computer science to approximate a random function because for all intents and purposes the output appears random to the untrained eye.

1 Like

That’s correct. playerAnimate itself is correct, the problem was just:

  • How it was being used (not actually inside an if)
  • Your actual frames are quite similar
    • 3 are exactly the same, 1 is only different by a single pixel

That’s one of the reasons some programmers prefer to use full curly braces even if there’s only a single statement.
I’ve tried that in the past, but I feel that it just adds unnecessary clutter.

Another way to think of it is that curly braces (within a function) are actually a statement themselves,
a ‘compound statement’ that groups together other statements (which are executed sequentially),
so really if statements only ever have a single sub-statement.
(I checked, I’m not making that up, compound statements are part of the language rules.)

If you aren’t sure what counts as a ‘statement’, have a skim of this article.
A good rule of thumb is “anything inside a function that ends in a curly brace” (with the addition of named statements (if/else, while, do/while, for, switch)").
(There’s a few others, but that’s probably all you’ll have to worry about.)


It’s one of the many reasons I didn’t bother to attain a higher qualification than what I have.

It’s also one of the reasons I started my Resource Collection.
Good, friendly, human readable explanations are like gold dust and should be clung to for dear life.

TL: It’s voodoo, just accept that it works. :P

1 Like