-
OpenGL shooting game
I'm trying to make a game which allows the user to rotate a canon thats sitting at the center of my window and shoot whenever they like.
Code:
void rotate_canon(int direction)
{
if ((direction == LEFT) && (canon_yaw < 90))
{
canon_yaw += 5;
}
else if ((direction == RIGHT) && (canon_yaw > -90))
{
canon_yaw -= 5;
}
else if ((direction == UP) && (canon_pitch < 90))
{
canon_pitch +=5;
}
else if ((direction == DOWN) && (canon_pitch > -90))
{
canon_pitch -=5;
}
draw_canon();
}
rotates the canon
Code:
void draw_canon()
{
/* Only redraw the part that is changing */
glPushMatrix();
glEnable(GL_SCISSOR_TEST);
glScissor(0, TEXTHEIGHT, WIDTH, HEIGHT);
glDisable(GL_SCISSOR_TEST);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glViewport(0, 0, WIDTH, HEIGHT);
gluPerspective(45.0, 1.0, 1.0, 300.0);
gluLookAt(
0.0, 0.0, 30.0,
0.0, 0.0, 0.0,
0.0, 1.0, 0.0);
glRotatef(canon_pitch, 1.0, 0.0, 0.0);
glRotatef(canon_yaw, 0.0, 1.0, 0.0);
glBegin(GL_QUADS);
glColor3f(0.0, 0.0, 1.0);
/* canon front */
glVertex3f(-0.5, -0.5, -1.5);
glVertex3f( 0.5, -0.5, -1.5);
glVertex3f( 0.5, 0.5, -1.5);
glVertex3f(-0.5, 0.5, -1.5);
// canon back */
glVertex3f(-0.5, -0.5, -0.5);
glVertex3f(-0.5, 0.5, -0.5);
glVertex3f( 0.5, 0.5, -0.5);
glVertex3f( 0.5, -0.5, -0.5);
/* canon left */
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5);
glVertex3f(-0.5, 0.5, -2.0);
glVertex3f(-0.5, -0.5, -2.0);
/* canon right */
glVertex3f( 0.5, -0.5, -2.0);
glVertex3f( 0.5, 0.5, -2.0);
glVertex3f( 0.5, 0.5, 0.5);
glVertex3f( 0.5, -0.5, 0.5);
glColor3f(0.2, 0.0, 1.0);
/* canon top */
glVertex3f(-0.5, 0.5, 0.5);
glVertex3f( 0.5, 0.5, 0.5);
glVertex3f( 0.5, 0.5, -2.0);
glVertex3f(-0.5, 0.5, -2.0);
/* canon bottom */
glVertex3f(-0.5, -0.5, 0.5);
glVertex3f(-0.5, -0.5, -2.0);
glVertex3f( 0.5, -0.5, -2.0);
glVertex3f( 0.5, -0.5, 0.5);
glEnd();
glPopMatrix();
glFlush();
}
draws the canon
everything is working good so far.
my question is, when the user clicks to fire....how can I find out where to draw a sphere that represents the canonball (front center of the gun is where?). and how can I determine a trajectory for the shot, so I will be able to update it, and have it seem like its moving.
-
You could keep a variable that holds the rotation degree, update it when the player rotates the cannon, and then use the current degree with the shoot() function
-
the rotate_canon function I posted updates 2 variables, holding the rotation degrees, canon_yaw and canon_pitch. what point do I use to rotate around?...since with a sphere those would just make it spin. And I still can't think of how I will figure out a trajectory for the canonball, other than maybe find a point on the back of the canon and one on the front and create a line. But if I could do that, I could draw the canonball correctly right off the bat
-
Well is this 2D or 3D?
For the following equations your 'gun' must be centered around Gun.x and Gun.y.
For 2D:
Gun=gun position
CannonBall=cannon ball position
Offset=a location representing the end of the gun
Angle=Rotation angle of the gun
This is a simple parametric form of a line equation:
Code:
CannonBall.x=Gun.x+cosf(Angle)+Offset.x;
CannonBall.y=Gun.y+sinf(Angle)+Offset.y;
CannonBall.direction.x=cosf(Angle);
CannonBall.direction.y=sinf(Angle);
For 3D:
matView - view matrix
matCannonBallTrans - cannon ball translation matrix - relative to gun position
matGunTrans
Gun.right = right vector of gun
Gun.up = up vector of gun
Gun.look = look vector of gun
Gun.fYaw = yaw angle of gun (radians)
Gun.fPitch = pitch angle of gun (radians)
Gun.fRoll = roll angle of gun (radians)
In 3D if you take an object at local 0,0,0 and multiply it by the inverse of the camera view matrix you will move the 3D object to the camera position.
Code:
...
Matrix4x4 matView;
Matrix4x4 matInvView;
Matrix4x4 matGunTrans;
Matrix4x4 matCannonBallTrans;
Matrix4x4 matGunRotation;
Matrix4x4 matWorld;
matView=Camera->GetViewMatrix();
MatrixInverse(&matInvView,&matView);
//Compute gun pos
Vector3 vecGunPos=Gun->GetWorldPosition();
//Compute end of gun in world space
float fGunLength=Gun->GetLength();
Vector3 vecEndOfGun=Gun->GetLook()*fGunLength;
//Create gun translation matrix
MatrixTranslation(&matGunTrans,vecGunPos);
//Create cannon ball translation matrix
MatrixTranslation(&matCannonBallTrans,vecEndOfGun);
//Now to display the gun in the correct orientation
//Build the gun rotation matrix from the view matrix we've been given
matGunRotation._11=matView._11;
matGunRotation._12=matView._21;
matGunRotation._13=matView._31;
matGunRotation._14=0.0f;
matGunRotation._21=matView._12;
matGunRotation._22=matView._22;
matGunRotation._23=matView._32;
matGunRotation._24=0.0f;
matGunRotation._31=matView._13;
matGunRotation._32=matView._23;
matGunRotation._33=matView._33;
matGunRotation._34=0.0f;
matGunRotation._41=vecGunPos.x;
matGunRotation._42=vecGunPos.y;
matGunRotation._43=vecGunPos.z;
matGunRotation._44=1.0f;
vecCannonBallDirection.z=Gun->GetLook().z;
vecCannonBallDirection.y=Gun->GetUp().y;
vecCannonBallDirection.x=Gun->GetRight().x;
//Gun world matrix
matWorld=matGunRotation*matGunTrans*matInvView;
Gun->SetWorld(&matWorld);
//Cannonball world matrix
matWorld=matGunRotation*matCannonBallTrans;
...
This code will put the camera at the gun position. The problem is you won't see the gun because you are inside of it. So you need to setup an object view mode in your camera class which will translate the camera away from the object prior to computing the final view matrix. Then once that is done you will see your gun.
This code will compute the end of the gun and set the cannonball's position to that 3D point/vector and will also set the orientation of the cannonball as well as set the direction vector of the cannonball.
Once you have your orientation class set up, you can move the cannonball with this code:
Code:
void CannonBall::Update(float fTimeDelta)
{
m_vecDirection+=vecLook*fSpeed*fTimeDelta;
}
This isn't the fastest code in the world and other may find some 3D math errors here but for the most part it is exactly what I'm doing in my 3D engine to achieve the same effect. I coded this from memory here so it may have some errors.
Also OpenGL uses different 'handedness' matrices so you will have to ask some OpenGL guys here about the order of my matrices. Bob and psychopath can help you more with GL.
I just tried to show the math here. As you can see for 3D you will need a matrix library that does basic matrix functions as well as a Vector3 class that operates on 3D vectors. You will also need a camera class, an object class, an orientation class, and other classes to get the system working.
A 3D engine is a well-oiled machine with many many parts to it.
You will run into gimbal lock with the code you have for your rotations.
Here is a workaround for left handed matrices.
Keep in mind this is for DirectX using the D3DX library so you will have to substitue in your own functions where D3DX functions and D3DX vectors are used. This class works in tandem with object classes so you may find some undefined references but I tried to code it as a standalone object.
COrient3D.h
Code:
#pragma once
#include "d3dx9.h"
//Implements a 3D orientation class for all object
//This class controls all vectors for the object
//It currently uses euler angles
//This class is very similar to a camera class, but it does not
//compute view matrices
enum OBJECT_TYPE
{
OBJECT_AIR,
OBJECT_GND
};
class COrient3D
{
protected:
D3DXVECTOR3 m_vecUp;
D3DXVECTOR3 m_vecRight;
D3DXVECTOR3 m_vecLook;
D3DXVECTOR3 m_vecPos;
OBJECT_TYPE m_iObjType;
float m_fRoll;
float m_fYaw;
float m_fPitch;
float m_fAzimuth;
float m_fElevation;
public:
COrient3D(void);
void GetLook(D3DXVECTOR3 *out_vecLook) {*out_vecLook=m_vecLook;}
void GetRight(D3DXVECTOR3 *out_vecRight) {*out_vecRight=m_vecRight;}
void GetUp(D3DXVECTOR3 *out_vecUp) {*out_vecUp=m_vecUp;}
void GetPosition(D3DXVECTOR3 *out_vecPos) {*out_vecPos=m_vecPos;}
void GetViewMatrix(D3DXMATRIX *outMatrix);
void GetViewMatrixAzEl(D3DXMATRIX *outMatrix);
float GetPitch() {return D3DX_PI-m_fPitch;}
float GetYaw() {return D3DX_PI-m_fYaw;}
float GetRoll() {return D3DX_PI-m_fRoll;}
float GetAzimuth() {return m_fAzimuth;}
float GetElevation() {return m_fElevation;}
D3DXVECTOR3 GetLook() {return m_vecLook;}
D3DXVECTOR3 GetRight() {return m_vecRight;}
D3DXVECTOR3 GetUp() {return m_vecUp;}
D3DXVECTOR3 GetPosition() {return m_vecPos;}
//Movement about the axes given current roll, pitch and yaw
void Fly(float fUnits);
void Strafe(float fUnits);
void Walk(float fUnits);
//Orientation
void Roll(float fAngle);
void Pitch(float fAngle);
void Yaw(float fAngle);
void MakeOrtho(void);
void AdjustRoll(float fAngle)
{
m_fRoll+=fAngle;
//if (m_fRoll>D3DX_PI) m_fRoll-=D3DX_PI;
//if (m_fRoll<=0) m_fRoll+=D3DX_PI;
}
void AdjustPitch(float fAngle)
{
m_fPitch+=fAngle;
//if (m_fPitch>D3DX_PI*2.0f) m_fPitch-=D3DX_PI*2.0f;
//if (m_fPitch<0) m_fPitch+=D3DX_PI*2.0f;
//if (m_fYaw>D3DX_PI) m_fPitch=D3DX_PI-m_fPitch;
}
void AdjustYaw(float fAngle)
{
m_fYaw+=fAngle;
//if (m_fYaw>D3DX_PI*2.0f) m_fYaw-=D3DX_PI*2.0f;
//if (m_fYaw<0) m_fYaw+=D3DX_PI*2.0f;
}
void SetOrientation(float fRoll,float fPitch,float fYaw)
{
AdjustRoll(fRoll);
AdjustPitch(fPitch);
AdjustYaw(fYaw);
}
void Reset(void)
{
m_vecRight=D3DXVECTOR3(1.0f,0.0f,0.0f);
m_vecUp=D3DXVECTOR3(0.0f,1.0f,0.0f);
m_vecLook=D3DXVECTOR3(0.0f,0.0f,1.0f);
}
void SetPosition(D3DXVECTOR3 vecPos) {m_vecPos=vecPos;}
void SetPosition(float x,float y,float z) {m_vecPos=D3DXVECTOR3(x,y,z);}
OBJECT_TYPE GetObjectType() {return m_iObjType;}
void SetObjectType(OBJECT_TYPE iNewType)
{
if (iNewType==OBJECT_AIR || iNewType==OBJECT_GND)
{
m_iObjType=iNewType;
return;
} else m_iObjType=OBJECT_AIR;
return;
}
};
COrient3D.cpp
Code:
COrient3D::COrient3D()
{
m_vecRight=D3DXVECTOR3(1.0f,0.0f,0.0f);
m_vecUp=D3DXVECTOR3(0.0f,1.0f,0.0f);
m_vecLook=D3DXVECTOR3(0.0f,0.0f,1.0f);
m_vecPos=D3DXVECTOR3(0.0f,0.0f,0.0f);
m_iObjType=OBJECT_AIR;
m_fYaw=0.0f;
m_fRoll=0.0f;
m_fPitch=0.0f;
m_fAzimuth=0.0f;
m_fElevation=0.0f;
}
void COrient3D::Fly(float fUnits)
{
if (m_iObjType==OBJECT_AIR)
m_vecPos+=m_vecUp*fUnits;
}
void COrient3D::Strafe(float fUnits)
{
if (m_iObjType==OBJECT_GND)
m_vecPos+=D3DXVECTOR3(m_vecRight.x,0.0f,m_vecRight.z)*fUnits;
if (m_iObjType==OBJECT_AIR)
m_vecPos+=m_vecRight*fUnits;
}
void COrient3D::Walk(float fUnits)
{
if (m_iObjType==OBJECT_GND)
m_vecPos+=D3DXVECTOR3(m_vecLook.x,0.0f,m_vecLook.z)*fUnits;
if (m_iObjType==OBJECT_AIR)
m_vecPos+=m_vecLook*fUnits;
}
void COrient3D::Roll(float fAngle)
{
m_fRoll+=fAngle;
if (m_fRoll>(D3DX_PI*2.0f)) m_fRoll-=(D3DX_PI*2.0f);
if (m_fRoll<0.0f) m_fRoll+=(D3DX_PI*2.0f);
D3DXMATRIX T;
D3DXMatrixRotationAxis(&T,&m_vecLook,fAngle);
D3DXVec3TransformCoord(&m_vecRight,&m_vecRight,&T);
D3DXVec3TransformCoord(&m_vecUp,&m_vecUp,&T);
}
void COrient3D::Pitch(float fAngle)
{
m_fPitch+=fAngle;
if (m_fPitch>(D3DX_PI*2.0f)) m_fPitch-=(D3DX_PI*2.0f);
if (m_fPitch<0.0f) m_fPitch+=(D3DX_PI*2.0f);
D3DXMATRIX T;
D3DXMatrixRotationAxis(&T,&m_vecRight,fAngle);
D3DXVec3TransformCoord(&m_vecUp,&m_vecUp,&T);
D3DXVec3TransformCoord(&m_vecLook,&m_vecLook,&T);
}
void COrient3D::Yaw(float fAngle)
{
m_fYaw+=fAngle;
if (m_fYaw>(D3DX_PI*2.0f)) m_fYaw-=(D3DX_PI*2.0f);
if (m_fYaw<0.0f) m_fYaw+=(D3DX_PI*2.0f);
D3DXMATRIX T;
if (m_iObjType==OBJECT_GND) D3DXMatrixRotationY(&T,fAngle);
if (m_iObjType==OBJECT_AIR) D3DXMatrixRotationAxis(&T,&m_vecUp,fAngle);
D3DXVec3TransformCoord(&m_vecRight,&m_vecRight,&T);
D3DXVec3TransformCoord(&m_vecLook,&m_vecLook,&T);
}
void COrient3D::MakeOrtho(void)
{
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
D3DXVec3Cross(&m_vecUp,&m_vecLook,&m_vecRight);
D3DXVec3Normalize(&m_vecRight,&m_vecRight);
D3DXVec3Cross(&m_vecRight,&m_vecUp,&m_vecLook);
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
}
void COrient3D::GetViewMatrix(D3DXMATRIX *outMatrix)
{
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
D3DXVec3Cross(&m_vecUp,&m_vecLook,&m_vecRight);
D3DXVec3Normalize(&m_vecUp,&m_vecUp);
D3DXVec3Cross(&m_vecRight,&m_vecUp,&m_vecLook);
D3DXVec3Normalize(&m_vecRight,&m_vecRight);
(*outMatrix)(0,0)=m_vecRight.x;
(*outMatrix)(0,1)=m_vecRight.y;
(*outMatrix)(0,2)=m_vecRight.z;
(*outMatrix)(0,3)=0.0f;
(*outMatrix)(1,0)=m_vecUp.x;
(*outMatrix)(1,1)=m_vecUp.y;
(*outMatrix)(1,2)=m_vecUp.z;
(*outMatrix)(1,3)=0.0f;
(*outMatrix)(2,0)=m_vecLook.x;
(*outMatrix)(2,1)=m_vecLook.y;
(*outMatrix)(2,2)=m_vecLook.z;
(*outMatrix)(2,3)=0.0f;
(*outMatrix)(3,0)=0.0f;
(*outMatrix)(3,1)=0.0f;
(*outMatrix)(3,2)=0.0f;
(*outMatrix)(3,3)=1.0f;
}
void COrient3D::GetViewMatrixAzEl(D3DXMATRIX *outMatrix)
{
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
D3DXVec3Cross(&m_vecUp,&m_vecLook,&m_vecRight);
D3DXVec3Normalize(&m_vecRight,&m_vecRight);
D3DXVec3Cross(&m_vecRight,&m_vecUp,&m_vecLook);
D3DXVec3Normalize(&m_vecLook,&m_vecLook);
D3DXVECTOR3 vecPos=m_vecPos;
(*outMatrix)(0,0)=m_vecRight.x;
(*outMatrix)(0,1)=m_vecUp.x;
(*outMatrix)(0,2)=sinf(m_fElevation)*cosf(m_fAzimuth);
(*outMatrix)(0,3)=0.0f;
(*outMatrix)(1,0)=m_vecRight.y;
(*outMatrix)(1,1)=m_vecUp.y;
(*outMatrix)(1,2)=sinf(m_fElevation)*sinf(m_fAzimuth);;
(*outMatrix)(1,3)=0.0f;
(*outMatrix)(2,0)=m_vecRight.z;
(*outMatrix)(2,1)=m_vecUp.z;
(*outMatrix)(2,2)=cosf(m_fElevation);
(*outMatrix)(2,3)=0.0f;
(*outMatrix)(3,0)=vecPos.x;
(*outMatrix)(3,1)=vecPos.y;
(*outMatrix)(3,2)=vecPos.z;
(*outMatrix)(3,3)=1.0f;
}
-
For your trajectory, you could find the height of the point where the cannonball leaves the cannon with some basic trig. Of course, that assumes you know the vertical angle of the cannon.
-
Yeah...or that. I just took the more complicated exact approach.
For 2D trig will do everything you need. For 3D you will need much more.
-
its 3d, thanks for all the help, thats a huge post bubba, I got alot to read I guess. Thanks for putting in the time.