How to make a 3D model follow the mouse movements? - c++

I'm writing a simple version of the game Duck Hunt in C++, using OpenGL. I managed to render the 3D model of a rifle in the center of the screen, and what I want is to rotate it on his y and z axes depending on the mouse movements, so that the rifle is always pointing to the mouse pointer. I have tried to compute the rotation angles using the arctan equation, in order to have the right proportion between the mouse movements and the distance of the pointer from the rifle, but the result is not really good as the sensibility of the rotation seems to be too low. Here there is my current implementation:
void passiveMotion(int x, int y) {
switch (gamePhase) {
case gameStarted:
if(x > 540 && x < 1000)
gunYrot = ((-(atan(abs(y-720) / (double)(x-540)))) * 180 / M_PI);
else if(x > 80 && x < 540)
gunYrot = (((atan(-abs(y - 720) / (double)(x - 540)))) * 180 / M_PI - 180);
if (y > 320 && y < 355) gunZrot = y;
break;
default: break;
}
}
The game screen is this:
Any clues about what could be the best approach to move the rifle?
Bonus question: at the moment, the bullet is shot from the point in which the rifle is rendered (so it starts from its center); how could I dinamically compute the coordinates of where the gun barrel ends to make it the starting point of the bullet?
Thank you for any help with this.

Related

SDL joystick shooting angle c++

I'm having some issues with my shooting mechanics in my c++ 2D platform game using the SDL joystick. When I direct the joystick in any direction the bullet seem to go in the right direction-ish. When I do not direct the joystick in any dirction but press the shoot button I want the bullet to go in a horizontal line in the direction the player is facing( either 0 or -180), but right now the angle seems to be -108ish.
This is the code I use to get the angle of the joystick relative to the players position.
controller_y = SDL_JoystickGetAxis(j, 1); // get controller y axis
controller_x = SDL_JoystickGetAxis(j, 0); // get controller x axis
int deltax = xpos - controller_x; // diference in x pos
int deltay = ypos - controller_y; // diference in Y pos
angle = atan2(-deltay, -deltax) * 180 / PI;
and in my update function I update the bullets position like this:
box.x += speed *(cos(angle*PI / 180)) * delta;
box.y += speed *(sin(angle*PI / 180)) * delta;
When I do not move the joystick in any direction the x and y value of the Joystick is usually lower 500 and bigger than -500. So my question is how I can get the bullet to go in the angle -180 if my player is facing left and I do not move the joystick and the angle 0 if my player is facing right when I do not move the joystick if that makes sense.

How do I flip an image and point a gun at the mouse at the same time? (SFML)

I'm making a shooter where the player can shoot at the mouse, so I got the guns to point at the mouse, but I can't figure out how to correctly flip the image once it's turned left. I mean, I did flip the image but it's not aligned right. I'm not really sure how to explain it, here's my code.
void PortalGun::update(Vector2i mPos) {
float pi = 3.14159265359;
float rotation = atan2(sprite.getGlobalBounds().top - mPos.y,sprite.getGlobalBounds().left - mPos.x) * 180 / pi;
int x = player->sprite.getGlobalBounds().left + 16;
int y = player->sprite.getGlobalBounds().top;
if (rotation > -90 && rotation < 90) {
player->dir = -1;
sprite.setTextureRect(IntRect(0, 32, 64, -32));
} else {
player->dir = 1;
sprite.setTextureRect(IntRect(0, 0, 64, 32));
}
sprite.setPosition(x, y + 15);
sprite.setRotation(rotation + 170);
}
When the mouse is to the left of the gun, it flips the image but keeps rotating upwards so the mouse is 20 ish pixels higher. I can't just change the position when rotating, so what do I do? Sorry for sounding a bit cryptic, it's a bit hard to explain.
First of all, you should set your sprite's origin to the point where you'd like to rotate the gun (typically the handle or mounting point). To do this, use sf::Sprite::setOrigin(). The passed coordinates are relative to the top left corner of the sprite.
To get or set your sprite's position in the world (where your origin is), you can use sf::Sprite::getPosition() and sf::Sprite::setPosition().
Your rotation can stay as it is. It will rotate around your set origin.
To mirror your sprite, just scale (sf::Sprite::setScale()) it using a negative factor: sprite.setScale(-1, 1); The negative factor will mirror/flip the image at the set origin, without forcing you to update the texture coordinates.

