[solved] logic in device->run but keeping it tidy

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
thenewkgb
Posts: 53
Joined: Thu Jan 25, 2024 6:54 pm
Location: UK

[solved] logic in device->run but keeping it tidy

Post by thenewkgb »

Nice to be here. I didn't want to ask unless necessary. I've only looked up to tutorial 10 so far, so maybe slap my hand.

I did manage to compile. I did add a quit key. I did add a jump button. I did use metatriangle. I have added a child cube to my camera which detects intersections. I have managed that...

Most of the examples have a tiny while loop and the smgr and driver automatically update the game. I felt triggers and logic can be dealt with in the same way. The only thing I've come across so far is adding a scene node animator, because all movement/intersection/hitting walls is essentially animation?

If I want to check intersections now, I do this... Which is messing up the while loop. Can all logic in Irrlicht be dealt with by the smgr?

Code: Select all

while(device->run())
{
    if(receiver.IsQuit())
    {
        device->closeDevice();
    }

    //
    // my messy code here
    //
    postBox = playerSmallBlock->getTransformedBoundingBox();
    earthBox = node4->getTransformedBoundingBox();
    playerBox = playerMesh->getTransformedBoundingBox();

    if(playerBox.intersectsWithBox(postBox))
    {
        std::cout << "Player collided with Post.";
    }
    if(playerBox.intersectsWithBox(earthBox))
    {
        std::cout << "Player collided with Earth.";
    }

    driver->beginScene(true, true, f);
    smgr->drawAll();
    driver->endScene();
}
    
So from that, to this...?

Code: Select all

while(device->run())
{
	driver->beginScene(true, true, SColor(255,100,101,140));
	smgr->drawAll();
	guienv->drawAll();
	driver->endScene();
}
Last edited by thenewkgb on Sat Feb 03, 2024 11:36 am, edited 1 time in total.
thenewkgb
Posts: 53
Joined: Thu Jan 25, 2024 6:54 pm
Location: UK

Re: logic in device->run but keeping it tidy

Post by thenewkgb »

Thinking about what I want - I'd like to remove getTransformBoundingBox out of run() and let Irrlicht update itself.

And thinking... An animator is used for collision. I shouldn't use an animator.

If objects are moving around the screen, I still need to test intersecting - but not in run().

(edit)
I believe it's not a big issue. If I know C++ enough I can make a function or class and call many lines of code from one line. I won't clutter run().

I've used Irrlicht for about a week and so far have copied the dll into every folder I use the header - so not expecting miracles!
CuteAlien
Admin
Posts: 9651
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: logic in device->run but keeping it tidy

Post by CuteAlien »

It's possible to let it handle by the scenemanager. You can derive your own classes from ISceneNodeAnimator and add those to SceneNodes (including the root scene node of the SceneManager). Those are called in OnAnimate which is the first thing called in smgr->drawAll.

Thought there is nothing messy about the way you do it either. In my code I also usually do all the physic related stuff (collision, movement) before starting with the rendering. Just move it into it's own function later to have a clean loop again. If you want to look at an example check App::Run in here: https://github.com/mzeilfelder/hc1/blob ... c/main.cpp. But do not copy the sleep calls in there, I learned by now those were a bad idea as Windows timer isn't exact enough and prevented that game from ever getting beyond 65 fps... (with newest Irrlicht svn trunk you can use sleep(0) and loop that for some time to get a nicer solution to avoid hogging the cpu).
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Noiecity
Posts: 92
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

Re: logic in device->run but keeping it tidy

Post by Noiecity »

I do not know very well what you want to achieve, I understand what you say but I would not know how in fact. So when you set your final application, avoid using std::cout or similar.

I also recommend using Struct to control the variables within the loop, C ++ is much faster if you guide it to data than objects.

IF are faster if you check if a value is 0, than if a value is 1.

Switch is generally faster than if.

Struct is faster than a class.

I add another observation in general about C ++, a smaller type of data slows down the CPU although it consumes less memory, the CPU read or 32 bits or 64 bits, and when trying a smaller fact from the RAM creates a conversion of data, The conversion creates a bottleneck, so, if you make an application for 32 bits, use S32 (for int) and F32 (floating point), although you will use more RAM.

It also avoids using array, seems stable, but in my experience, it is slow and generates errors in conversion when the array is very large, struct is everything you need.

Instead of std::cout you can also use Irricht Logger:

core::stringw messageLog = stringw(playerSmallBlock->getPosition().X);
ILogger* logger = device->getLogger();
logger->log("playerSmallBlock Position(X) = ",messageLog.c_str(), ELL_INFORMATION);

