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

Author Topic: Issue with rendering sprites  (Read 439 times)

0 Members and 1 Guest are viewing this topic.

Driftmaniak

  • Newbie
  • *
  • Posts: 4
    • View Profile
Issue with rendering sprites
« on: October 13, 2023, 07:10:01 am »
Hi to all!)
I started learning c++ and to make it more interesting I make a small game pseudo3d racing.
And i have a strange problem, maybe with sprites or maybe with my c++ skills)
so, i have struct that contains information about traffic cars
struct trafficCar
{
    sf::Sprite sprite;
    int index;    
    float xOffset;
    float speed;
    float zPosition;
    float percent;
};
also i have struct that describes info about 1 road segment, here is part of code
struct segment
{
        //variables

    std::vector<billboardSprite> sideRoadSprites;

    std::vector<trafficCar*> segmentTrafficCars;


    void renderSprite()
    {          
        for (int i = 0; i < sideRoadSprites.size(); i++)
        {
            auto& roadSprite = sideRoadSprites[i];
            float spriteScale = point1.screenScale*1300.f;
            float spriteX = point1.screenPosition.x + (point1.screenScale * roadSprite.xOffset * roadWidth * wWidth /2.f);
            float spriteY = point1.screenPosition.y;

            const float destX = 215.f / 215.f * spriteScale;
            const float destY = 540.f / 540.f * spriteScale;
           
            roadSprite.sprite.setPosition(sf::Vector2f(spriteX, spriteY));
            roadSprite.sprite.setScale(destX, destY);
        }

        for (int i = 0; i < segmentTrafficCars.size(); i++)
        {
            auto& car = segmentTrafficCars[i];
            float spriteScale = interpolate(point1.screenScale,point2.screenScale,car->percent) *1300.f;
            float spriteX = interpolate(point1.screenPosition.x,point2.screenPosition.x,car->percent) + (spriteScale * car->xOffset * roadWidth * wWidth/2.f);
            float spriteY = interpolate(point1.screenPosition.y,point2.screenPosition.y,car->percent);

            const float destX = 80.f / 80.f * spriteScale;
            const float destY = 57.f / 57.f * spriteScale;
           
            car->sprite.setPosition(sf::Vector2f(spriteX, spriteY));
            car->sprite.setScale(destX, destY);
        }
    }
       
        //calculation functions
};

in segment i have vector array of pointers to trafficCar struct
and also i have vector array that contains all cars for track
here is how i create all this
void resetTrafficCars()
{
    std::random_device rd; // a seed source for the random number engine
    std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd()
    std::uniform_int_distribution<> distrib(0, 1);
    std::uniform_int_distribution<> distrib1(0, roadSegments.size());
   
    for(int i=0;i<100;i++)
    {
        trafficCar car;
        car.index = i;
        car.speed = maxSpeed/4 + distrib(gen) * maxSpeed/4.f;
        car.xOffset = 0;
        car.percent = 0;
        car.zPosition = distrib1(gen)*segmentLength;
        car.sprite.setTexture(testBotCarTexture);
        car.sprite.setTextureRect(sf::IntRect(sf::Vector2<int>(1383,894),sf::Vector2<int>(80,57)));
        car.sprite.setOrigin(80.f/2,57);
        auto& segment = roadSegments[(static_cast<int>(car.zPosition) / static_cast<int>(segmentLength)) %
        roadSegments.size()];
        segment.segmentTrafficCars.push_back(&car);
        allTrafficCars.push_back(car);        
    }
}
and here is function that update car state, in general it calculates car position and swap car between segment pointers array, i store them in segment to properly render later
void updateTrafficCars(float dt, segment* playerSegment,float playerW)
{
    for(int i=0;i<allTrafficCars.size();i++)
    {
        auto& car = allTrafficCars[i];
        auto& oldSegment = roadSegments[(static_cast<int>(car.zPosition) / static_cast<int>(segmentLength)) %
        roadSegments.size()];
        car.zPosition = increase(car.zPosition,dt * car.speed,trackLength);
        car.percent = percentRemaining(car.zPosition,segmentLength);
        auto& newSegment = roadSegments[(static_cast<int>(car.zPosition) / static_cast<int>(segmentLength)) %
        roadSegments.size()];

        if(oldSegment.index != newSegment.index)
        {
            int index = 0;
            for(int i=0;i<oldSegment.segmentTrafficCars.size();i++)
            {
                const auto& carPointer = oldSegment.segmentTrafficCars[i];
                if(carPointer->index == car.index)
                {
                    index = i;
                    break;
                }                
            }
            //switch car arrays
            oldSegment.segmentTrafficCars.erase(oldSegment.segmentTrafficCars.begin() + index);
            newSegment.segmentTrafficCars.push_back(&car);
        }
    }
}
and here is part of render code
for (auto& sideRoadSprite : roadSegments[currentIndex].sideRoadSprites)
                window.draw(sideRoadSprite.sprite);
           
            for (auto& trafficCar : roadSegments[currentIndex].segmentTrafficCars)
            {
                window.draw(trafficCar->sprite);
            }
