SDL question - Game Freezes when applying a surface from one object onto another

Hi all,
Been trying to figure out why my program freezes. I know exactly what line of code is causing it, but I can't figure out WHY it's causing it. It compiles fine, there are no errors returned, and then the game just stalls and I have to ctrl+alt+del to kill it.

Anyway, what I have set up is something like this:

main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "SDL.h"
#include "SDL_gfxPrimitives.h"
#include "SDL_image.h"
#include "SDL_rotozoom.h"

#include "player.h"

int Num_Players = 4;

SDL_Surface *Screen = NULL;
SDL_Surface *Ships = NULL;

SDL_Surface *Load_Image (std::string FileName);
SDL_Surface *Optimize (SDL_Surface *Original);

void Apply_Surface (int x, int y, SDL_Surface *Source, SDL_Surface *Destination, SDL_Rect *Clip);
bool Init();
bool Load_Files();

int rnd(int Min, int Max);
float dist(int x1, int y1, int x2, int y2);

int main (int argc, char* args[])
{
    bool Quit_Program = false;
    
    if (Init() == false)
    {
        return 1;
    }

    if (Load_Files() == false)
    {
        return 2;
    }

    Player play[4];
    
    for (int i = 0; i < 4; i++)
    {
        play[i].ID = i;
    }    

    while (Quit_Program == false)
    {
        for (int i = 0 ; i < Num_Players; i++)
        {
            play[i].update(play);
            Apply_Surface(play[i].screenX, play[i].screenY, play[i].PlayScreen, Screen);
        }       

        if (SDL_Flip (Screen) == -1)
        {
            return 1;
        }        
    }

    return 0;
}

bool Init()
{
    if (SDL_Init (SDL_INIT_EVERYTHING) == -1)
    {
        return false;
    }

    Screen = SDL_SetVideoMode (800, 600, 32, SDL_SWSURFACE );

    if (Screen == NULL )
    {
        return false;
    }

    return true;
}

bool Load_Files()
{
    Ships = Load_Image ("./graphics/ships.png");

    if (Ships == NULL)
    {
        return false;
    }

    return true;
}

SDL_Surface *Load_Image (std::string FileName)
{
    SDL_Surface* LoadedImage = NULL;
    SDL_Surface* OptimizedImage = NULL;

    LoadedImage = IMG_Load (FileName.c_str());

    if (LoadedImage != NULL)
    {
        OptimizedImage = SDL_DisplayFormat (LoadedImage);
        SDL_FreeSurface (LoadedImage);

        if (OptimizedImage != NULL)
        {
            SDL_SetColorKey (OptimizedImage, SDL_SRCCOLORKEY, SDL_MapRGB (OptimizedImage->format, 0, 0, 0));
        }
    }
    return OptimizedImage;
}

void Apply_Surface (int x, int y, SDL_Surface* Source, SDL_Surface* Destination, SDL_Rect* Clip)
{
    SDL_Rect Offset;

    Offset.x = x;
    Offset.y = y;

    SDL_BlitSurface (Source, Clip, Destination, &Offset );
}

int rnd(int Min, int Max)
{
    return ((double)rand() / ((double)RAND_MAX + 1.0)) * (Max - Min + 1) + Min;
}

float dist(int x1, int y1, int x2, int y2)
{
    return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

SDL_Surface *Get_Ship(int which, float zoom)
{
    //Size of ships in original sprite sheet.
    int Ship_Width = 500;
    int Ship_Height = 315;

    int Num_Ships = Ships->h / Ship_Height;
    if ((which + 1) > Num_Ships)
    {
        which = (Num_Ships - 1);
    }

    SDL_Surface *original = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, Ship_Width, Ship_Height, Screen_BPP, 0, 0, 0, 0);
    SDL_Surface *finished = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, (int)(Ship_Width * zoom), (int)(Ship_Height * zoom), Screen_BPP, 0, 0, 0, 0);

    SDL_Rect ship_box;
    ship_box.x = 0;
    ship_box.y = which * Ship_Height;
    ship_box.w = Ship_Width;
    ship_box.h = Ship_Height;

    Apply_Surface(0, 0, Ships, original, &ship_box);
    finished = zoomSurface(original, zoom, zoom, SMOOTHING_ON);
    SDL_FreeSurface(original);

    return finished;

}


player.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Player
{
    public:
        float x;
        float y;        
        float angle;
        int which_ship;      //Which ship picture is the player using
        int ID;              //Identifier

        SDL_Surface *ShipPic[360];  //all rotated ship pictures (shrunk and clipped from original ship sheet)

        SDL_Surface *PlayScreen;
        
        Player();
        ~Player();

        void update(Player p[]);

    private:

        void draw_screen(Player p[]);

};


player.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68

#include "SDL_gfxPrimitives.h"
#include "SDL_rotozoom.h"
#include "SDL.h"

#include "sstream"
#include "math.h"

#include "common.h"
#include "player.h"

const float Rad = 180 / 3.14159265;

Player::Player()
{
    x = 0;
    y = 0;    
    angle = rnd(0, 359);
    which_ship = rnd(0, 4);

    PlayScreen = SDL_CreateRGBSurface(SDL_SWSURFACE | SDL_SRCALPHA, 400, 300, 32, 0, 0, 0, 0);

    ShipPic[0] = Get_Ship(which_ship, .2);    //Clips and shrinks a single ship picture from the main ship sprite sheet.

    for (int angle = 359; angle >= 0; angle--)
    {
        ShipPic[angle] = rotozoomSurface(ShipPic[0], angle, 1, SMOOTHING_ON);
    }
}

Player::~Player()
{
    delete PlayScreen;
}

void Player::update(Player p[])
{    
    draw_screen(p);
}

