Tile Collisions?

At least the author calls it out. I hadn’t read that or maybe I forgot!

Yep … but then again articles simply reflected the author’s interests at the time. Was ‘variables’ spelt incorrectly in the article?

I’m playing all the right notes, but not necessarily in the right order.
- Eric Morecambe (John Eric Bartholomew)

I was more interested to see if they had ‘spell-checked’ the mag - I wasn’t testing you!

In that case, yes, the magazine was spell-checked for that part.
(Though obviously not fully grammar-checked as my earlier [sic] should indicate.)

I think I better understand what it’s doing, but the whole static_cast line throws me off.

When trying to compile in the Arduboy emulator it throws this error: 02%20AM

Obviously I can’t really comprehend that error either, I’m mostly sharing it FYI :stuck_out_tongue:

I understand that a pointer refers to the address in memory where a certain value is stored. I guess my confusion starts when I try to comprehend what the point (pun intended, I guess) is when it’s always possible to just store something in a variable and grab it again later without needing its address-of at all.

I agree with this! I’m a web developer, so I have the absolute fundamentals of control flow, variables, arrays, etc. etc., but everything beyond that related to game development/C++ is out of my reach currently. I went through @crait’s tutorial with no problem (at least until the tile rendering part), but obviously that only covers the bare minimum.

I’m a little afraid all these intermediate/advanced concepts are scaring me away from starting to actually develop a game, but at the same time I’d rather learn how to do these things correctly from the start. It’s looking like the magazines might not be the best route to take for all this.

When you said ‘fundamentals’, were you referring to fundamentals of just programming logic in general or more specific game development/Arduino/C++ stuff? That’s the stuff that’s a little harder to grasp, since looking at the source code of, say, 10 Arduboy games has shown me 10 different ways to do just about everything.

I’ll be going through your (@filmote)'s tutorial for the endless scroller shortly, which I’m hoping to get some fundamentals to make my own sort-of endless scroller game idea with, while using all these things from @Pharap also. But I try to make sure I can at least grasp what it’s all doing before just copying and pasting it in, since I’ll surely be using it more than once.

1 Like

Drat.

I know what the problem is, and I’ve actually learnt something interesting in the process.
I thought static_cast would work because it works with pointers to other types,
but apparently function pointers are a special case where static_cast won’t work for technical reasons.

Use reinterpret_cast instead and it should work.

Presumably you already know that casting is how you convert types.

In C++ there are several different kinds of cast that perform different kinds of conversions.

Really you only need to know about static_cast and reinterpret_cast because those are the ones you’re most likely to need,
but I’ll include information about the others for the sake of completeness and to explain why you probably won’t need them and/or shouldn’t use them.

static_cast is the most common kind of cast,
which simply converts one type to another type when there’s a well-defined way to do so and when the conversion is safe.
Some of the things you can’t do with static_cast include:

  • Converting types for which no conversion operator is defined
  • Converting a pointer to a (non-void) type to another (non-void) type*
  • Converting void * to a function pointer
  • Converting pointers to integers
  • Casting away const

* There are cases where this is possible, but doing so can be dangerous because the type compatibility check only happens at compile time. See dynamic_cast for more info.

reinterpret_cast is the second (or maybe third) most common cast.
It can perform various unsafe conversion operations.
It can be used to:

  • Convert pointers to integers
  • Convert a pointer to a (non-void) type to another (non-void) type
  • Convert a void * to a function pointer

If you find yourself using reinterpret_cast is usually means you’re doing something platform-specific that relies on hardware details, or something unsafe and dangerous that you really ought to think twice about.

Some say it’s actually the most dangerous cast, but it’s quite common in embedded systems because there’s a lot of unfortunate hardware details that have to be taken into account.

dynamic_cast **`dynamic_cast`** is the third (or maybe second) most common cast. It's the only C++\-style cast that has a runtime cost. It converts pointers or references to classes up, down or sideways along the inheritance hierarchy. Most often it's used to convert a parent class to a child class. The runtime cost exists because it checks that the conversion is valid at runtime, which requires checking runtime type information (RTTI). E.g. if you try to convert `Parent *` to `ChildA *` when the object is actually a `ChildB` then you'll get a `nullptr` because the conversion isn't valid.

static_cast can perform the same conversions that dynamic_cast can, but it only checks at compile time,
so dynamic_cast is actually the safer option in that particular case.

This is one of those cases where C++ hands you the chainsaw and says “try not to cut your fingers off, it’s messy!”.
Most other languages just won’t give you the chainsaw in the first place because they don’t trust you to use it properly.

If you find yourself using dynamic_cast, it’s another sign that you might want to stop and rethink your design.
Most of the time dynamic_cast can (and should) be replaced by polymorphism.
Personally I’ve never had to use it in any code, embedded or desktop,
but when it is used it makes more sense on desktop than on an embedded system because RTTI costs a fair bit of extra memory.

const_cast **`const_cast`** is the least used cast. You should almost _never_ use this. `const_cast` is used for removing `const` from an object, which allows an object that should be 'read only' to be modified. Unsurprisingly, this is undefined behaviour, so the result could be anything. It could work perfectly, or it could crash your program spectactularly, [cause the CPU to catch fire](https://en.wikipedia.org/wiki/Halt_and_Catch_Fire) and then [make demons fly out of your nose](http://catb.org/jargon/html/N/nasal-demons.html). `:P`

It also has the legitimate use of removing volatile,
but needing to do that is an exceptionally rare occurance.

And lastly, the special mention:

C-style casting

C-style casting is used far more than it should be.
Ideally it should never be used, but a lot of people use it because it’s the style of casting that many other languages adopted.

C-style casting is actually a mixture of static_cast, dynamic_cast and const_cast,
which means it makes it a lot easier to accidentally introduce a bug into your program.
E.g. to accidentally cast away const, or to do a dangerous reinterpret_cast conversion instead of safe static_cast.

It tries each cast in this order:

  1. const_cast
  2. static_cast*
  3. static_cast*, then const_cast
  4. reinterpret_cast
  5. reinterpret_cast, then const_cast

* Whilst completely ignoring access restrictions that static_cast would normally respect.

(Personally I think a good reason to not use it is simply because remembering the order of those operations is a hassle. :P)

Another reason C-style casting is bad is that it’s really hard to search for using a find/find&replace tool.
If you were to take the expression (type) out of context, you can’t tell whether it’s a C-style cast or just a redundant pair of brackets around a variable without knowing whether type is a type name or a variable.

For the sake of completeness, here’s a relevant C++ Core Guidelines link:
http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Res-casts-named

Other stuff

There’s a similar SO answer [here](https://stackoverflow.com/a/332086.

And cppreference has articles for all the casts, which you can find here:
https://en.cppreference.com/w/cpp/language/expressions#Conversions

You can’t actually store a function in a variable*,
you can only store some kind of pointer or reference to a function.
(* Technically you might be able to with some hackery on certain systems, but let’s not complicate things too much.)

If that seems odd, think about what a function actually is -
a function is basically a list of machine code instructions.
If you were storing the actual function in a variable, you’d passing around the entire list of functions.
Aside from being a bit daft, on some architectures you wouldn’t be able to call that function for various reasons.
For example, if the architecture isn’t capable of executing instructions stored in RAM (the Arduboy is one of these as far as I’m aware).

So instead, you take the address at which the function is stored in memory (as a pointer),
and pass that around.

As you’re a web developer I’m guessing you’re used to storing functions in JavaScript without really knowing how that works internally.

In JavaScript a function is still a reference like it is in C++,
but it’ll almost certainly be implemented as something other than a pointer.

C++ uses pointers because it compiles down to machine code.
JavaScript uses references because it’s either interpreted or compiled to machine-independent bytecode that runs on a virtual machine, which might then be compiled to machine code at runtime using ‘just in time’ (JIT) compilation.

Honestly, some of these things you don’t actually need to know.

You would be perfectly fine with the switch statement approach,
you don’t really need to know anything about function pointers.
Neither approach is more correct, they’re different ways of solving the same problem with different nuances.
Knowing which one is more appropriate only comes with experience.
(As opposed to enum class vs macros and constexpr vs macros, where macros are the objectively inferior approach.)

You only need to know about static_cast and dynamic_cast for doing type conversions, you don’t need to know the other stuff that I included.

You will need to know about pointers to be able to make any decently sized game.
(Unless you’re happy to be given a handful of helper functions and not worry about how they work.)

The magazines are fine if you’re being more casual about learning to program,
or if you only ever want to write for the Arduboy and aren’t planning to ever write a desktop program in C++.

But they’re not really representative of what’s considered good C++.

I think that would be true of code for any language.
There’s lots of different ways to solve the same problem in any language.
Even in JavaScript you’d have the split between the switch statement and the array of function pointers (which would be ‘function objects’ in JavaScript).

C++ does have a number of language features that are somewhat similar,
but there’s usually a preferred way of doing things in most cases.

For example, C++-style casts are prefered over C-style casts and using alias = type; is preferred over typedef type alias;.
(If in doubt, find out which feature came from C and which one was added by C++, then avoid the one from C like the plague. :P).

I might be biased

That’s a good sign that your head’s screwed on correctly. :P

If in doubt about anything, just ask.
Absolutely anything, no matter how daft you think the question is or how much you think “this is probably really obvious” or “they must be fed up with this question by now”.


I’d like to add that I’m rarely fond of the word ‘obvious’. ‘Obvious’ is completely subjective - what’s obvious to one person is a complex mystery to another, and sometimes what’s ‘obvious’ turns out to actually be wrong.


Lastly, I want to leave this here:

Technically you’re not a new programmer,
but I think the advice is really good and it captures the spirit of programming.

1 Like

Thanks for all that. I appreciate all your info and honesty.

Casting and converting types is actually completely new to me, I’ve never seen anything like it in JS or even PHP. This game dev stuff is really different than web dev stuff, in my experience so far.

I’m still going through the endless scroller tutorial, as well as lessons at https://www.learncpp.com, which I saw you reference in another thread somewhere. I’m really loving it, so many practical examples and explanations about why certain things are important. I noticed that the teacher there is also hard against object-like macro #defines , and the reasoning definitely makes sense to me.

1 Like

How is that going? I sort of assumed that people would have a reasonable level of understanding but some have complained the jump between Crait’s and my tutorials is too much.

1 Like

On the one hand I’m disappointed (in the languages),
but on the other hand I’m really not surprised.

Neither JavaScript nor PHP are examples of good languages.
They both have a long list of particularly notable problems.
(No language is without its problems, C++ included, but some are more bearable than others.)

JavaScript is dynamically and (horrendously) loosely typed, which means all the bugs happen at runtime instead of getting caught at compile time.

C++ is statically and strongly typed, which means it aims to make as many potential bugs detectable at compile time as possible.

The main reason for this is that compile time bugs are generally easier to fix than runtime bugs.

Fixing runtime bugs often means examining the program’s state and trying to figure out how the program got into an invalid state in the first place, which means backtracking through a load of state changes and function calls.

To fix compile time bugs, you generally just have to understand the compiler’s error messages and examine the code.
There’s no state to worry about and no stack of called functions to step through, just code (types, declarations, statements and expressions).

One of the best real-world examples I’ve ever seen for why a static type system is better is when mixing units.

Kilometres distance = 600;
Hours time = 3;

// Works perfectly:
KilometresPerHour speed = distance / time;

// This line causes a compiler error because '3' is a unitless integer
// In a weakly typed language this would either do something unexpected
// or you wouldn't find out about the error until runtime
KilometresPerHour speed3 = distance / 3;

In fact in C++11 they added a feature that allows you to do this:

// Both of these variables end up having the same type:
// 'KilometresPerHour'
auto speed = 600_km / 3_h;
auto speed2 = 200_kmph;

Of course, C++ being C++ lets you break things if you really want to,
but having the better type safety means you’re unlikely to do so by accident.

If you haven’t encountered auto yet, it’s a C++11 feature that infers the type of the variable for you so you don’t have to type the same type twice.

This isn’t exactly the example I saw, but it’s close enough to get the idea across.
The actual example was from Bjarne Stroustrup’s 2012 Keynote.
Normally I don’t watch programming talks/seminars because I typically don’t have the patience for them (I find reading much quicker), but that one was particularly interesting.
(I can find a link to if you’re interested enough and have an hour to spare, but I won’t blame you if you can’t be bothered.)

Also there’s two reasons I mention C++11 so often:

  1. because it was the most dramatic change C++ has ever been through, and it introduced the most new features of any standard so far.
  2. because it’s the standard that Arduino programs (Arduboy games included) are compiled with (i.e. C++14+ features aren’t available)

There’s several good reasons for that.

To name a few:

  • You’ve been used to a dynamic, loosely typed language with different rules
  • You’ve been working many abstractions up from the hardware
  • Most of your code will probably have been centred around manipulating the HTML DOM tree
  • Unless you’ve been working with canvas, you probably won’t have written your own rendering code

I’m really glad to hear that.

I don’t think I’ve ever had anyone give any feedback about that website before,
usually people either ignore it or visit it and then don’t tell me what they thought of it (I can’t tell which).

I would have kept recommending it to people anyway,
but at least now I’ll know it’s not just me that thinks it’s a good website.

(It’s actually the third link on the C++ Resources in my Resource Collection, directly after cppreference and the isocpp guidelines.)

Pretty much all the sane, more experienced C++ programmers are.
Hating macros is generally a sign that someone has seen enough C++ code to have had their backside bitten and in the process learnt that macros generally aren’t worth the hassle,
or has at least heard enough horror stories to know to stay clear of them.

(They do still have one valid application, which is conditional compliation, but the more the language evolves the less relevant that use becomes because new language features are steadily eliminating macros’ monopoly on that.)

1 Like

So far it’s pretty easy to understand. I guess a little bit more explanation of the enums and how it connects to the sprite being drawn would make it a little more accessible, since classes or enums weren’t mentioned at all in crait’s

I’ll let you know as I keep going if I come across anything else with a huge jump.

OK good to know … I might revisit some of the sections if you have more feedback. The tutorial was not supposed to be a direct progression from Crait’s as he was going to complete his ‘Dino Smasher’ tutorial in between.

2 Likes

Having a quick look at the tutorial, I think it would be simpler if you only explained scoped enums and didn’t even mention plain enums.

Also maybe more emphasis on how structs behave like a cluster of variables. I might have missed an explanation because I only had a very quick skim, but whenever I introduce someone to structs I always compare the code using structs to what it would be like if the code used individual variables instead.

E.g.

struct Point
{
	int x;
	int y;
};

Point p1 { 5, 6 };
Point p2 { 10, 8 };
// Et cetera

Versus

int x1 = 5;
int y1 = 6;
int x2 = 10;
int y3 = 8;

And it soon becomes clear that structs are essentially just a way of grouping data.

(You might already have done something like that and I’ve missed it - I only skimmed.)

1 Like

Yes, looking at the code I should probably ditch the plain enums as they are not adding to the reader’s understanding. I am happy with the struct definition though.

I changed the enums to enum classes and it had a bit of a knock on effect - I then had to show how to cast them to integers and back again. I also had to mention the data types … and so on.

I think you did a nice job with this. It took me a little while last night to figure out how the enum GroundType was working, but you explained it well. Changing it to an enum class added a little extra confusion, but it didn’t take long to make sense of it again and it’s cool that you now have an introduction to static_cast in the tutorial.

Do you mention why the const byte *ground_images[] is a pointer? I might’ve missed it, but it looks like it’s just referred to as a regular “array of images” and not a pointer.

I think there’s a little mistake in the last block of code in section 3 of the tutorial, case 5:. type should be groundType, though I could be reading it wrong.

If anything it’s just teaching them bad habits,
and probably making them wonder why enums are better than #defines.
Really plain enums aren’t actually that much better because they’re not type safe.

They do have two advantages - introducing a new type, which can make code clearer (e.g. void draw(int, int, Colour) is clearer than void draw(int, int, int)) and not having to care what the integer values actually are.

But either way, scoped enums are better.
Type safety is far more important than either of the other two advantages.

If you really wanted to you could have avoided it by using a function with a switch inside it,
but that would result in more expensive code.

Ultimately if people want to dive in to being able to write code without learning the theory first then they’ll have to learn a lot of features simultaneously, it’s almost impossible to escape it.

That’s because images are actually const uint8_t *.
Specifcally they’re stored as arrays of bytes,
so to refer to them you actually use a pointer to the first element.
In fact, if you try to pass an array to a function then it will always end up becoming a pointer (something known as ‘array decay’ - the array is said to ‘decay’ to a pointer).
This is another one of those many quirks inherited from C.

(There is a way to pass whole arrays around, but there are some complications which I won’t get into unless you particularly want to know.)

If you’re wondering about uint8_t, uint8_t is a standard type that’s part of the C standard library (and also exists in the C++ standard library as std::uint8_t).
byte only exists in the Arduino library.

I’d be tempted to do away with byte altogether, but I’m guessing @filmote’s tutorial uses it becuase crait’s did and introducing uint8_t would take more explaining.

(As of C++17, the C++ standard library has a std::byte type,
but it has a different purpose - it specifically behaves as a group of bits rather than an integer.)

And this is related to those arrays of bytes being saved to PROGMEM? Just for hahas I removed that asterisk and the images came in as a jumbled mess.

Not at all, this is a C++ thing, not an AVR thing.

The only AVR factor here is that anything stored in progmem must be marked const to prevent attempts to modify the data.

If you read my explanation of const_cast then you know that const doesn’t completely prevent attempts to modify a variable, and this should also make it clear why const_cast is actually undefined behaviour - C++ can’t dictate what happens if you try to modify something that’s been stored in ROM rather than RAM.

I’m surprised the code even compiled properly.
Removing the asterisk means the array is no longer an array of pointers to const bytes, instead it’s an array of const bytes.

I couldn’t tell you exactly what would have happened without seeing the code or having more information,
but pretty much all the posibilities involve data being misinterpreted.

Yes there is and I have fixed it, thank you.

Agreed but in the original tut, I had avoided a number of topics (like casting) be using non-scoped enums. Likewise I had stuck with Crait’s use of int everywhere rather than delve to 8 and 16 bit, signed and unsigned integers. I have swapped them all out now but it just means there is yet another thing making the gap between the two tutorials wider.

Using int isn’t inherantly bad, it’s just a bit more expensive in places.

Similarly unsigned char instead of uint8_t is also not that bad,
but uint8_t will always be exactly 8 bits wheras unsigned char won’t always,
and of course it’s a bit more self-documenting (and less typing if typing bothers you).

But with char you pretty much have to specify signed or unsigned because char is classed as a distinct type and its signedness is unspecified.
(As with a lot of the weirder quirks of C++, this was a decision inherited from C.)
(I ought to start maintaining a list of weird things that were inherited from C.)

I’d say the best solution would be to introduce introduce your own set of prequel tutorials so you’re no longer trying to follow crait’s footsteps, but I know writing tutorials can be a hassle.