# Rubik Cube Animation Example In Android

This example shows how you can create Rubik’s cube in android.

Algorithm:

1.) Create a new project by File-> New -> Android Project name it RubikCubeAnimationExample.

2.) Create and write following into src/M4.java:

```package com.example.RubikCubeAnimationExample;

public class M4 {
public float[][] m = new float[4][4];

public M4() {
}

public M4(M4 other) {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
m[i][j] = other.m[i][j];
}
}
}

public void multiply(GLVertex src, GLVertex dest) {
dest.x = src.x * m[0][0] + src.y * m[1][0] + src.z * m[2][0] + m[3][0];
dest.y = src.x * m[0][1] + src.y * m[1][1] + src.z * m[2][1] + m[3][1];
dest.z = src.x * m[0][2] + src.y * m[1][2] + src.z * m[2][2] + m[3][2];
}

public M4 multiply(M4 other) {
M4 result = new M4();
float[][] m1 = m;
float[][] m2 = other.m;

for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
result.m[i][j] = m1[i][0]*m2[0][j] + m1[i][1]*m2[1][j] + m1[i][2]*m2[2][j] + m1[i][3]*m2[3][j];
}
}

return result;
}

public void setIdentity() {
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
m[i][j] = (i == j ? 1f : 0f);
}
}
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder("[ ");
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
builder.append(m[i][j]);
builder.append(" ");
}
if (i < 2)
builder.append("n ");
}
builder.append(" ]");
return builder.toString();
}
}```

3.) Create and write following into src/Layer.java:

```package com.example.RubikCubeAnimationExample;

public class Layer {

public Layer(int axis) {
mAxis = axis;
mTransform.setIdentity();
}

public void startAnimation() {
for (int i = 0; i < mShapes.length; i++) {
GLShape shape = mShapes[i];
if (shape != null) {
shape.startAnimation();
}
}
}

public void endAnimation() {
for (int i = 0; i < mShapes.length; i++) {
GLShape shape = mShapes[i];
if (shape != null) {
shape.endAnimation();
}
}
}

public void setAngle(float angle) {
// normalize the angle
float twopi = (float)Math.PI *2f;
while (angle >= twopi) angle -= twopi;
while (angle < 0f) angle += twopi;
// mAngle = angle;

float sin = (float)Math.sin(angle);
float cos = (float)Math.cos(angle);

float[][] m = mTransform.m;
switch (mAxis) {
case kAxisX:
m[1][1] = cos;
m[1][2] = sin;
m[2][1] = -sin;
m[2][2] = cos;
m[0][0] = 1f;
m[0][1] = m[0][2] = m[1][0] = m[2][0] = 0f;
break;
case kAxisY:
m[0][0] = cos;
m[0][2] = sin;
m[2][0] = -sin;
m[2][2] = cos;
m[1][1] = 1f;
m[0][1] = m[1][0] = m[1][2] = m[2][1] = 0f;
break;
case kAxisZ:
m[0][0] = cos;
m[0][1] = sin;
m[1][0] = -sin;
m[1][1] = cos;
m[2][2] = 1f;
m[2][0] = m[2][1] = m[0][2] = m[1][2] = 0f;
break;
}

for (int i = 0; i < mShapes.length; i++) {
GLShape shape = mShapes[i];
if (shape != null) {
shape.animateTransform(mTransform);
}
}
}

GLShape[] mShapes = new GLShape[9];
M4 mTransform = new M4();
int mAxis;
static public final int kAxisX = 0;
static public final int kAxisY = 1;
static public final int kAxisZ = 2;
}```

4.) Create and write following into src/KubeRenderer.java:

