I have an instance where a SDL_Rect is inside of a big SDL_Rect and i need it to make it so it cannot leave that rect but can still move. The movement of the little rect needs to be like board game movement where you click the button once and it moves a certain cords here is my code:
if( event.type == SDL_KEYDOWN) {
switch( event.key.keysym.sym ) {
case SDLK_UP:
yVel -= 10;
if (!check_collision(box,Cont))
{
std::cout<<"in the water"<<std::endl;
box.y -= yVel - 10;
}
break;
case SDLK_DOWN:
if (!check_collision(box,Cont))
{
std::cout<<"in the water"<<std::endl;
box.y -= yVel + 20;
}
else
{
yVel += 10;
}
break;
case SDLK_LEFT:
xVel -= 10;
if (!check_collision(box,Cont))
{
std::cout<<"in the water"<<std::endl;
}
break;
case SDLK_RIGHT:
xVel += 10;
if (!check_collision(box,Cont))
{
std::cout<<"in the water"<<std::endl;
}
break;
case SDLK_1:
return 2;
break;
}
}
You have inconsistencies in your SDLK_DOWN and the rest of your inputs - no velocity change happens if there are no collisions.
Your input code is changing coordinates, it shouldn't be like that. Make your input code manage the "intent", and have a game loop apply velocity to the object and to the collision detection.
Also, your collision checks should check if I'm at position and I move of delta, will I collide? If I do collide, what's the collision reaction? Do you want the entity to "slide" on collisions or simply stop as soon as a collision is detected?
Considering you are doing a board game, you shouldn't even have to do collision detection. Represent your board as a graph of possible positions your unit can be, translate mouse clicks into board coordinates and calculate the shortest path (use the A* algorithm) between your current position and your destination; invalid clicks (out of bounds) shouldn't translate into movement commands.
Related
I'm currently working on a small game and recently tried to introduce smoother movements for the player using velocity variables: when a key is pressed, the velocity is increased in the appropriate direction; and, when the same key is released, the velocity goes back to 0. However, when moving on the y axis, the character won't stop moving as it should when the key is released, which is weird considering everything works as intended when moving on the x axis.
Here's the function responsible for keyboard events:
void Game::processEvent(){
switch(Engine::Instance().event.type){
case SDL_KEYDOWN:
switch(Engine::Instance().event.key.keysym.sym){
case SDLK_LEFT: Entities[0]->vx=-0.0001f; break; //Entities is a vector filled with pointers to objects like enemies, the player etc..
case SDLK_RIGHT: Entities[0]->vx=0.0001f; break; //This is how velocity is set
case SDLK_UP: Entities[0]->vy=-0.0001f; break;
case SDLK_DOWN: Entities[0]->vy=0.0001f; break;
}
break;
case SDL_KEYUP:
switch(Engine::Instance().event.key.keysym.sym){ //Reset velocity in a direction only if the player was previously moving in that direction
case SDLK_LEFT: if(Entities[0]->vx>0) Entities[0]->vx=0.0f; break;
case SDLK_RIGHT: if(Entities[0]->vx<0) Entities[0]->vx=0.0f; break;
case SDLK_UP: if(Entities[0]->vy<0) Entities[0]->vy=0.0f; break;
case SDLK_DOWN: if (Entities[0]->vy>0) Entities[0]->vy=0.0f; break;
}
break;
default:
break;
}
}
And the function used to update objects' position:
void Entity::updatePos(){
x += vx; //Velocity is added to the sprite's coords
y += vy;
dstrect = {static_cast<int>(x*800), static_cast<int>(y*800), static_cast<int>(w*800), static_ cast<int>(h*800)}; //Workaround to make sprites' coords and dimensions always relative to the screen, not great I know XD that's why x and y are floats between 0 and 1.
}
I've been scratching my head for a while as to why vy isn't reset properly when vx is. Any idea?
EDIT: Removing the 'if' statements before setting the velocity to 0 solved the problem, guess it was unnecessary in the first place.
Which give us instead:
case SDL_KEYUP:
switch(Engine::Instance().event.key.keysym.sym){
case SDLK_LEFT: Entities[0]->vx=0; break;
case SDLK_RIGHT: Entities[0]->vx=0; break;
case SDLK_UP: Entities[0]->vy=0; break;
case SDLK_DOWN: Entities[0]->vy=0; break;
default: break;
(I can't flag this as the answer yet, sorry 'bout that)
For some reason when I run the code below... The character only moves diagonally down. Lets say line I"m drawing is character:
\
\
\
\
\
That's the only direction it moves if I press up, right, down or left key!
Please help, I want to go right if right, up if up, down if down, and left if left.
My Code is:
#include<iostream>
#include<string>
#include<SFML\Graphics.hpp>
using std::cout;
using std::endl;
enum Direction
{
DOWN,
LEFT,
RIGHT,
UP
};
int main()
{
sf::RenderWindow _Win(sf::VideoMode(600, 600), "Hello World");
sf::Texture _texture;
if (!(_texture.loadFromFile("Resources/SPRITE.png")))
{
cout << "Could not load iamge" << endl;
}
//Source, tell us our starting position.
//Vector2i = Vector of 2 in SFML
sf::Vector2i source(1, DOWN/*or 0*/);
sf::Sprite _sprite(_texture);
float x = _sprite.getPosition().x;
float y = _sprite.getPosition().y;
while (true)
{
sf::Event _event;
while (_Win.pollEvent(_event))
{
switch (_event.type)
{
case sf::Event::Closed:
_Win.close();
exit(1);
break;
case sf::Event::KeyPressed:
switch (_event.key.code)
{
case sf::Keyboard::Up:
source.y = UP;
_sprite.move(sf::Vector2f(x,y--));
y = 3, x=3;
break;
case sf::Keyboard::Down:
source.y = DOWN;
_sprite.move(sf::Vector2f(x, y++));
y = 3, x = 3;
break;
case sf::Keyboard::Right:
source.y = RIGHT;
_sprite.move(sf::Vector2f(x++, y));
y = 3, x = 3;
break;
case sf::Keyboard::Left:
source.y = LEFT;
_sprite.move(sf::Vector2f(x--, y));
y = 3, x = 3;
break;
}
break;
}
}
//Cropping Out Image
//Please Look at sprite in resources/Sprite.png
//When we run this :
//_sprite.setTextureRect(sf::IntRect( source.x*32 , source.y*32 , 32 , 32 ));
//Its going to give us the top left corner sprite image. Thats so because
//we are cropping source.x*32 , which of 32 is the width of the sprite.. So it
//starts from 1 * 32. 32 is the width of one sprite so it goes to the end of it.
//Same Applies to the y. source.y * 32. It just goes to the end of the down sprite.
//As you go down the y increases, 1 * 32 = 32. And 32 is the width of one sprite
//so it shows body of one full sprite.
_sprite.setTextureRect(sf::IntRect( source.x*32 , source.y*32 , 32 , 32 ));
//Clears Window(Flickering..)
_Win.clear();
//Draw Sprite
_Win.draw(_sprite);
//And Finally Display the Window.
_Win.display();
}
}
In every case of your switch statement, you move the sprite by (x,y), and then either increment or decrement x or y, depending upon the direction. However, this is fruitless, since on the very next line, you reset them both to 3. So in effect, whatever direction key is pressed, you are doing this:
_sprite.move(sf::Vector2f(3, 3));
That is, 3 units to the right and 3 units down, which seems to fit your description of the movement you are seeing. I'm not sure what kind of movement you're going for, but here's an example that could work:
switch (_event.key.code) {
case sf::Keyboard::Up:
_sprite.move(sf::Vector2f(0, -3));
break;
case sf::Keyboard::Down:
_sprite.move(sf::Vector2f(0, 3));
break;
case sf::Keyboard::Right:
_sprite.move(sf::Vector2f(3, 0));
break;
case sf::Keyboard::Left:
_sprite.move(sf::Vector2f(-3, 0));
break;
}
This would move the sprite 3 units each time a direction key was pressed, in that direction.
I'm trying to create a smaller game and I need to get a rectangle to move left to right within the window. Note that this is not the fully completed code. Below is a snippet of a created window class and the run function of it.
I can draw the rectangle, and at the moment it's also moving. However, when I'm pressing up/down it'll move to the right as well, but I want it to do it automatically. If I move the for-loop calling movement() outside of while (which I assume it should..?), the rectangle just disappears.
Another thing to note is that movement should be called through the vector pcEnhet, since I'll use it with other sprites later on.
void Spelplan::run() {
SDL_RenderClear(render);
for (PCKomponent* k : pcEnhet)
k->draw();
SDL_RenderPresent(render);
bool spela = true;
while (spela) {
SDL_Event eve;
while (SDL_PollEvent(&eve)) {
switch (eve.type) {
case SDL_QUIT:
spela = false;
break;
case SDL_KEYDOWN:
switch (eve.key.keysym.sym) {
case SDLK_DOWN:
for (PCKomponent* k : pcEnhet)
k->knappNer(eve);
break;
case SDLK_UP:
for (PCKomponent* k : pcEnhet)
k->knappUpp(eve);
break;
}//keysym switch
SDL_RenderClear(render);
for (PCKomponent* k : pcEnhet)
k->draw();
SDL_RenderPresent(render);
}//eve.type switch
for (PCKomponent* k : pcEnhet) {
k->movement();
k->draw();
}
}//while SDL_Poll
}//while spela
}
void Spelare::movement() {
area.x++;
}
void Spelare::draw() {
SDL_RenderCopy(sp->getPlan(), spelareTexture, NULL, &area);
}
Don't do the rendering in while (SDL_PollEvent(&eve)), but in while (spela). Your items have to be moved/drawn not depending on whether the input is being registered.
while (SDL_PollEvent(&eve)) {
...
}
SDL_RenderClear(render);
for (PCKomponent* k : pcEnhet) {
k->movement();
k->draw();
}
SDL_RenderPresent(render);
Remove the "pre-rendering" code you have above the bool spela = true; line, and remember to make your event loop similar to this from now on.
Note that rather than moving all the objects, you could think of them as stationary and move just the camera (viewport), with which you would calculate the absolute coordinates of the objects in their draw function.
And also, pick one from the two:
spela = false; // will render one last frame
break; // ^ will not, and does not require spela variable at all
I'm writing code that draws a polygon and gives it two feet, walks from the right until it gets to the middle, does a flip, and then lands and walks to the left. I'm having a lot of trouble figuring out how to animate his feet. All I want to do is make one go up, then come down, then the other go up, and then come down. I know all I have to do is change the Y values of his feet, but I can't figure out how.
My professor talks about key frames a lot, but wouldn't every step that my "Polyman" would take be a key frame leading to infinite amount of cases? Here is my timer function...
void TimerFunction(int value) //float plx = 7.0, ply=-3.0, linet=0.00;
{
switch(frame)
{
case 1:
dx-=0.15;
plx-=0.15; //dx=polygon, plx = one foot, pl2x = other foot
pl2x-=0.15;
if(dx<=0.0)
{
plx=0.0; //this case makes polyman walk to the middle
dx=0.0;
pl2x=0.0;
frame=2;
}
break;
case 2:
dxt+=0.05;
if (dxt<=-0.00) //this is a triangle I translate over polyman appearing as if he's opening his mouth
{
dxt=0.00;
frame=3;
}
break;
case 3:
dy+=0.2;
theta+=10.0;
thetat+=10.0;
dyt+=0.2; //this is the flip with polyman's mouth open
ply+=0.2;
pl2y+=0.2;
linet2+=10.0;
linet+=10.0;
if(dy>5.0 || theta>360.00)
{
dy=5.0;
dyt=5.0;
ply=5.0;
pl2y=5.0;
linet2=0.0;
theta=0.0;
thetat=0.0;
linet=0.0;
frame=4;
}
break;
case 4:
dy-=0.2;
dyt-=0.2;
ply-=0.2;
pl2y-=0.2;
if(dy<=-3.0) //this is polyman coming back down to earth
{
dy=-3.0;
dyt=-3.0;
ply=-3.0;
pl2y=-3.0;
frame=5;
}
break;
case 5:
dxt-=0.2;
if (dxt<-3)
{ //this is the triangle slowly translating left appearing as if he's closing his mouth
dxt-=3.0;
}
if (dxt<=-8)
{
dxt = -8;
frame = 6;
}
break;
case 6:
dx-= 0.15;
plx-= 0.15;
pl2x-=0.15; //this is polyman walking off the stage to the left
if(dx<=-8.0)
{
dx=-8.0;
plx=-8.0;
pl2x=-8.0;
}
break;
}
glutPostRedisplay();
glutTimerFunc(30, TimerFunction, 1);
}
All variables that are used in my timerfunction are global. Thanks for your time! If you need any more of my code just ask and i'll append.
as I'm new to coding in general I'm sure that my thinking is just heading in the wrong direction with this however..
I'm trying to get a sprite to chase the mouse on left click. I had tried to use else if statements but only the first 2 statements would run even on multiple clicks.
I want to be able to say if mouseposition.x > playerposition.x then move playerimage right, and so one for the other directions.
as I'm using sfml, I've used the below to get the positions of both.
sf::Vector2i mousePosition = sf::Mouse::getPosition(window);
sf::Vector2f playerPosition = playerImage.getPosition();
I was hoping to use the switch statement as below but I'm at a loss as to how to create the argument and compare the cases to that argument.
if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
switch()
{
case 1:
playerImage.move(0.02, 0);
case 2:
playerImage.move(-0.02, 0);
case 3:
playerImage.move(0, -0.02);
case 4:
playerImage.move(0, 0.02);
}
Maybe something like this?
if (sf::Mouse::isButtonPressed(sf::Mouse::Left)) {
sf::Vector2f offset;
if (mousePosition.x > playerPosition.x) {
offset.x = 0.02f;
} else if (mousePosition.x < playerPosition.x) {
offset.x = -0.02f;
}
if (mousePosition.y > playerPosition.y) {
offset.y = 0.02f;
} else if (mousePosition.y < playerPosition.y) {
offset.y = -0.02f;
}
playerImage.move(offset);
}