Inverse Kinematics Demo

Hi,
I wanted to take a look at C++ classes so I made a small Demo where you can move a Rope around.
Nothing special just a small experiment.

My Pokitto didnt arrive yet so I have no Idea if this runs on actual Hardware it worked fine on the emulator though.

3 Likes

:open_mouth: Do you have a gif? I’ll try this as soon as I get to my PC.

(EDIT: F3 on emulator records gifs.)

1

adding more elements would obviousy make it look more organic right now it has 10 segments each 8 pixels long

EDIT:
Here is another example with 30 segments
1

EDIT2:
Another quick gif where the rope segments get bigger and further apart
1

4 Likes

Cool! Is it demanding on performance? I can see this potentially being used for some nice effects.

EDIT:

Switching from float to fixed point should help to make it faster.

I would guess so. I used some floating point math to get it to look this wavy. However I didnt make an effort to optimise and I have no Idea how this runs on Hardware.
The concept is quite scalable in the sense that you can choose how many segments you want to have and how often per frame you want to calculate the positions of the segments since this is only a heuristic.
Calculating it only one time per frame seems fine but you can see the tail of the rope moving slightly for a good second after you stopped moving

Let me check how it runs on Pokitto for you.

You’ve made a very nice framework, switching to fixed point shouldn’t really be a problem for anybody. I imagine the performance would matter if you had a lot of strings, like an octopus boss or something :stuck_out_tongue:

EDIT:

Runs very smooth even now (sorry, recorded via webcam :smile:):

3 Likes

@Xhaku Cool stuff! Btw I am looking into why the Pokitto has not arrived yet.

I have had bad luck with shipments lately, it seems 2 shipments have gotten lost last week.

1 Like

Thanks. I am having lots of fun with the simulator so it’s no big deal. i am starting to think that I’m cursed however. my last 3 packages didnt arrive. the 1st item was destroyed in shipment. the 2nd item was sent 3 times after which i found out that the ebay seller sent it to the wrong adress (i verified that i entered the correct one) and never bothered to send a 4th time so i got kinda nervous when the pokitto didnt arrive :stuck_out_tongue:

1 Like

Hahaha! Your luck is even worse than mine.

Posting packages through “postal services” is like:

tumblr_owu0d9l9Sv1wzvt9qo2_500

2 Likes

Made it more C++11-ish:

1 Like

I barely understand some stuff you did :blush: but you definitely made the angle situation more readable. Guess im gonna have to look structs up and what “this->direction” does.

1 Like

Forgot to mention, I didn’t check if it actually compiles so there might be a mistake or two.
I’ll compile later and correct any mistakes if I find any.


struct is the same thing as class, the only difference is that everything in a struct is public by default, whereas everything in a class is private by default.

I tend to only use struct if I’m sure I want absolutely everything to be public, otherwise I use class and mix the accessors.

this-> just accesses the class’s member variables.
Using this-> is optional, so most people don’t bother using it, but I make sure to always use this-> because it makes it clearer that I’m accessing a member variable and not a global variable, local variable or function argument

That way when you take a function out of context you don’t have to sit there guessing “is this a global or a member variable?”.
You know that anything with this-> is a member variable,
and anything else is either a local variable, a function argument or a global variable,
and you’ll be able to see where the local variables and function arguments are defined,
so you’ll be able to deduce that anything else must be a global variable.

If there’s anything else you don’t understand then I’m happy to explain it.


To preempt one of the things you’re probably going to ask, this:

Segment(float x, float y, int direction)
	: x(x), y(y), direction(direction)
{
}

Is (roughly) the same as this:

Segment(float x, float y, int direction)
{
	this->x = x;
	this->y = y;
	this->direction = direction;
}

Which is the same as this:

Segment(float _x, float _y, int _direction)
{
	x = _x;
	y = _y;
	direction = _direction;
}

So hopefully that clears that up.


