Advertisement

click and drag sprite

Started by January 11, 2025 12:23 AM
48 comments, last by pbivens67 23 hours, 2 minutes ago

Well after much studying and many hours of work I finally solved my sprite movement problem. here is my updated code

			bool isDragging = false;
			int objectX = 1900, objectY = 725;
			int prevX=0, prevY=0;
			bool quit = false;
			int deltaX = 0, deltaY = 0;

			while (quit == false) {
				SDL_BlitSurface(gHelloWorld, NULL, gScreenSurface, NULL);

				SDL_Event event;
				while (SDL_PollEvent(&event)) {
					if (event.type == SDL_KEYDOWN)
					{
						Uint8 const* keys = SDL_GetKeyboardState(nullptr);
						if (keys[SDL_SCANCODE_ESCAPE] == 1)
							quit = true;

					}
					else if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT)
						{
							prevX = event.button.x;
							prevY = event.button.y;
							if(prevX>=objectX&&prevX<=objectX+45 && prevY>=objectY&&prevY<=objectY+45)
								isDragging = true;
					}
						else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT)
						{
								isDragging = false;
						}
							else if (event.type == SDL_MOUSEMOTION && isDragging)
							{
						deltaX = event.motion.x -prevX;
						deltaY = event.motion.y -prevY;
						cout << prevX << " " << prevY << " " << event.motion.x << " " << event.motion.y << endl;
								prevX = event.motion.x;
								prevY = event.motion.y;
								objectX += deltaX;
								objectY += deltaY;
							}
					SDL_Rect rect;
					rect.x = 2005;
					rect.y = 725;
					SDL_BlitSurface(gHelloWorld_one, NULL, gScreenSurface, &rect);

					SDL_Rect rect_one;
					rect_one.x = 2010;
					rect_one.y = 725;
					SDL_BlitSurface(gHelloWorld_two, NULL, gScreenSurface, &rect_one);

					SDL_Rect rect_two;
					rect_two.x = objectX;
					rect_two.y = objectY;
					SDL_BlitSurface(gHelloWorld_one, NULL, gScreenSurface, &rect_two);
					
					SDL_UpdateWindowSurface((gWindow));
				}

I am going to use a vector to store multiple sprites

Advertisement

pbivens67 said:
Well after much studying and many hours of work I finally solved my sprite movement problem.

Yeah, that's the way. You put more in than you get out most of the time. : )

pbivens67 said:
I am going to use a vector to store multiple sprites

So you need a struct or class for a sprite first, ideally.
You can go through the current code to see which data should be in that class.
If i do that, it's those lines showing data which i think belongs to the sprite:

int objectX = 1900, objectY = 725;

if(prevX>=objectX&&prevX<=objectX+45 && prevY>=objectY&&prevY<=objectY+45) 
// probably width and height should be part of sprite, instead using hardcoded constants.

objectX += deltaX;
objectY += deltaY;

rect_two.x = objectX;
rect_two.y = objectY;

So that's not many lines of code you need to change to work with a sprite data structure instead of loose spaghetti code global variables.

Your first step should be now to make this sprite class, one instance to hanfdle the single sprite you currently have, update the sections to use it. After that your program should still work is it does now, and only then you shoudl start adding more sprites than one.

Basically the process is refactoring your working code to improve it, but not yet really changing what it does. This way you can focus on doing the changes without breaking it, instead risking to break it with adding new functionality.

I am working on using vectors to store the sprites

Here is some code that I am working with that stores objects of vectors

#include <iostream>
#include <vector>

using namespace std;

class Sprite
{
public:
	Sprite(int x, int y) : x(x), y(y) {}
	int x;
	int y;
};

int main()
{
	vector <Sprite> sprites;

	sprites.push_back(Sprite(1900,725));
	sprites.push_back(Sprite(2005, 725));

	for (auto& sprite : sprites)
	{
		cout << sprite.x << endl;
		cout << sprite.y << endl;
	}

	return 0;
}

I am trying to get the push_back function to work and to store values in the vector

			vector <Sprite> sprites;
			bool isDragging = false;
			int objectX = 1900, objectY = 725;
			int prevX=0, prevY=0;
			bool quit = false;
			int deltaX = 0, deltaY = 0;

			while (quit == false) {
				SDL_BlitSurface(gHelloWorld, NULL, gScreenSurface, NULL);

				SDL_Event event;
				while (SDL_PollEvent(&event)) {
					if (event.type == SDL_KEYDOWN)
					{
						Uint8 const* keys = SDL_GetKeyboardState(nullptr);
						if (keys[SDL_SCANCODE_ESCAPE] == 1)
							quit = true;

					}
					else if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT)
						{
							prevX = event.button.x;
							prevY = event.button.y;
							if(prevX>=objectX&&prevX<=objectX+45 && prevY>=objectY&&prevY<=objectY+45)
								isDragging = true;
					}
						else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT)
						{
								isDragging = false;
						}
							else if (event.type == SDL_MOUSEMOTION && isDragging)
							{
						deltaX = event.motion.x -prevX;
						deltaY = event.motion.y -prevY;
								prevX = event.motion.x;
								prevY = event.motion.y;
								objectX += deltaX;
								objectY += deltaY;
					}

					SDL_Rect rect;
					rect.x = 2005;
					rect.y = 725;
					SDL_BlitSurface(gHelloWorld_one, NULL, gScreenSurface, &rect);

					SDL_Rect rect_one;
					rect_one.x = 2010;
					rect_one.y = 725;
					SDL_BlitSurface(gHelloWorld_two, NULL, gScreenSurface, &rect_one);
					sprites.push_back(objectX, objectY);
						SDL_Rect rect_two;
						rect_two.x = objectX;
						rect_two.y = objectY;
//						cout << objectX << " " << objectY << " " << sprites.size() << endl;
						SDL_BlitSurface(gHelloWorld_one, NULL, gScreenSurface, &rect_two);
						SDL_UpdateWindowSurface((gWindow));
					
				}
Advertisement

I guess it does puch to the vector, each time some event happens. So it might add too many sprites. You can check this by printing the size of the vector, which probably grows over timem for example if you move the mouse.

What do you try to do? Showing two sprites on screen, click one and drag it to another place? Then you would create the two sprites once before the while loop starts, and istead objectX/Y variables you would use x/y from the selected sprite instance.
So you could remove objectX/Y.

But you also need a new variable to know ehich sprite is selected.
Currently you have bool isDragging. You could replace this with int dragSriteIndex. If the number is -1, it could mean no sprite is selected and no dragging is going on. Otherwise it would be 0 or 1 to index one of the two sprites.

Not really difficult, but still multiple things to think of.
It's easier to do it step by step.
Start with just one sprite and care about the objectX/Y variables,
then add a second sprite and work on isDragging variable.

I got one sprite to move just not several

I will implement your advice

here is my updated code as per joes suggestions

			vector <Sprite> sprites;
			int dragSpriteIndex = 0;
			Sprite sprite;
			int prevX=0, prevY=0;
			bool quit = false;
			int deltaX = 0, deltaY = 0;

			while (quit == false) {
				SDL_BlitSurface(gHelloWorld, NULL, gScreenSurface, NULL);

				SDL_Event event;
				while (SDL_PollEvent(&event)) {
					if (event.type == SDL_KEYDOWN)
					{
						Uint8 const* keys = SDL_GetKeyboardState(nullptr);
						if (keys[SDL_SCANCODE_ESCAPE] == 1)
							quit = true;

					}
					else if (event.type == SDL_MOUSEBUTTONDOWN && event.button.button == SDL_BUTTON_LEFT)
					{
						prevX = event.button.x;
						prevY = event.button.y;
						if (prevX >= sprite.x&&prevX <= sprite.x + 45 && prevY >= sprite.y&&prevY <= sprite.y + 45)
							dragSpriteIndex = 1;
					}
					else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT)
					{
						dragSpriteIndex = 0;
					}
					else if (event.type == SDL_MOUSEMOTION && dragSpriteIndex)
					{
						deltaX = event.motion.x - prevX;
						deltaY = event.motion.y - prevY;
						prevX = event.motion.x;
						prevY = event.motion.y;
						sprite.x += deltaX;
						sprite.y += deltaY;
					}

					SDL_Rect rect;
					rect.x = 2005;
					rect.y = 725;
					SDL_BlitSurface(gHelloWorld_one, NULL, gScreenSurface, &rect);

					SDL_Rect rect_one;
					rect_one.x = 2010;
					rect_one.y = 725;
					SDL_BlitSurface(gHelloWorld_two, NULL, gScreenSurface, &rect_one);

					SDL_Rect rect_two;
					rect_two.x = sprite.x;
					rect_two.y = sprite.y;
					SDL_BlitSurface(gHelloWorld_one, NULL, gScreenSurface, &rect_two);
					SDL_UpdateWindowSurface((gWindow));
				
			}
Advertisement