Also avoid defining variables within the loop (only if possible), with practice you may be used to use struct
**
If you are looking for people with whom to develop your game, even to try functionalities, I can help you, free and in an anonymous way if necessary. You can send me a private message.

https://www.artstation.com/noiecty
**
thenewkgb
Posts: 53
Joined: Thu Jan 25, 2024 6:54 pm
Location: UK

Re: logic in device->run but keeping it tidy

Post by thenewkgb »

I'll use ILogger now you mention it. That's if I'm able to read the output somehow. I'll also use cutealien's idea to derive a class from IMeshSceneNode as I see it can handle OnAnimate (with my understanding will be able to call getTransformedBoundingBox within it).

As for now, I'll tell myself to read my Principles & Practice book again and also check cppreference. I need to learn more C++.

I have succeeded in using SDL2 from (half skimming) reading up to Chapter 9 in P&P, and I did have to experiment with pointers and addresses with trial and error, but now when the compiler tells me Irrlicht can't convert an IMesh to type AutoMeshNode I know I lack C++ skills.

I was afraid I jumped in the deep end again when compiling Irrlicht, and I hope using Irrlicht spurs me on to learn more C++. My excitement to make a game like the ones I played on PS1 or older PC games gets in the way. Programming is really hard.
CuteAlien
Admin
Posts: 9651
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: logic in device->run but keeping it tidy

Post by CuteAlien »

Derive from ISceneNodeAnimator, not derive from IMeshSceneNode for this ;-) (and then add the animator to the scenenode). And you really don't have to, the way you did it was OK as well!

ILogger can be used, but std::cout is often fine as well. Logger has the advantage that you can decide in the event-handler where to print your logs later (like print to file, print to console, write out into some gui element or something like that). cout has the advantage that it's easier to format strings. I mainly use std::cout for quick tests and some other logger for larger applications. Changing the code later is also not that hard, start with what's easier for you.

I don't think you'll have to worry much about micro-optimizations at this point. Stuff like "switch" faster than "if" is true sometimes, but it's rare to have a situation where it matters. structs and class are the same in c++ aside from struct members being public by default while those in class are private. Thinking about 32-bit values getting converted to 64-bit in the processor or declaring variables in loops is rarely a good idea - think about making your code readable first. There's more micro-optimization rules like that floating around and at some point you'll learn them, but cases where they really matter are rare and they often depend on the platform you are working on. The key to optimization is in general: measure first, find out where your bottleneck is and only then start optimizing. And in 90% of the cases it's the algorithm, not the data structures which are to blame. For small games speed often does not even matter because PCs are simply fast enough. Like c++ is kinda fast by default and people still write nice games even in Python or Ruby or JS, etc which are way slower.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Noiecity
Posts: 92
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

Re: logic in device->run but keeping it tidy

Post by Noiecity »

What you say is true, but still, struct shows in most cases, about 10 times more performance than using class, there are conferences that talk about this, data oriented programming is more difficult to understand and many times to implement, but it really makes a difference when it comes to low latency, because the cpu is designed to work data oriented, and in fact, new cpu's are not "faster" in every sense of the word, they have more cores, there are also conferences that talk about cpu's being slower working small data.


I summarize it like this, a ferrari carrying a single person is faster than a truck, but if you put a ferrari in competition with a truck of who carries 1 ton from one city to another, certainly the truck will have the advantage and statistically it will be faster, new cpu's are like trucks, more powerful, but not necessarily faster.

Modern games are slow in this context, they are more powerful and faster like a truck carrying a ton but slow carrying a single person, they all have a high latency and their responses are slow. It is not the same to have 1000 frames per second in a 2010 cpu, where each frame is rendered every 0.1 ms continuously, and varies very few times, to have a modern cpu that renders 2000 or 3000 fps, but varies between 0.05ms to 4 ms, ie, for seconds it will seem faster, but there will be time where it will be slower, this will lead to be more prone to errors in calculations, and as is well known .... leads to clear errors in collisions and animations based on keyframes, this is common in modern games, even unreal engine often crashes out of nowhere in most modern cpu's, just like 3dsmax, modern cpu's are more prone to errors.

This is more noticeable in competitive games where the response of this type makes the difference, or if we go to something simpler, in platform games like Mario bros, it is incredible that a supernintendo game running on a supernintendo has a faster response with the buttons of your joystick, Imagine, pressing the jump key accurately and precisely, and the cpu does not load it instantly, or the loading times vary, you will lose, and not because of your lack of skill, but because of how invariable the performance of modern cpu's is, which will lead the player to frustration.