```package com.example.RubikCubeAnimationExample;

import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

class KubeRenderer implements GLSurfaceView.Renderer {
public interface AnimationCallback {
void animate();
}

public KubeRenderer(GLWorld world, AnimationCallback callback) {
mWorld = world;
mCallback = callback;
}

public void onDrawFrame(GL10 gl) {
if (mCallback != null) {
mCallback.animate();
}
gl.glClearColor(0.5f,0.5f,0.5f,1);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glMatrixMode(GL10.GL_MODELVIEW);
gl.glTranslatef(0, 0, -3.0f);
gl.glScalef(0.5f, 0.5f, 0.5f);
gl.glRotatef(mAngle, 0, 1, 0);
gl.glRotatef(mAngle*0.25f, 1, 0, 0);

gl.glColor4f(0.7f, 0.7f, 0.7f, 1.0f);
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_COLOR_ARRAY);
gl.glEnable(GL10.GL_CULL_FACE);
gl.glEnable(GL10.GL_DEPTH_TEST);

mWorld.draw(gl);
}

public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
float ratio = (float)width / height;
gl.glMatrixMode(GL10.GL_PROJECTION);
gl.glFrustumf(-ratio, ratio, -1, 1, 2, 12);
gl.glDisable(GL10.GL_DITHER);
gl.glActiveTexture(GL10.GL_TEXTURE0);
}

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
}

public void setAngle(float angle) {
mAngle = angle;
}

public float getAngle() {
return mAngle;
}

private GLWorld mWorld;
private AnimationCallback mCallback;
private float mAngle;
}```

5.) Create and write following into src/GLWorld.java:

```package com.example.RubikCubeAnimationExample;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Iterator;
import java.util.ArrayList;

import javax.microedition.khronos.opengles.GL10;

public class GLWorld {

mIndexCount += shape.getIndexCount();
}

public void generate() {
ByteBuffer bb = ByteBuffer.allocateDirect(mVertexList.size()*4*4);
bb.order(ByteOrder.nativeOrder());
mColorBuffer = bb.asIntBuffer();

bb = ByteBuffer.allocateDirect(mVertexList.size()*4*3);
bb.order(ByteOrder.nativeOrder());
mVertexBuffer = bb.asIntBuffer();

bb = ByteBuffer.allocateDirect(mIndexCount*2);
bb.order(ByteOrder.nativeOrder());
mIndexBuffer = bb.asShortBuffer();

Iterator iter2 = mVertexList.iterator();
while (iter2.hasNext()) {
GLVertex vertex = iter2.next();
vertex.put(mVertexBuffer, mColorBuffer);
}

Iterator iter3 = mShapeList.iterator();
while (iter3.hasNext()) {
GLShape shape = iter3.next();
shape.putIndices(mIndexBuffer);
}
}

public GLVertex addVertex(float x, float y, float z) {
GLVertex vertex = new GLVertex(x, y, z, mVertexList.size());
return vertex;
}

public void transformVertex(GLVertex vertex, M4 transform) {
vertex.update(mVertexBuffer, transform);
}

int count = 0;
public void draw(GL10 gl)
{
mColorBuffer.position(0);
mVertexBuffer.position(0);
mIndexBuffer.position(0);

gl.glFrontFace(GL10.GL_CW);
gl.glVertexPointer(3, GL10.GL_FIXED, 0, mVertexBuffer);
gl.glColorPointer(4, GL10.GL_FIXED, 0, mColorBuffer);
gl.glDrawElements(GL10.GL_TRIANGLES, mIndexCount, GL10.GL_UNSIGNED_SHORT, mIndexBuffer);
count++;
}

static public float toFloat(int x) {
return x/65536.0f;
}

private ArrayList mShapeList = new ArrayList();
private ArrayList mVertexList = new ArrayList();

private int mIndexCount = 0;

private IntBuffer mVertexBuffer;
private IntBuffer mColorBuffer;
private ShortBuffer mIndexBuffer;
}```

6.) Create and write following into src/GLVertex.java:

```package com.example.RubikCubeAnimationExample;

import java.nio.IntBuffer;

public class GLVertex {

public float x;
public float y;
public float z;
final short index; // index in vertex table
GLColor color;

GLVertex() {
this.x = 0;
this.y = 0;
this.z = 0;
this.index = -1;
}

GLVertex(float x, float y, float z, int index) {
this.x = x;
this.y = y;
this.z = z;
this.index = (short)index;
}

@Override
public boolean equals(Object other) {
if (other instanceof GLVertex) {
GLVertex v = (GLVertex)other;
return (x == v.x && y == v.y && z == v.z);
}
return false;
}

static public int toFixed(float x) {
return (int)(x * 65536.0f);
}

public void put(IntBuffer vertexBuffer, IntBuffer colorBuffer) {
vertexBuffer.put(toFixed(x));
vertexBuffer.put(toFixed(y));
vertexBuffer.put(toFixed(z));
if (color == null) {
colorBuffer.put(0);
colorBuffer.put(0);
colorBuffer.put(0);
colorBuffer.put(0);
} else {
colorBuffer.put(color.red);
colorBuffer.put(color.green);
colorBuffer.put(color.blue);
colorBuffer.put(color.alpha);
}
}

public void update(IntBuffer vertexBuffer, M4 transform) {
vertexBuffer.position(index * 3);

if (transform == null) {
vertexBuffer.put(toFixed(x));
vertexBuffer.put(toFixed(y));
vertexBuffer.put(toFixed(z));
} else {
GLVertex temp = new GLVertex();
transform.multiply(this, temp);
vertexBuffer.put(toFixed(temp.x));
vertexBuffer.put(toFixed(temp.y));
vertexBuffer.put(toFixed(temp.z));
}
}
}```

7.) Create and write following into src/GLShape.java:

```package com.example.RubikCubeAnimationExample;

import java.nio.ShortBuffer;
import java.util.ArrayList;
import java.util.Iterator;

public class GLShape {

public GLShape(GLWorld world) {
mWorld = world;
}

}

public void setFaceColor(int face, GLColor color) {
mFaceList.get(face).setColor(color);
}

public void putIndices(ShortBuffer buffer) {
Iterator iter = mFaceList.iterator();
while (iter.hasNext()) {
GLFace face = iter.next();
face.putIndices(buffer);
}
}

public int getIndexCount() {
int count = 0;
Iterator iter = mFaceList.iterator();
while (iter.hasNext()) {
GLFace face = iter.next();
count += face.getIndexCount();
}
return count;
}

public GLVertex addVertex(float x, float y, float z) {

// look for an existing GLVertex first
Iterator iter = mVertexList.iterator();
while (iter.hasNext()) {
GLVertex vertex = iter.next();
if (vertex.x == x && vertex.y == y && vertex.z == z) {
return vertex;
}
}

// doesn't exist, so create new vertex
GLVertex vertex = mWorld.addVertex(x, y, z);
return vertex;
}

public void animateTransform(M4 transform) {
mAnimateTransform = transform;

if (mTransform != null)
transform = mTransform.multiply(transform);

Iterator iter = mVertexList.iterator();
while (iter.hasNext()) {
GLVertex vertex = iter.next();
mWorld.transformVertex(vertex, transform);
}
}

public void startAnimation() {
}

public void endAnimation() {
if (mTransform == null) {
mTransform = new M4(mAnimateTransform);
} else {
mTransform = mTransform.multiply(mAnimateTransform);
}
}

public M4 mTransform;
public M4 mAnimateTransform;
protected ArrayList mFaceList = new ArrayList();
protected ArrayList mVertexList = new ArrayList();
protected ArrayList mIndexList = new ArrayList(); // make more efficient?
protected GLWorld mWorld;
}```

8.) Create and write following into src/GLFace.java:

```package com.example.RubikCubeAnimationExample;

import android.util.Log;

import java.nio.ShortBuffer;
import java.util.ArrayList;

public class GLFace {

public GLFace() {

}

// for triangles
public GLFace(GLVertex v1, GLVertex v2, GLVertex v3) {
}
public GLFace(GLVertex v1, GLVertex v2, GLVertex v3, GLVertex v4) {
}

}

// must be called after all vertices are added
public void setColor(GLColor c) {

int last = mVertexList.size() - 1;
if (last < 2) {
Log.e("GLFace", "not enough vertices in setColor()");
} else {
GLVertex vertex = mVertexList.get(last);

// only need to do this if the color has never been set
if (mColor == null) {
while (vertex.color != null) {
mVertexList.remove(last + 1);
vertex = mVertexList.get(last);
}
}

vertex.color = c;
}

mColor = c;
}

public int getIndexCount() {
return (mVertexList.size() - 2) * 3;
}

public void putIndices(ShortBuffer buffer) {
int last = mVertexList.size() - 1;

GLVertex v0 = mVertexList.get(0);
GLVertex vn = mVertexList.get(last);

// push triangles into the buffer
for (int i = 1; i < last; i++) {
GLVertex v1 = mVertexList.get(i);
buffer.put(v0.index);
buffer.put(v1.index);
buffer.put(vn.index);
v0 = v1;
}
}

private ArrayList mVertexList = new ArrayList();
private GLColor mColor;
}
[/code]

9.) Create and write following into src/GLColor.java:

package com.example.RubikCubeAnimationExample;

public class GLColor {

public final int red;
public final int green;
public final int blue;
public final int alpha;

public GLColor(int red, int green, int blue, int alpha) {
this.red = red;
this.green = green;
this.blue = blue;
this.alpha = alpha;
}

public GLColor(int red, int green, int blue) {
this.red = red;
this.green = green;
this.blue = blue;
this.alpha = 0x10000;
}

@Override
public boolean equals(Object other) {
if (other instanceof GLColor) {
GLColor color = (GLColor)other;
return (red == color.red &&
green == color.green &&
blue == color.blue &&
alpha == color.alpha);
}
return false;
}
}```

10.) Create and write following into src/Cube.java:

```package com.example.RubikCubeAnimationExample;

public class Cube extends GLShape {

public Cube(GLWorld world, float left, float bottom, float back, float right, float top, float front) {
super(world);
GLVertex leftBottomBack = addVertex(left, bottom, back);
GLVertex rightBottomBack = addVertex(right, bottom, back);
GLVertex leftTopBack = addVertex(left, top, back);
GLVertex rightTopBack = addVertex(right, top, back);
GLVertex leftBottomFront = addVertex(left, bottom, front);
GLVertex rightBottomFront = addVertex(right, bottom, front);
GLVertex leftTopFront = addVertex(left, top, front);
GLVertex rightTopFront = addVertex(right, top, front);

}

public static final int kBottom = 0;
public static final int kFront = 1;
public static final int kLeft = 2;
public static final int kRight = 3;
public static final int kBack = 4;
public static final int kTop = 5;

}```

11.) Run for output.

Steps:

1.) Create a project named RubikCubeAnimationExample and set the information as stated in the image.

Build Target: Android 4.0
Application Name: RubikCubeAnimationExample
Package Name: com. example. RubikCubeAnimationExample
Activity Name: RubikCubeAnimationExampleActivity
Min SDK Version: 14

2.) Open RubikCubeAnimationExampleActivity.java file and write following code there:

