Hi guys, I'm currently attempting to create a game similar to that of a Rubik's Cube but I've come to a standstill.

I have a Cube made up of 8 smaller cubes, so its 2x2x2. Problem is, I have no idea how to go about rotating each of these cubes. I want it so when the user uses the left or right arrow, the cubes on that side of the big Cube would rotate clockwise/anti-clockwise by 90 degrees. I was reading that Quartenions would be good to use, as I already have the positions of the smaller cubes, and all I'd have to do is rotate it around the last position of that specific cube.

Problem is, I have no idea how to implement this! Most of the articles/tutorials I have read only deal with Quarternion Cameras, and not the rotation of an object around an axis.

Any help/advice/pointers would be greatly appreciated.

DaveT

Recommended Answers

All 17 Replies

Use the same principle. You're simply rotating a bunch of objects rather than a single one.

Thanks for the reply - it's just all a bit confusing as I've never used Quaternions before so I think I am over complicating things.

So what I understand in psuedo-code is:

cubePosition = new Vector3 (0,0,1);
cubeRotation = Quaternion.Identity;

then

float rightleftrot = 0.0f;

keyboardState keys = Keyboard.getState();
if(key.down(left))
rightleftrot = -0.1f;
if(key.down(right))
rightleftrot = 0.1f;


Quaternion addRot = Quaternion.CreateFromAxisAngle(Vector3(centre point of the four smaller cubes), rightleftrot));
cubeRotation = cubeRotation * addRot;

Would I need to add something else here so to calculate the new position? Something like: cubeNewPos = Vector3.Transform(cubePosition, cubeRotation)

Then using the new cube position I would do:

Vector3 cubeFinalPosition = cubePosition + cubeNewPos;


Then in the draw world where I have:

Matrix.CreateTranslation
Matrix.CreateScale etc

I would include:

Matrix.CreateFromQuaternion(cubeRotation);


Does that look like I am on the right path?


Any help/advice would be greatly appreciated.

DaveT

Unless you have "attached" your smaller cubes to something logically in code, I would rotate each cube individually. I'm sure there's a better way but I can't think clearly as my office is currently at 39C and everyone including myself is starting to fall asleep. >.<

I'll take another look when I get home.

Thanks for the reply.

I'm a bit confused though, when you say rotating each cube individually - I think that's what I am doing. In the game, the left or right arrow will rotate the left or right face of the cube by 90 degrees clockwise/anti-clockwise, which would be half of the cubes. So I would be rotating four cubes around the center of those four cubes 90 degrees.

I probably wasn't clear with my declarations above in the psuedo-code, I wrote that to see if I was on the right path of what I needed to do.

Any help/advice would be greatly appreciated.

DaveT

I would move the camera around when you press the arrow keys and rotate the objects around for when they get turned.

I was making a rubik's cube and came across the same problems because if you turn the cube 90 deg on the y axis then when you rotate it on the x axis it looks like the z axis moves because of where you are viewing from.

So what I would do is move the camera around the cube using x rotation and y rotations on its axis and instead of using rotate to move it use glTranslate based on the angles x and y are at.

Thanks for the reply.

I don't quite understand you however: so the arrow keys would move the camera and rotate the object (cubes?)? The left and right arrows are used to select the face to rotate, and by pressing the left or right arrow again - that face will be rotated 90 degrees. I already have a camera working by using the Z, X and Y keys on the keyboard. They orbit around the cube.

Is the glTranslate for the rotation of the cubes or the camera? Would you mind posting some psuedo-code or describing how you overcame the problem a bit more, so I can understand where you're coming from.

Any help/advice would be greatly appreciated.

DaveT

For the camera I would move the camera to the right x y z position and then rotate it to look at the rubik's cube.

The way I calculated that is

GLfloat _r = 10; //the radius (distance) from the centre of the cube
GLfloat _d; //used to calculate the x and z offset from the centre of the cube

GLfloat _xrot, _yrot; //x and y rotation of the camera
GLfloat _xpos, _ypos, _zpos; //x y and z position of the camera

