PDA

View Full Version : Best way to move objects around?



hallik
01-22-2011, 08:56 PM
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_UNSIGNED_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.

All help is welcome. Thank you.

dehebo
01-23-2011, 01:51 AM
from reading your post it sounds like you have your game logic imbedded with the 'physical' objects.

imo if you have not done so already I would completely decouple logic from rendering.
I would have a data structure to represent your board, a 2D array is the first choice that may come to mind but not the only one for certain. This data structure could just store a flag to represent what is in it, or if needed some struct to hold more info.

for rendering, at the most basic level, you would pass through the data structure to find which tiles have a piece on them, which would correspond to a position in world space to draw the appropriate model.

the math is pretty basic stuff if you think about it logically. if you are having trouble visualising it then have your model in simple rounded units, i.e. each tile is 2 units wide.
each tile in your data structure could store the corresponding world space so it is available to look up. when clicking on the board can either pick by tile/poly which looks up an index in data structure, or transform to model space and then work out which tile the position clicked is in.

with regards to finding what piece is within each tile (or if empty) can do basic look up in data structure. could get messy for chess.
this decision for me would be based on if this was to be a human vs human game or if it needed to incorporate AI (which is a beast of a job in chess).

anyway outside of basic look ups I would research bit-boards to start off with. and if having AI it can be advantageous to pad your data structure to represent offboard pieces, so to prevent an AI trying to move a piece off the board, but this depends on what type of structure is chosen.

most chess programs for AI use more than one representation of the board state to help with logic, AI etc.

dehebo
01-23-2011, 01:59 AM
also, I know you are just hard coding numbers in your translates to test, but now would be the time to move away from this and switch to a more extensible method, i.e. using vectors. this will also simplify working out translates.

you need to decide what a move and a capture is, how you record these. basic really. a path of tile IDs and a capture routine if occupied on final ID. or something similar.

hallik
01-23-2011, 09:26 AM
Thanks for your response. I haven't put in any game logic at all. I am in the process of setting up a class(es) that will handle it all that will be executed right before the draw, but need to determine this stuff first. It will also be human vs. human, so no AI needed. I am more trying to mess with openGL and get it working properly that worried about a fully functional chess game.

I am trying to store all the information in a vector. I have this vector class



#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 &amp;vec)
{
return (*this = (*this + vec) );
}

Vector3 operator+(const Vector3 &amp;vec)
{
return Vector3(vec.x + x, vec.y + y, vec.z + z);
}

Vector3 operator-=(const Vector3 &amp;vec)
{
return (*this = (*this - vec) );
}

Vector3 operator-(const Vector3 &amp;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 &amp;vec)
{
return (x * vec.x + y * vec.y + z * vec.z);
}

Vector3 operator*(const Vector3 &amp;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 &amp;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 &amp;vec)
{
return (vec.x == x &amp;&amp; vec.y == y &amp;&amp; vec.z == z);
}