so my problem is - a lot of pointers in segmentTrafficCars contains weird corrupted data, and it crush on trying to render it, even if i try to filter this pointers so it contain proper data, still i have black square instead of sprite,
i tested this sprite separatly and it loads and render's properly
also i tried for test create vector array for all sideRoadSprites and store pointers there, it also fails to render via pointer, help me pls with this)

kojack

  • Sr. Member
  • ****
  • Posts: 314
  • C++/C# game dev teacher.
    • View Profile
Re: Issue with rendering sprites
« Reply #1 on: October 13, 2023, 09:02:05 am »
The issue is you are pushing the addresses of temporary local variables into a vector.
In resetTrafficCars() in the for loop you make a local car with:
trafficCar car;
then further down you push its address with:
segment.segmentTrafficCars.push_back(&car);

But after each pass of the for loop it deletes the car and makes a new one, so all of the pointers in segmentTrafficCars are invalid.

You could create the car on the heap with trafficCar *car = new trafficCar(); then push that into both vectors (assuming you need both vectors to have the same cars, so make allTrafficCars have pointers too)

Driftmaniak

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Issue with rendering sprites
« Reply #2 on: October 13, 2023, 09:25:24 am »
The issue is you are pushing the addresses of temporary local variables into a vector.
In resetTrafficCars() in the for loop you make a local car with:
trafficCar car;
then further down you push its address with:
segment.segmentTrafficCars.push_back(&car);

But after each pass of the for loop it deletes the car and makes a new one, so all of the pointers in segmentTrafficCars are invalid.

You could create the car on the heap with trafficCar *car = new trafficCar(); then push that into both vectors (assuming you need both vectors to have the same cars, so make allTrafficCars have pointers too)

Thanks, it helped with corrupted data, but sprite is still black square(
i attached screenshot to post
« Last Edit: October 13, 2023, 09:30:06 am by Driftmaniak »

kojack

  • Sr. Member
  • ****
  • Posts: 314
  • C++/C# game dev teacher.
    • View Profile
Re: Issue with rendering sprites
« Reply #3 on: October 13, 2023, 09:42:13 am »
How's testBotCarTexture being created? It's being used in the code, but not where its made. One thing that can go wrong with textures is SFML doesn't copy them when you attach them to sprites, internally it just stores a pointer. So you need to make sure the texture stays alive as long as the sprite, and doesn't move around in memory.

Driftmaniak

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Issue with rendering sprites
« Reply #4 on: October 13, 2023, 09:51:24 am »
How's testBotCarTexture being created? It's being used in the code, but not where its made. One thing that can go wrong with textures is SFML doesn't copy them when you attach them to sprites, internally it just stores a pointer. So you need to make sure the texture stays alive as long as the sprite, and doesn't move around in memory.
it is created in function before main loop and stored in global variable like other textures for trees or player car
i can render it if i create another Sprite object, that not stored somewhere, i think it's some other problem with this pointers array

Driftmaniak

  • Newbie
  • *
  • Posts: 4
    • View Profile
Re: Issue with rendering sprites
« Reply #5 on: October 13, 2023, 01:57:06 pm »
also i tried to change texture to other just before draw this sprite, it is sky texture that drawn on background, and i recieve white rectangle, screenshot in attachments
if i debug sprite parametres - all is ok, texture rect, size position and scale also ok, so this is very strange problem)