GLfloat sine[360], cosine[360]; //sine and cosine take lots of processing power to calculate so just store them
for(int i = 0; i < 360; i++ )
{
	sine[i] = sin(i*PI/180);
	cosine[i] = cos(i*PI/180);
}
//calculates the position of the camera based on xrot and yrot
_d = _r*cosine[(int)_xrot]; //gets the adjacent side of the _xrot triangle 
_xpos = (_d*sine[(int)_yrot]) + cubeXPos; //cubeXPos is where you have the cube
_ypos = (_r*sine[(int)_xrot]) + cubeYPos;
_zpos = (_d*cosine[(int)_yrot]) +cubeZPos;

//in your drawing code (glMatrixMode(GL_PROJECTION))
//rotate first then translate otherwise you will get a different result
glRotatef(_xrot, 1.0, 0.0, 0.0);
glRotatef(-_yrot, 0.0, 1.0, 0.0);
glTranslatef(-_xpos, -_ypos, -_zpos);

Now for the "units" in the rubik's cube I would make some form of array to keep track of the position of each cube so you can swap them when doing your row/col rotations because if you spin a row then spin the column it will mess up the cube and will not give you the result you want.

So swap the cubes then rotate them so they face the right direction.

If you have any questions just ask.

Just noticed that you aren't using OpenGL sorry, I had no idea what XNA was until I looked it up just now.

Thanks for the reply anyway! Storing all the cube positions in an array is probably the best way to go about moving the cubes, so that is something I will look into.

DaveT

Right, so far I have managed to create a Quaternion for rotation. Only problem is now, how do I apply it to only certain cubes? As when I press the right key on the keyboard at the moment, every cube is being rotated continiously.

In my update method:

// declare rotation floats   
            float updownRotation = 0.0f;   
            float leftrightRot = 0.0f;   
  
            // get state of keyboard   
            KeyboardState keys = Keyboard.GetState();   
  
            // if key is pressed, change value of rotation   
            if (keys.IsKeyDown(Keys.Right))   
            {   
                leftrightRot = -0.10f;   
            }   
  
            // if key is pressed, change value of rotation   
            if (keys.IsKeyDown(Keys.Left))   
            {   
                leftrightRot = 0.1f;   
            }   
  
            // if key is pressed, change value of rotation   
            if (keys.IsKeyDown(Keys.Up))   
            {   
                updownRotation = 0.1f;   
            }   
  
  
  
            // rotation around axis   
            Quaternion addRot = Quaternion.CreateFromAxisAngle(new Vector3(1.0f, 0.0f, 0.0f), leftrightRot);   
  
            //rotation of cubes   
            cubeRotation = cubeRotation * addRot;

My draw function:

void DrawGameObject(GameObject gameobject)   
        {   
            //graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;   
            foreach (ModelMesh mesh in gameobject.model.Meshes)   
            {   
                foreach (BasicEffect effect in mesh.Effects)   
                {   
                    effect.EnableDefaultLighting();   
                    effect.PreferPerPixelLighting = true;   
  
  
                    effect.World =   
  
                        Matrix.CreateScale(gameobject.scale) *   
  
                        Matrix.CreateFromQuaternion(cubeRotation) *   
  
                       Matrix.CreateTranslation(gameobject.position);   
  
  
                           
                    effect.Projection = cameraProjectionMatrix;   
                    effect.View = cameraViewMatrix;   
                }   
  
                mesh.Draw();   
            }   
        }   
    }

What I think is the problem is that matrix.createtranslation(gameobject.position) is obviously affecting all my cubes. I've tried creating new vector3 i.e c_component1 = vector3.transform(cube1pos, cubeRotation) but even then, I am unsure where to put that code and actually use it properly.

Any ideas anyone?

-DaveT

Isn't it because you're applying the rotation to all your objects? That what it looks like from your first code source.

If not, then you could try resetting to the identity matrix between drawing each object.

Isn't it because you're applying the rotation to all your objects? That what it looks like from your first code source.

That's what I assumed too.

I've since created three arrays for the different faces of the Cube.

public void LeftFace()
        {
            leftfacecube = new GameObject[3];

            leftfacecube[0].position = new Vector3(0.55f, 0.55f, 0.55f); //cube at pos 1
            leftfacecube[0].model = subCube1.model;
            leftfacecube[1].position = new Vector3(-0.55f, 0.55f, 0.55f);//cube at pos 2
            leftfacecube[1].model = subCube2.model;
            leftfacecube[2].position = new Vector3(-0.55f, -0.55f, 0.55f); //cube at pos 3
            leftfacecube[2].model = subCube3.model;
            leftfacecube[3].position = new Vector3(0.55f, -0.55f, 0.55f);//cube at pos 4
            leftfacecube[3].model = subCube4.model;

        }


        //draw models on left side
        void DrawLeftFace(GameObject gameobject)
        {
            //graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
            foreach (ModelMesh mesh in gameobject.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;


                    effect.World =

                        Matrix.CreateScale(gameobject.scale) *

                        Matrix.CreateFromQuaternion(cubeRotation) *

                       Matrix.CreateTranslation((leftfacecube[0].position) + (leftfacecube[1].position) + (leftfacecube[2].position) + (leftfacecube[3].position));



                    effect.Projection = cameraProjectionMatrix;
                    effect.View = cameraViewMatrix;
                }

                mesh.Draw();
            }
        }

        public void RightFace()
        {
            rightfacecube = new GameObject[3];

            rightfacecube[0].position = new Vector3(-0.55f, 0.55f, 0.55f);//cube at pos 2
            rightfacecube[0].model = subCube1.model;
            rightfacecube[1].position = new Vector3(0.55f, -0.55f, 0.55f);//cube at pos 4
            rightfacecube[2].position = new Vector3(-0.55f, -0.55f, -0.55f);//cube at pos 6
            rightfacecube[3].position = new Vector3(0.55f, 0.55f, -0.55f);//cube at pos 8
        }

        //draw models on right side
        void DrawRightFace(GameObject gameobject)
        {
            //graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
            foreach (ModelMesh mesh in gameobject.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;


                    effect.World =

                        Matrix.CreateScale(gameobject.scale) *

                        Matrix.CreateFromQuaternion(cubeRotation) *

                       Matrix.CreateTranslation((rightfacecube[0].position) + (rightfacecube[1].position) + (rightfacecube[2].position) + (rightfacecube[3].position));



                    effect.Projection = cameraProjectionMatrix;
                    effect.View = cameraViewMatrix;
                }

                mesh.Draw();
            }
        }



        public void TopFace()
        {
            topfacecube = new GameObject[3];

            topfacecube[0].position = new Vector3(0.55f, 0.55f, 0.55f);//cube at pos 1
            topfacecube[1].position = new Vector3(-0.55f, 0.55f, 0.55f);//cube at pos 2
            topfacecube[2].position = new Vector3(0.55f, -0.55f, -0.55f);//cube at pos 5
            topfacecube[3].position = new Vector3(-0.55f, -0.55f, -0.55f);//cube at pos 6
        
        }

        //draw models on top
        void DrawTopFace(GameObject gameobject)
        {
            //graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
            foreach (ModelMesh mesh in gameobject.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;


                    effect.World =

                        Matrix.CreateScale(gameobject.scale) *

                        Matrix.CreateFromQuaternion(cubeRotation) *

                       Matrix.CreateTranslation((topfacecube[0].position) + (topfacecube[1].position) + (topfacecube[2].position) + (topfacecube[3].position));



                    effect.Projection = cameraProjectionMatrix;
                    effect.View = cameraViewMatrix;
                }

                mesh.Draw();
            }
        }

But I am unsure of what to do now.

Any help is much appreciated.

DaveT

Ok had a bit of a rethink with this. I don't normally plan how I go about creating games but I felt I needed to for this otherwise I'd confuse myself. My train of thought to now creating this is/was:

- Positions of Cubes are stored as Vector3's as their default position (cube1 = cube1pos etc) with relation to the world axis
- Current positions will constantly be updated in the Game1 Update() method following rotations
- Current positions are referred to as c_components; e.g. cube 1 = c_component1

For example in loadcontent():

subCube1.model = Content.Load<Model>("Models//rub1");
            subCube1.position = subCube1Pos;
            subCube1Pos = new Vector3(c_component1.X, c_component1.Y, c_component1.Z);

- Cubes are then drawn at the c_component vector3
- Methods for rotating the left/right/top face of the Cube will then take the current positions and rotate that
- The 'new' current positions after the method is then returned
- The cubes are then drawn at that position

I think that should be okay?

Anyway, I'm running into a bit of trouble with how to return the positions after being transformed and implementing it into the Update() and Draw() functions.

Method to rotate left face of Cube:

