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

Author Topic: Re:creation - a top down action adventure about undeads [hiatus]  (Read 507417 times)

0 Members and 1 Guest are viewing this topic.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re:creation - a top down action adventure about undeads
« Reply #390 on: December 09, 2015, 01:31:32 pm »
Quote
How do I make a better interface to this?
In the end it will always be a global access to some variable. So whether it is behind a function, a parent structure, or whatever, won't make much difference. Some will say that using a getter function is more flexible, since you can change the implementation without impacting the API. In real life, I can hardly see what you would change in a function that just returns an object.

Quote
Avoiding usage of global engine_system.
It is a fact that global access to some objects is the best design sometimes. There's no need to try to avoid it at all costs, if it's the best solution for you. What's important is to avoid global lifetimes whenever possible, because this is what causes problems: construction before main() and destruction after main(). But to me, global access is fine for objects that are used everywhere, and not really tied to what a function does (it would be silly to pass a log manager argument to every function that may log something).

A design that I often use is a globally accessible Application class (*), instanciated in main(), and which takes care of construction and destruction of all other "global" objects, as well as giving access to them. This way you avoid lots of global objects scattered all over the code, and you have fine control over order of construction, dependencies between them, etc. And you only have a single true global object to deal with, in case one day you decide that this is not a good design anymore.

(*) in a Qt application it is kind of mandatory anyway, because that's already how Qt works -- and I work with Qt ;D
« Last Edit: December 09, 2015, 01:36:01 pm by Laurent »
Laurent Gomila - SFML developer

Jabberwocky

  • Full Member
  • ***
  • Posts: 157
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #391 on: December 09, 2015, 08:42:03 pm »
What's important is to avoid global lifetimes whenever possible, because this is what causes problems: construction before main() and destruction after main(). But to me, global access is fine for objects that are used everywhere, and not really tied to what a function does (it would be silly to pass a log manager argument to every function that may log something)

Good approach, Laurent.
I agree, and bolded what I consider the most important part for emphasis.


Ricky

  • Jr. Member
  • **
  • Posts: 99
    • View Profile
    • Tejada
    • Email
Re:creation - a top down action adventure about undeads
« Reply #392 on: December 10, 2015, 01:22:31 am »
What Laurent Said

All of this and also I understand where you are coming from Elias. The problem is that sometimes OOP is NOT the best solution to the problem but we have been sort of indoctrinated into this OOP religion where all the problems we have we think we can solve with OOP and UML charts.

I recommend watching this http://www.twitch.tv/handmade_hero/v/28507308 recent talk at Handmade Con 2015. Very eye opening. Being dogmatic about programming is counter productive. If what you need is a global then do it. I also use a global for logging. I'm also considering a simpler design using a global gCurrActor and gCurrScene and then just have functions that operate on them. This is to simplify the process of Lua binding.

--Edit: Here is a link to the Logger I'm using https://github.com/ricanteja/MoonySpriteBatch/blob/master/include/Log.h
Wilt thou yet say before him that slayeth thee, I am God? but thou shalt be a man, and no God, in the hand of him that slayeth thee.

SeriousITGuy

  • Full Member
  • ***
  • Posts: 123
  • Still learning...
    • View Profile
Re:creation - a top down action adventure about undeads
« Reply #393 on: December 10, 2015, 07:59:02 am »
I also use one global data structure which holds (non-owning) pointers to all engine subsystems (which are owned by the main application class), like renderer, audio, logger (even a blackboard for simple data exchange between different game states). In my opinion it is a simple and at the same time elegant solution to this problem. So everthing I do is to pass this global object to all gamestates, and from there every state has access to all engine subsystems.
I think in the book SFML Game Development the same concept is used, and it worked perfectly.

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11042
    • View Profile
    • development blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #394 on: December 10, 2015, 08:30:40 am »
(it would be silly to pass a log manager argument to every function that may log something).
Not according to my prof. :P
We're only allowed to use std::cin/std::cout in the main file and otherwise have to pass around the streams. But it does make sense to some extend, because that way we can easily test all classes and functions.
Then again a log class maybe a slightly different topic. Point being that in general globally accessible objects create side effects which are often nearly impossible to test against. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #395 on: December 10, 2015, 02:21:47 pm »
But to me, global access is fine for objects that are used everywhere, and not really tied to what a function does (it would be silly to pass a log manager argument to every function that may log something).
Yep, agreed. Thanks for making me stop doubting this stuff :D

(*) in a Qt application it is kind of mandatory anyway, because that's already how Qt works -- and I work with Qt ;D

Didn't really think about this before, that's a good analogy :D

Ricky, I'm currently watching Handmade Con and it's one of the best stuff to happen ever, haha. Lots of cool stories from awesome guys! :D

SeriousITGuy, yeah I mostly use this approach too (try to avoid using the global engine_system as possible), but sometimes the object is not really connected to game states and still needs to log stuff, that's where global engine_system is useful.

eXpl0it3r, yeah, sometimes it makes sense to pass a stream, but only when you know that this function will write some stuff most of the time. Passing it "just in case" may be poor design in some cases, IMHO.

After all, I think that some managers are almost like free functions which perform stuff without changing lots of stuff. They have their own members sometimes, but they don't change that much, so this is not a big deal. If I had some global stuff which was used everywhere and could change in some places, that would be another problem! :D
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #396 on: December 12, 2015, 12:06:25 pm »
I'm starting to write a small animation tool for my game in Qt, so I don't have to modify JSON by hand. Why don't I just use JSON editor? That's because I'll add animation preview window soon.

I would like to ask: what's the current status on Qt + SFML? Do they work together? Are there many problems? :D

I would like to have a widget which would render stuff in SFML and I'll use Qt for GUI (possibly I'll create GUI for level editor using Qt if it all works all right, this would save me so much time!)

Progress update
Got some basic stuff working

The coolest thing about it is that it's much more readable than JSON because I can display better variable names. Here's how this animation looks in JSON:

{
    "directions" : null,
    "frame" :
    [
        0,
        64,
        32,
        32
    ],
    "frameTime" : 100,
    "isLooped" : false,
    "name" : "die",
    "numOfFrames" : 13,
    "offset" :
    [
        2,
        -2
    ]
},
 

I think I'll move most of the entity stuff (data) in JSON and use Lua for functions for the rest, so I may create Entity Creation Tool which will work the same way as Animation Tool and if I integrate it with my engine, I'll be able to see how entity would look like as I create it. Isn't it awesome? :D
« Last Edit: December 12, 2015, 04:38:02 pm by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #397 on: December 13, 2015, 09:00:50 am »

It's happening! This is Qt with SFML drawing! :D
Animations are not yet implemented, but as you can see Qt and SFML work very well together! Integrating them was very easy, here's what I did. Feel free to give me some tips on how to make stuff better and tell me your experience with Qt + SFML :D

SFMLWidget.h
#ifndef SFMLWIDGET
#define SFMLWIDGET

#include <QWidget>
#include <SFML/Graphics/RenderWindow.hpp>

class SFMLWidget : public QWidget
{
public:
    SFMLWidget(QWidget* parent = nullptr);

    void processEvents();
    void processInput(int dt);
    void update (int dt);
    void draw();
private:
    QPaintEngine *paintEngine() const;
    void enterEvent(QEvent *) override;
    void paintEvent(QPaintEvent*) override;

    sf::RenderWindow window;
    sf::View view;
};

#endif // SFMLWIDGET
 

SFMLWidget.cpp

#include "sfmlwidget.h"
#include <SFML/Window/Event.hpp>

SFMLWidget::SFMLWidget(QWidget *parent) :
    QWidget(parent),
    view(sf::FloatRect(0.f, 0.f, 128.f, 120.f))
{
    //Setup some states to allow direct rendering into the widget.
    setAttribute(Qt::WA_PaintOnScreen);
    setAttribute(Qt::WA_OpaquePaintEvent);
    setAttribute(Qt::WA_NoSystemBackground);
    setAttribute(Qt::WA_PaintUnclipped);

    //Set strong focus to enable keyboard events to be received.
    setFocusPolicy(Qt::StrongFocus);

    //Under X11, we need to flush the commands sent to the server to ensure that
    //SFML will get an updated view of the windows
#ifdef Q_WS_X11
    XFlush(QX11Info::display());
#endif

    window.create((HWND)winId()); //Create the SFML window with the widget handle
    window.setView(view);
}

QPaintEngine* SFMLWidget::paintEngine() const
{
    //We make the paintEvent function return a null paint engine. This functions works together with
    //the WA_PaintOnScreen flag to tell Qt that we're not using any of its built-in paint engines.
    return nullptr;
}

void SFMLWidget::enterEvent(QEvent *)
{
    setFocus();
}

void SFMLWidget::paintEvent(QPaintEvent *event)
{
    draw();
}

void SFMLWidget::processEvents()
{
    sf::Event event;
    while(window.pollEvent(event)) {
        ... // process events
    }
}

void SFMLWidget::processInput(int dt)
{
    ... // process input
}

void SFMLWidget::update(int dt)
{
    ... // update stuff
}

void SFMLWidget::draw()
{
    window.clear();
    ... // draw
    window.display();
}

And then you can use SFMLWidget as QWidget without any problems!
And now I need to figure out how to do game loop inside this stuff and I'll try to use it with my engine if this works out well :D
« Last Edit: December 13, 2015, 12:08:27 pm by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #398 on: December 13, 2015, 10:42:17 am »
I'm writing a lot today :D
Managed to get a basic loop working.


Code:

#include "mainwindow.h"
#include "sfmlwidget.h"

#include <QApplication>
#include <QTime>

int main(int argv, char *args[])
{
    QApplication app(argv, args);
    MainWindow window;
    window.show();

    SFMLWidget* sfmlWidget = window.getSFMLWidget();

    int timeSinceLastUpdate = 0;
    int TimePerFrame = 16;

    QTime mainClock = QTime::currentTime();

    while(window.isVisible()) {
        app.processEvents();

        int delta = mainClock.restart(); // just like in SFML, lol
        timeSinceLastUpdate += delta;

        while (timeSinceLastUpdate > TimePerFrame) {
            timeSinceLastUpdate -= TimePerFrame;
            sfmlWidget->processEvents();
            sfmlWidget->update(TimePerFrame);
        }
        sfmlWidget->draw();

        // add small sleep time, so we don't get delta == 0
        QTime dieTime= QTime::currentTime().addMSecs(1);
        while (QTime::currentTime() < dieTime) { } // wait until time passes
    }

    app.exit();

    return 0;
}

So, fixed-delta, pretty cool. But I have to add small sleep period (1 ms), or else delta will be 0 most of the time (Qt's timer is not very precise). Is it the best way to deal with this problem?
(And I need to figure out how to process SFML events for keyboard input, and then most of the work is done! :D)

Update: SFML events work well, I can easily get sf::Event::MouseEntered/Left to capture input
sf::Keyboard::isPressed works too! :D
« Last Edit: December 13, 2015, 11:57:08 am by Elias Daler »
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11042
    • View Profile
    • development blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #399 on: December 13, 2015, 08:28:59 pm »
Oh nice! :)

I've often thought about playing around with SFML and Qt, but never got around to it. Also nice to see that events are working, some threads about SFML and Qt had issues with event processing.

What exactly do you need the Qt timer for? C++11 introduces <chrono> which also has some highprecision timer (iirc).
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re:creation - a top down action adventure about undeads
« Reply #400 on: December 13, 2015, 08:49:32 pm »
Or sf::Clock, or QElapsedTimer. But please don't use QTime as a timer :P

And simply use sf::sleep or QThread::msleep if you want to pause the execution.
Laurent Gomila - SFML developer

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #401 on: December 13, 2015, 09:36:25 pm »
Oh nice! :)

I've often thought about playing around with SFML and Qt, but never got around to it. Also nice to see that events are working, some threads about SFML and Qt had issues with event processing.
Yeah, this was a pleasant surprise for me, much easier than I expected.
Well, I didn't test all events, but MouseEntered/MouseLeft work well, and that's pretty much all I need for now. :D