bool operator!=(Vector3 &amp;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 = <SOME 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. You say store it's world space so it's available for lookup, but how do I figure out it's world space? Are you referring to the vertices of a square? I can easily lookup all the vertices that make the square, but not sure the best way to see if something occupies the same space.

dehebo
01-23-2011, 01:47 PM
ok, simple example. I will treat X & Y as length/width of board, Z as depth.

You have a model for the board.
Lets say if you look from above, white start is bottom, black at top.
In your 3D software (DCC) like maya/max you position the board model so that the bottom left-hand corner of its bottom left-hand square(white) is at 0,0,0.
Any depth to the board is negative. So the base of pieces sitting on board will be at 0.

This is the Model Space of your board model. And since with chess the board is the world where the game is played you could keep it simple and let this also represent your World Space, i.e. 0,0,0 in Model is 0,0,0 in World - though this is not necessary but may help you to visualise the layout.

This same square is also going to be our first square in our data structure. For simplicity sake I will use an 8x8 2D array. So this square is [0][0].

Lets say each square is 2 units in length & width.

So the centre of our origin square at [0][0] is 1,1,0. Therefore the square to its immediate right is 3,1,0.
The top-left square(black) centre is 1,15,0.

So to translate a Rook from white bottom-left to black top-left it is (1,15,0) - (1,1,0) = (0,14,0).

With such a simple setup you would would not even need to store centres since its easy to calculate from the position in the array.

When you ask "how to I decide how to determine if a tile has an occupying piece at the start" I am unsure of the problem.

You load your board model, and one model for each piece type.
So board, rook, knight, bishop, king, queen, pawn.
7 Models total, since you can tint the pieces black/white in pixel shader.

So on Init for your data-structure, 2D array in this example, you could have two methods; a Default boardInit and a Load boardInit.

Default places a piece in the relevant starting positions for chess into the array, e.g. White & Rook at [0][0], Black & Rook at [7][7] etc
Load does the same for the a saved board state from txt file or stream.

The remaining tiles are flagged as Empty.

Then for the very first frame to be rendered as with any other frame thereafter you traverse the data-structure to determine what models need to be rendered at what positions.
This would need to be changed/extended if you want to be able to click on pieces and not just tiles.


I want to point out this is a very basic example that I have given little to no thought to.
There are many ways to do this, and you need to decide how you want to handle certain events, like picking pieces/tiles, because things like these will shape the design & implementation of how the DCC assets and game logic is to be handled.
As an example you could procedurally generate all board tiles and just model pieces and maybe a fancy board-border. Just an example to say there are many paths to the same goal.

You would need to decide what a tile represents e.g.
enum Color { black, white }, enum Piece { pawn, rook, ... }, Struct Tile { Color, Piece }.

Imo get pen, paper and draw basic diagrams etc.

hallik
01-23-2011, 03:44 PM
Thank you for detailing some stuff out. It's definitely going to help in deciding how to do this.



In your 3D software (DCC) like maya/max you position the board model so that the bottom left-hand corner of its bottom left-hand square(white) is at 0,0,0.


I have never used 3dsMax. I got this chess set from turbosquid.com, and had someone convert it into an OBJ file for me. Not sure if this is how it was done in that app. When I said I wasn't sure which game piece was occupying which square on load, I meant that everything is initially drawn how it is imported. There is nothing in the OBJ file that indicates that "white pawn 1 is sitting on square A3" or anything like that, except maybe the vertices, and I wasn't sure how to identify the starting point from each piece by comparing vertices.

With that said, I will take a step back draw out a few squares, looking at their vertices values and see what I come up with. It sounds like I am just thinking incorrectly about my problem, and it's simpler than I am making it. Again, that you for your response.

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.

hallik
01-24-2011, 08:31 AM
Still very confused. Your simple example makes complete sense, but the numbers I am getting back are much larger than the smaller float values that make sense in glTranslatef. I am getting the absolute world coords(it appears) from starting & ending position of the square->center. But the difference between the two is much much greater than the small numbers glTranslatef is expecting.


After looking at the dimensions in 3ds max and calculating the center of squares, it seems they need to be scaled down, but not sure if that's true, or how to, etc.

If anyone is willing to take a look at my learning project:
https://github.com/nbyloff/KinectChess

Line 107-109 in main.cpp & line 518-526 in GLEngine.cpp is where I am playing around with translating objects. Starting at line 1010 in ModelOBJ.cpp, that's where I calculate the square->center.

It's a Visual Studio 2010 project, but should compile without any further configuration.

Any insight into the discrepancy between the square center's calculated above and/or the reason why glTranslatef needs such small values to stay within the board is extremely appreciated.

dehebo
01-25-2011, 08:12 AM
ok. I had a quick look.
A couple of things:

#1.
The reason why translates of the size of about 0.2 work as opposed to say 35-40 is the scale of your model within World Space has been decreased.

If I comment out your call to Scale in ModelOBJ.cpp Line 279, then update the hardcoded glTranslatef you use in glEngine to distances of about 35,0,-10 then a red pawn will move one square forward.

edit: n.b. need to update your camera distance on init or zoom out abit to see board, as stock scale of model is far bigger than your initial view space.

If you run debug on your scale method then you will see your scaling factors are tiny.

#2.
The model is poor. I Looked at it in Max and it has overlapping tiles and its orientation is all skewed. I.e. it is not positioned orthogonally, so when it exports this is recorded to you OBJ file, hence why in your OGL it loaded in at an angle and when you translate you need to do it using 2 components for horiz movement(x & z, not x or z).
I know you were maybe thinking you can compensate for this by fetching the centre of the Tiles to calc a direction, and you could; but imo this is messy and confusing - the model needs to be aligned properly prior to export.

hallik
01-25-2011, 08:36 PM
I can't thank you enough for looking at the import and pointing out that flaw. It makes complete sense, but I kept overlooking at it playing with this so much. Thank you!

As far as the model, I got it from turbosquid.com. One of their free models. It was also one of the few that had a complete set already in their correct positions. As I progress more, I will probably pick a different model, and try duplicating & placing the pieces on the board where they should be.

Thanks again!