Move objects to specified points in a scene?
I have been trying to throw together a chess game using a 3dsmax model. At this point, I have been able to import the model, highlight the selected game piece I am interested in moving, and choose a square I want to move to. Here is a screenshot of the current state:
http://img26.imageshack.us/img26/9555/chessk.png
The black circle represents where I clicked, and you can see where the pawn went. I haven't done specific calculations on where it should go. Whenever I click on the board with a selected piece, it always moves in the same direction. It's because just threw in this dummy code to start off:
if ( isObjectSelected && isSquareSelected && moveObject )
{
glPushMatrix();
glTranslatef(0.2f, 0.0f, 0.0f); //PLACEHOLDER-DUMMY CODE
}
glDrawElements( GL_TRIANGLES, pMaterial->triangleCount * 3, GL_UNS开发者_如何学JAVAIGNED_INT, model.getIndexBuffer() + pMaterial->startIndex );
if ( isObjectSelected && isSquareSelected )
glPopMatrix();
What I was considering doing was after the model was done loading, is to somehow check which square on the board a game piece occupies. Then, when a piece is selected and a "move to" square is selected, find the x,y,z glTranslate3f to move to that center square.
Is this the best way? It seems as the game progresses, I will need to store the glTranslate of each piece individually. And when a piece goes from it's 2nd to 3rd spot, I should calculate the glTranslate from the original starting point to the 3rd spot, right?
But how would you figure out whether or not a game piece occupies a square, and how would you figure out glTranslate3f(X, Y, Z) between two squares? Here is an example of a square from my .OBJ file
#
# object Square58
#
v -37.1874 18.6313 80.7864
v -67.0955 18.6313 91.4436
v -56.4384 18.6313 121.3513
v -26.5306 18.6313 110.6938
# 4 vertices
vn 0.0000 1.0000 -0.0000
# 1 vertex normals
vt 0.0000 0.0000 0.0000
# 1 texture coords
I am assuming I would need to find the center of each square and say once the app knows this piece is in square1, and you clicked on sqaure4, calculate the translate & go. I am just not sure how to calculate the center of each square, and figure out what the translate coords should be from square1-->square4.
OR how I would determine which pieces occupies which square from the beginning. I can hard code this in during load, but it would help me more in understanding if there was a sound way to accomplish this.
Each square & game piece is a struct GroupObject
like:
//A chess piece or square
struct GroupObject
{
std::vector<Material *> materials;
std::string objectName;
std::string groupName;
int index;
std::vector<Vector3 *> vertices;
Vector3 center;
};
And Vector3 looks like:
#ifndef VECTOR3_H
#define VECTOR3_H
#include <math.h>
class Vector3
{
public:
Vector3(float X = 0.0f, float Y = 0.0f, float Z = 0.0f)
{
x = X;
y = Y;
z = Z;
}
Vector3 operator+=(const Vector3 &vec)
{
return (*this = (*this + vec) );
}
Vector3 operator+(const Vector3 &vec)
{
return Vector3(vec.x + x, vec.y + y, vec.z + z);
}
Vector3 operator-=(const Vector3 &vec)
{
return (*this = (*this - vec) );
}
Vector3 operator-(const Vector3 &vec)
{
return Vector3(x - vec.x, y - vec.y, z - vec.z);
}
Vector3 operator*=(float num)
{
return (*this = (*this * num) );
}
Vector3 operator*(float num)
{
return Vector3(x * num, y * num, z * num);
}
Vector3 operator/=(float num)
{
return (*this = (*this / num) );
}
Vector3 operator/(float num)
{
return Vector3(x / num, y / num, z / num);
}
Vector3 operator-(void)
{
//invert direction of vector
return Vector3(-x, -y, -z);
}
float Dot(Vector3 &vec)
{
return (x * vec.x + y * vec.y + z * vec.z);
}
Vector3 operator*(const Vector3 &vec)
{
//cross product
return Vector3( y * vec.z - z * vec.y,
z * vec.x - x * vec.z,
x * vec.y - y * vec.x );
}
float Length(void)
{
//length of vector
return sqrt( x * x + y * y + z * z);
}
Vector3 Normalize(void)
{
float length = Length();
x /= length;
y /= length;
z /= length;
return *this;
}
float Distance(Vector3 &vec)
{
//find distance between two separate vectors
float disX = vec.x - x;
float disY = vec.y - y;
float disZ = vec.z - z;
return sqrt(disX * disX + disY * disY + disZ * disZ);
}
bool operator==(Vector3 &vec)
{
return (vec.x == x && vec.y == y && vec.z == z);
}
bool operator!=(Vector3 &vec)
{
return !(vec == *this);
}
public: float x, y, z; };
#endif
I was going to use this to store the center of each square like:
Vector3 square->center = X, Y, Z
Hopefully this would help it determining where to move, and if something occupies that space, but figured I should get some help since I haven't done this before. I am also not sure how I should calculate it, or still completely clear on how to figure out whether a square has a game piece that occupies it at the beginning, or it's empty.
Any and all help is welcome. Thank you.
UPDATE
Right now I had a buddy look in 3ds max and on a square object properties it said dimensions were x: 40.565 y: 40.565
Then I picked two squares, one in front of the other. I calculated the center of each by added all the vertices together and divided by the sum of the vertices. I got this:
#square 1
x: 111.12125
y: 18.631268
z: 78.286982
#square 2
x: 82.276817
y: 17.615297
z: 88.545845
But from my original example, the only way I could get even close to moving to the right spot was moving glTranslatef(0.2f, 0.0f, 0.0f);
The difference between the two centers listed above is much larger. I am doing something incorrect, but not seeing it.
[a-bit-offtopic] When i was coding my univercity project, i used to draw my 'world' (which has something similar with check-desk: it is endless and have no colour distincts) using simple math formulas for determining each line cross points. When i got those points, i was able to simply determine which particular square cursor is pointing. To be honest, i used simple mathematics to determine those centers in the last ('production') version.
Here and there are my old screens.
So, what's the trouble? When you're doing glPushMatrix()
, your matrix resets to its defaults - the position becomes (0, 0, 0) and rotations are reset. If you wanna put your object in the point of intersect {line, plane}, where the line is the ray from camera origin through cursor position (recall camera theory in OpenGL: actually, screen is the plane in front of camera 'position' point) and the plane is something in front of that ray. Note: if you'll not define the plane - you'll be not able to determine intersection point.
Now, when you'll got intersection point, just do glTranslatef(<intersection_point>)
and then draw your pawn or whatever.
If you are interested in pure code on how to determine intersection point - just notify me in comments.
Hope this will help.
UPD: here's the intersection point code i've mentioned before. It uses sf::Vector3f
structure/class - it is taken from SFML (i'm using it for all my GL projects to handle input events and forget 'bout window creation). You can define it as a simple structure with 3 floats. Function arguments are the mouse cursor' coordinates. Calling this would provide you with intersection point coordinates.
sf::Vector3f ScreenToSpace(int x, int y)
{
GLint viewport[4];
GLdouble modelview[16];
GLdouble projection[16];
GLfloat winX, winY, winZ;
GLdouble posX, posY, posZ;
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
winX = (float) x;
winY = (float) viewport[3] - (float) y;
glReadPixels(x, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);
gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
return sf::Vector3f((float) posX, (float) posY, (float) posZ);
}
Here's the example on how you should use this (as far as i've understood your problem):
sf::Vector3f v = ScreenToSpace(App.GetInput().GetMouseX(), App.GetInput().GetMouseY()); // get global coordinates
v = SpaceToDeskCorrection(v.x, v.y, v.z); // align v to the check-desk cell center
glPushMatrix(); // reset matrix state (incl. position and rotation) and save previous one
glTranslatef(v.x, v.y, v.z); // set matrix position to the intersection point
DrawPawn(); // well, you'll understand this line, right? =)
glPopMatrix();
I have recently done a checkers game myself, 2D but the same principles apply. First of all I would suggest you keep an array with board squares, which as you defined in your struct has a centre var.
To know where each piece is, you could for instance add a variable which is a pointer to a given square, or simply a representation like 'E4' or 'A8' (square code). Having this, you would automatically have the x,y coordinates of where the piece is, and once detecting which square you want to move it to, you just substitute the pointer to the new piece and get its centre information, which is where you want to translate the piece to. This also has the added benefit that it makes it easier for you to check later when a piece takes over another one from the adversary, or simply if it can move to a certain square (go through all the pieces, if any of them is laying on the square you want to go to, don't allow the move).
To find out the centre of any square, assuming you don't know it when you create the board (don't you ?), and do an average over all the constituting vertices x and y coordinates (if the board is laying on the xy plane). For instance, Square58 centre = (v1(x)+v2(x)+v3(x)+v4(x) ; v1(y)+v2(y)+v3(y)+v4(y)).
I hope that was clear enough, if not just let me know what you didn't get and I'll try to explain.
EDIT: Sorry, I wrote something wrong. In the Square58 centre.... line, you divide the final sum by 4 (to get the average).. ie:
Square58 centre = ((v1(x)+v2(x)+v3(x)+v4(x))/4 ; (v1(y)+v2(y)+v3(y)+v4(y))/4).
精彩评论