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

Author Topic: New to SFML, game design questions  (Read 15448 times)

0 Members and 3 Guests are viewing this topic.

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
New to SFML, game design questions
« on: August 14, 2011, 01:10:36 pm »
Hi,

Ive looked through the published tutorials and some of the samples, but am still unclear on some of the best practices for designing a non-trival game.

e.g. the Drawable classes store position, rotation, etc with getters and setters. Obviously these classes don't have all the logic required for a game object, and so I need to make my own class that adds this logic. However I'm not clear on what the intended way to do this is, since there seems to be a few posibilites.
Code: [Select]

//A, inherit sf::Sprite and use its getters and setters directly for positional stuff
class Bullet : public sf::Sprite
{...};

//B, have sf::Sprite as a member, and use its getters and setters for positional stuff
class Bullet
{
private:
    sf::Sprite spr;
public:
    const sf::Vector2f& getPos()const{return spr.GetPosition();}
    ...
};

//C, have sf::Sprite as a member, have my own positional stuff, and set it in a render function
class Bullet
{
private:
    sf::Sprite spr;
    sf::Vector2f pos;
    float direction;
public:
    void render()
    {
        spr.SetPosition(pos);
        ...
    }
   ...
};



Also does SFML do any rendering optimisation itself (i.e. look at what it was told to draw on the frame, and draw it such to avoid constant texture and state switches between every object), or have I got to do such batching myself? If so what are the recommended ways to do this where the Z order of the sprites is important and alpha blending is used (I had some previous success just putting all my games sprites in one big texture, so it could all be drawn in one big D3D batch)?


And one last thing. It looks like a major update to SFML is coming soon. Is it worth goign straight there rather than learning 1.6, and is there some resources around for doing so?

It would also be useful to see the code for somthing more complete that follows fairly good code practices. The best ive found so far is like that pong sample that stuck everything in the main function...

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
Re: New to SFML, game design questions
« Reply #1 on: August 14, 2011, 03:18:39 pm »
Quote from: "Sync Views"
Obviously these classes don't have all the logic required for a game object, and so I need to make my own class that adds this logic.
Yes. Don't inherit from sf::Sprite for logic objects, since sf::Sprite is a pure graphics-related class. You could take a sprite as member, or go even further and separate graphics and logics. That is, the object doesn't know how to draw itself, it just contains data required for the game logics. You could write a Renderer class that has overloaded Draw() functions for different logic objects, and create sprites on the fly (this should usually be very fast). Or you leave sprites as a member, but don't let the logic object draw them itself. Or create a map that associates logic objects with sprites. Or...

There are many possibilities. Generally, it is a good idea if graphics and logics are not too tightly coupled.

Quote from: "Sync Views"
If so what are the recommended ways to do this
I don't think you should implement any batching unless you really get into trouble with performance. But usually, SFML is very fast.

Quote from: "Sync Views"
And one last thing. It looks like a major update to SFML is coming soon. Is it worth goign straight there rather than learning 1.6, and is there some resources around for doing so?
Yes, I would directly use SFML 2. The main principles are more or less the same, however there are a lot of API changes. You could use the old tutorials combined with the new documentation to learn SFML 2.

Quote from: "Sync Views"
It would also be useful to see the code for somthing more complete that follows fairly good code practices. The best ive found so far is like that pong sample that stuck everything in the main function...
Hm, good code samples are rare, and chances that you learn bad pratices when looking at existing games are very high. But we've had a lot of design discussions in this forum, maybe you could search for them.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: New to SFML, game design questions
« Reply #2 on: August 14, 2011, 05:53:59 pm »
Quote from: "Nexus"
Quote from: "Sync Views"
Obviously these classes don't have all the logic required for a game object, and so I need to make my own class that adds this logic.
Yes. Don't inherit from sf::Sprite for logic objects, since sf::Sprite is a pure graphics-related class. You could take a sprite as member, or go even further and separate graphics and logics. That is, the object doesn't know how to draw itself, it just contains data required for the game logics. You could write a Renderer class that has overloaded Draw() functions for different logic objects, and create sprites on the fly (this should usually be very fast). Or you leave sprites as a member, but don't let the logic object draw them itself. Or create a map that associates logic objects with sprites. Or...