algorithm for drawing a sort of nozzle(line),whose is direction determined by the mouse?

i am using The old Turbo C++ and am a beginner.
This is the code of a ongoing project that i am planning.
the circle moves withe WSAD keys
But the problem is that i want the nozzle(a line from the center) of that circle to follow the movement of the mouse,but i cant figure out the mathematical part to restrict the length of that nozzle to, say 30 pixels. the line goes on touching the pointer's location.
I tried to use the Distance formula and the line equation to get with an expression which has both the slope and the length of the line. But the problem here is that there is an square root in the denominator, and i think that is causing the problem
Most of the code here is unnecessary for the following problem, so please ignore
here is the relevant code
originx=getmaxx()/2;
originy=getmaxy()/2;
while(doga==0) //main game loop
{ if(kbhit())
op=getch();
if(limiter>10) //limiter is used to restrict the motion of the circle for a limited // time
{ op=0;limiter=0;} // otherwise the cirlce moves in that direction unless another //key is pressed
//movement of the circle
if(op==72)
{ originy--; limiter++;}
if(op==80)
{originy++; limiter++;}
if(op==75)
{ originx--; limiter++ ;}
if(op==77)
{ originx++; limiter++; }
circle(originx,originy,5);
mouseposi(x,y,cl);
printf(" %d %d",x,y);
printf("\b\b\b\b\b\b\b\b");
m=sloper(originx,originy,x,y);
line(originx,originy,80/sqrt(1+m*m),m*80/sqrt(1+m*m)); //THIS LINE IS WHERE THE PROBLEM IS
delay(30);
cleardevice();
if(op==49) //for exiting
doga=2;
}
}
Let (x,y) be the point you're after, (ox, oy) be your origin, and (mx, my) be the mouse location.
The vector from the origin to the mouse is (dx, dy) = (mx - ox, my - oy).
The distance between the mouse and the origin is the same as the norm of that vector:
distance = sqrt(dx * dx + dy * dy);
Normalizing (scaling) the vector to get a new vector of length 1 ("unit length") we get
nx = dx / distance;
ny = dy / distance;
And finally we can scale those coordinates by the desired length (remembering to add back the origin)
x = ox + length * nx;
y = oy + length * ny;

How do I make projectiles?