I’d like to point out that it’s bad practice to use a leading underscore in an identifier beacause according to the standard:

Each name that begins with an underscore is reserved to the implementation for use as a name in the global namespace


If you have any questions whatsoever, feel free to ask,
either here or in a PM, whichever you’re more comfortable with.
(That goes for anyone else reading this too.)

1 Like

Thanks fo the explenation. The only thing i still dont get is all this Valuetype stuff in the Point struct

template<typename Type>
struct Point
{
	using ValueType = Type;

	ValueType x;
	ValueType y;
	
	Point(void) = default;
	Point(ValueType x, ValueType y)
		: x(x), y(y)
	{
	}
};

is this comparable to generics in java?

Yes, AFAIK it’s two names for the same thing.

1 Like

The template<typename Type> part is a template declaration.
Templates are C++'s implementation of generics, so it’s similar to Java’s generics system.
The implementation is quite different from Java’s, but the basic idea is the same - you have type arguments that allow a class or struct to work for multiple different types.

If you’re used to Java’s generics system then you can think of them as being the same but with different syntax.
Truthfully the implementation details are _a lot differen_t and at some point that difference will become important,
but for now you can think of them as the same thing but with different syntax.

(I’m happy to explain the differences, but it would probably be a very long explanation.)

Beware assuming them to be the same thing,
the implementations are vastly different and C++'s template system is far more powerful.

Edit:
Importantly, thanks to Java’s Type Erasure mechanism,
when a Java object talks about T it’s actually using java.lang.Object with a load of casts everywhere.
In other words, List<String> is the same as List<Integer> and both are actually just List<Object> with some added runtime (i.e. performance penalty) casts.
For more info see Wikipedia.

Type erasure is a cheap and nasty approach to generics.
C# learned from this mistake and used reified generics instead.

C++ doesn’t have this issue because every instantiation of a template is a distinct type.
All type checking is done at compile time - there’s no extra runtime cost.


using ValueType = Type creates what’s called a type alias.
It means that from then on, ValueType is equivalent to Type - both identifiers represent the same type.

I could have not bothered with the type alias, and just written this:

template<typename Type>
struct Point
{
	Type x;
	Type y;
	
	Point(void) = default;
	Point(Type x, Type y)
		: x(x), y(y)
	{
	}
};

Which would have worked just as well, and for the sake of your program wouldn’t have made any difference.

I included the alias because it makes obtaining the type of the members easier in certain circumstances.

For example, if I was using the definition of Point<T> without using ValueType = Type;, and then did:

using IntPoint = Point<int>;

I would have no easy way of retrieving the int type.
(There are ways, which I’ll demonstrate later.)

However, if I used the definition of Point<T> that includes using ValueType = Type; then I can do this:

IntPoint point = IntPoint(4, 5);
IntPoint::ValueType x = point.x;

So basically, it provides a way of accessing the type parameter when you aren’t the one supplying it.
This is quite common for templated types from the C++ standard library.
For example, here are the aliases that std::array defines.(Which includes value_type - the standard library prefers ‘snake case’ for its types, I usually prefer ‘Pascal case’ unless I’m trying to make something compatible with the standard library.)


Now, if I hadn’t defined ValueType, there are still two ways I could have obtained the type.
Firstly:

IntPoint point = IntPoint(4, 5);
using ValueType = decltype(point.x);
ValueType x = point.x;

And secondly:

IntPoint point = IntPoint(4, 5);
auto x = point.x;

(Technically this second way only works for variables and certain specific situations.)

So, why is the using ValueType = Type; approach used despite having these other two methods?
There’s three reasons.

Firstly, because auto and decltype were both added in C++11, prior to that in C++03 and C++98 they didn’t exist, so the type alias approach was the only viable approach.
(In fact, using didn’t exist prior to C++11. Originally you had to use typedef, which has much more confusing syntax.)

