[SDL] Vreemde waarden in SDL_Rect

Status
Niet open voor verdere reacties.

Supersnail

Terugkerende gebruiker
Lid geworden
25 jul 2001
Berichten
1.804
Hallo,

Voor een open-source spel dat ik gemaakt heb gebruik ik SDL. Bij het aanpassen van mijn code merkte ik dat de waarden in de gebruikte SDL_Rects veranderden zonder dat ik ze zelf aanpas. Het gaat om de volgende code (teruggebracht tot het hoogst nodige):

sprite.h
[cpp]#ifndef SPRITE_H
#define SPRITE_H

#include "SDL.h"

class sprite
{
protected:
SDL_Surface *image;
SDL_Rect dst, black;

public:
sprite(const char file[])
{
image = SDL_LoadBMP(file);
SDL_SetColorKey(image, SDL_SRCCOLORKEY, SDL_MapRGB(image->format, 255, 255, 0));
}

~sprite()
{
}
SDL_Rect getDstRect() {return dst;};
SDL_Surface *getSurface() {return image;};
SDL_Rect getBlack() {return black;};
};
#endif[/cpp]
Dit is de sprite-klasse. Het gaat om de SDL_Rects in deze klasse. "dst" is de SDL_Rect die bepaalt waar het plaatje getoond wordt. "black" is de SDL_Rect om bij het verplaatsen van het plaatje, het oude plaatje te bedekken met zwart.

Deze sprite-klasse heeft een subklasse:

chopper.h:
[cpp]#ifndef CHOPPER_H
#define CHOPPER_H

#include <iostream>
#include "SDL.h"
#include "sprite.h"

class chopper: public sprite
{
public:
chopper(int x);
void move(SDL_Surface *screen);
};

#endif[/cpp]

en chopper.cpp:
[cpp]#include "SDL.h"
#include "chopper.h"

chopper::chopper(int x) : sprite("heli1.bmp")
{
dst.x = x;
dst.y = 5;
dst.w = image->w;
dst.h = image->h;
black.w = image->w + 2*3;
black.h = image->h + 3;
black.x = dst.x - 3;
black.y = dst.y - 3;
std::cout << "Created new chopper!\n";
std::cout << "dst.x: " << dst.x << std::endl;
std::cout << "dst.y: " << dst.y << std::endl;
std::cout << "dst.w: " << dst.w << std::endl;
std::cout << "dst.h: " << dst.h << std::endl;
std::cout << "black.x: " << black.x << std::endl;
std::cout << "black.y: " << black.y << std::endl;
std::cout << "black.w: " << black.w << std::endl;
std::cout << "black.h: " << black.h << std::endl;
}

void chopper::move(SDL_Surface *screen)
{
std::cout << "Moved chopper!\n";
std::cout << "dst.x: " << dst.x << std::endl;
std::cout << "dst.y: " << dst.y << std::endl;
std::cout << "dst.w: " << dst.w << std::endl;
std::cout << "dst.h: " << dst.h << std::endl;
std::cout << "black.x: " << black.x << std::endl;
std::cout << "black.y: " << black.y << std::endl;
std::cout << "black.w: " << black.w << std::endl;
std::cout << "black.h: " << black.h << std::endl;
std::cout << "image->w: " << image->w << std::endl;
SDL_FillRect(screen, &black, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_BlitSurface(this->getSurface(), NULL, screen, &dst);
if (dst.x < 0-image->w)
{
dst.x = 800+image->w;
}
dst.x-=3;
black.x = dst.x - 3;
}

void move_choppers(SDL_Surface *screen, chopper *chop)
{
chop->move(screen);
}[/cpp]
Deze subklasse bestaat uit een constructor die de SDL_Rects initeel waardes geeft en een move-functie om het plaatje te verplaatsen. Er is ook een "gewone" move functie die de move-functie van de klasse aanroept.

Verder is er nog een main.cpp:
[cpp]#include "SDL.h"
#include "sprite.h"
#include "chopper.h"

using namespace std;

void move_choppers(SDL_Surface *screen, chopper *chop);

int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_NOPARACHUTE);
SDL_Surface *screen = SDL_SetVideoMode(800, 600, 16, SDL_DOUBLEBUF);

