SFML draw() not drawing first object shape

52 views Asked by At

I am creating physics simulation engine in C++ and SFML. I encountered issues where I want to draw a vector of objects however draw does not draw first object from the vector. If I want to draw next objects it works fine. Has anybody else had any similar issues?

main.cpp:

#include "../include/engine.hpp"

int main()
{
    auto engine = new Engine();

    while(engine->isRunning())
    {
        engine->update(0.25f);
        engine->draw();
    }
}

engine.cpp:

#include "../../include/engine.hpp"

Engine::Engine()
    : window("Collision Engine")
{
    generateObjects(totalObjects);                             
}

void Engine::update(float dt)
{
    window.update();
    releaseObject(dt);
    applyConstraint();    
    applyGravity();

    for(int i = 0; i < objectReleaseCount; i++)
        objects[i].updatePosition(dt);
}

void Engine::draw()
{
    window.beginDraw();

    for(int i = 0; i < objectReleaseCount; i++)
        window.draw(objects[i].shape);
    
    window.endDraw();
}

bool Engine::isRunning() const
{
    return window.isOpen();
}

void Engine::generateObjects(int objectsCount)
{
    for(int i = 0; i < objectsCount; i++)
    {
        Sphere object;
        object.radius = 40.0;
        object.color.red = 255;
        object.color.green = 150;
        object.color.blue = 0;
        object.color.opacity = 255;
        objects.push_back(object);
    }
}

void Engine::releaseObject(float dt)
{
    totalTime += dt;
    if(totalTime == releaseTime)
        if(objectReleaseCount < totalObjects)
        {
            objectReleaseCount++;
            totalTime = 0;
        }
}

void Engine::applyGravity()
{
    for(int i = 0; i < objectReleaseCount; i++)
        objects[i].accelerate(gravity);
}

void Engine::applyConstraint()
{
    for(int i = 0; i < objectReleaseCount; i++)
    {
        sf::Vector2f position = objects[i].position.current;
        sf::Vector2f size(objects[i].radius * 2, objects[i].radius * 2);

        // Left border
        if (position.x - size.x < 0) 
            position.x = size.x; 

        // Right border
        if (position.x + size.x > window.screenWidth) 
            position.x = window.screenWidth - size.x; 

        // Top border
        if (position.y - size.y < 0) 
            position.y = -size.y; 

        // Bottom border
        if (position.y + size.y > window.screenHeight) 
            position.y = window.screenHeight - size.y; 

        objects[i].position.current = position;
    }
} 

engine.hpp:

#ifndef ENGINE_HPP
#define ENGINE_HPP

#include <SFML/Graphics.hpp>
#include <math.h>

#include "window.hpp"
#include "workingDirectory.hpp"
#include "sphere.hpp"

class Engine
{
    public:
        Engine();
        void update(float dt);
        void draw();
        bool isRunning() const;

        void generateObjects(int count);
        void releaseObject(float dt);
        void applyGravity();
        void applyConstraint();
        
    private:
        Window window;
        WorkingDirectory workingDir;
        std::vector<Sphere> objects;

        sf::Vector2f gravity = {-1.0f, 1.0f};

        int objectReleaseCount = 1;  
        int totalObjects = 2;
        float totalTime = 0;
        float releaseTime = 40.0f;
}; 

#endif

sphere.cpp:

#include "../../include/sphere.hpp"

Sphere::Sphere()
{
    shape.setRadius(radius);
    shape.setFillColor(sf::Color(color.red, 
                                 color.green, 
                                 color.blue, 
                                 color.opacity));    
    setInitialPosition(position.initial);
}

void Sphere::updatePosition(float dt)
{
    velocity = position.current - position.previous;

    position.previous = position.current;

    position.current = position.current + velocity + acceleration * dt * dt;

    shape.setPosition(position.current);
    
    std::cout << "Position = x: " << position.current.x << "y: " << position.current.y << std::endl; 

    acceleration = {};
}

void Sphere::setInitialPosition(sf::Vector2f newPosition)
{
    position.current = position.initial;

    position.previous = newPosition;

    shape.setPosition(newPosition);
}

void Sphere::accelerate(sf::Vector2f acc)
{
    acceleration += acc;
}

sphere.hpp:

#ifndef SPHERE_HPP
#define SPHERE_HPP

#include <iostream>
#include <SFML/Graphics.hpp>
#include "window.hpp"

class Sphere
{
    public:
        Sphere();
        void updatePosition(float dt);
        void setInitialPosition(sf::Vector2f newPosition);
        void accelerate(sf::Vector2f acc);

        // Custom shape
        sf::CircleShape shape; 
        int radius;
        struct 
        {
            sf::Uint8 red = 255;
            sf::Uint8 green = 0;
            sf::Uint8 blue = 255;
            sf::Uint8 opacity = 255;
        } color;   

        struct 
        {
            sf::Vector2f initial {400.0f, 100.0f};
            sf::Vector2f current;
            sf::Vector2f previous;
        } position;

        sf::Vector2f velocity;

        sf::Vector2f acceleration;
};

#endif

I tried making an object inside draw() function and it worked however it does not work when I want to access objects variable declared inside .hpp file.

1

There are 1 answers

0
Aleksander Piprek On

Moving some functions from generateObjects() to Sphere constructor solved this issue.

The error comes from the use of objectReleaseCount instead of objects.size(), for its name and use in other places, objectReleaseCount was meant for a totally different usage. Use objects.size() as an upper limit for looping, of better yet, use ranged for loops, as is for (auto& obj : objects) {...}, and the bug will disappear.