Secondly, because it’s a better way of making the type self-documenting.
By using IntPoint::ValueType explicitly, it makes your intent more obvious - it makes it clear that the type is intended for holding values.
(Using auto everywhere can start to make the code look a bit cryptic in some cases.)

And thirdly, sometimes it’s just easier to work with than the alternatives.

2 Likes

Read dangerous :smiley:

1 Like

Templates is very time consuming, but sooooo worth it when it finally manage to compile

How exactly are they dangerous?

I can’t think of anything dangerous that they can achieve that isn’t already possible in non-templated code (like messing around with void *s, or doing type-punning - both of which creep into the nasal demon realm).

Time consuming to learn or time consuming to make?
In my experience they usually take the same amount of time as a specialised class,
unless you’re doing something especially difficult (e.g. fixed points, SI units).

They can take some time to truly understand, but they’re well worth knowing.
I think many people misconstrue normal template usage as being like meta-template programming,
when really it isn’t.
Most of the time, it’s no more difficult than the Point struct that I introduced to this kinematics demo.

Meta-template programming isn’t something people are going to need often (especially with C++11’s introduction of constexpr, which allows many former meta-template classes to be replaced with functions).

Really though, with the exception of a few rare cases,
meta-template programming typically isn’t much different to using higher-order functions.
If you can sit through LYAH from chapter 1 through to chapter 6 then meta-template programming should be a doddle in 80% of cases.

Factorial Example

Factorial as a function:

constepxr std::uintmax_t factorial(std::uintmax_t n)
{
	return (n > 0) ? 1 : (n * factorial(n - 1));
}

Factorial as a meta-template:

template<std::uintmax_t n>
struct factorial
{
	static constexpr std::uintmax_t value = (n * factorial<n - 1>::value);
};

template<>
struct factorial<0>
{
	static constexpr std::uintmax_t value = 1;
};

The syntax is different, but the concepts are the same:
Pattern-matching, Recursion and piecewise functions.

(And arguably recurrance relations, but that’s just a fancy term for a recursive function that generates a sequence.)

To make! Usually it’s simpler to use - thought it can be a pain in the ass because of the diagnostics messages.

Well, I’m not an expert C++ programmer either; just talking from my limited experience, and I’m certainly not a genius programmer either; and I feel like my focus capacity has been downed for

I rely more and more on template, and they’re definitely an indispensable tool for me.
Still, I maintain that, for me, thinking in “template” -especially when conceiving them- is harder than template-less code.

Also, I’m not talking about basic stuff like std::max and Points, etc! I’m skilled enough to tackle them as easily. However, for the more complex stuff I do struggle much more with template-based solutions (funny thing is that I’m also much more satisfied when achieving something hahaha) than with non-template-based ones, with my everyday adventures in C++.

There are some reasons for this:

  • I don’t craft each day -sometimes weeks- new template class/function that requires advanced concepts such as SFINAE.
  • Thinking in templates is about thinking the problems under sometimes very different angles, frequently a plain 180° haha
  • Diagnostics messages don’t help much. I’m really sorry, but most of the time they’re just misleading, plenty of way too much information and very hard to read. However they DO improve them, and I feel like it’s getting better and better every year.

I love template programming because it’s so rewarding when it works. Compile-time checks are just awesome, and it’s like seeing a puzzle making itself haha

1 Like

More power is always more dangerous, all I’m saying :slight_smile: It’s a double edged sword.

More power implies for example a bigger probability of misuse, compiler bugs, confusion, … means more work, complexity, fewer things we can assume about the system, …

I’ve once listened to an interview with CMake devs and they said they specifically didn’t want to use an existing general purpose language and rather made their own computationally limited language because if they used e.g. Python, people would start abusing it and messing things up. They’d have to think about all the possible imaginable things users could potentially do. So I think it’s important to also think about not making a tool more powerful than it needs to be.

I guess I just wanted to point out this general principle, nothing personel against templates. You know, I’m always the antithesis :smile: