Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2  (Read 41437 times)

0 Members and 1 Guest are viewing this topic.

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #15 on: December 29, 2013, 08:27:45 pm »
I've looked at part 3, and it's really nice how detailed you explain everything. Also the comments in the code are very useful.

Some remarks:
  • You could use size_t for indices, to avoid conversion warnings on some compilers.
  • In the NaiveVector, the condition should be if (capacity <= size) instead of if (capacity < size). Imagine the case size == 1: After writing the element size will be 2, but you don't reallocate the array, so the next time you have the invalid index access ptrToArray[2]. Likewise, the copy loop accesses an element out of range, since size > capacity. In fact, size should never be bigger than the capacity.
  • Less important: It might be meaningful to reallocate at the beginning, so you only do it when necessary. I personally also find if (size >= capacity) more intuitive, since the variable you query and which you have just changed appears first.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

SuperV1234

  • SFML Team
  • Full Member
  • *****
  • Posts: 188
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #16 on: December 31, 2013, 06:03:59 pm »
I've looked at part 3, and it's really nice how detailed you explain everything. Also the comments in the code are very useful.

Some remarks:
  • You could use size_t for indices, to avoid conversion warnings on some compilers.
  • In the NaiveVector, the condition should be if (capacity <= size) instead of if (capacity < size). Imagine the case size == 1: After writing the element size will be 2, but you don't reallocate the array, so the next time you have the invalid index access ptrToArray[2]. Likewise, the copy loop accesses an element out of range, since size > capacity. In fact, size should never be bigger than the capacity.
  • Less important: It might be meaningful to reallocate at the beginning, so you only do it when necessary. I personally also find if (size >= capacity) more intuitive, since the variable you query and which you have just changed appears first.

Thanks for the feedback. I've made the changes to code.

SuperV1234

  • SFML Team
  • Full Member
  • *****
  • Posts: 188
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #17 on: January 04, 2014, 02:38:34 am »
I've uploaded the fourth episode of "Dive into C++11" on my YouTube channel.

Video || Playlist

After looking at C and C++'s memory and lifetime management in part 3, we'll take a brief look at C++11 smart pointers. We will learn what they are, what problem they solve, their advantages and their uses.

The intended audience for this tutorial/screencast are people who have some experience with C++ in general, and who watched the previous episodes.
This episode may be very interesting for pre-C++11 users who want to learn modern C++11 memory management, but it is also suitable for beginners.

I greatly appreciate comments and criticism, and ideas for future videos/tutorials.

Feel free to fork/analyze the source code at: https://github.com/SuperV1234/Tutorials

SuperV1234

  • SFML Team
  • Full Member
  • *****
  • Posts: 188
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #18 on: December 02, 2014, 03:25:06 pm »
I'll resurrect the thread with a new video that game developers could find interesting:

"If I want to store entities contiguously to improve efficiency, how can I keep track of them?"

http://www.youtube.com/watch?v=_-KSlhppzNE

In the video, I show two possible ways of dealing with entity storage and management:
  • Storing entities on the heap. Entities are easy to keep track of, but iteration is inefficient. Very easy implementation.
  • Storing entities contiguously. Iteration is cache-friendly, however it is hard to keep track of specific instances. Complex implementation with custom handles.

Hope you find some of the concepts in the video interesting!
I'm looking forward to your feedback and to more ideas on entity management.

Rhimlock

  • Jr. Member
  • **
  • Posts: 73
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #19 on: December 05, 2014, 01:13:12 pm »
Nice video.

In my current project, I'm storing my entities in a heap (vector of unique_ptr).

Storing the entities cintiguously sounds interesting. but I'm wondering if sorting the atoms, marks etc. might turn out to be more inefficient than using a heap.

What if you don't delete the dead entities, but keep track of their index in a vector and just overwrite them, when you create new entities. That way each entity would keep its index.

Mörkö

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #20 on: December 07, 2014, 12:52:03 am »
What problem have you solved? It seems like a solution to a non-existent problem.

You are asserting that the new approach is better but I don't see any reason to believe it. I was going to call it "premature optimization" but you haven't actually optimized anything, where is the analysis that proves the new system is more efficient? All you have is a code comment that says it's better.

If you are going to optimize something, then start by taking a real problem or at the very least an abstracted version of a real problem and apply your solution there so that you can show the data reflecting the improvement.

SuperV1234

  • SFML Team
  • Full Member
  • *****
  • Posts: 188
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #21 on: December 07, 2014, 03:09:21 pm »
Nice video.

In my current project, I'm storing my entities in a heap (vector of unique_ptr).

Storing the entities cintiguously sounds interesting. but I'm wondering if sorting the atoms, marks etc. might turn out to be more inefficient than using a heap.

What if you don't delete the dead entities, but keep track of their index in a vector and just overwrite them, when you create new entities. That way each entity would keep its index.

Thanks for the feedback.

The advantage of storing the entities contiguously is cache-friendliness, which makes iteration very efficient.
I'm already "recycling" dead entities, as I'm not deallocating/reallocating any memory. The control counter is there to make sure that recycled entities are not mistaken for the entities they were previously.



What problem have you solved? It seems like a solution to a non-existent problem.

You are asserting that the new approach is better but I don't see any reason to believe it. I was going to call it "premature optimization" but you haven't actually optimized anything, where is the analysis that proves the new system is more efficient? All you have is a code comment that says it's better.

If you are going to optimize something, then start by taking a real problem or at the very least an abstracted version of a real problem and apply your solution there so that you can show the data reflecting the improvement.

Thanks for the feedback.

It isn't a magical "solution to a problem", it's more of a different approach to entity management to increase iteration speed and still retain the possibility of tracking several entity instances.

Using a vector of unique pointers is still the easiest (and sometimes best) solution for games that do not require particular iteration efficiency.

There are many studies/, slides and benchmarks online (done by AAA game developers, as well) that show how important is cache-efficiency for game development. Just look for "data-driven design" and "cache friendliness" on google.


SuperV1234

  • SFML Team
  • Full Member
  • *****
  • Posts: 188
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #22 on: March 15, 2015, 05:40:16 pm »
Hello everyone! I've just finished uploading the latest episode of "Dive into C++11".

http://www.youtube.com/watch?v=QAmtgvwHInM

In this episode we'll see various ways of implementing entity management in your games, starting with a very simple "one vector per object type" approach. We'll consider a "polymorphic inheritance tree" approach as well, and finish the video by re-implementing our Arkanoid clone with a simple but effective component-based design.

The goal of the episode is showing the thought process behind the design and improvement of an entity management system.

The intended audience for this tutorial/screencast are people who have some experience with C++ in general, and who watched the previous episodes. This episode also teaches the basics of polymorphism and component-based design.

Hope you'll find the video interesting!
I greatly appreciate comments and criticism, and ideas for future videos/tutorials.

JuDelCo

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • JuDelCo's Twitter
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #23 on: March 15, 2015, 11:29:29 pm »
Instead the template trick you talk about (static getID with a counter++ for each class) I use this:

// In Entity class...
std::unordered_map<std::type_index, std::list<std::weak_ptr<Component>>> mComponentArray;

So the type_index can be retrieved doing:

std::typeid(T)

... in the template methods, for example:

template <typename T>
bool Entity::HasComponent() const
{
        if(mComponentArray.count(std::typeid(T)))
        {
                return (! mComponentArray.at(std::typeid(T)).empty());
        }

        return false;
}

--------------------

I store too a list in the EntityManager to get fast all entities which have a specific component attached:

// In EntityManager class ...
std::unordered_map<std::type_index, std::list<std::weak_ptr<Entity>>> mEntityComponentContainer;

template <typename T>
auto EntityManager::GetEntities() -> std::list<std::weak_ptr<Entity>>&
{
        if(EntityManager::HasEntities<T>())
        {
                return EntityManager::mInstance->mEntityComponentContainer.at(std::typeid(T));
        }

        return EntityManager::mInstance->mEntityComponentContainer[std::typeid(T)];
}

then it can be used for example with this:

template <typename T>
void EntityManager::ForEach(const function<void(std::weak_ptr<Entity>)> function)
{
        for(auto& iEntity : GetEntities<T>())
        {
                function(iEntity);
        }
}

SuperV1234

  • SFML Team
  • Full Member
  • *****
  • Posts: 188
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #24 on: March 16, 2015, 01:20:41 am »
It will certainly work, but it seems unnecessarily inefficient and complex.

`std::typeid` and an `std::unordered_map` have a significant runtime overhead. Also, you cannot use `noexcept` to allow even more aggressive compiler optimizations.

I don't think it can get much faster than a bitset lookup for component availability checks and a direct array access to retrieve a component of a specific type.