I remember when windows 10 came out, it was slower and did not run directx9 applications, damn, now if you want to program, you have to make an app for windows 7, and another for windows 10, because if you do it only for windows 7, it is likely that the new driver will not run on windows 10, and the same happens for windows 7, stupid industry, it does everything wrong, all for the money. In fact to this day there are problems to run old games on modern computers, like age of empires for directdraw, or warcraft 3 reign of chaos and need for speed carbon in sound for directx9 on windows 10.

I work my apps for high performance and low latency, because in many parts of the world there are poor people with old computers, and these problems are noticeable in them.

Regarding the topic of low latency and data-driven programming, it is often discussed at cppcon:

https://www.youtube.com/watch?v=yy8jqgmhbau

https://www.youtube.com/watch?v=Rx0itvevjhc

Regarding the CPU, Herb Sutter talks about it in "High Performance & Low Latency C++ Introduction and Fundamentals Herb Sutter".

https://alfasoft.com/files/herb/00-intropion.pdf

In unity there is also a noticeable difference in performance:

https://www.youtube.com/watch?v=0VQyWo-gb2c


:mrgreen: :mrgreen:
**
If you are looking for people with whom to develop your game, even to try functionalities, I can help you, free and in an anonymous way if necessary. You can send me a private message.

https://www.artstation.com/noiecty
**
CuteAlien
Admin
Posts: 9651
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: logic in device->run but keeping it tidy

Post by CuteAlien »

You are not talking about the keywords here. In c++ "struct" and "class" are identical aside from default access.

Data oriented programming (or entity component systems) are another topic. It doesn't matter if you use struct or class for that, although people may use structs. Not because they are faster, but because it gives a hint about that they are working with plain old data (also known as POD). Which means it's kinda pure data with no virtual functions, constructors/destructors or any memory management. And _that_ is often faster. It makes not difference to the compiler if you use struct/class, but it's a hint for the person reading the code. The speed comes for example from the way data oriented programming is often cache-friendly (unlike virtual functions which can easily cause cache misses). But again - this is not about the c++ keywords struct/class in any way. It's about data layout and the way the data is processed.
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Noiecity
Posts: 92
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

Re: logic in device->run but keeping it tidy

Post by Noiecity »

I have done tests, using class shows less performance in terms of FPS in irrlicht, also the response is slower, I do not know why, also depending on how the code is generated class may show the same performance as struct, if you program struct wrong you may not see the benefits of its performance, its performance is denoted more in entities.

I test what I see, I do not produce algorithms, I try and see, it is the best way after all.

In fact, in GCC Struct and Class they behave differently when it translates into Assembly, the difference is minimal, but there is, so that Struct and Class are the same except that one is public by default As work in Assembly, it is not the same, depending on the compiler, and if we use Visual Studio, different versions you get different results.

So yes, in many contexts, in C ++ the difference is not seen, in my case, i use visual Studio 2015 in Windows 7, and if there is a difference, it is likely that if compile using it using GCC in its latest versions obtain the same performance both in Struct and Class, but i use visual Studio 2015

Remember that the code is translated to assembly, I have seen code in assembly execute slower in c++, although c++ translates the code to assembly, that is to say, the compiler produces better code assembly and more optimal than programs written by people in assembly.

The struct and class thing perhaps in c++ have not been made many tests, it depends on how the compiler works it, in one of the videos that I sent they analyze that different compilers translate the c++ code in different ways, that is to say, different codes in assembly.

I will quote some tests I saw in .net 6:

Image

"The key differences

Structs are value types, allocated on the stack (or inline in containing types, based on compiler optimizations).
Classes are reference types, allocated on the heap and managed by the garbage collector.
Handling of structs is cheaper than handling classes, if we talk about allocations.
Since structs are values, you copy those values (which costs time too!) instead of using an existing reference."

"Benchmark Results

🔋 Both struct samples produce no allocations!
🚀 Struct has a better performance over all!

Remarks!

The use of struct or class is part of the software architecture.
Not in all scenarios struct makes sense or can be used (e.g. serialization)!
The change from class to struct is a breaking change!
It's all a matter of perspective, whether these are small or large samples here - names are smoke and mirrors."

https://schwabencode.com/blog/2021/09/2 ... erformance
**
If you are looking for people with whom to develop your game, even to try functionalities, I can help you, free and in an anonymous way if necessary. You can send me a private message.