// rotation to the left face of the cube, components 5-8 don't move so I've set the vector to 0.0f
        public void leftRotation(Vector3 c_component, Matrix leftRotMatrix)
        {
            c_component1 = Vector3.Transform(c_component1, Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component2 = Vector3.Transform(c_component2, Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component3 = Vector3.Transform(c_component3, Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component4 = Vector3.Transform(c_component4, Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component5 = Vector3.Transform((new Vector3(0.0f, 0.0f, 0.0f)), Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component6 = Vector3.Transform((new Vector3(0.0f, 0.0f, 0.0f)), Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component7 = Vector3.Transform((new Vector3(0.0f, 0.0f, 0.0f)), Matrix.CreateFromQuaternion(cubeRotationLeft));
            c_component8 = Vector3.Transform((new Vector3(0.0f, 0.0f, 0.0f)), Matrix.CreateFromQuaternion(cubeRotationLeft));
        }

How would I return these positions of c_components and update accordingly by drawing the Cubes at these points?

Also, would I need to create a new World Matrix for every rotation?

Any help/advice would be much appreciated.

DaveT

Ok this is getting quite complicated from an external perspective so lets go back to the beginning slightly.

I'm not actually a user of XNA but I do use DirectX.

In DirectX each object must have a copy of its own world matrix. (I form this from 4 matrices; translation, transformation, rotation & scale)

When I wish to render my mesh, I multiply the 4 matrices together and apply it to the World Matrix.

My World Matrix is initially set to the identity matrix. My "game" has a root scene object, I can then add children and siblings to the scene and to each object in the scene.

As I render down the graph, the world matrix takes the form of the combined parent matrices. So if I had:

Root -> Child -> Child -> Sibling -> Child
                       -> Sibling -> Child

My matrices would be as follows:
Matrix = Identity * Child * Child
up until the siblings. Then the sibling each take a copy of Matrix to pass to their child..
Matrix = Matrix * Sibling * Child

etc etc.

From what you're saying, you're applying a full world matrix to all your objects, so they all do the same thing.

World -> Transform -> Render objects -> Transform (overwrites previous transform) -> Render etc.

I hope my explanation helps. Not too sure it makes sense ^^

Thanks for the reply. I too think I am over-complicating things too. Well, my current worldMatrix is:

void DrawGameObject(GameObject gameobject)
        {
            //graphics.GraphicsDevice.RenderState.CullMode = CullMode.None;
            foreach (ModelMesh mesh in gameobject.model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.PreferPerPixelLighting = true;


                    effect.World =
                        Matrix.CreateScale(gameobject.scale) *
                        Matrix.CreateFromYawPitchRoll(gameobject.rotation.X, gameobject.rotation.Y, gameobject.rotation.Z) *
                        //Matrix.CreateFromQuaternion(cubeRotation) *
                        Matrix.CreateTranslation(gameobject.position);

                    effect.Projection = cameraProjectionMatrix;
                    effect.View = cameraViewMatrix;
                }

                mesh.Draw();
            }
        }

Which quite obviously affects all the gameObjects (which are all the cubes).

So what you are saying is that EACH cube has it's own function like that above?

DaveT

Apologies for the double post (only allowed to edit a post 30mins after originally posting it), but would it be best to store all of this in a seperate class? So for example:

class Cube   
{  
    public Vector3 Scale;  
    public Vector3 Position;   
    public Quaternion Rotation;   
   
    public Matrix WorldMatrix   
    {   
        return Matrix.CreateFromQuaternion(Rotation) *   
               Matrix.CreateScale(Scale) *  
               Matrix.CreateTranslation(Position);   
    }   
}

And then in this class I'd have cube_components, and in the update method when I press right/left, I'd update each cube's matrix accordingly? Only thing is, how would I get all of this into the Game1.cs file in the draw function etc (I'll cross this bridge when I get to it).

And also when you say "apply it to the "world matrix"" what do you mean? My current worldMatrix is in my previous post.

DaveT

I've only just seen this message and I'm about to head home, but a quick reply is.

Yes every cube should have its own transformation matrix. When you render, you need to take the Identity matrix and multiply it with the cube's transform matrix.

Any cube that is a CHILD of that cube, should use the matrix you just calculated on the parent as its base transformation matrix, rather than use the identity. (This means if you translate a parent left by 20 units, but translate the child RIGHT by 5 units, your final transformation on the child is LEFT by 15 units)

By world matrix I simply mean the D3D Constant pDevice->SetTransform(D3DTS_WORLD,&m_matCombined); , which you probably won't use :)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.