```package com.example.RubikCubeAnimationExample;

import java.util.Random;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.Window;

public class RubikCubeAnimationExampleActivity extends Activity implements KubeRenderer.AnimationCallback {

private GLWorld makeGLWorld()
{
GLWorld world = new GLWorld();

int one = 0x10000;
int half = 0x08000;
GLColor red = new GLColor(one, 0, 0);
GLColor green = new GLColor(0, one, 0);
GLColor blue = new GLColor(0, 0, one);
GLColor yellow = new GLColor(one, one, 0);
GLColor orange = new GLColor(one, half, 0);
GLColor white = new GLColor(one, one, one);
GLColor black = new GLColor(0, 0, 0);

float c0 = -1.0f;
float c1 = -0.38f;
float c2 = -0.32f;
float c3 = 0.32f;
float c4 = 0.38f;
float c5 = 1.0f;

// top back, left to right
mCubes[0] = new Cube(world, c0, c4, c0, c1, c5, c1);
mCubes[1] = new Cube(world, c2, c4, c0, c3, c5, c1);
mCubes[2] = new Cube(world, c4, c4, c0, c5, c5, c1);
// top middle, left to right
mCubes[3] = new Cube(world, c0, c4, c2, c1, c5, c3);
mCubes[4] = new Cube(world, c2, c4, c2, c3, c5, c3);
mCubes[5] = new Cube(world, c4, c4, c2, c5, c5, c3);
// top front, left to right
mCubes[6] = new Cube(world, c0, c4, c4, c1, c5, c5);
mCubes[7] = new Cube(world, c2, c4, c4, c3, c5, c5);
mCubes[8] = new Cube(world, c4, c4, c4, c5, c5, c5);
// middle back, left to right
mCubes[9] = new Cube(world, c0, c2, c0, c1, c3, c1);
mCubes[10] = new Cube(world, c2, c2, c0, c3, c3, c1);
mCubes[11] = new Cube(world, c4, c2, c0, c5, c3, c1);
// middle middle, left to right
mCubes[12] = new Cube(world, c0, c2, c2, c1, c3, c3);
mCubes[13] = null;
mCubes[14] = new Cube(world, c4, c2, c2, c5, c3, c3);
// middle front, left to right
mCubes[15] = new Cube(world, c0, c2, c4, c1, c3, c5);
mCubes[16] = new Cube(world, c2, c2, c4, c3, c3, c5);
mCubes[17] = new Cube(world, c4, c2, c4, c5, c3, c5);
// bottom back, left to right
mCubes[18] = new Cube(world, c0, c0, c0, c1, c1, c1);
mCubes[19] = new Cube(world, c2, c0, c0, c3, c1, c1);
mCubes[20] = new Cube(world, c4, c0, c0, c5, c1, c1);
// bottom middle, left to right
mCubes[21] = new Cube(world, c0, c0, c2, c1, c1, c3);
mCubes[22] = new Cube(world, c2, c0, c2, c3, c1, c3);
mCubes[23] = new Cube(world, c4, c0, c2, c5, c1, c3);
// bottom front, left to right
mCubes[24] = new Cube(world, c0, c0, c4, c1, c1, c5);
mCubes[25] = new Cube(world, c2, c0, c4, c3, c1, c5);
mCubes[26] = new Cube(world, c4, c0, c4, c5, c1, c5);

// paint the sides
int i, j;
// set all faces black by default
for (i = 0; i < 27; i++) {
Cube cube = mCubes[i];
if (cube != null) {
for (j = 0; j < 6; j++)
cube.setFaceColor(j, black);
}
}

// paint top
for (i = 0; i < 9; i++)
mCubes[i].setFaceColor(Cube.kTop, orange);
// paint bottom
for (i = 18; i < 27; i++)
mCubes[i].setFaceColor(Cube.kBottom, red);
// paint left
for (i = 0; i < 27; i += 3)
mCubes[i].setFaceColor(Cube.kLeft, yellow);
// paint right
for (i = 2; i < 27; i += 3)
mCubes[i].setFaceColor(Cube.kRight, white);
// paint back
for (i = 0; i < 27; i += 9)
for (j = 0; j < 3; j++)
mCubes[i + j].setFaceColor(Cube.kBack, blue);
// paint front
for (i = 6; i < 27; i += 9)
for (j = 0; j < 3; j++)
mCubes[i + j].setFaceColor(Cube.kFront, green);

for (i = 0; i < 27; i++)
if (mCubes[i] != null)

// initialize our permutation to solved position
mPermutation = new int[27];
for (i = 0; i < mPermutation.length; i++)
mPermutation[i] = i;

createLayers();
updateLayers();

world.generate();

return world;
}

private void createLayers() {
mLayers[kUp] = new Layer(Layer.kAxisY);
mLayers[kDown] = new Layer(Layer.kAxisY);
mLayers[kLeft] = new Layer(Layer.kAxisX);
mLayers[kRight] = new Layer(Layer.kAxisX);
mLayers[kFront] = new Layer(Layer.kAxisZ);
mLayers[kBack] = new Layer(Layer.kAxisZ);
mLayers[kMiddle] = new Layer(Layer.kAxisX);
mLayers[kEquator] = new Layer(Layer.kAxisY);
mLayers[kSide] = new Layer(Layer.kAxisZ);
}

private void updateLayers() {
Layer layer;
GLShape[] shapes;
int i, j, k;

// up layer
layer = mLayers[kUp];
shapes = layer.mShapes;
for (i = 0; i < 9; i++)
shapes[i] = mCubes[mPermutation[i]];

// down layer
layer = mLayers[kDown];
shapes = layer.mShapes;
for (i = 18, k = 0; i < 27; i++)
shapes[k++] = mCubes[mPermutation[i]];

// left layer
layer = mLayers[kLeft];
shapes = layer.mShapes;
for (i = 0, k = 0; i < 27; i += 9)
for (j = 0; j < 9; j += 3)
shapes[k++] = mCubes[mPermutation[i + j]];

// right layer
layer = mLayers[kRight];
shapes = layer.mShapes;
for (i = 2, k = 0; i < 27; i += 9)
for (j = 0; j < 9; j += 3)
shapes[k++] = mCubes[mPermutation[i + j]];

// front layer
layer = mLayers[kFront];
shapes = layer.mShapes;
for (i = 6, k = 0; i < 27; i += 9)
for (j = 0; j < 3; j++)
shapes[k++] = mCubes[mPermutation[i + j]];

// back layer
layer = mLayers[kBack];
shapes = layer.mShapes;
for (i = 0, k = 0; i < 27; i += 9)
for (j = 0; j < 3; j++)
shapes[k++] = mCubes[mPermutation[i + j]];

// middle layer
layer = mLayers[kMiddle];
shapes = layer.mShapes;
for (i = 1, k = 0; i < 27; i += 9)
for (j = 0; j < 9; j += 3)
shapes[k++] = mCubes[mPermutation[i + j]];

// equator layer
layer = mLayers[kEquator];
shapes = layer.mShapes;
for (i = 9, k = 0; i < 18; i++)
shapes[k++] = mCubes[mPermutation[i]];

// side layer
layer = mLayers[kSide];
shapes = layer.mShapes;
for (i = 3, k = 0; i < 27; i += 9)
for (j = 0; j < 3; j++)
shapes[k++] = mCubes[mPermutation[i + j]];
}

@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);

// We don't need a title either.
requestWindowFeature(Window.FEATURE_NO_TITLE);

mView = new GLSurfaceView(getApplication());
mRenderer = new KubeRenderer(makeGLWorld(), this);
mView.setRenderer(mRenderer);
setContentView(mView);
}

@Override
protected void onResume()
{
super.onResume();
mView.onResume();
}

@Override
protected void onPause()
{
super.onPause();
mView.onPause();
}

public void animate() {
// change our angle of view
mRenderer.setAngle(mRenderer.getAngle() + 1.2f);

if (mCurrentLayer == null) {
int layerID = mRandom.nextInt(9);
mCurrentLayer = mLayers[layerID];
mCurrentLayerPermutation = mLayerPermutations[layerID];
mCurrentLayer.startAnimation();
boolean direction = mRandom.nextBoolean();
int count = mRandom.nextInt(3) + 1;

count = 1;
direction = false;
mCurrentAngle = 0;
if (direction) {
mAngleIncrement = (float)Math.PI / 50;
mEndAngle = mCurrentAngle + ((float)Math.PI * count) / 2f;
} else {
mAngleIncrement = -(float)Math.PI / 50;
mEndAngle = mCurrentAngle - ((float)Math.PI * count) / 2f;
}
}

mCurrentAngle += mAngleIncrement;

if ((mAngleIncrement > 0f && mCurrentAngle >= mEndAngle) ||
(mAngleIncrement < 0f && mCurrentAngle <= mEndAngle)) {
mCurrentLayer.setAngle(mEndAngle);
mCurrentLayer.endAnimation();
mCurrentLayer = null;

// adjust mPermutation based on the completed layer rotation
int[] newPermutation = new int[27];
for (int i = 0; i < 27; i++) {
newPermutation[i] = mPermutation[mCurrentLayerPermutation[i]];
}
mPermutation = newPermutation;
updateLayers();

} else {
mCurrentLayer.setAngle(mCurrentAngle);
}
}

GLSurfaceView mView;
KubeRenderer mRenderer;
Cube[] mCubes = new Cube[27];
// a Layer for each possible move
Layer[] mLayers = new Layer[9];
// permutations corresponding to a pi/2 rotation of each layer about its axis
static int[][] mLayerPermutations = {
// permutation for UP layer
{ 2, 5, 8, 1, 4, 7, 0, 3, 6, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 },
// permutation for DOWN layer
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 20, 23, 26, 19, 22, 25, 18, 21, 24 },
// permutation for LEFT layer
{ 6, 1, 2, 15, 4, 5, 24, 7, 8, 3, 10, 11, 12, 13, 14, 21, 16, 17, 0, 19, 20, 9, 22, 23, 18, 25, 26 },
// permutation for RIGHT layer
{ 0, 1, 8, 3, 4, 17, 6, 7, 26, 9, 10, 5, 12, 13, 14, 15, 16, 23, 18, 19, 2, 21, 22, 11, 24, 25, 20 },
// permutation for FRONT layer
{ 0, 1, 2, 3, 4, 5, 24, 15, 6, 9, 10, 11, 12, 13, 14, 25, 16, 7, 18, 19, 20, 21, 22, 23, 26, 17, 8 },
// permutation for BACK layer
{ 18, 9, 0, 3, 4, 5, 6, 7, 8, 19, 10, 1, 12, 13, 14, 15, 16, 17, 20, 11, 2, 21, 22, 23, 24, 25, 26 },
// permutation for MIDDLE layer
{ 0, 7, 2, 3, 16, 5, 6, 25, 8, 9, 4, 11, 12, 13, 14, 15, 22, 17, 18, 1, 20, 21, 10, 23, 24, 19, 26 },
// permutation for EQUATOR layer
{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 11, 14, 17, 10, 13, 16, 9, 12, 15, 18, 19, 20, 21, 22, 23, 24, 25, 26 },
// permutation for SIDE layer
{ 0, 1, 2, 21, 12, 3, 6, 7, 8, 9, 10, 11, 22, 13, 4, 15, 16, 17, 18, 19, 20, 23, 14, 5, 24, 25, 26 }
};

// current permutation of starting position
int[] mPermutation;

// for random cube movements
Random mRandom = new Random(System.currentTimeMillis());
// currently turning layer
Layer mCurrentLayer = null;
// current and final angle for current Layer animation
float mCurrentAngle, mEndAngle;
// amount to increment angle
float mAngleIncrement;
int[] mCurrentLayerPermutation;

// names for our 9 layers (based on notation from http://www.cubefreak.net/notation.html)
static final int kUp = 0;
static final int kDown = 1;
static final int kLeft = 2;
static final int kRight = 3;
static final int kFront = 4;
static final int kBack = 5;
static final int kMiddle = 6;
static final int kEquator = 7;
static final int kSide = 8;

}```