void Player::draw_screen(Player p[])
{

    SDL_FillRect(PlayScreen, &PlayScreen->clip_rect, SDL_MapRGB (PlayScreen->format, 0, 0, 0));

    for (int i = 0; i < Num_Players; i++)
    {
        if (i != ID)
        {
            if (dist(x, y, p[i].x, p[i].y) < 1500)
            {                    
                    if (p[i].ShipPic[(int)p[i].angle] != NULL)
                    {
                        int ShipX = (Player_Screen_Width - x + p[i].x;
                        int ShipY = (Player_Screen_Height - y + p[i].y;
                        if ((int)p[i].angle >= 0 && (int)p[i].angle <= 359)
                        {
                            Apply_Surface(ShipX, ShipY, p[i].ShipPic[(int)p[i].angle], PlayScreen);      //THIS IS THE LINE OF CODE THAT FREEZES THE PROGRAM
                        }
                    }                    
            }
        }
    }

    int CenterX = 200 - (ShipPic[(int)angle]->w / 2);
    int CenterY = 150 - (ShipPic[(int)angle]->h / 2);
    Apply_Surface(CenterX, CenterY, ShipPic[(int)angle], PlayScreen);
}


1
2
Apply_Surface(ShipX, ShipY, p[i].ShipPic[(int)p[i].angle], PlayScreen);
//player(i)'s ShipPic[player(i)'s angle] 


This is the line of code that's freezing the program and I have no idea why.
Simply put, so that you don't really have to go through it piece by piece, what I have done is:

*each player gets their own drawing surface called PlayScreen
*each player gets an array of 360 drawing surfaces called ShipPic. These are to keep the game from having to render the rotation pics of the ship on the fly.
*Get_Ship clips the requested ship picture out of the ship sprite sheet and puts it in ShipPic[0] for the original angle.
*the original picture is rotated by 1 degree and put into the 360 ShipPic slots.
*when the player rotates their ship, the angle changes, and it calls the ShipPic with the same number as the player's angle and places it on the screen.


All of this works perfectly.

Then, in Player::draw_screen(), I have it set up so that each player looks at all the other players and gets their distance. If they're within range, it takes the other player's picture rotated by the other player's angle and puts it on the current player's PlayScreen. This is where it freezes. I simply cannot figure out why. I've checked for NULL pictures, I've checked to be sure the angle is between 0 and 359, nothing makes any difference.
I know it's reading the other player's information since I can output all of the player's X & Y coordinates, angles, the width/height of their pictures, etc. on each other's screens. So they're definitely talking.

To test the code, I've changed it from

 
Apply_Surface(ShipX, ShipY, p[i].ShipPic[(int)p[i].angle], PlayScreen);


to

 
Apply_Surface(ShipX, ShipY, p[ID].ShipPic[(int)p[ID].angle], PlayScreen);


And it works perfectly, placing the player's OWN picture in for the other players. So the function works.
It's just when I try to take another player's picture and place it on the current player's screen that it freezes.


Does anyone have any idea as to why? I've tried quite a few different ideas, such as creating a temp drawing surface to blit the other player's picture onto, but again, it freezes as soon as I try using the other player's pictures.

Any help would be appreciated. I'm out of ideas. Thanks.
BUMP

Anyone have any ideas on this? I'm trying everything I can think of, such as functions that return the correct SDL surface, but nothing. It just freezes with no reasoning.

If there's a better place (and frequently visited forum) to post this question, please let me know.
I'm not familiar with SDL, but I'm quite versed in OpenGL. As I understand, many of these game libraries are based on OpenGL, so maybe there's a chance I can help.
Of course, that all depends on what exactly is going on.
So, please treat me like an idiot. Just by looking at your function I don't really see what's going on. By reading your description, I have a vague idea of what you're trying to accomplish. What kind of game is it intended to be exactly? I'm reminded of EV Nova, but give me some examples.

You can try to kind of troubleshoot your problem function. Is Apply_Surface() really causing a crash, or is it just painfully processing intensive? Is the function being invoked unnecessarily? There are no run-time errors?

Also, I noticed you never seeded your pseudo-random number generator. Might wanna fix that.
closed account (N36fSL3A)
Does it just freeze or does it close your program with an error.

What I mean by closing with an error is this
http://prntscr.com/17gkhu
Ive recently been programming in SDL and this has happened quite often due to trying to blit a null or uninitialized pointer.
Also, just a suggestion, but it would probably be easier if you had a single surface for
SDL_Surface *ShipPic[360]
Instead of an array of 360 and then use a single image and clip the parts that you want.


P.s i dont know what rotozoomSurface does but this line
ShipPic[angle] = rotozoomSurface(ShipPic[0], angle, 1, SMOOTHING_ON);
looks a little suspicious.
Thanks for the replies everyone. The game is a 4 player space ship shooter where players each get their own screen and the 4 players fly around, try to find each other, and blow each other up.
Each player gets their own personal screen / SDL_surface and everything pertaining to that player gets drawn on their own surface. Then, when all's said and done, is just pops each player's drawing screen up on the monitor.

Here's a pic:

http://i75.photobucket.com/albums/i291/sandmann999/ScreenCap.png

The rotozoomSurface(ShipPic[0], angle, 1, SMOOTHING_ON) is a SDL_GFX library extension. I originally had it do this while it was running and redraw the ship rotated every frame but it slowed down the FPS significantly, which is why I went to pre-drawing all 360 frames.
That all works great (although you're right in that I could just make one spritesheet, and I should probably do that).

Then, each class has 360 frames of its own ship stored, and blits whichever one is the current angle of that player's ship.

The game runs at around 250 - 300 fps when left un-regulated, so I know the code works great.

What happens though, as shown in the right two view screens in the pic I posted up, is when another player enters a player's view, it grabs that person's picture from their object's 360 ship sprites and puts it on the other player's view screen. The moment that happens, the game just freezes. No errors, just straight up locks and I have to either ctrl+alt+del, or continually click the X in the corner until Windows finally realizes it's no longer running. Right now, I have them represented with a circle and a line to show their position and angle.

I'm pretty sure the code is written correctly since it just uses a player's ID to know who's picture to grab and if the player uses their own, it'll effortlessly put their own picture in place of the other players'. Even if all 4 players are next to each other, it'll still run at 300 fps doing this. It's just when it tries to get another player's picture that it locks.

I have it checking for NULL pictures, and it passes.


(Also, in my game, I do have the random number gen. seeded. I just removed irrelevant code from above so I wouldn't go over the post size limit)
Last edited on
Topic archived. No new replies allowed.