I am totally stumped on this one. I'm using C++ and SFML 1.6 for a game I'm developing, and I have no bloody idea. How do I make projectiles (like bullets)? I just don't understand it. It could be my lack of sleep but I don't know.
So my question is how do I create a Sprite that moves in a definite direction based on where the mouse is? (Think of a top down shooter with mouse aiming)
Easiest solution:
If the mouse is at Mx,My and the ship is at Sx,Sy then calculate the direction from the ship to the mouse:
Dx=Sx-Mx
Dy=Sy-My
Now normalise D (this means scale it so that it's length is one):
DLen=sqrt(Dx*Dx + Dy*Dy)
Dx/=DLen;
Dy/=DLen;
Now Dx is the distance you want to move the bullet on the x axis in order to get bullet speed of 1.
Thus each frame you move the bullet like so (position of bullet: Bx,By Speed of bullet: Bs [in pixels per millisec] Frame time Ft[in millisec])
Bx=Bx+Dx*Bs*Ft
By=By+Dy*Bs*Ft
This give you a bullet that moves towards the mouse position at a speed independent of the direction of the mouse or framerate of the game.
EDIT: As #MSalters says you need to check for the DLen==0 case when the mouse is directly above the ship to avoid division by zero errors on the normalise
One way to do it is to make the bullet face the mouse and then move it across the x and y axis by using trigonometry to find the hypotinuse from the angle. I don't think i explained this very well, so here the code to make a sprite move from its rotation:
void sMove(sf::Sprite& input,float toMove, int rotation){
bool negY = false;
bool negX = false;
int newRot = rotation;
if (rotation <= 90){
negY = true;
}
else if (rotation <= 180){
//newRot -= 90;
negY = true;
}
else if (rotation <= 360){
newRot -= 270;
negY = true;
negX = true;
}
float y = toMove*cos(newRot*PI/180);
float x = toMove*sin(newRot*PI/180);
if (negY){
y = y*-1;
}
if (negX){
x = x*-1
}
input.move(x, y);
}

How do you rotate a sprite around its center by calculating a new x and y position?

I'm using Dark GDK and C++ to create a simple 2d game. I'm rotating an object but it rotates from the top left corner of the sprite.
I have the following variables available:
PlayerX
PlayerY
PlayerWidth
PlayerHeight
RotateAngle (360 > x > 0)
Is there an algorithm that will modify the pivot point of the sprite, preferable to the center?
Here is a small code sample:
void Player::Move( void )
{
if ( checkLeft() )
{
PlayerX -= PlayerSpeed;
if ( PlayerX < 0 )
PlayerX = 0;
}
if ( checkRight() )
{
PlayerX += PlayerSpeed ;
if ( PlayerX > 800 - PlayerWidth )
PlayerX = 800 - PlayerWidth;
}
if ( checkUp())
{
PlayerY -= PlayerSpeed;
if ( PlayerY < 0 )
PlayerY = 0;
}
if ( checkDown())
{
PlayerY += PlayerSpeed;
if ( PlayerY > 600 - PlayerHeight)
PlayerY = 600 - PlayerHeight;
}
RotateAngle += 5;
if(RotateAngle > 360)
RotateAngle -=360;
dbRotateSprite(Handle,RotateAngle);
dbSprite ( 1 , PlayerX , PlayerY , Handle );
}
Edit
I'm considering opening up some reputation for this question, I have yet to be provided with an answer that works for me. If someone can provide an actual code sample that does the job, I'd be very happy.
The problem with Blindy's answer is that no matter how much I simply translate it back or forth, the spirte still rotates around the top left hand corner and moving it somewhere rotating around the top left corner, then moving it back to the same position accomplishes nothing. Here is what I believe to be going on:
alt text http://img248.imageshack.us/img248/6717/36512474.png
Just so there is no confusion I have created a an image of what is going on. The left shows what is actually happening and the right shows what I need to happen.
alt text http://img101.imageshack.us/img101/1593/36679446.png
You'd need to do something like:
translate by (-playerx-playerwidth/2, -playery-playerheight/2)
rotate by rotateangle
translate by (playerx+playerwidth/2, playery+playerheight/2)
The idea is to center your sprite on the origin then rotate around the origin (glRotate) and after you get the rotated sprite you translate it back in its place.
NB: If your sprite is initially "centered" around the origin, but with a corner not the actual center of the sprite, you first translate the object to center the sprite's center with the origin. So like if your sprite had the top-left corner in the origin, you'd translate by (-playerwidth/2, -playerheight/2), then rotate then translate by (playerx,playery).
The answers so far are correct in telling you how it should be done but I fear that the Dark GDK API seems to be too primitive to be able to do it that simple way.
Unfortunately dbRotateSprite rotates the sprite about the top left regardless of the sprite's transform which is why you're having no luck with the other suggestions. To simulate rotation about the centre you must manually correct the position of the sprite i.e. you simply have to rotate the sprite and then move it as a two-step process.
I'm not familiar with the API and I don't know if y is measured up or down and which way the angle is measured so I'm going to make some assumptions. If y is measured down like many other 2D graphics systems, and the angle is measured from the x-axis increasing as it goes from the positive x-axis to the positive y-axis, then I believe the correct psuedo-code would look like
// PlayerX and PlayerY denote the sprite centre
// RotateAngle is an absolute rotation i.e. not a relative, incremental rotation
RotateAngle += 5;
RotateAngle %= 360;
RadiansRotate = (RotateAngle * PI) / 180;
dbRotateSprite( Handle, RotateAngle );
HalfSpriteWidth = dbSpriteWidth( Handle ) / 2;
HalfSpriteHeight = dbSpriteHeight( Handle ) / 2;
SpriteX = PlayerX
- HalfSpriteWidth * cos(RadiansRotate)
+ HalfSpriteHeight * sin(RadiansRotate);
SpriteY = PlayerY
- HalfSpriteHeight * cos(RadiansRotate)
- HalfSpriteWidth * sin(RadiansRotate);
// Position the top left of the sprite at ( SpriteX, SpriteY )
dbSprite ( 1 , SpriteX , SpriteY , Handle );
When you rotate the object, you are applying a transformation to the points that compose the object. In this case, the four corners each rotate on their own, and the end result is the quad formed in their new locations. As everyone else has mentioned, the critical part of this is knowing where the origin about which the points rotate.
Imagine if instead of a sprite, you only had one point. If its origin was at the same position as that point, rotating it would have no effect (the position of the point would not move). However, if the origin was anywhere else, the point would rotate in a circle, with the origin as the center of that circle. And how would you get that origin to be somewhere other than at the same position as the point? Move the point within the coordinate system. In other words, translate it.
The order of the various transformations (rotate, translate, scale, etc.) is critical to this. If you rotated the point 180 degrees and then translated it to the right, it would end up to the right of where it started, but if you moved it to the right and then rotated it 180 degrees, it would end up on the left.
I'd recommend reading up on 2D transformations. Understanding how matrices play in all this would also be useful, but not strictly necessary to get the effect you're looking for.
Looking at your image, what you're doing is you're rotating the square in place, you're not translating it at all. This is what you're doing:
^ ^
| |
| |
| ====> |
| |
+--+-----> x---------->
| | / \
+--+ \ /
x
As you can see, your square is with its top-left corner in the origin and all you're doing is rotating it around the origin.
This is what I'm saying you should do:
^ ^ ^
| | |
| | ===> | ==> translate to
| ====> | x ==> where you want
| +-+ /|\ ==> to draw it
+--+-----> |+|---------> +-------->
| | +-+ \ /
+--+ x
You can only rotate around the center, so center the point you want to rotate your primitives around then place them where you want.
OMG ive been tryna do this for a while now to, n i found this page, just copy this.
this is based on one of the previous posts.
void dbRotateSpriteCenter(int iID, int iX, int iY, int fRotate, int iImage)
{
int x = iX
- dbSpriteWidth(iID) / 2 * cos(fRotate * 3.1415926536 / 180)
+ dbSpriteHeight(iID) / 2 * sin(fRotate * 3.1415926536 / 180);
int y = iY
- dbSpriteHeight(iID) / 2 * cos(fRotate * 3.1415926536 / 180)
- dbSpriteWidth(iID) / 2 * sin(fRotate * 3.1415926536 / 180);
dbRotateSprite(iID, fRotate);
dbSprite(iID, x, y, iImage);
}
you could use dbOffsetSprite();
when sprites are created, their insertion point is upper-left corner by default (and dbRotateSprite(); rotates them around the insertion point), you can use this function to change the insertion point. its format is dbOffsetSprite(sprite number, amount to offset X, amount to offset Y);
so you could say
dbOffsetSprite(NUMBER, dbSpriteWidth(NUMBER) / 2, dbSpriteHeight(NUMBER) / 2);
where NUMBER is the sprite ID number.
The sprite's insertion point is now in the center of its image.
Of course, this might open a whole new can of worms, as the insertion point is now in the center of the sprite (or where ever you set it), meaning calling dbSpriteX(NUMBER); will give you the center of the sprite instead of the edge.