A possibly even more efficient version could use a variadic list of component types passed in the manager (which would be a template class) so that appropriate data structures and unique IDs could be generated at compile-time. But I don't think it would be much faster than the implementation I show in the video.

I'm also a little perplexed by the use of `std::list` (which is highly not recommended by Bjarne itself, because of its cache unfriendliness), `std::weak_ptr` (wouldn't a raw pointer do the trick here?) and `std::function`, which, again, has some runtime overhead.

Instead of passing an `std::function` to `EntityManager::ForEach` you can simply add and use a template parameter for the passed function type, which will have no runtime overhead.

Your design and implementation is probably fine for any kind of game that has a small amount of entities... but I really like to make my life harder by trying to squeeze every last bit of performance in my code.
It feels rewarding and I always learn unexpected things about efficient code :)

JuDelCo

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • JuDelCo's Twitter
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #25 on: March 16, 2015, 08:26:20 pm »
Wtf, I thought my code had at least some optimization but okay....

Anyway, I'm focused in FINISH something, optimization can be done later ... I appreciate the comments though   ;D

I think the article you mean when said "std::list (which is highly not recommended by Bjarne itself)" is this one, so here is the link:   http://isocpp.org/blog/2014/06/stroustrup-lists

Maybe i'll optimize the std::function part ... I'm pretty sure they are slow

SpeCter

  • Full Member
  • ***
  • Posts: 151
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #26 on: March 17, 2015, 10:30:50 am »
I'm not sure if you meantioned it in your handle-video(didn't have time to watch it yet), but it should be noted that the std::aligned_storage_t Helper type and many more features(like return type deduction without a trailing return type specifier) are only available since C++14.

If you already mentioned it in your video then nevermind.

Last but not least(really nitpicking):
You should use the uniform_int_distribution for uniform random numbers. The modulo 50 operation generates slightly biased values, which should not be what anyone wants :D

JuDelCo

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • JuDelCo's Twitter
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #27 on: March 20, 2015, 11:06:03 pm »
Dammm.... okay I replaced all the lists (I had only 3, but okay), and replaced all weak_ptr by raw pointers (but still using shared_ptr to allow RAII and clear ownership).

There's a good replacement for the unordered_map containers (I use them a lot) ? Anyway I really dont think they are too bad in perfomance/memory ...

Btw ! I forgot to say that in my implementation I allow the creation of TWO or more components of the same type for an entity (thats why I use an unordered_map with a list [now a vector] of components for the second type). How would be in your bitset implementation ?

GCodergr

  • Newbie
  • *
  • Posts: 2
    • View Profile
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #28 on: May 10, 2015, 01:43:29 pm »
I really like your YouTube series!

I recently started again developing in C++  (I usually use C# for work) and your tutorials helped me a lot. ;)

I have 2 questions:

1) In Episode 2 (about Frametime and FPS) is there a benefit using std::chrono instead of sf::Time? I am researching about Game Loop and Game Time and I am still trying to find the best approach. BTW I really liked the Fixed time slice approach.

2) Based on Episode 5 (Game entity management basics) I wanted to make a space invaders clone.
I expanded the p9.cpp and created my game. The problem is that I haven't figured out how to create Entities in real time. For example when player presses the space bar, a bullets gets fired from player ship. (Maybe I need to brush up my C++ skills  :-[)


Thanks in advance!

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6286
  • Thor Developer
    • View Profile
    • Bromeon
Re: [Video Tutorial] Arkanoid in 160 lines - C++11 + SFML2
« Reply #29 on: May 11, 2015, 12:13:37 am »
Your tutorials are still very good. I like the way you describe the ECS and visualize it with comments and ASCII art in code. The verbosity of comments allows to pause the video and makes the code really clear! :)

A few comments about video 5, again just minor issues:
  • Base classes that aren't instantiated should be abstract, corresponding virtual member functions pure.
  • You could show std::make_unique() (C++14). emplace_back() with raw new is not exception-safe, leading to possible memory leaks. In general, I would avoid new where possible -- especially if you wrap the pointer in a smart pointer anyway.
  • It's a matter of style, but I personally mark virtual methods always with the virtual keyword (even if there is override)
  • Calling a parameter mArgs is rather unusual; the "m" prefix is commonly used for members.
  • You mix uniform initialization {} with constructor-style parentheses () for no apparent reason. Same with different integer types in the same loop... Both around 20min in the video.
  • You use both abs() and std::abs(), the latter is correct.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything