Here are my functions:
void main_loop(){
SDL_Surface* image;
image=SDL_LoadBMP("plane.bmp");
plane=SDL_CreateTextureFromSurface(renderer,image);
double angle=90;
int speed=1;
SDL_Event event;
bool quit=false;
while(!quit){
while(SDL_PollEvent(&event)!=0){
if(event.type==SDL_QUIT)
quit=true;
if(event.type==SDL_KEYDOWN){
switch(event.key.keysym.sym){
case SDLK_RIGHT:
angle+=90*delta;
break;
case SDLK_LEFT:
angle-=90*delta;
break;
}
}
}
//update_delta();
int angle_rad=angle*PI/180;
x+=sin(angle_rad)*speed*delta;
y-=cos(angle_rad)*speed*delta;
draw((int)x,(int)y,angle);
}
last_time=SDL_GetTicks()/1000;
return;
}
void draw(Uint32 x,Uint32 y,double angle){
SDL_RenderClear(renderer);
SDL_Rect rect;
rect.x=x;
rect.y=y;
rect.h=100;
rect.w=100;
SDL_RenderCopyEx(renderer,plane,NULL,&rect,angle,NULL,SDL_FLIP_NONE);
SDL_SetRenderDrawColor(renderer,0,0,0,255);
SDL_RenderPresent(renderer);
}
Basically what I want to do is to rotate a texture, and move it a fixed speed in the direction it is facing. The delta value is the time between two frames, and i use this to figure out the increment of x and y coordinates per frame. However , there is some problem with the angles. The texture does not move properly, but at some awkward angle which makes it look like it is drifting. So far I have tried changing trig functions, negating x and y, but it simply does not work.
I am using SDL 2.0 with C++.
int angle_rad=angle*PI/180;
Your radians are being stored in an integer, so they will get truncated to the nearest whole number. Store them in a float or a double instead.
Related
I’m making a game with C++ and SFML. I have delta time in my game by setting it to clock.restart().asSeconds() and then multiplying that by a movement offset. The only issue is that when the final movement value is not an integer (or .0f), it causes rendering artifacts between my sprites. I have a grid of sprites that are all lined up next to each other. When I move by an integer offset, it looks good. However, when moving with a decimal, I can see strange lines between the sprites. Is there any way of fixing this?
note: I don't want to round the deltatime * offset value because when fps is too high, it will be rounded to 0 and the player will not move at all.
delta time code:
void Game::run()
{
init();
Gui::init();
Gui::mainMenu();
sf::Clock deltaClock;
while (window.isOpen())
{
sf::Event loopEvent;
while (window.pollEvent(loopEvent))
{
switch (loopEvent.type)
{
case sf::Event::Closed:
saveGame();
window.close();
break;
case sf::Event::KeyPressed:
if (loopEvent.key.code == Gui::keybinds[Action::EXIT_MENU] && Player::hasSpawned)
{
Gui::inMenu = false;
Gui::currentGameState = GameState::SETTINGS;
}
}
}
deltaTime = deltaClock.restart().asSeconds();
update();
window.setView(camera);
window.clear(sf::Color::White);
draw();
window.display();
Gui::checkGameState();
}
}
const float Game::MAKE_DELTA(const float OFFSET)
{
return OFFSET * deltaTime;
}
Moving with integer offset (or when I round the return value of MAKE_DELTA()):
Moving with decimal offset (unrounded return value from MAKE_DELTA()):
I've been lately working on a simple game using C++ and SFML latest version, but I had a problem which is that the collision detection is not that good, for example the player dies even if the enemy didn't touch him yet, but just near him. Here is the code of the player class with the move function and collision detection code AND the moves of the enemy class:
`class PlayerA : public CircleShape
{
public:
//Constructor:
PlayerA(float xposition, float yposition, float radius, float s)
{
setRadius(radius);
setFillColor(Color::Yellow);
setOutlineColor(Color(00,80,00));
setOutlineThickness(-2);
setPointCount(3);
setSpeed(s);
setPosition(xposition,yposition);
}
//Movements of the player:
void up()
{
move(0,-10*speed);
}
void down()
{
move(0,10*speed);
}
void right()
{
move(10*speed,0);
}
void left()
{
move(-10*speed,0);
}
void checkA(ObsA *obs1=NULL,ObsA *obs2=NULL, ObsA *obs3=NULL, ObsA *obs4=NULL, ObsA *obs5=NULL)
{
if(obs2==NULL)
{
if(getGlobalBounds().intersects(obs1->getGlobalBounds()))
{
relevel();
}
}
private:
float speed=0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
void obs()
{
if(speed > 0)
{
rotate(0.5*speed);
}
else
{
rotate(0.5*speed);
}
}
private:
float speed = 0.00;
Is there something wrong with the code, how to fix the problem, thank you!
The intersects function just check if two rectangles intersect. If you want pixel perfect collision detection in SFML you have to write that yourself.
Basically, start with intersects, if it is true, then get the intersecting rectangle and check if any pixels therein from both original rectangles contains overlaping relevant pixels.
You can use this function to perform better collision detection.Its a basic one but works well
bool circleTest(const sf::Sprite &first, const sf::Sprite &second)
{
sf::Vector2f firstRect(first.getTextureRect().width, first.getTextureRect().height);
firstRect.x *= first.getScale().x;
firstRect.y *= first.getScale().y;
sf::Vector2f secondRect(second.getTextureRect().width, second.getTextureRect().height);
secondRect.x *= second.getScale().x;
secondRect.y *= second.getScale().y;
float r1 = (firstRect.x + firstRect.y) / 4;
float r2 = (secondRect.x + secondRect.y) / 4;
float xd = first.getPosition().x - second.getPosition().x;
float yd = first.getPosition().y - second.getPosition().y;
return std::sqrt(xd * xd + yd * yd) <= r1 + r2;
}
Are you using a circle? If I remember correctly, the circle will have a rectangle hitbox. If that is the case, then you may have collision between the invisible rectangle corners.
If you're using a circle, Perhaps change class to a square rectangle and see if collision works correctly. Or try testing collision directly on an x or y axis with your circles; i.e. having them moving in a straight line towards each other only changing 1 axis. (the edge of the circle will be the same as the edge of the rectangle at the left, right, top, and bottom sections).
If you're needing a better collision for circles, there may be one already built in SFML. But I don't think it would be too much to write your own logic using the radius of your two circles, the center of your two objects, and the angle hypotenuse between the centers.
edit based on Merlyn Morgan-Graham's comment.
I need to create two Boxes, which should both be rotating with the same speed in the same way, only their position should be different. All i got is this:
http://i.stack.imgur.com/JMua9.png
I have used the following code:
float rotatevalue;
void setup()
{
rotatevalue = 0;
size(500, 500, OPENGL);
if (frame != null) {
frame.setResizable(true);
}
}
void draw()
{
background(245, 238, 184);
fill(246, 225, 65);
rotatevalue = rotatevalue + 2;
pushMatrix();
translate(width/4, height/4);
rotateX(radians(rotatevalue));
rotateY(radians(rotatevalue));
box(50);
popMatrix();
pushMatrix();
translate(3*width/4, height/4);
rotateX(radians(rotatevalue));
rotateY(radians(rotatevalue));
box(50);
popMatrix();
}
What is wrong that makes them to rotate differently?
I'm not used to using the OpenGL matrix stack, so this may be a little off-base. I calculate my own model matrices to pass to the vertex shader. When I do this, I do the rotations first before the translation.
If you want draw 3D object inside 2D sketch you must use some type of projection same as your eye is projecting real world. For more information you should study more about perspective and projection.
So your boxes are rotating in the same way! I will try to demonstrate it on this basic example. Here you can see 5 boxes around middle of sketch:
void setup(){
size(500, 500, OPENGL);
fill(246, 225, 65);
//ortho();
}
void draw(){
background(245, 238, 184);
translate(width/2, height/2);
draw_box(0);
draw_box(1);
draw_box(2);
draw_box(3);
draw_box(4);
}
void draw_box(int pos){
pushMatrix();
switch(pos){
case 0: translate( 0, 0); break;
case 1: translate( 0,-100); break;
case 2: translate( 0, 100); break;
case 3: translate( 100, 0); break;
case 4: translate(-100, 0); break;
}
box(50);
popMatrix();
}
There is no rotation so they should be same? NO! It is same as railway tracks = they are parallel but in long distance you can almost see them touching (img)
You can try orthographic projection to get more similar boxes for more info see ortho. Also you should be more centric if you want better results.
I would like to implement a simple example in OpenGL just to test the first perspective view (without using lookAt facility), but it is driving me crazy!
I made a little prototype using Processing (that for this stuff is quite similar to OpenGL), but I got strange behavior when camera start to move!
It's not clear to me which it is the order of transformation (I have already tried all combination ;-))!
I was thinking that it should be simple and a possible solution could be:
Translate to the position of the camera
Rotate by angle of the camera
Translate each object in its position
In my simple example I positioned a box and a grid in the (0, 0, -400), but it doesn't work as expected. When I move camera along the X or Z axis the rotation around Y axis seems to rotate around a wrong center! I'd like to simulate a rotation of the camera around its own Y axis, just like a classic FPS game.
Here my sample code where user can move the camera and rotate (just around Y axis), you can test with Processing or using OpenProcessing.
Only the first few lines are relevant to the problem... So it's a very little test!
float cameraXPos = 0;
float cameraYPos = 0;
float cameraZPos = 0;
float cameraYAngle = 0;
float moveIncrement = 5;
float angleIncrement = 5;
// Keys:
// W
// ^
// |
// A <- -> D
// |
// V
// S
//
// F and R for Z+/Z-
// O and P for rotation around Y axis
void setup()
{
size(640, 480, OPENGL);
resetCameraPos();
}
// Reset camera
void resetCameraPos()
{
cameraXPos = width / 2;
cameraYPos = height / 2;
cameraZPos = (height /2 ) / tan(PI/6);
cameraYAngle = 0;
}
void draw()
{
// Clear screen
background(0);
// View transform
translate(cameraXPos, cameraYPos, cameraZPos);
rotateY(radians(cameraYAngle));
// World transform
translate(0, 0, -400);
// Draw a red box and a grid in the center
stroke(255, 0, 0);
noFill();
box(100);
drawGrid();
// Check if user is pressing some key and update the camera position
updateCameraPos();
}
/////////////////////////////////////////////////////////////////////
// The following part is not so relevant to the problem (I hope! ;-))
/////////////////////////////////////////////////////////////////////
void drawGrid()
{
// Draw a white grid (not so important thing here!)
stroke(255, 255, 255);
float cellSize = 40;
int gridSize = 10;
float cY = 100;
for(int z = 0; z < gridSize; z++)
{
float cZ = (gridSize / 2 - z) * cellSize;
for(int x = 0; x < gridSize; x++)
{
float cX = (x - gridSize / 2) * cellSize;
beginShape();
vertex(cX, cY, cZ);
vertex(cX + cellSize, cY, cZ);
vertex(cX + cellSize, cY, cZ - cellSize);
vertex(cX, cY, cZ - cellSize);
vertex(cX, cY, cZ);
endShape();
}
}
}
// Just update camera position and angle rotation
// according to the pressed key on the keyboard
void updateCameraPos()
{
if (keyPressed)
{
switch(this.key)
{
case 'w': // Y++
cameraYPos += moveIncrement;
break;
case 's': // Y--
cameraYPos -= moveIncrement;
break;
case 'a': // X--
cameraXPos += moveIncrement;
break;
case 'd': // X++
cameraXPos -= moveIncrement;
break;
case 'r': // Z++
cameraZPos += moveIncrement;
break;
case 'f': // Z--
cameraZPos -= moveIncrement;
break;
case ' ': // RESET
resetCameraPos();
break;
case 'o': // Angle++
cameraYAngle += angleIncrement;
break;
case 'p': // Angle--
cameraYAngle -= angleIncrement;
break;
}
}
}
Your comment above seems to indicate that you want your cameraYAngle to rotate the camera about its current position. If so, you want to do your camera rotation first; try this:
// View transform
rotateY(radians(cameraYAngle));
translate(cameraXPos, cameraYPos, cameraZPos);
// World transform
translate(0, 0, -400);
Note that the above does nothing to keep you looking at the origin -- that is, it doesn't do anything like lookAt. Also recall that your camera starts out looking down the Z axis...
Here's where I guess you went wrong. Even though your camera and object poses are comparable, you need to generate your "View transform" and "World transform" differently: your camera pose must be inverted to generate your "View transform".
If you're chaining raw transforms (as in your example code), this means that your camera pose transforms need to be in reverse order relative to your object transforms, as well as in the reverse direction (that is, you must negate both translation vectors and rotation angles for the camera transforms).
To be more explicit, suppose both your camera and your object have comparable pose parameters: a position vector and 3 rotations about X, Y, and Z in that order. Then, your transformation sequence might be something like:
// View transform
rotateZ(radians(-cameraZAngle));
rotateY(radians(-cameraYAngle));
rotateX(radians(-cameraXAngle));
translate(-cameraXPos, -cameraYPos, -cameraZPos);
// Model transform
translate(objectXPos, objectYPos, objectZPos);
rotateX(radians(objectXAngle));
rotateY(radians(objectYAngle));
rotateZ(radians(objectZAngle));
As a conceptual check, suppose that your camera is exactly following your object, so that all position and location variables are exactly the same for camera and object. You'd expect the same view as if they were both sitting at the origin with no rotations.
Then note that, if cameraXPos==objectXPos, cameraYPos==objectYPos and so forth, the transforms in the above transform sequence all cancel out in pairs, starting at the center -- so that the end result is the same view as if they were both sitting at the origin with no rotations.
I've tried to port the same example on C and OpenGL, and... It works!
To be precise it works after I inverted the sequence of rotation and translation (as suggested by #comingstorm and as I formerly already tried).
So I come back to Processing and try to figure out why this problem happens. I had already noticed that the default camera position is in:
(width/2, height/2, (height/2) / (PI/6))
So in my code I was moving the camera off by the same distance (in opposite direction) in order to center the camera to my objects, but it didn't work. I also try to leave the camera where it was and then move manually (using the keyboard keys) to reach my objects, but it didn't work either.
So I noticed that in the draw() method there isn't any initialization of the transformation matrix.
In all examples I've seen none does this initialization, and I'm pretty sure to have read somewhere that is automatically initialized. So I was thinking/sure that it wasn't necessary.
Anyway I've tried to put as first statement of draw() method:
resetMatrix(); // Same as glLoadIdentity in OpenGL
...And now everything is working!
(For the record I noticed the same problem also in openFramework library.)
To be honest I don't understand why they (these libraries) don't put camera in the origin and above all I was expecting that if the transformation matrix is not clear at each execution of draw method the camera should be translated automatically (summing the old matrix with the new one), so it would move fast in some direction (or spinning around Y axis).
It's not clear to me the pipeline implemented in these libraries (and I can't find a good document where it is shown), but by now it is important that this problem has been fixed.
I'm trying to detect horizontal mouse motion with OpenGL, so, when detected, execute a glutPostRedisplay(). Problem is that scene is also redrawed on vertical mouse movement.
This is the code of the registered callbacks (note mouse_inix and mouse_iniy are global (double) variables):
void mouse(int button, int state, int x, int y)
{
if (state == GLUT_DOWN) {
mouse_inix = (double)x;
mouse_iniy = (double)y;
}
}
void motion(int x, int y)
{
if (((double)x) != mouse_inix) {
angle += 20.0;
glutPostRedisplay();
}
}
Are you sure? It doesn't look like from the code you've posted that vertical mouse movement will trigger the glutPostRedisplay() call.
BUT, you've defined "horizontal mouse movement" very narrowly here. If you move the mouse up and down, you're almost sure to get a few pixels of horizontal movement. Maybe you could put a dead zone around the mouse to keep it from moving on every pixel. Something like:
void motion(int x, int y)
{
if ((abs(x - (int)mouse_inix) > 10) {
angle += 20.0;
glutPostRedisplay();
}
}
That's one thing that's going on here. Another is the use of "double". Since glut is returning mouse coordinates as ints, you're better off sticking with that. Trying to compare "(double)x != mouse_inix" will almost certainly be true because of the precision issues with doubles. You generally don't want to compare for exactly equal to or not equal to using floating point numbers. The use of the dead zone will negate that issue, but still, why convert to doubles if you don't need them?
I don't know if "20" is degrees or radians, but it could result in some pretty jumpy moves either way. Consider scaling the size of the move to the size of the mouse move:
void motion(int x, int y)
{
int deltaX = (abs(x - (int)mouse_inix);
if (deltaX > 10) {
angle += (double)deltaX; // or "deltaX/scaleFactor" to make it move more/less
glutPostRedisplay();
}
}
It will still only rotate one way. If you used the sign of "deltaX", you would be able to rotated both directions depending on how you moved the mouse.