chopper *chop;
chop = new chopper(800);
SDL_FillRect(screen, NULL, SDL_MapRGB(screen->format, 0, 0, 0));
bool end = false;
while (!end)
{
move_choppers(screen, chop);
SDL_Flip(screen);
}
return 0;
}[/cpp]
Dit maakt een chopper aan en roept continue de move-functie aan.

Als ik dit uitvoer krijg ik dit als uitvoer:
Created new chopper!
dst.x: 800
dst.y: 5
dst.w: 137
dst.h: 44
black.x: 797
black.y: 2
black.w: 143
black.h: 47
Moved chopper!
dst.x: 800
dst.y: 5
dst.w: 137
dst.h: 44
black.x: 797
black.y: 2
black.w: 143
black.h: 47
image->w: 137
Moved chopper!
dst.x: 797
dst.y: 5
dst.w: 0
dst.h: 0
black.x: 794
black.y: 2
black.w: 3
black.h: 47
image->w: 137
Moved chopper!
dst.x: 794
dst.y: 5
dst.w: 3
dst.h: 44
black.x: 791
black.y: 2
black.w: 3
black.h: 47
image->w: 137
...
Bij het maken van de chopper en na de eerste verplaatsing kloppen de waardes nog. Echter bij de tweede verplaatsing veranderen de waardes van dst.w, dst.h, black.w en black.h.

Als ik in chopper.cpp de regels
[cpp]SDL_FillRect(screen, &black, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_BlitSurface(this->getSurface(), NULL, screen, &dst);[/cpp]
verander in
[cpp]SDL_Rect chopperltemp = dst;
SDL_Rect chopperblack = black;
SDL_FillRect(screen, &chopperblack, SDL_MapRGB(screen->format, 0, 0, 0));
SDL_BlitSurface(this->getSurface(), NULL, screen, &chopperltemp);[/cpp]
Dus door twee nieuwe SDL_Rects aan te maken en deze dezelfde waardes te geven als dst en black en deze nieuwe SDL_Rects te gebruiken werkt het wel en klopt de uitvoer ook.

Created new chopper!
dst.x: 800
dst.y: 5
dst.w: 137
dst.h: 44
black.x: 797
black.y: 2
black.w: 143
black.h: 47
Moved chopper!
dst.x: 800
dst.y: 5
dst.w: 137
dst.h: 44
black.x: 797
black.y: 2
black.w: 143
black.h: 47
image->w: 137
Moved chopper!
dst.x: 797
dst.y: 5
dst.w: 137
dst.h: 44
black.x: 794
black.y: 2
black.w: 143
black.h: 47
image->w: 137

Ik kan het spel zo wel werkend krijgen, maar ik snap niet waarom het zo wel werkt en met de originele SDL_Rects niet. Is er iemand die dit wel snapt?

Bij voorbaat dank.

[edit]Het plaatje dat ik gebruik is hier te vinden. De broncode, het plaatje en een Makefile (Linux) is hier te vinden.[/edit]
 
Laatst bewerkt:
Ik heb geen ervaring met SDL noch heb ik je volledige code bekeken, maar de documentatie van bijvoorbeeld SDL_FillRect zegt dat dstrect ("black" in jouw geval) gewijzigd kan worden:

If there is a clip rectangle set on the destination (set via SDL_SetClipRect), then this function will clip based on the intersection of the clip rectangle and the dstrect rectangle, and the dstrect rectangle will be modified to represent the area actually filled.

En dan is het dus niet vreemd dat je andere waardes kunt krijgen. (naar de rest heb ik niet gekeken, moet zo naar de dokter. Maar wellicht heb je er iets aan :P)
 
Dank je voor je antwoord, volgens mij heb je gelijk.
Hoewel ik geen gebruik heb gemaakt van SDL_SetClipRect blijkt er (volgens SDL_GetClipRect) wel een clip rectangle op de achtergrond te zitten (impliciet "geset" door SDL_SetVideoMode?).
Ik zie nu ook in de documentatie dat SDL_BlitSurface een soortgelijk effect heeft:
The final blit rectangle is saved in dstrect after all clipping is performed (srcrect is not modified).
(note to self: volgende keer eerst de documentatie lezen)

Dan is het raadsel bij dezen opgelost. Nogmaals bedankt, dan hoef ik nu niet meer wakker te liggen van dit probleem ;).
 
Laatst bewerkt:
Status
Niet open voor verdere reacties.
Terug
Bovenaan Onderaan