https://www.artstation.com/noiecty
**
CuteAlien
Admin
Posts: 9651
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: logic in device->run but keeping it tidy

Post by CuteAlien »

Noiecity wrote: Wed Jan 31, 2024 7:22 pm I will quote some tests I saw in .net 6:

"The key differences

Structs are value types, allocated on the stack (or inline in containing types, based on compiler optimizations).
Classes are reference types, allocated on the heap and managed by the garbage collector.
Handling of structs is cheaper than handling classes, if we talk about allocations.
Since structs are values, you copy those values (which costs time too!) instead of using an existing reference."

"Benchmark Results

🔋 Both struct samples produce no allocations!
🚀 Struct has a better performance over all!
You are talking about C#, not c++. In C# they are different. Google something like struct/class difference in c++ if you don't believe me. Or if you got "The c++ programming language" from Stroustrup - in the 4th edition it's in the chapter about class basics: "A struct is a class where members are by default public."
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
Noiecity
Posts: 92
Joined: Wed Aug 23, 2023 7:22 pm
Contact:

Re: logic in device->run but keeping it tidy

Post by Noiecity »

In fact, they are exactly the same in C ++, I just translated the code in Assembly using MSVC 19.14, and they are exactly the same, without any difference, it is possible that it has been blinded by C#, sorry
**
If you are looking for people with whom to develop your game, even to try functionalities, I can help you, free and in an anonymous way if necessary. You can send me a private message.

https://www.artstation.com/noiecty
**
CuteAlien
Admin
Posts: 9651
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: logic in device->run but keeping it tidy

Post by CuteAlien »

No worries, I've run into this difference myself once when reading c# code (I've only dabbled in c# minimally).

This all goes a bit beyond cleaning up the game-loop for someone new to coding Irrlicht ;-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
thenewkgb
Posts: 53
Joined: Thu Jan 25, 2024 6:54 pm
Location: UK

Re: logic in device->run but keeping it tidy

Post by thenewkgb »

Yes. haha :)
thenewkgb
Posts: 53
Joined: Thu Jan 25, 2024 6:54 pm
Location: UK

Re: logic in device->run but keeping it tidy

Post by thenewkgb »

This was a funny assignment in the end. I crossed my fingers hoping it would work. For this to work I set and used the ID of the player mesh. IDs and getNodeFromID look handy.

My run code looks like this...

Code: Select all

while(device->run())
{
    if(receiver.IsQuit()){
        device->closeDevice();
    }
    driver->beginScene(true, true, f);
    smgr->drawAll();
    driver->endScene();
    }
And I did finally use you idea CuteAlien for my derived class (looking at how FPSCamera creates a clone helped)

Code: Select all

class MyAutoNode : public irr::scene::ISceneNodeAnimator
{
    private:
    irr::core::aabbox3df _box;
    irr::u32 _id;
    irr::scene::ISceneNode* _collisionNode;
    irr::core::aabbox3df _colBox;
    irr::scene::ISceneManager* _mgr;

    public:

    MyAutoNode(irr::scene::ISceneManager* mgr, irr::u32 id)
    {
        _mgr = mgr;
        _id = id;
        _collisionNode = mgr->getSceneNodeFromId(_id);
    }

    virtual void animateNode(irr::scene::ISceneNode* node, irr::u32 timeMs)
    {
        _box = node->getTransformedBoundingBox();
        _colBox = _collisionNode->getTransformedBoundingBox();

        if(_box.intersectsWithBox(_colBox))
        {
            std::cout << "We have really pushed it for this collision." << std::endl;
        }
    }

    virtual irr::scene::ISceneNodeAnimator* createClone
        (irr::scene::ISceneNode* node, irr::scene::ISceneManager* newMgr)
    {
        MyAutoNode* copy = new MyAutoNode(_mgr, _id);
        return copy;
    }
};
thenewkgb
Posts: 53
Joined: Thu Jan 25, 2024 6:54 pm
Location: UK

Re: [solved] logic in device->run but keeping it tidy

Post by thenewkgb »

Looking back over this, it worked, but now I see possible errors and it's not easily understood. I also don't understand why pure functions are needed, especially for my target IMeshSceneNode which needs half a dozen pure functions wrote by me.

I guess I can keep intersections in the run loop and refactor them out. I'm overwhelmed by what I wrote and don't understand it :( How does animateNode know what node I'm on about, and the IDs would be the same if cloned.

I'll keep trying to read my C++ book. Not easy.
Post Reply