Jump to content
  • Advertisement
Sign in to follow this  
sheep19

Which is the better way to treat x, y, w and h of a sprite?

This topic is 3623 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

First I need to say I'm using SDL. This is my sprite class:
#ifndef SPRITE_H
#define SPRITE_H

#include "SDL/SDL.h"

#include "constants.h"

class Sprite
{
public:
	Sprite(int _x, int _y, SDL_Surface *img);
	~Sprite();

	void setStep(unsigned int pixels) {step = pixels;}
	int getStep() {return step;}

	void move();

	void setDirectionLeft() {goesLeft = true; goesRight = false;}
	void setDirectionRight() {goesLeft = false; goesRight = true;}
	void setDirectionUp() {goesUp = true; goesDown = false;}
	void setDirectionDown() {goesUp = false; goesDown = true;}

	int getDirectionY() const; // returns 1 if goes up, -1 if goes down

	bool setImage(SDL_Surface *img);
	SDL_Surface* getImage() const;

private:
	//the copy constructor and the = operator aren't used
	Sprite(const Sprite &b);
	Sprite &operator = (const Sprite &b);

	int step; // the step (in pixels) that the ball does every time it moves, both in x and y axis

	// boolean variables that indicate the ball's direction
	bool goesUp, goesDown;
	bool goesLeft, goesRight;

	SDL_Surface *image;
};

#endif


when the surface image is loaded, it gets the width and height of the image (w and h members of SDL_surface). So it better to do this? 1. //constructor //load the image //have sprite have x, y, w and h members //x = x_pos; y = y_pos; (values passed int the constructor) //w = img->w; h = img->h; this? 2. //SDL_Rect rect as private member, values accessed via functions (eg int X()) //rect.x = x; rect.y = y; rect.w = img->w; rect.h = img->h; or this? 3. //int x, y; as private members //x = x_pos; y = _pos; (in constructor) //then, int X() const {return x;}......int W() const {return img->w;} //and have functions that set those values (only of x and y); which is the best way? I seem to prefer #3. ----------------------- I have another question.
void Sprite::move()
{
	//x axis
	if(goesLeft)
	{
		if(x - step >= 0)
		{
			x -= step;
		}
		else
		{
			goesLeft = false;
			goesRight = true;
		}
	}
	else // if(goes right), because when one of them is true, the other is false
	{
		if(x + w + step <= SCREEN_WIDTH)
		{
			x += step;
		}
		else
		{
			goesLeft = true;
			goesRight = false;
		}
	}
	
	if(goesUp)
	{
		if(y - step >= 0)
		{
			y -= step;
		}
		else
		{
			goesUp = false;
			goesDown = true;
		}
	}
	else // if goesDown == true
	{
		if(y + h + step <= SCREEN_HEIGHT)
		{
			y += step;
		}
		else
		{
			goesUp = true;
			goesDown = false;
		}
	}
}


This is the move functions. It uses SCREEN_WIDTH and SCREEN_HEIGHT which are declared in constants.h, so I need to incldude it. Is there another way to do this without including the header? maybe have functions: void setMaxX(usigned val); void setMaxY(unsigned val); But this means that the object will have an "uninitialized" state which I don't want. What is a better alternative? Thanks :)

Share this post


Link to post
Share on other sites
Advertisement
Assuming you wish to go for an XYWH representation:


struct Hull { float x, y, w, h; };
class Sprite
{
Hull hull;
public:
Sprite(/* ... */)
{
/* Initialize this->hull */
}
const Hull& GetHull() const { return hull; }
};

Share this post


Link to post
Share on other sites
Quote:
Original post by sheep19
I have another question.

*** Source Snippet Removed ***

This is the move functions. It uses SCREEN_WIDTH and SCREEN_HEIGHT which are declared in constants.h, so I need to incldude it. Is there another way to do this without including the header? maybe have functions:
void setMaxX(usigned val); void setMaxY(unsigned val);
But this means that the object will have an "uninitialized" state which I don't want. What is a better alternative?

Thanks :)


Have you considered something like:


class play_area
{
private:
rect r;

public:
play_area(rect r) : r(r) { }

rect get_area() const { return r; }
};

int main()
{
play_area a(rect(0,0,WIDTH,HEIGHT));
sprite s;

while(loop)
{
s->move(play_area);
}
}

void sprite::move(const play_area &a)
{
if(left)
{
// etc
}
}


This way, if you need to add more complex info (other collidable blocks, whatever) to the play area, you have a place now to do it and it is simple to change play areas.

Also, just a minor nitpick, but rather than having two separate GoesLeft and GoesRight booleans (that you have to keep in sync), would it not be easier to just have an int Direction set to -1 or +1?

Share this post


Link to post
Share on other sites
Thanks for the replies!

Hmm, so create another class playArea?
How about a rect named playArea private to Sprite?

Edit: Ok, I made it a private member.

However when trying to compiler I get some strange errors (?)


#ifndef MY_SDL_FUNCTIONS_H
#define MY_SDL_FUNCTIONS_H

#include "SDL/SDL.h"

#include "rect.h"

bool pointInRect(const int pointX, const int pointY, const SDL_Rect &rect);

bool collision(const Rect &rectA, const Rect &rectB);
bool collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
bool collision(const SDL_rect &rectA, const SDL_Rect &rectB);

#endif






#include "mySDLfunctions.h"

bool pointInRect(const int pointX, const int pointY, const SDL_Rect &rect)
{
if(pointX >= rect.x && pointX <= rect.x + rect.w )
if(pointY >= rect.y && pointY <= rect.y + rect.h )
return true;

return false;
}

bool collision(const Rect &rectA, const Rect &rectB)
{
// create a temporary SDL_Rect struct so the values of rectB can be passed to pointInRect easily
SDL_Rect temp;

temp.x = rectB.x;
temp.y = rectB.y;
temp.w = rectB.Width();
temp.h = rectB.Height();

for(int i = rectA.x; i <= rectA.x + rectA.Width(); ++i)
{
for(int j = rectA.y; j <= rectA.y + rectA.Height(); ++j)
{
if(pointInRect(i, j, temp))
return true;
}
}

return false;
}

bool collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2)
{
SDL_Rect temp;

temp.x = x2;
temp.y = y2;
temp.w = w2;
temp.h = h2;

for(int i = x1; i <= x1 + w1; ++i)
{
for(int j = y1; j <= y1 + h1; ++j)
{
if(pointInRect(i, j, temp))
return true;
}
}
return false;
}

bool collision(const SDL_rect &rectA, const SDL_Rect &rectB)
{
for(int i = rectA.x; i <= rectA.x + rectA.w; ++i)
{
for(int j = rectA.y; j <= rectA.y + rectA.h; ++j)
{
if(pointInRect(i, j, rectB))
return true;
}
}
return false;
}




1>------ Build started: Project: Pong, Configuration: Debug Win32 ------
1>Compiling...
1>mySDLfunctions.cpp
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.h(12) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.h(12) : error C2143: syntax error : missing ',' before '&'
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(54) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(54) : error C2143: syntax error : missing ',' before '&'
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(56) : error C2065: 'rectA' : undeclared identifier
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(56) : error C2228: left of '.x' must have class/struct/union
1> type is ''unknown-type''
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(56) : error C2065: 'rectA' : undeclared identifier
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(56) : error C2228: left of '.x' must have class/struct/union
1> type is ''unknown-type''
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(56) : error C2065: 'rectA' : undeclared identifier
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(56) : error C2228: left of '.w' must have class/struct/union
1> type is ''unknown-type''
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(58) : error C2065: 'rectA' : undeclared identifier
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(58) : error C2228: left of '.y' must have class/struct/union
1> type is ''unknown-type''
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(58) : error C2065: 'rectA' : undeclared identifier
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(58) : error C2228: left of '.y' must have class/struct/union
1> type is ''unknown-type''
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(58) : error C2065: 'rectA' : undeclared identifier
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(58) : error C2228: left of '.h' must have class/struct/union
1> type is ''unknown-type''
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.cpp(60) : error C2065: 'rectB' : undeclared identifier
1>Generating Code...
1>Compiling...
1>main.cpp
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.h(12) : error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
1>c:\users\user\documents\visual studio 2008\projects\pong\pong\mysdlfunctions.h(12) : error C2143: syntax error : missing ',' before '&'
1>Generating Code...
1>Build log was saved at "file://c:\Users\User\Documents\Visual Studio 2008\Projects\Pong\Pong\Debug\BuildLog.htm"
1>Pong - 19 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

EDIT:
Found it, I had SDL_rect instead of SDL_Rect :p

[Edited by - sheep19 on January 8, 2009 4:46:05 AM]

Share this post


Link to post
Share on other sites
I'm getting a logical error, the ball is moving in the Y axis while I have no code doing so :|

in main:

// the ball
SDL_Rect bounds; bounds.x = 0; bounds.y = 0; bounds.w = SCREEN_WIDTH; bounds.h = SCREEN_HEIGHT;
Sprite ball(100, 100, loadImage("ball.gif"), bounds );
ball.setStep(BALL_SPEED);





sprite.h

#ifndef SPRITE_H
#define SPRITE_H

#include "SDL/SDL.h"

#include "constants.h"

class Sprite
{
public:
//constructor and destructor
Sprite(int _x, int _y, SDL_Surface *img, const SDL_Rect &_playArea);
~Sprite();

void setStep(unsigned int pixels) {step = pixels;}
int getStep() {return step;}

//perform a move
void move();

int X() const;
int Y() const;
int W() const;
int H() const;

bool setImage(SDL_Surface *img);
SDL_Surface* getImage() const;

//get a rect to x, y, w and h
SDL_Rect getOffset() const;

enum DIRECTION {TO_ZERO, NOT_MOVING, TO_INFINITY}; // the sprite's direction
DIRECTION getDirectionX() const;
DIRECTION getDirectionY() const;

private:
//the copy constructor and the = operator aren't used
Sprite(const Sprite &b);
Sprite &operator = (const Sprite &b);

int step; // the step (in pixels) that the ball does every time it moves, both in x and y axis

DIRECTION directionX, directionY;

SDL_Surface *image;
//offset holds the x and y positions of the sprite, plus its width and height
SDL_Rect offset;
//
SDL_Rect playArea;
};

#endif




sprite.cpp

#include "sprite.h"

Sprite::Sprite(int _x, int _y, SDL_Surface *img, const SDL_Rect &_playArea): image(0), step(1)
{
image = SDL_DisplayFormat(img);

offset.x = _x;
offset.y = _y;
offset.w = image->w;
offset.h = image->h;

playArea = _playArea;

directionX = TO_ZERO;
directionY = NOT_MOVING;
}

Sprite::~Sprite()
{
SDL_FreeSurface(image);
image = 0;
}


void Sprite::move()
{
//x axis
if(directionX == Sprite::DIRECTION::TO_ZERO)
{
if(offset.x - step >= playArea.x)
{
offset.x -= step;
}
else
{
directionX = Sprite::DIRECTION::TO_INFINITY;
}
}
if(directionX == Sprite::DIRECTION::TO_INFINITY) // if(goes right), because when one of them is true, the other is false
{
if(offset.x + offset.w + step <= playArea.w)
{
offset.x += step;
}
else
{
directionX = Sprite::DIRECTION::TO_ZERO;
}
}
}

bool Sprite::setImage(SDL_Surface *img)
{
if(!image) // if the image is null assign to it and return true
{
image = SDL_DisplayFormat(img);
return true;
}
return false;
}

SDL_Surface* Sprite::getImage() const
{
return image;
}

SDL_Rect Sprite::getOffset() const
{
return offset;
}

int Sprite::X() const
{
return offset.x;
}

int Sprite::Y() const
{
return offset.y;
}

int Sprite::W() const
{
return offset.w;
}

int Sprite::H() const
{
return offset.h;
}

Sprite::DIRECTION Sprite::getDirectionX() const
{
return directionX;
}

Sprite::DIRECTION Sprite::getDirectionY() const
{
return directionY;
}





The ball is moving diagonally!!

even this make it move dianonally..

void Sprite::move()
{
//x axis
offset.x += step;
}



Why is that?

[Edited by - sheep19 on January 8, 2009 5:00:38 AM]

Share this post


Link to post
Share on other sites
Something's really strange here.

In main, I do this to display the ball:
applySurface(ball.X(), ball.Y(), ball.getImage(), screen);

I changed it to this:
applySurface(ball.X(), 0, ball.getImage(), screen);
and the ball still moves diagonally!! :| I'm not calling applySurface on that image anywhere else.

Share this post


Link to post
Share on other sites

ball.move();
Uint32 c = SDL_MapRGB(screen->format, 255, 255, 255);
SDL_FillRect(screen, &ball.getOffset(), c);
SDL_UpdateRect(screen, 0, 0, 0, 0);

applySurface(ball.getOffset().x, ball.getOffset().y, ball.getImage(), screen);


I did this for some testing. The rectangle behaves well, it moves like it should. On the other hand the ball's image stays still.

When I use to code to move only on Y axis the ball doesn't move at all.
When I use to move ONLY on X axis it moves diagonally.

By the way I checked the values of x and y using the debugger and they are correct.

Image and video hosting by TinyPic

Is something wrong when I draw the surfaces? This is strange.

Share this post


Link to post
Share on other sites
Argh.


void applySurface(Sint16 x, Sint16 y, SDL_Surface *source, SDL_Surface *destination)
{
SDL_Rect offset;
offset.x = x;
offset.y = x; // damn man

SDL_BlitSurface(source, 0, screen, &offset);
}

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!