What exactly do you need the Qt timer for? C++11 introduces <chrono> which also has some highprecision timer (iirc).
No need for it, yeah. I just saw people doing stuff with Qt timer and now I realize that I can just use sf::Clock, ha-ha :D
(Hmm, I wonder what's better: <chrono> or sf::Timer?)

Or sf::Clock, or QElapsedTimer. But please don't use QTime as a timer :P

And simply use sf::sleep or QThread::msleep if you want to pause the execution.
Okay, thanks :D
So, should I use sleep to wait for some time if the delta was too low to not waste lots of resources, updating events all the time?

Starting to think about how I should map components to JSON objects, this will be very interesting to solve...
Basically I want to change some value in JSON object and automatically change corresponding value in the object without tons of if/else stuff.
I also wonder how to decouple editor from game. I guess I should have some game.dll and Qt application will call some functions from it... I've never done stuff like this before, this will be something new :D

Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re:creation - a top down action adventure about undeads
« Reply #402 on: December 13, 2015, 10:29:05 pm »
(Hmm, I wonder what's better: <chrono> or sf::Timer?)
In general, you should prefer the standard library where possible. However, in this particular case your code will be more portable with sf::Clock, because some standard library implementations (e.g. those of Visual Studio) were known to not use high-precision timers in Chrono until a few years ago.

Starting to think about how I should map components to JSON objects, this will be very interesting to solve...
Basically I want to change some value in JSON object and automatically change corresponding value in the object without tons of if/else stuff.
You should work with a C++ data structure that represents the JSON tree layout (which is very simple: arrays and objects=maps). I'm pretty sure good JSON libraries already come with that.

I also wonder how to decouple editor from game. I guess I should have some game.dll and Qt application will call some functions from it... I've never done stuff like this before, this will be something new :D
I wouldn't stick to one dynamic library format (DLL) unless you actually need it. There are various options for inter-process communication, see here for a list of common ones. Network sockets are also a possibility.

But are game and editor actually running in parallel, in two applications, and they need to know each other?
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re:creation - a top down action adventure about undeads
« Reply #403 on: December 13, 2015, 10:52:41 pm »
In general, you should prefer the standard library where possible. However, in this particular case your code will be more portable with sf::Clock, because some standard library implementations (e.g. those of Visual Studio) were known to not use high-precision timers in Chrono until a few years ago.
Alright, thanks. Less differences between game and level editor code, yay! :D

You should work with a C++ data structure that represents the JSON tree layout (which is very simple: arrays and objects=maps). I'm pretty sure good JSON libraries already come with that.
I use jsoncpp which has that, but I want to do this.
Suppose I have a class like this in C++
class Animation {
     int frameTime;
     int frameCount;
     ...
};
which looks like this in JSON:
{
     "frameTime" : 100,
     "frameCount" : 10
}
I output Json table (Json::Value in C++) to Qt table which then maps every field to Json::Value object, so when I change table value, corresponding Json::Value changes. But I also need to update corresponding C++ value. So I have to map Json::Value object to pointer to corresponding value, so when Json::Value changes, the variable value changes automatically. I already have some ideas how to implement this, but maybe there are easy ways to do this stuff.

I wouldn't stick to one dynamic library format (DLL) unless you actually need it. There are various options for inter-process communication, see here for a list of common ones. Network sockets are also a possibility.

But are game and editor actually running in parallel, in two applications, and they need to know each other?
Thanks, I'll check this out.
I want to have an instance of game running in Qt application. I can use code directly from my game project and then call functions from it, but I feel like this is a bad idea.
So, I need some other way to link editor and game engine code.
They, of course, need to communicate somehow. Suppose I click on some object. Level editor calls some function from game engine like this:
Entity* findEntity(sf::Vector& mousePos);
and now I get a pointer to entity and level editor can do pretty much everything with it, so if I decide to delete it, it does calls function from Game:
removeEntity(selectedEntity);
This would be trivial if I just #included some stuff from main code base, but I feel like game engine and level editor need to be separate somehow. (Hell, some devs write their editors in C# while the game engine is in C++, you can't do #include's in C# for code in C++, so you can't call it directly)
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re:creation - a top down action adventure about undeads
« Reply #404 on: December 13, 2015, 11:25:33 pm »
I already have some ideas how to implement this, but maybe there are easy ways to do this stuff.
MVC is a common pattern. Your C++ Json::Value class would then be the model, and the Qt table (or even the JSON file) the view. Changes in one will notify and update the other. Have a look at the Qt documentation to see how it provides such functionality.

I can use code directly from my game project and then call functions from it, but I feel like this is a bad idea.
So, I need some other way to link editor and game engine code.
If we're only talking about code, and not actual concurrent processes at runtime, why don't you simply outsource the shared code into a library?

This would be trivial if I just #included some stuff from main code base, but I feel like game engine and level editor need to be separate somehow.
Don't make your life overly complicated because you feel something. You know, keeping things simple is a skill.
A library is the straightforward approach here.

(Hell, some devs write their editors in C# while the game engine is in C++, you can't do #include's in C# for code in C++, so you can't call it directly)
There are well-established techniques for ports between languages (e.g. P/Invoke in this case). But you're dealing with a different problem ;)
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

 

anything