There are many possibilities. Generally, it is a good idea if graphics and logics are not too tightly coupled.

So along the lines of the method C I showed, where the actual logic stuff works with a seperate data set, and its only when I want to render stuff I deal with the sf::Sprite?

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
New to SFML, game design questions
« Reply #3 on: August 23, 2011, 02:25:01 pm »
I set up SFML 2.0 and made pong to learn the classes and test design. I plan to make a much larger game using more or less this design, so it would be useful to get some feed back on it (e.g. I'm really not sure I like the "((LevelState*)getGame()->getState())->getBall()->getPos()" I have somewhere, but also I don't really want to make singletons left right and centre...).

http://www.mediafire.com/?pc05ooqa8eatxlk

Its only a very small amount of code. Ive got some extracts to show what I was doing for the most part:


I often see it said that its better for a number of reasons to keep the logic simulation at a fixed rate and use interpolation to keep rendering smooth. However I found finding actual implementation examples hard to come across :( So this is pretty much my own solution to the problem, and probably flawed in some way...
Code: [Select]

void Game::run()
{
    running = true;
    sf::Event evt;
   
    sf::Clock clk;
    unsigned stepSize = 1000/30;
    unsigned nextStep = clk.GetElapsedTime();
    unsigned time;//current time
    while(running)
    {
        //handle events
        while(window.PollEvent(evt))
            handleEvent(evt);
       
        time = clk.GetElapsedTime();
        //update simulation
        while(clk.GetElapsedTime() >= nextStep)
        {
            nextStep += stepSize;
            //will be called 30 times a second
            update();
           
            time = clk.GetElapsedTime();
        }
        //render game

        //calc time position between nextStep-stepSize and nextStep
        unsigned untilNext = nextStep - time;
        //fraction
        float dt = untilNext / (float)stepSize;
        assert(dt >= 0 && dt <= 1);
        render(dt);
    }
}


The various parts of the game (main menu, the level, etc) all implement this interface. The Game object then maintains the current state, and handles switching to a new state.
Code: [Select]

class State
{
public:
    State(){};
    virtual ~State(){};
   
    virtual void update()=0;
    virtual void render(float dt)=0;
    virtual void onEvent(sf::Event &evt)=0;
};


The moving objects have a pos and lastPos variables. In the objects update code lastPos is set to the position at the start of the update (except for teleports, that ensure pos == lastPos at the end). The render code then interpolates between pos and lastPos. In the game I plan to work on, similar things will be done for rotation etc.
Code: [Select]


void Paddle::update()
{
    ...ai/player input stuff, sets move var (within range -moveSpeed to moveSpeed)...
    //move
    lastPos = pos;
    pos.y += move;
    //limit to window edges
    if(pos.y < 0)pos.y = 0;
    else if(pos.y + spr.GetSize().y > getGame()->getSize().y)
        pos.y = getGame()->getSize().y - spr.GetSize().y;
}
void Paddle::render(float dt)
{
    //draw
    sf::Vector2f renderPos = pos + dt*(lastPos - pos);
    spr.SetPosition(renderPos);
    getGame()->getWindow()->Draw(spr);

N1ghtly

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
New to SFML, game design questions
« Reply #4 on: August 24, 2011, 11:57:06 pm »
I use a design in my game where each object has it's own draw function.
I call game.draw() which in turn calls level.draw() , ball.draw() , and panel.draw(). I don't see why this is a bad approach?

Also, how should i handle different game states like the menu etc. Have a draw function and update function for each different state?

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
New to SFML, game design questions
« Reply #5 on: August 25, 2011, 03:42:52 am »
Having the logic and the graphic seperated opens new possiblities and easier changes to one side.
It's an easier way to have everything in one object, also because it's very hard to keep both strictly seperated...
I tried once, it work at the beginning but suddendly I noticed that I needed some information in the logic of the graphics and the other way around, and I started hacking around my interfaces... :(

The other question can be discussed here or here. ^^

eXpl0it3r
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

N1ghtly

  • Jr. Member
  • **
  • Posts: 96
    • View Profile
New to SFML, game design questions
« Reply #6 on: August 25, 2011, 11:07:57 am »
I don't see why it would open new possibilities? After all, it's just moving code around?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
New to SFML, game design questions
« Reply #7 on: August 25, 2011, 11:28:04 am »
Quote from: "N1ghtly"
I don't see why it would open new possibilities? After all, it's just moving code around?
The separation leads to higher abstraction, less dependencies and thus more flexibility. If panel, balls and levels know everything about graphics, you have to adapt each of them if the graphic functionality changes (when you add another feature, or if SFML changes). In contrast, when you use an external entity to take care of graphical representation, such as a Renderer class, these modifications are necessary in only one place. At the same time, game objects (panel etc.) become more lightweight, since they mainly store logical data. Initialization, copies and serialization are easier and faster.

You can even go further and use different renderers to draw the same level in different ways. This is only possible if graphics and logics are decoupled, so that one component can be exchanged independently.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
New to SFML, game design questions
« Reply #8 on: August 25, 2011, 01:35:34 pm »
So you saying I should have a singleton class like:
Code: [Select]

class Renderer
{
public:
    void drawBall(sf::Vector2f);
    void drawPaddle(sf::Vector2f);
    void drawScoreText(int player, int score);
    void drawWinText(int frame, int player);
    void drawMenuButton(sf::Vector2f, string text, bool hover, int alignment);
    ...
};


and paddles/balls/buttons/etc get there "size" from "some other source"?

Nexus

  • SFML Team
  • Hero Member
  • *****
  • Posts: 6287
  • Thor Developer
    • View Profile
    • Bromeon
New to SFML, game design questions
« Reply #9 on: August 25, 2011, 01:48:09 pm »
Something like this, but preferably not a singleton.

Or you can also overload a Draw() function directly for different classes. Then, the Renderer depends on all the classes, but you don't need to change the Renderer interface if you need more information about the game objects.
Code: [Select]
class Renderer
{
    public:
        void Draw(const Ball& ball);
        void Draw(const Paddle& paddle);
        ...
};

As always, there are many possibilities, you can experiment with them.
Zloxx II: action platformer
Thor Library: particle systems, animations, dot products, ...
SFML Game Development:

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
New to SFML, game design questions
« Reply #10 on: August 25, 2011, 02:27:57 pm »
Well regardless if its singleton itself, or accssed via a Game::GetRenderer method is littel difference? Unless your suggesting I pass the Renderer* around the majority of objects in my game?

Also how would I extend this to add say a particle effect trail to the ball? Have seperate Renderer::Draw(ball) and Renderer::Draw(ParticleTrail)? Or would the Renderer::Draw(ball) somehow "know" to render the particle effect, perhaps even update the particles simulation itself (since they dont effect logic of other objects, and so dont really gain anything froma  fixed timestep anyway?)?


EDIT:

Also I was kind of thinking, in the interest of allowing certain optimisations should they be required without much effort, take care of Z ordering automatically (e.g. if I say hae some space ships shooting bullets, and 1 space ship is above the other, I need to make sure the bullet fired by the one "below" doesnt get rendered ontop of the other), and also perhaps (allthough I have even less of an idea on this one) provide some sort of capability to perform logic and rendering on seperate threads.

I seem to recall 3D games use somthing called a scene graph for somthing along those lines, but I could be way off on that since Ive never programed any 3D stuff.

MorleyDev

  • Full Member
  • ***
  • Posts: 219
  • "It is not enough for code to work."
    • View Profile
    • http://www.morleydev.co.uk/
New to SFML, game design questions
« Reply #11 on: August 25, 2011, 02:37:38 pm »
Well the basic gist is you pass a reference to Renderer (* or &).

 You could use services: http://www.nuclex.org/articles/4-architecture/6-game-components-and-game-services
And just make each class aware of the service provider. Then they just get the services they need from the provider and you can abstract it out to use different renderers if you like.
UnitTest11 - A unit testing library in C++ written to take advantage of C++11.

All code is guilty until proven innocent, unworthy until tested, and pointless without singular and well-defined purpose.

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
New to SFML, game design questions
« Reply #12 on: September 02, 2011, 04:20:54 pm »
Ive looked a bit at this services thing, but I'm not entirly sure what problem it solves?

It seems to just add an interface for each "component" and then provide a "IRenderer *Game::getRenderer()" instead of a "Renderer *Game::getRenderer()"? What good is this doing except making function calls more expensive, preventing inlining, etc?

If I do the rendering as describe here with a bunch of draw overloads neither IRenderer or Renderer are useable between games anyway, and even in general I don't think an interface makes a class more or less useable between projects?



Also I thought some more about Z-ordering, but am still not sure on what the "standard" solution is. Currently I'm thinking of some kind of renderer tree structure that is ordered back to front, and then can be transversed. e.g. the tree might look like this in a space invaders syle game with nodes containing other items, and the leafs being the visible objects.
Code: [Select]

Game Root Node
    Ship Node(Player)
        Ship
        Bullet
        Bullet
        Bullet
        Missile Node
            Missile
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
    Ship Node
        Ship
        Turret
        Turret
        Bullet
        Bullet
        Bullet
        Bullet
        Missile Impact Effect Node
            Explosion
            Shockwave
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
    Ship Node
        Ship
        Missile Node
            Missile
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
        Missile Node
            Missile
            Smoke Particle
            Smoke Particle
            Smoke Particle
            Smoke Particle
        Damage Effect Node
            Explosion
            Smoke Particle
            Smoke Particle
            Smoke Particle

As far as keeping this completly seperate from the simulation logic goes I have no idea, since an object needs to know which "render node" it is working with in order for new objects to know where to insert themselves into this tree?

MorleyDev

  • Full Member
  • ***
  • Posts: 219
  • "It is not enough for code to work."
    • View Profile
    • http://www.morleydev.co.uk/
New to SFML, game design questions
« Reply #13 on: September 02, 2011, 05:42:51 pm »
The abstract IRenderer is just something you'd need with multiple possible renderers, so you could have IRenderer that then becomes a CSFMLRenderer, a CDX9Renderer, a CDX11Renderer, a CSoftwareRenderer etc.

Otherwise you don't need it, and can just use Renderer*.

The concept of a service as used in XNA seems to be essentially only giving the information other components actually need to those components and hiding the rest of it.

The way they show them there could easily be you have a RendererService and then a RendererComponent that could also be a RendererService, or could even be a friend of RendererService or something, but more importantly it does all the "hidden" work the Renderer needs but doesn't need to expose to the rest of the system.
Or you could even just have a RendererService (Renderer).

Basically a service provider is an extensible way of sharing information between discrete components of the game engine without making that information global. Like I said, it's something you can look into or not ^^
UnitTest11 - A unit testing library in C++ written to take advantage of C++11.

All code is guilty until proven innocent, unworthy until tested, and pointless without singular and well-defined purpose.

Sync Views

  • Newbie
  • *
  • Posts: 12
    • View Profile
New to SFML, game design questions
« Reply #14 on: September 02, 2011, 06:06:19 pm »
Quote from: "MorleyDev"
The abstract IRenderer is just something you'd need with multiple possible renderers, so you could have IRenderer that then becomes a CSFMLRenderer, a CDX9Renderer, a CDX11Renderer, a CSoftwareRenderer etc.

As ok, that makes more sense, and is along the lines of what I considered on a direct d3d/opengl solution, but there doesnt seem much advantage to doing that when using SFML except a lot of extra work :)

Quote

The concept of a service as used in XNA seems to be essentially only giving the information other components actually need to those components and hiding the rest of it.

You got some code example to show of this (Ive never used XNA)? Sounding somwhat what like public/protected/private/friend does?


Any suggestions on my tree idea? The only other solution ive personally seen in 2D was to give each object a "depth", sort the objects by depth and then render in that order. But I found such a system difficult when I wanted to insert objects immediatly before/after other objects.

 

anything