3.) Compile and build the project.

Output

James says January 6, 2013

You call this a beginner tutorial…Lame

pnelnik says January 8, 2013

Looks cool.
Have you published this in the google play store?

dhruva says January 14, 2013

Followed your directions, but when I try to create the second example (Step. 11) Eclipse gives a response that “A project already exists in the workspace.

Any suggestions?

nayana bhoj says April 9, 2013

Gud example!!!

fatma says June 21, 2013

i have a graduate project for rubik cube in android and i need for rubik animation using touch rather than permutation i try more but i can’t please help me and thank you very much

Deepak Swami says July 27, 2013

Hello Sushant Das,

nice series of tutorials.
i have read almost all tutorials by you.
helped me a lot.
but i want to say only one thing instead of “xyz.java file and write following code there” can you please explain more about that class like what is the working of this class/ why this class useful to us/by adding this class what effect would be on our app.
i think you will look on this.

and thanks again for your tutorial series..

Regards,
Deepak Swami

Vivek Agrawal says April 5, 2015

Hey !

I ran your app and I really liked it. I am currently working on an app by which people can learn to solve the Rubik’s cube in an easy way. And I was wondering if I can use your code in that app. Coz I am not that good with the animation programming.

But, I do need a cube which can be animated to show the user a series of movements which the user can see and understand the workings of it.

Hope to see a reply from you.

Regards
Vivek Agrawal