Game Design Questions (low level-ish)

Started by
18 comments, last by Jossos 11 years ago

You need to unproject your mouse position. I can't tell you how it exactly works with OpenGL, but I can give you some DirectX-code with a little explanation, you should be able to figure out the rest yourself:


	//todo: access camera differently
	const Camera* pCamera = m_pGfx3D->GetCamera();

	//todo: access cursor differently
	Vector2 mousePos = Input::GetMousePos();
        //translate mouse coordinates to scene area
	mousePos.x -= m_pArea->GetX();
	mousePos.y -= m_pArea->GetY();
	D3DXVECTOR3 vMouse((float)mousePos.x, (float)mousePos.y, 0.0f);
	D3DXVECTOR3 vMouse2((float)mousePos.x, (float)mousePos.y, 1.0f);
	const D3DVIEWPORT9& ViewPort(m_pGfx3D->GetViewport());

	D3DXMATRIX mWorld;
	D3DXMatrixIdentity(&mWorld);

	D3DXVECTOR3 vP1, vP2;
	D3DXVec3Unproject(&vP1, &vMouse, &ViewPort, &pCamera->GetProjectionMatrix(), &pCamera->GetViewMatrix(), &mWorld); 

	D3DXVec3Unproject(&vP2, &vMouse2, &ViewPort, &pCamera->GetProjectionMatrix(), &pCamera->GetViewMatrix(), &mWorld); 

	D3DXVECTOR3 vDist = vP2;
	vDist -= vP1;
	D3DXVec3Normalize(&vDist, &vDist);

	const Ray mouseRay(vP1, vDist);

You basically create two points from the mouse, one on the near and one on the far clip plane. Now given the view matrix, projection matrix, viewport and (most likely identity) world matrix you can unproject these two points to their location in the world. You then construct your ray from these two points an voîla, you're done.

I used some of what you said, did a heap of research... and Now it works ^^ - thanks - except the mouse seems to be like 8 pixels off... idk. It works for the most part, so I will probably leave it for now, and start building this program up with other features.

Just as a small observation, what you're calling "logic.cpp" is in fact the input portion of your program. This would run in the input function of your game loop, while logic is a separate function of the game loop that would run after the input.

Alright, So I'll just make a "handle_input" function in my main file then. I'm just worried that it's gonna be huge.

Also to the Animation stuff - seems like bones are the way to go, which means I'll just use static models to start off with lol.

I'm sure I'm way outta my league here - but how feasible is it to make your own modelling program? I mean, I already got the camera and mouse stuff sorted. Just need modelling tools... Animation tools... bone tools, ik tools, texturing tools. Not sure how big of a thing this would be. I'm not talking 3ds or blender, just something for models, and a bit of animation.

Advertisement

I used some of what you said, did a heap of research... and Now it works ^^ - thanks - except the mouse seems to be like 8 pixels off... idk. It works for the most part, so I will probably leave it for now, and start building this program up with other features.

Did you account for the window borders? Thats why I sub'd the m_pArea-coordinates, this is my gui element containing the scene view. Don't know if SDL converts the mouse position correctly, you might want to output the coordinates and make a screenshot to see if they are off, or if the problem is with the unprojecting.

Did you account for the window borders? Thats why I sub'd the m_pArea-coordinates, this is my gui element containing the scene view. Don't know if SDL converts the mouse position correctly, you might want to output the coordinates and make a screenshot to see if they are off, or if the problem is with the unprojecting.

No, the coordinates are exactly in the window. I can get to 0,0, and 799, 449 (window is 800 x 450). Very strange - Actually, it seems to be a problem in the actual 3D world. If i Rotate the camera, the offset might be to the left, but If i rotate it all the way around, it's to the right

No, the coordinates are exactly in the window. I can get to 0,0, and 799, 449 (window is 800 x 450). Very strange - Actually, it seems to be a problem in the actual 3D world. If i Rotate the camera, the offset might be to the left, but If i rotate it all the way around, it's to the right

Can you post the code responsible for unprojecting so I might take a look at that first?

Alright, So I'll just make a "handle_input" function in my main file then. I'm just worried that it's gonna be huge.

It's possible to spread the function definitions of a single class over multiple source files. I recommend having a separate source file that contains only the definition of the "handle_input" function.

It's possible to spread the function definitions of a single class over multiple source files. I recommend having a separate source file that contains only the definition of the "handle_input" function.

How did I not know this? lol thanks a lot!

Can you post the code responsible for unprojecting so I might take a look at that first?

sure can:

vector3d GetOGLPos(int x, int y, float z)
{
GLint viewport[4]; // contains x, y, width and height
GLdouble modelview[16]; // modelview matrix information
GLdouble projection[16]; // projection matrix information


glGetIntegerv(GL_VIEWPORT, viewport);
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);


GLfloat winX, winY, winZ;
    GLdouble posX, posY, posZ;


winX = (GLdouble)x;
winY = (GLdouble)viewport[3] - (GLdouble)y;
winZ = (GLdouble)z;


    gluUnProject( winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);


    return vector3d(posX, posY, posZ);
}
 

And I use this like so:


// mousePosNear and mousePosFar are of type "vector3d"

mousePosNear = GetOGLPos(m_mouseX, m_mouseY, 0.0);
mousePosFar = GetOGLPos(m_mouseX, m_mouseY, 1.0);

And these are used in the rayplane function. Want to see that too?

Question 4: Input to Logic
I'd like to have all of my logic and graphics seperate from Input. How should I do this?


Another solution could be to have entities or components register for certain key presses with the Input System. In this manner, only the parts of the game that need to know about some key preses gets notified.

For instance, your player would need to know all movement key presses, but your weapon class may be interested in the weapon keys (fire, and alt fire for instance), while your Menu system wants Esc, and when the Menu is activated, it would then maybe tell the Input system to not send any keys to the other systems (since your "fire" key may not be the "select" key in menu mode), and register for other keys it needs (and the opposite when leaving menu).

Maybe something like this:

// Interface to be called for registered key presses
class IKeyPressCallback
{
  virtual ~IKeyPressCallback() {}
  virtual void OnKeyPress(TGameKey keyPressed, bool isDown) = 0;
}
 
class TWeapon : public IKeyPressCallback
{
private:
  // stuff ...
  TInputSystem& InputSystem;
public:
  TWeapon(TInputSystem& inputSystem);
 
  void OnKeyPress(TGameKey keyPressed, bool isDown);
}
 
// In TWeapons.cpp
 
TWeapon::TWeapon(TInputSystem& inputSystem) :
  InputSystem(inputSystem)
{
  InputSystem.RegisterKey(FIRE_KEY, this);
  InputSystem.RegisterKey(ALT_FIRE_KEY, this);
}
 
void TWeapon::OnKeyPressed(TGameKey keyPressed, bool isDown)
{
  if (keyPressed == FIRE_KEY) {
    // Do firing stuff
  }
}

// in TInputSystem.h
class TInputSystem
{
private:
  struct TKeyPressData
  {
    IKeyPressCallback* KeyPressCallback;
    TGameKey GameKey;
  }
  std::vector<TKeyPressData> KeyPressCallbacks;

public:
  void RegisterKey(TGameKey gameKey, IKeyPressCallback* keyPressCallback);

My Gamedev Journal: 2D Game Making, the Easy Way

---(Old Blog, still has good info): 2dGameMaking
-----
"No one ever posts on that message board; it's too crowded." - Yoga Berra (sorta)

question 5: pick test

here's the ray-plane pick test i cobbled together for a real time wargame i'm working on.

directx, but i think you'll be able to follow it.....

D3DXVECTOR3 intersect_point;
void calc_intersection(int x,int y)
{
char s[100];
D3DXVECTOR3 v,dir,origin,
p1,p2, // line
p3,p4,p5; // plane
D3DXMATRIX m;
D3DXPLANE p;
v.x = ( ( ( 2.0f * x ) / screen_width ) - 1 ) / Zprojection_matrix._11;
v.y = - ( ( ( 2.0f * y ) / screen_height ) - 1 ) / Zprojection_matrix._22;
v.z = 1.0f;
// MICROSOFT COMMENTS:
// Get the inverse view matrix
//const D3DXMATRIX matView = *g_Camera.GetViewMatrix(); // view matrix (camera orientation & location)
//const D3DXMATRIX matWorld = *g_Camera.GetWorldMatrix(); // world matrix (orientation & location of the mesh - not used?)
//D3DXMATRIX mWorldView = matWorld * ZmView;
//D3DXMatrixInverse( &m, NULL, &mWorldView );
D3DXMatrixInverse(&m,NULL,&ZmView);
// MICROSOFT COMMENTS:
// Transform the screen space pick ray into 3D space
// ROCKLAND COMMENTS:
// actually - object space of the mesh, not world space. the view matrix alone gets you to world space.
// adding the world matrix gets you object space.
// object space -> (world mat) -> world space -> (view mat) -> camera space -> (proj mat) -> screen space.
// MS uses the world mat because they're picking tri's off a single mesh
dir.x = v.x * m._11 + v.y * m._21 + v.z * m._31;
dir.y = v.x * m._12 + v.y * m._22 + v.z * m._32;
dir.z = v.x * m._13 + v.y * m._23 + v.z * m._33;
origin.x = m._41;
origin.y = m._42;
origin.z = m._43;
Znewmenu("Pick ray results:");
f2s(origin.x,s);
Zaddmenu(s);
f2s(origin.y,s);
Zaddmenu(s);
f2s(origin.z,s);
Zaddmenu(s);
f2s(dir.x,s);
Zaddmenu(s);
f2s(dir.y,s);
Zaddmenu(s);
f2s(dir.z,s);
Zaddmenu(s);
//menu();
// need intersect of line and plane
// need to convert ray to line
p1.x=origin.x;
p1.y=origin.y;
p1.z=origin.z;
p2.x=dir.x*1000.0f+origin.x;
p2.y=dir.y*1000.0f+origin.y;
p2.z=dir.z*1000.0f+origin.z;
// now we have a nice long line from p1 (origin) to p2 (dir)
// now we need a plane...
// calc 3 points on the plane, or a point and a normal.
// use them to create a plane data structure.
p3.x=0.0f;
p3.y=0.0f;
p3.z=0.0f;
p4.x=0.0f;
p4.y=0.0f;
p4.z=1.0f;
p5.x=1.0f;
p5.y=0.0f;
p5.z=0.0f;
D3DXPlaneFromPoints(&p,&p3,&p4,&p5);
// then test ray vs plane intersection.
D3DXPlaneIntersectLine( &intersect_point, &p, &p1, &p2);
Znewmenu("plane line intersect:");
if (intersect_point == NULL)
{
Zaddmenu("intersect_point = NULL");
}
else
{
f2s(intersect_point.x,s);
Zaddmenu(s);
f2s(intersect_point.y,s);
Zaddmenu(s);
f2s(intersect_point.z,s);
Zaddmenu(s);
}
//menu();
}
void draw_ground()
{
int x,z;
Zdrawinfo a;
ZeroMemory(&a,sizeof(Zdrawinfo));
a.sx=10.0f;
a.sy=10.0f;
a.sz=10.0f;
for (x=0; x<200; x+=10)
for (z=0; z<200; z+=10)
{
a.x=(float)x;
a.z=(float)z;
Zdraw(&a);
}
}
void picktest()
{
/*
while ! quit
clearscreen
drawmouse
if leftclick
calc ray - plane intersection
show results
else if esc - quit
*/
int quit,x,y,b;
Zdrawinfo a;
Zsetcam(10.0f,50.0f,-10.0f,1.0f,0.0f,0.0f);
Zsetlite(0,1.0f,-1.0f,1.0f,1.0f);
Zlite(0,1);
quit=0;
ZeroMemory(&a,sizeof(Zdrawinfo));
a.sx=1.0f;
a.sy=1.0f;
a.sz=1.0f;
a.texID=2;
a.y=0.1f;
intersect_point.x=0.0f;
intersect_point.y=0.0f;
intersect_point.z=0.0f;
while (! quit)
{
Zclearscreen(0,0,0);
Zclearzbuf();
Zbeginscene();
Zcleardrawlist();
draw_ground();
a.x=intersect_point.x;
a.z=intersect_point.z;
Zdraw(&a);
Ztext3d(0,0,"Press ESC to quit");
Zdrawlist();
Zbeginsprite();
drawmouse();
Zendsprite();
Zshowscene();
Zdomessages();
Zgetmouse(&x,&y,&b);
if (b==1)
{
calc_intersection(x,y);
}
else if (Zkeypressed(VK_ESCAPE))
{
quit=1;
}
}
}

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php

I would skip the whole "design units" part and focus on gameplay. Instead of sofisticated tanks and units I would use pyramids and squares and color these in nice cool ways. This way you can pump out hundreds of randomized custom units quickly. Think minecraft but RTS ;)

I would skip the whole "design units" part and focus on gameplay. Instead of sofisticated tanks and units I would use pyramids and squares and color these in nice cool ways. This way you can pump out hundreds of randomized custom units quickly. Think minecraft but RTS ;)

I like that idea. Cubes and pyramids it is!

And also, the mouse offset is actually really annoying. I posted my code above if anyone could please help.

I'll add this problem to the first post:

This topic is closed to new replies.

Advertisement