I'm getting some strange behaviour with the mouse position in SDL. If I re-size the window bigger, the x,y positions from either mouse events, seem to be restricted to the original window Width and Height.
If there some function call that I'm missing to tell SDL that the mousing area has increased in size.
The relevant parts of the app:
void Resize(int width, int height)
{
WindowWidth = width;
WindowHeight = height;
/* update OpenGL */
}
void Init()
{
glClearColor(0.f, 0.f, 0.f, 1.f);
Resize(WindowWidth, WindowHeight);
}
void MouseClick(int button, int state, int x, int y)
{
unsigned int MouseButton = unsigned(Mouse.z);
unsigned int b = (1 << (button-1));
if (state)
MouseButton = MouseButton | b;
else
MouseButton = MouseButton & (~b);
Mouse.z = MouseButton;
Mouse.x = x;
Mouse.y = y;
}
void MouseMove(int x, int y)
{
MouseRel.x = x - Mouse.x;
MouseRel.y = y - Mouse.y;
Mouse.x = x;
Mouse.y = y;
}
int main(int agrc, char *argv[])
{
bool quit = false;
SDL_Event event;
if ( SDL_Init(SDL_INIT_VIDEO) < 0)
return 1;
if (SDL_SetVideoMode(WindowWidth, WindowHeight, 0, SDL_OPENGL | SDL_RESIZABLE) == NULL)
return 2;
Init();
while (!quit)
{
DrawScene();
while ( SDL_PollEvent(&event) )
{
if ( event.type == SDL_VIDEORESIZE)
{
Resize(event.resize.w, event.resize.h);
}
else if ( event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP )
{
MouseClick(event.button.button, event.button.state, event.button.x, WindowHeight - event.button.y);
printf("event.button (%i, %i)\n", event.button.x, event.button.y);
MouseHandler();
}
else if ( event.type == SDL_MOUSEMOTION )
{
MouseMove(event.motion.x, WindowHeight - event.motion.y);
printf("event.motion (%i, %i)\n", event.motion.x, event.motion.y);
MouseHandler();
}
else if (event.type == SDL_QUIT)
quit |= true;
}
quit |= KeyboardHandler();
SDL_Delay(10);
}
SDL_Quit();
return 0;
}
Try re-calling SDL_SetVideoMode() in your SDL_VIDEORESIZE handler.
Related
I am writing a program that will continuously draw a polygon until the user right-clicks. The user can only draw if and only if the user makes a selection in the menu, if the user does not make a selection in the menu, the program will not draw. Up to now, my program has successfully drawn a polygon with the mouse, but the problem is that when I right-click to complete, the program pops up the menu instead of completing the polygon. Now how can I right-click to be able to complete the polygon, here's my program:
const int MAX = 100;
float mouseX, mouseY, ListX[MAX], ListY[MAX];
int numPoints = 0, closed = 0, shape = 0;
void mouse(int button, int state, int x, int y)
{
mouseX = x;
mouseY = y;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
if (closed || numPoints >= MAX - 1)
numPoints = 0;
closed = 0;
ListX[numPoints] = mouseX;
ListY[numPoints] = mouseY;
numPoints++;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
closed = 1;
}
void motion(int x, int y)
{
mouseX = x;
mouseY = y;
glutPostRedisplay();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
if (shape == 1)
{
if (numPoints)
{
glBegin(GL_LINE_STRIP);
for (int i = 0; i < numPoints; ++i)
glVertex2f(ListX[i], ListY[i]);
if (closed)
glVertex2f(ListX[0], ListY[0]);
else
glVertex2f(mouseX, mouseY);
glEnd();
}
}
glFlush();
}
void menu(int choice)
{
switch (choice)
{
case 1:
shape = 1;
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 100);
glutCreateWindow("");
gluOrtho2D(0, 640, 480, 0);
glutCreateMenu(menu);
glutAddMenuEntry("Polygon", 1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutPassiveMotionFunc(motion);
glutMainLoop();
}
Edit: Thanks to genpfault, I finished the polygon by right-clicking but I don't know how to reattach it so I can re-open the menu.
...
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
if (shape == 1)
{
glutDetachMenu(GLUT_RIGHT_BUTTON); // Add this
...
}
glFlush();
}
void menu(int choice)
{
switch (choice)
{
case 1:
shape = 1;
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutInitWindowPosition(100, 100);
glutCreateWindow("");
gluOrtho2D(0, 640, 480, 0);
glutCreateMenu(menu);
glutAddMenuEntry("Polygon", 1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutPassiveMotionFunc(mouse_move);
glutMainLoop();
}
Capture the return-value from glutCreateMenu(), that's the handle for the new menu.
Detach the menu in the menu callback via glutDetachMenu() and set a bool indicating you're in "add points" mode.
If you're in "add points" mode and detect a right-click, set the current menu to the menu handle from #1 via glutSetMenu(), then re-attach the menu with glutAttachMenu(). Reset the "add points" bool to false.
All together:
#include <GL/glut.h>
const int MAX = 100;
float mouseX, mouseY, ListX[MAX], ListY[MAX];
int numPoints = 0, closed = 0, shape = 0;
int hMenu = 0;
bool addingPoints = false;
void mouse(int button, int state, int x, int y)
{
mouseX = x;
mouseY = y;
if( addingPoints )
{
if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
if (closed || numPoints >= MAX - 1)
numPoints = 0;
closed = 0;
ListX[numPoints] = mouseX;
ListY[numPoints] = mouseY;
numPoints++;
}
if( button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN )
{
closed = 1;
addingPoints = false;
glutSetMenu(hMenu);
glutAttachMenu(GLUT_RIGHT_BUTTON);
}
}
}
void motion(int x, int y)
{
mouseX = x;
mouseY = y;
glutPostRedisplay();
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, 640, 480, 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
if (shape == 1)
{
if (numPoints)
{
glBegin(GL_LINE_STRIP);
for (int i = 0; i < numPoints; ++i)
glVertex2f(ListX[i], ListY[i]);
if (closed)
glVertex2f(ListX[0], ListY[0]);
else
glVertex2f(mouseX, mouseY);
glEnd();
}
}
glutSwapBuffers();
}
void menu(int choice)
{
switch (choice)
{
case 1:
numPoints = 0;
shape = 1;
addingPoints = true;
glutDetachMenu(GLUT_RIGHT_BUTTON);
break;
}
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);
glutInitWindowSize(640, 480);
glutCreateWindow("");
hMenu = glutCreateMenu(menu);
glutSetMenu(hMenu);
glutAddMenuEntry("Polygon", 1);
glutAttachMenu(GLUT_RIGHT_BUTTON);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutPassiveMotionFunc(motion);
glutMainLoop();
}
I'm writing the program that continuously draws a polygon until the user clicks right-click, but when I continue to draw something else on the screen the polygon disappears, how can I avoid this? This is my program:
float mouseX, mouseY;
vector<float> vecX(40);
vector<float> vecY(40);
int numPoints = 0;
int closed = 0;
void mouse(int button, int state, int x, int y)
{
mouseX = x;
mouseY = y;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
if (closed || numPoints > 40)
numPoints = 0;
closed = 0;
vecX[numPoints] = mouseX;
vecY[numPoints] = mouseY;
numPoints++;
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
closed = 1;
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
if (numPoints)
{
glBegin(GL_LINE_STRIP);
for (int i = 0; i < numPoints; ++i)
glVertex2f(vecX[i], vecY[i]);
if (closed)
glVertex2f(vecX[0], vecY[0]);
else
glVertex2f(mouseX, mouseY);
glEnd();
}
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(600, 400);
glutInitWindowPosition(0, 0);
glutCreateWindow("Testing");
gluOrtho2D(0, 600, 400, 0);
glutDisplayFunc(display);
glutMouseFunc(mouse);
glutMainLoop();
}
The vecX and vecY are used to store the coordinate of the mouse click.
Once a polyline is finished, you need to store it to a container. Use a std::vector of polylines. The type of a polyline is std::vector<float>. At the begin, just 1 empty polyline is in the container:
std::vector<std::vector<float>> polylines(1);
When you left-click, a new vertex coordinate is added to the last polyline in the container. When you right-click, a new polyline is added to the container:
void mouse(int button, int state, int x, int y)
{
mouseX = x;
mouseY = y;
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
polylines.back().push_back(mouseX);
polylines.back().push_back(mouseY);
}
if (button == GLUT_RIGHT_BUTTON && state == GLUT_DOWN)
{
polylines.push_back(std::vector<float>());
}
}
Draw the polylines in nested loops:
void display()
{
glClear(GL_COLOR_BUFFER_BIT);
for (auto i=0; i < polylines.size(); ++ i)
{
bool is_last = i == polylines.size() - 1;
const auto& polyline = polylines[i];
glBegin(is_last ? GL_LINE_STRIP : GL_LINE_LOOP);
for (auto j = 0; j < polyline.size(); j += 2)
glVertex2f(polyline[j], polyline[j+1]);
if (is_last)
glVertex2f(mouseX, mouseY);
glEnd();
}
glutSwapBuffers();
}
Ok so this week I have put a lot of time into learning how to open and run multiple sfml widows at once. I have a vector of unique pointers to the windows and a for loop that displays them and processes their events. The issue I am having that I can't think of a way to fix is that the for loop also runs a gravity function. As more and more windows open the keys drop at slower rates. What is something I can do to make sure that they are always dropping at a somewhat consistent rate no matter how many windows I am processing. For reference here is my code:
MakeKey.h
class MakeKey
{
public:
class NewKey {
public:
sf::Image Img;
sf::Texture Tex;
sf::Sprite Sprite;
int velocetyX;
int velocetyY;
int accelerationX;
int accelerationY;
static bool hitLeft(sf::RenderWindow * window, sf::Image image)
{
int XPos{ window->getPosition().x };
if (XPos <= -40)
return true;
return false;
}
static bool hitRight(sf::RenderWindow * window, sf::Image image)
{
int XPos{ window->getPosition().x };
if (XPos >= sf::VideoMode::getDesktopMode().width - image.getSize().x + 30)
return true;
return false;
}
static bool hitTop(sf::RenderWindow * window, sf::Image image)
{
int YPos = window->getPosition().y;
if (YPos <= -22)
return true;
return false;
}
static bool hitBottom(sf::RenderWindow * window, sf::Image image)
{
int YPos = window->getPosition().y;
if (YPos >= sf::VideoMode::getDesktopMode().height - image.getSize().y + 20)
return true;
return false;
}
static void impact(int & velocity)
{
if (velocity > 0) {
velocity -= 6;
velocity *= -1;
}
if (velocity < 0) {
velocity += 6;
velocity *= -1;
}
}
sf::Clock OffGroundClock;
};
sf::Vector2i Gravity(MakeKey::NewKey& Key, sf::RenderWindow* window);
bool setShape(sf::RenderWindow * window, const sf::Image& image);
sf::Vector2i RandSpawn(sf::Image image);
bool setTransparency(HWND hwnd, unsigned char alpha);
void MakeTopWindow(sf::RenderWindow* window);
void StepWindows();
void RunEvents(sf::RenderWindow* window);
void DrawKey(string input);
private:
vector <MakeKey::NewKey> KeyArray;
vector <unique_ptr <sf::RenderWindow>> WindowArray;
bool grabbedWindow{ false };
sf::Vector2i grabbedOffSet;
};
MakeKey.cpp
static void StepVelocity(MakeKey::NewKey* Key) {
Key->velocetyX += Key->accelerationX;
Key->velocetyY += Key->accelerationY;
}
sf::Vector2i MakeKey::Gravity(MakeKey::NewKey & Key, sf::RenderWindow * window)
{
int XPos = window->getPosition().x;
int YPos = window->getPosition().y;
YPos += 10;
if (Key.hitTop(window, Key.Img))
YPos = -22;
if (Key.hitBottom(window, Key.Img))
YPos = sf::VideoMode::getDesktopMode().height - Key.Img.getSize().y + 20;
if (Key.hitRight(window, Key.Img))
XPos = sf::VideoMode::getDesktopMode().width - Key.Img.getSize().x + 30;
if (Key.hitLeft(window, Key.Img))
XPos = (-44);
/*StepVelocity(Key);
XPos += Key->velocetyX;
YPos += Key->velocetyY;*/
return sf::Vector2i(XPos, YPos);
}
bool MakeKey::setShape(sf::RenderWindow * window, const sf::Image& image)
{
HWND hwnd = window->getSystemHandle();
const sf::Uint8* pixelData = image.getPixelsPtr();
HRGN hRegion = CreateRectRgn(0, 0, image.getSize().x, image.getSize().y);
// Determine the visible region
for (unsigned int y = 0; y < image.getSize().y; y++)
{
for (unsigned int x = 0; x < image.getSize().x; x++)
{
if (pixelData[y * image.getSize().x * 4 + x * 4 + 3] == 0)
{
HRGN hRegionPixel = CreateRectRgn(x, y, x + 1, y + 1);
CombineRgn(hRegion, hRegion, hRegionPixel, RGN_XOR);
DeleteObject(hRegionPixel);
}
}
}
SetWindowRgn(hwnd, hRegion, true);
DeleteObject(hRegion);
return true;
}
sf::Vector2i MakeKey::RandSpawn(sf::Image image)
{
std::random_device rand;
int RandX = (rand() % sf::VideoMode::getDesktopMode().width) - image.getSize().x;
int RandY = (rand() % sf::VideoMode::getDesktopMode().height) - image.getSize().y;
if (RandX < 1 + image.getSize().x)
RandX = image.getSize().x;
if (RandY < 1 + image.getSize().y)
RandY = image.getSize().y;
return sf::Vector2i(RandX, RandY);
}
bool MakeKey::setTransparency(HWND hwnd, unsigned char alpha)
{
SetWindowLong(hwnd, GWL_EXSTYLE, GetWindowLong(hwnd, GWL_EXSTYLE) | WS_EX_LAYERED);
SetLayeredWindowAttributes(hwnd, 0, alpha, LWA_ALPHA);
return true;
}
void MakeKey::MakeTopWindow(sf::RenderWindow* window)
{
HWND hwndPoint = window->getSystemHandle();
SetWindowPos(hwndPoint, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
void MakeKey::RunEvents(sf::RenderWindow* window) {
sf::Event event;
while (window->pollEvent(event))
{
//Key Presses
if (event.type == sf::Event::KeyPressed) {
if (event.key.code == sf::Keyboard::A) {
DrawKey("A");
}
else if (event.key.code == sf::Keyboard::D)
{
DrawKey("D");
}
else if (event.key.code == sf::Keyboard::E)
{
DrawKey("E");
}
else if (event.key.code == sf::Keyboard::Q)
{
DrawKey("Q");
}
else if (event.key.code == sf::Keyboard::S)
{
DrawKey("S");
}
else if (event.key.code == sf::Keyboard::W)
{
DrawKey("W");
}
else if (event.key.code == sf::Keyboard::X)
{
DrawKey("X");
}
else if (event.key.code == sf::Keyboard::Z)
{
DrawKey("Z");
}
else if (event.key.code == sf::Keyboard::Escape)
{
DrawKey("Esc");
}
}
else if (event.type == sf::Event::MouseButtonPressed)
{
if (event.mouseButton.button == sf::Mouse::Left)
{
grabbedOffSet = window->getPosition() - sf::Mouse::getPosition();
grabbedWindow = true;
}
}
else if (event.type == sf::Event::MouseButtonReleased)
{
if (event.mouseButton.button == sf::Mouse::Left)
grabbedWindow = false;
}
else if (event.type == sf::Event::MouseMoved)
{
if (grabbedWindow)
window->setPosition(sf::Mouse::getPosition() + grabbedOffSet);
}
}
}
void MakeKey::StepWindows()
{
for (int i{ 0 }; i < WindowArray.size(); i++)
{
cout << "Inside Step Windows For Loop" << endl;
WindowArray[i]->setActive(true);
MakeTopWindow(WindowArray[i].get());
setShape(WindowArray[i].get(), KeyArray[i].Img);
RunEvents(WindowArray[i].get());
WindowArray[i]->clear(sf::Color::Transparent);
KeyArray[i].Sprite.setTexture(KeyArray[i].Tex);
WindowArray[i]->draw(KeyArray[i].Sprite);
WindowArray[i]->display();
WindowArray[i]->setPosition(Gravity(KeyArray[i], WindowArray[i].get()));
}
}
void MakeKey::DrawKey(string input)
{
unique_ptr <sf::RenderWindow> window = make_unique<sf::RenderWindow>();
NewKey Key;
if (input == "A")
Key.Img.loadFromFile("Assets/Images/A.png");
else if (input == "D")
Key.Img.loadFromFile("Assets/Images/D.png");
else if (input == "E")
Key.Img.loadFromFile("Assets/Images/E.png");
else if (input == "Q")
Key.Img.loadFromFile("Assets/Images/Q.png");
else if (input == "S")
Key.Img.loadFromFile("Assets/Images/S.png");
else if (input == "W")
Key.Img.loadFromFile("Assets/Images/W.png");
else if (input == "X")
Key.Img.loadFromFile("Assets/Images/X.png");
else if (input == "Z")
Key.Img.loadFromFile("Assets/Images/Z.png");
else if (input == "Esc")
Key.Img.loadFromFile("Assets/Images/esc.png");
window->create(sf::VideoMode(Key.Img.getSize().x, Key.Img.getSize().y, 32), "Key", sf::Style::None);
Key.Tex.loadFromImage(Key.Img);
Key.Sprite.setTexture(Key.Tex);
window->setPosition(RandSpawn(Key.Img));
//Make Transparent
const unsigned char opacity = 1000;
setTransparency(window->getSystemHandle(), opacity);
KeyArray.emplace_back(move(Key));
WindowArray.emplace_back(move(window));
}
Main
int main()
{
sf::RenderWindow window(sf::VideoMode(100, 100, 32), "Main Window", sf::Style::Default);
MakeKey MakeKey;
while (window.isOpen())
{
MakeKey::NewKey Key;
MakeKey.RunEvents(&window);
MakeKey.StepWindows();
}
return EXIT_SUCCESS;
}
I'am new there. I've been learning classes and tried to make a very simple platform game. But I have problem now. I've wanted to set Class "Player" to collide with 2 objects of Class "Block" But Collision do not work for one of them.
Here is my code:
#include <iostream>
#include <SDL.h>
#include <SDL_image.h>
#undef main
class Block
{
private:
SDL_Texture *BlockTexture;
public:
Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height);
~Block();
void Draw(SDL_Renderer *renderTarget);
SDL_Rect BlockPos;
};
Block::Block(SDL_Renderer *renderTarget, std::string filePath, int xPos, int yPos, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
BlockTexture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
BlockPos.x = xPos;
BlockPos.y = yPos;
BlockPos.w = Width;
BlockPos.h = Height;
}
Block::~Block()
{
SDL_DestroyTexture(BlockTexture);
}
void Block::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, BlockTexture, NULL, &BlockPos);
}
class Player
{
private:
SDL_Texture *Texture;
float moveSpeed;
float jumpSpeed;
int falling = 0;
SDL_Scancode keys [3];
public:
SDL_Rect PlayerPos;
Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height);
~Player();
void Update(float delta, const Uint8 *Keystate);
void Draw(SDL_Renderer *renderTarget);
bool Collision(Block &p);
};
Player::Player(SDL_Renderer *renderTarget, std::string filePath, int PosX, int PosY, int Width, int Height)
{
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
Texture = SDL_CreateTextureFromSurface(renderTarget, surface);
}
SDL_FreeSurface(surface);
PlayerPos.x = PosX;
PlayerPos.y = PosY;
PlayerPos.w = Width;
PlayerPos.h = Height;
keys[0] = SDL_SCANCODE_UP;
keys[1] = SDL_SCANCODE_LEFT;
keys[2] = SDL_SCANCODE_RIGHT;
moveSpeed = 200.f;
jumpSpeed = 100.f;
}
Player::~Player()
{
SDL_DestroyTexture(Texture);
}
void Player::Update(float delta, const Uint8 *KeyState)
{
if(KeyState[keys[0]])
{
PlayerPos.y -= moveSpeed * delta;
}
if(KeyState[keys[1]])
{
PlayerPos.x -= (moveSpeed / 2) * delta;
}
if(KeyState[keys[2]])
{
PlayerPos.x += moveSpeed * delta;
}
if(falling == 0)
{
PlayerPos.y += jumpSpeed * delta;
}
}
void Player::Draw(SDL_Renderer *renderTarget)
{
SDL_RenderCopy(renderTarget, Texture, NULL, &PlayerPos);
}
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
SDL_Texture *LoadTexture(std::string filePath, SDL_Renderer *Renderer)
{
SDL_Texture *texture = NULL;
SDL_Surface *surface = IMG_Load(filePath.c_str());
{
texture = SDL_CreateTextureFromSurface(Renderer, surface);
}
SDL_FreeSurface(surface);
return texture;
}
int main(int argc, char *argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Window *window = SDL_CreateWindow("Platform", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
SDL_Renderer *renderTarget = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
int imgFlags = IMG_INIT_PNG;
int currentTime = 0;
int previousTime = 0;
float delta = 0;
const Uint8 *Keystate;
Player Player(renderTarget, "BlockP.png", 100, 100, 50, 50);
Block Block1(renderTarget, "Block.png", 0, 500, 800, 100);
Block Block2(renderTarget, "Block.png", 100, 300, 300, 50);
bool isRunning = true;
SDL_Event ev;
while(isRunning)
{
Keystate = SDL_GetKeyboardState(NULL);
Player.Collision(Block1);
Player.Collision(Block2);
previousTime = currentTime;
currentTime = SDL_GetTicks();
delta = (currentTime - previousTime) / 1000.0f;
Player.Update(delta, Keystate);
while(SDL_PollEvent(&ev) != 0)
{
if(ev.type == SDL_QUIT)
isRunning = false;
}
SDL_RenderClear(renderTarget);
Player.Draw(renderTarget);
Block1.Draw(renderTarget);
Block2.Draw(renderTarget);
SDL_RenderPresent(renderTarget);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderTarget);
window = NULL;
renderTarget = NULL;
SDL_Quit();
return 0;
}
The problem with your code is that each call to Player.Collision overwrites the "falling" variable.
Player.Collision(Block1); //this call calculates a falling value
Player.Collision(Block2); //...then this call overwrites falling with a new value
So effectively your code is only testing if the player is colliding with Block2, so collisions with Block1 are ignored.
Currently your Collision function is:
bool Player::Collision(Block &p)
{
if(PlayerPos.x + PlayerPos.w <= p.BlockPos.x || PlayerPos.x >= p.BlockPos.x + p.BlockPos.w ||
PlayerPos.y + PlayerPos.h <= p.BlockPos.y || PlayerPos.y >= p.BlockPos.y + p.BlockPos.h)
{
falling = 0;
return true;
}
else
falling = 1;
return false;
}
Firstly, your "return false;" is not actually part of the else, as you don't have {}. In this particular case it makes no difference as the else is exited and then the return happens but your indentation would suggest you expect the "return false;" line to be executed as part of the else block so you should put:
else
{
falling = 1;
return false;
}
Next you want to say if you have already detected a collision (eg, with Block1) then don't set falling to 1, to do this add an if statement.
else
{
if(falling != 0) //if we haven't already detected a collision this frame
{
falling = 1;
}
return false;
}
You will however need to set falling back to 1 at the start of each frame, otherwise if a collision is detected on one frame then the player will never fall on subsequent frames, even if they are not colliding with a block.
As a side note, your Player.Update code modifies the player's y position if falling == 0, this seems counter intuitive as usually 0 is false and 1 is true, hence you seem to be saying if not falling then update y, where as it should be if falling update y. Personally I would use a bool rather than an int to hold the value of falling, and then say if(falling) update y, this would make your code clearer.
I have been struggling with this for a while and was wondering if anyone could help. I am trying to make a particle sample using C++ and SDL1.3 and I have had great success up until this point. The program compiles and the screen opens and nothing happens. When I run the debugger I get this error:
Unhandled exception at 0x0102414a in SDL 1.3 Space.exe: 0xC0000005: Access violation reading location 0x00000008.
The program '[7272] SDL 1.3 Space.exe: Native' has exited with code -1073741819 (0xc0000005).
and it points to this piece of the code:
bool particle::isDead()
{
return (SDL_GetTicks() >= endTime || x == 0 || y == 0 || x == SDL_GetVideoSurface()->w -1 || y == SDL_GetVideoSurface()->h - 1);
}
It would be greatly appreciated if someone would be so kind as to help me and /or point me in the right direction.
This is the entire program:
#include "SDL.h"
#include "common.h"
#include <stdio.h>
#include <string>
#include <cstdlib>
#include <vector>
#include <ctime>
/*static SDL_Texture *background = 0; //background
SDL_Renderer *renderer;
void render()
{
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, background, NULL, NULL); //Display background
SDL_RenderPresent(renderer);
endFrame = SDL_GetTicks();
};*/
class particle
{
float x, y, xvel, yvel;
Uint32 endTime;
Uint8 color;
public:
particle( float X, float Y, float Xvel, float Yvel, int life, Uint8 Color );
void move();
void show();
bool isDead();
};
particle::particle( float X, float Y, float Xvel, float Yvel, int life, Uint8 Color )
{
x = X;
y = Y;
xvel = Xvel;
yvel = Yvel;
endTime = SDL_GetTicks() + life;
color = Color;
}
void particle::move()
{
x += xvel;
y += yvel;
if ( x < 0 )
x = 0;
if ( y < 0 )
y = 0;
if ( x > SDL_GetVideoSurface() -> w)
x = SDL_GetVideoSurface() -> w - 1;
if ( y > SDL_GetVideoSurface() -> h)
y = SDL_GetVideoSurface() -> h -1;
}
void particle::show()
{
Uint8* pixels = (Uint8*) SDL_GetVideoSurface()->pixels;
Uint8* pixel = pixels + (int) y * SDL_GetVideoSurface()->pitch + (int) x;
*pixel = color;
}
bool particle::isDead()
{
return (SDL_GetTicks() >= endTime || x == 0 || y == 0 || x == SDL_GetVideoSurface()->w -1 || y == SDL_GetVideoSurface()->h - 1);
}
class particleEngine
{
std::vector <particle*> particles;
int x, y, maxparticle;
public:
particleEngine( int maxpart, int X, int Y );
~particleEngine();
void refresh();
};
particleEngine::particleEngine( int maxpart, int X, int Y )
{
x = X;
y = Y;
maxparticle = maxpart;
for ( int i = 0; i < maxparticle; i++ )
particles.push_back (new particle( x + rand()%6-3, y + rand()%6-3, rand()%10 + (float)rand()/(float)RAND_MAX - 5, rand()%10 + (float)rand()/(float)RAND_MAX - 5, 500 + rand()%1000, 0));
}
particleEngine::~particleEngine()
{
for ( int i = 0; i < maxparticle; i++)
delete particles[i];
}
void particleEngine::refresh()
{
for ( int i = 0; i < maxparticle; i++)
{
if ( particles[i]->isDead())
{
delete particles[i];
particles[i] = new particle( x + rand()%6-3, y + rand()%6-3, rand()%10 + (float)rand()/(float)RAND_MAX - 5, rand()%10 + (float)rand()/(float)RAND_MAX - 5, 500 + rand()%1000, 0);
}
else
{
particles[i]->move();
particles[i]->show();
}
}
}
int main( int argc, char* argv[] )
{
bool running = true;
const int FPS = 30;
Uint32 startFrame;
srand (time(0));
particleEngine ps(1000, SCREEN_WIDTH/2, SCREEN_HEIGHT/2);
SDL_Window *window; /* main window */
SDL_Renderer *renderer;
if (SDL_Init(SDL_INIT_EVERYTHING)!= 0)
{
printf("Could not initialize SDL");
}
window = SDL_CreateWindow("SDL 1.3 Particles", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, SCREEN_WIDTH, SCREEN_HEIGHT,
SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN );
renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);
// Body of the program goes here.
while (running)
{
startFrame = SDL_GetTicks();
SDL_Event event;
//render();
//While there's events to handle
while( SDL_PollEvent( &event ) )
{
//If the user has Xed out the window
if (event.type == SDL_QUIT)
{
running = false;
}
}
//SDL_FillRect(renderer, &renderer->clip_rect, SDL_MapRGB(renderer->format, 0x00,0x00, 0x00));
ps.refresh();
//SDL_RenderCopy(renderer, 0, 0, 0);
SDL_RenderPresent(renderer);
//SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
//SDL_RenderClear(renderer);
if (1000/FPS>SDL_GetTicks()-startFrame)
SDL_Delay(1000/FPS-(SDL_GetTicks()-startFrame));
}
SDL_Quit();
return 0;
}
Access violations mean you are dereferencing null pointers(or pointers to memory you don't have access to), so this would mean (assuming the debugger synced with the source correctly) that SDL_GetVideoSurface is returning null, so you'll probably wanna throw a few checks in isDead. Secondly, its probably a good idea to store the w/h of the surface minus 1 in your class at during the creation of the surface, should mean a little less computational overhead along with shorter code.