How to Create a 3D Rubik's Cube in Java Netbeans
In this Java Tutorial we will see How To Create a 3D Rubik's Cube with realistic lighting effects, smooth rotations, floating animations, and mouse controls.
The cube features authentic Rubik's cube colors, gradient shading, and perspective projection to create a 3D experience In Java Using Netbeans.
This Rubik's Cube in Java Swing is an excellent project that combines computer graphics, 3D mathematics, and user interface design - all without using external 3D libraries..
What We Are Gonna Use In This Project:
- Java Programming Language.- NetBeans Editor.
Project Source Code:
/**
*
* @author 1BestCsharp
*/
public class RubiksCube extends JFrame {
// Target and current rotation angles
private double currentRotationX = -30; // Current X rotation in degrees
private double currentRotationY = 45; // Current Y rotation in degrees
private double currentRotationZ = 0; // Current Z rotation in degrees
private double targetRotationX = -30; // Target X rotation for smooth animation
private double targetRotationY = 45; // Target Y rotation for smooth animation
private double targetRotationZ = 0; // Target Z rotation for smooth animation
// Animation properties
private final double ROTATION_SPEED = 0.15; // Speed of rotation interpolation (0-1)
private boolean isAnimating = false; // Tracks if rotation animation is in progress
// For mouse dragging interaction
private boolean isDragging = false; // Tracks if user is dragging the cube
private Point previousPoint; // Stores previous mouse position for drag calculations
// Faces colors - standard Rubik's cube colors
private static final Color[] FACE_COLORS = {
new Color(255, 0, 0), // Front - Red
new Color(255, 165, 0), // Back - Orange
new Color(0, 255, 0), // Right - Green
new Color(0, 0, 255), // Left - Blue
new Color(255, 255, 255),// Top - White
new Color(255, 255, 0) // Bottom - Yellow
};
// Darker versions of face colors for gradients and shading effects
private static final Color[] FACE_COLORS_DARK = {
new Color(180, 0, 0), // Front - Dark Red
new Color(180, 117, 0), // Back - Dark Orange
new Color(0, 180, 0), // Right - Dark Green
new Color(0, 0, 180), // Left - Dark Blue
new Color(200, 200, 200),// Top - Light Gray
new Color(180, 180, 0) // Bottom - Dark Yellow
};
// Face indices for improved code readability
private static final int FRONT = 0;
private static final int BACK = 1;
private static final int RIGHT = 2;
private static final int LEFT = 3;
private static final int TOP = 4;
private static final int BOTTOM = 5;
// Stores cube state (colors of all cells)
private CubeModel cubeModel;
// Main drawing panel
private CubePanel cubePanel;
// Animation timers
private Timer floatAnimationTimer; // Timer for floating effect animation
private Timer rotationAnimationTimer; // Timer for smooth rotation animation
private double floatOffset = 0; // Current offset for floating animation
private boolean floatingUp = true; // Direction of floating animation
public RubiksCube(){
setTitle("Rubik's Cube");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
// Initialize cube model (stores the state of all cube cells)
cubeModel = new CubeModel();
// Create and configure the cube rendering panel
cubePanel = new CubePanel();
cubePanel.setPreferredSize(new Dimension(800, 600));
cubePanel.setBackground(new Color(15, 15, 15)); // Very dark background
add(cubePanel, BorderLayout.CENTER);
// Create control panel with buttons
JPanel controlPanel = createControlPanel();
add(controlPanel, BorderLayout.SOUTH);
// Set up mouse listeners for interactive rotation
setupMouseListeners();
// Start animation timers
startRotationAnimation();
startFloatingAnimation();
pack();
setLocationRelativeTo(null); // Center on screen
}
/**
* Creates the control panel with rotation buttons
* @return JPanel containing control buttons
*/
private JPanel createControlPanel() {
JPanel panel = new JPanel();
panel.setBackground(new Color(30, 30, 30));
panel.setBorder(new EmptyBorder(15, 15, 15, 15));
panel.setLayout(new FlowLayout(FlowLayout.CENTER, 15, 0));
// Create control buttons
JButton rotateXButton = createControlButton("Rotate X");
JButton rotateYButton = createControlButton("Rotate Y");
JButton rotateZButton = createControlButton("Rotate Z");
JButton resetButton = createControlButton("Reset View");
// Add action listeners to buttons
rotateXButton.addActionListener(e -> {
targetRotationX += 90; // Rotate 90 degrees around X axis
isAnimating = true;
});
rotateYButton.addActionListener(e -> {
targetRotationY += 90; // Rotate 90 degrees around Y axis
isAnimating = true;
});
rotateZButton.addActionListener(e -> {
targetRotationZ += 90; // Rotate 90 degrees around Z axis
isAnimating = true;
});
resetButton.addActionListener(e -> {
// Reset to default view angles
targetRotationX = -30;
targetRotationY = 45;
targetRotationZ = 0;
isAnimating = true;
});
// Add buttons to panel
panel.add(rotateXButton);
panel.add(rotateYButton);
panel.add(rotateZButton);
panel.add(resetButton);
return panel;
}
/**
* Creates a styled control button with hover effects
* @param text Button text
* @return Styled JButton
*/
private JButton createControlButton(String text) {
JButton button = new JButton(text);
button.setForeground(Color.WHITE);
button.setBackground(new Color(60, 60, 60));
button.setFocusPainted(false);
button.setBorderPainted(false);
button.setFont(new Font("SansSerif", Font.BOLD, 14));
button.setPreferredSize(new Dimension(120, 40));
// Add custom hover and press effects
button.addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
button.setBackground(new Color(80, 80, 80)); // Lighter on hover
button.setCursor(new Cursor(Cursor.HAND_CURSOR));
}
@Override
public void mouseExited(MouseEvent e) {
button.setBackground(new Color(60, 60, 60)); // Back to normal when not hovering
button.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
@Override
public void mousePressed(MouseEvent e) {
button.setBackground(new Color(100, 100, 100)); // Even lighter when pressed
}
@Override
public void mouseReleased(MouseEvent e) {
button.setBackground(new Color(80, 80, 80)); // Back to hover state when released
}
});
return button;
}
/**
* Sets up mouse listeners for interactive cube rotation
*/
private void setupMouseListeners() {
cubePanel.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
isDragging = true;
previousPoint = e.getPoint();
cubePanel.setCursor(new Cursor(Cursor.MOVE_CURSOR));
}
@Override
public void mouseReleased(MouseEvent e) {
isDragging = false;
cubePanel.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
}
});
cubePanel.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
if (isDragging) {
Point currentPoint = e.getPoint();
// Calculate movement deltas
double deltaX = currentPoint.x - previousPoint.x;
double deltaY = currentPoint.y - previousPoint.y;
// Update target rotations - mouse X movement rotates Y axis and vice versa
targetRotationY += deltaX * 0.5; // Horizontal movement -> Y rotation
targetRotationX += deltaY * 0.5; // Vertical movement -> X rotation
// Update current rotations partially for immediate visual feedback
currentRotationY += deltaX * 0.25;
currentRotationX += deltaY * 0.25;
previousPoint = currentPoint;
cubePanel.repaint();
}
}
});
}
/**
* Starts the floating animation that makes the cube hover up and down
*/
private void startFloatingAnimation() {
floatAnimationTimer = new Timer(50, e -> {
// Update floating offset based on direction
if (floatingUp) {
floatOffset += 0.15;
if (floatOffset >= 8) { // Max height reached
floatingUp = false; // Change direction
}
}
else {
floatOffset -= 0.15;
if (floatOffset <= -8) { // Min height reached
floatingUp = true; // Change direction
}
}
cubePanel.repaint();
});
floatAnimationTimer.start();
}
/**
* Starts the rotation animation for smooth transitions
*/
private void startRotationAnimation() {
rotationAnimationTimer = new Timer(16, e -> {
boolean needsUpdate = false;
// Smoothly interpolate X rotation using easing
if (Math.abs(targetRotationX - currentRotationX) > 0.1) {
currentRotationX += (targetRotationX - currentRotationX) * ROTATION_SPEED;
needsUpdate = true;
}
else {
currentRotationX = targetRotationX; // Snap to exact value when close enough
}
// Smoothly interpolate Y rotation using easing
if (Math.abs(targetRotationY - currentRotationY) > 0.1) {
currentRotationY += (targetRotationY - currentRotationY) * ROTATION_SPEED;
needsUpdate = true;
}
else {
currentRotationY = targetRotationY; // Snap to exact value when close enough
}
// Smoothly interpolate Z rotation using easing
if (Math.abs(targetRotationZ - currentRotationZ) > 0.1) {
currentRotationZ += (targetRotationZ - currentRotationZ) * ROTATION_SPEED;
needsUpdate = true;
}
else {
currentRotationZ = targetRotationZ; // Snap to exact value when close enough
}
// Only repaint if rotations changed
if (needsUpdate) {
cubePanel.repaint();
}
else if (isAnimating) {
isAnimating = false; // Stop animation flag when target reached
}
});
rotationAnimationTimer.start();
}
/**
* Inner class to store the state of the Rubik's Cube
* Currently just stores colors, but could be extended for moves/rotations
*/
class CubeModel {
private final int SIZE = 3; // 3x3x3 standard cube
private Color[][][] cells; // [face][row][col] array of cell colors
public CubeModel() {
cells = new Color[6][SIZE][SIZE];
for (int face = 0; face < 6; face++) {
for (int row = 0; row < SIZE; row++) {
for (int col = 0; col < SIZE; col++) {
cells[face][row][col] = FACE_COLORS[face];
}
}
}
}
/**
* Gets the color of a specific cell
* @param face Face index (0-5)
* @param row Row index (0-2)
* @param col Column index (0-2)
* @return Color of the specified cell
*/
public Color getCellColor(int face, int row, int col) {
return cells[face][row][col];
}
/**
* Gets the darker color variant for a specific cell (for gradients)
* @param face Face index (0-5)
* @param row Row index (0-2)
* @param col Column index (0-2)
* @return Darker version of the cell color
*/
public Color getCellDarkColor(int face, int row, int col) {
return FACE_COLORS_DARK[face];
}
}
/**
* Inner class for rendering the 3D cube
*/
class CubePanel extends JPanel {
private static final int CUBE_SIZE = 300; // Size of the cube in pixels
private static final int CELL_GAP = 6; // Gap between cells for visual separation
// Array to store 3D coordinates of cube corners for each face
private double[][][] faceVertices;
public CubePanel() {
// Initialize 3D vertices for all cube faces
initFaceVertices();
// Set cursor to show interactivity
setCursor(new Cursor(Cursor.HAND_CURSOR));
}
/**
* Initializes the 3D vertices for all cube faces
* Each face has 4 corners defined in 3D space
*/
private void initFaceVertices() {
// Each face has 4 vertices in 3D space
faceVertices = new double[16][4][3];
double s = CUBE_SIZE / 2.0; // Half size of the cube
// FRONT face (z = s)
faceVertices[FRONT][0] = new double[]{-s, -s, s}; // Top-left
faceVertices[FRONT][1] = new double[]{s, -s, s}; // Top-right
faceVertices[FRONT][2] = new double[]{s, s, s}; // Bottom-right
faceVertices[FRONT][3] = new double[]{-s, s, s}; // Bottom-left
// BACK face (z = -s)
faceVertices[BACK][0] = new double[]{s, -s, -s}; // Top-left (mirrored)
faceVertices[BACK][1] = new double[]{-s, -s, -s}; // Top-right (mirrored)
faceVertices[BACK][2] = new double[]{-s, s, -s}; // Bottom-right (mirrored)
faceVertices[BACK][3] = new double[]{s, s, -s}; // Bottom-left (mirrored)
// RIGHT face (x = s)
faceVertices[RIGHT][0] = new double[]{s, -s, s}; // Top-left
faceVertices[RIGHT][1] = new double[]{s, -s, -s}; // Top-right
faceVertices[RIGHT][2] = new double[]{s, s, -s}; // Bottom-right
faceVertices[RIGHT][3] = new double[]{s, s, s}; // Bottom-left
// LEFT face (x = -s)
faceVertices[LEFT][0] = new double[]{-s, -s, -s}; // Top-left
faceVertices[LEFT][1] = new double[]{-s, -s, s}; // Top-right
faceVertices[LEFT][2] = new double[]{-s, s, s}; // Bottom-right
faceVertices[LEFT][3] = new double[]{-s, s, -s}; // Bottom-left
// TOP face (y = -s)
faceVertices[TOP][0] = new double[]{-s, -s, -s}; // Top-left
faceVertices[TOP][1] = new double[]{s, -s, -s}; // Top-right
faceVertices[TOP][2] = new double[]{s, -s, s}; // Bottom-right
faceVertices[TOP][3] = new double[]{-s, -s, s}; // Bottom-left
// BOTTOM face (y = s)
faceVertices[BOTTOM][0] = new double[]{-s, s, s}; // Top-left
faceVertices[BOTTOM][1] = new double[]{s, s, s}; // Top-right
faceVertices[BOTTOM][2] = new double[]{s, s, -s}; // Bottom-right
faceVertices[BOTTOM][3] = new double[]{-s, s, -s}; // Bottom-left
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
// Enable antialiasing for smoother rendering
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
// Create background gradient
GradientPaint bgGradient = new GradientPaint(
0, 0, new Color(25, 25, 30),
getWidth(), getHeight(), new Color(10, 10, 15)
);
g2d.setPaint(bgGradient);
g2d.fillRect(0, 0, getWidth(), getHeight());
// Get center of panel for translation
int centerX = getWidth() / 2;
int centerY = getHeight() / 2;
// Apply floating animation effect
double scaleFloat = 1.0 + Math.abs(floatOffset) / 100.0; // Subtle scale change
double yFloat = floatOffset; // Y position offset for floating
// Move to center of panel with floating offset
g2d.translate(centerX, centerY + yFloat);
g2d.scale(scaleFloat, scaleFloat); // Apply subtle scaling
// Calculate visibility of faces based on current rotation
int[] faceVisibility = calculateFaceVisibility();
// Draw faces in order of visibility (back to front)
for (int i = 0; i < 6; i++) {
int face = faceVisibility[i];
drawFace(g2d, face);
}
}
/**
* Calculates which faces are visible and their drawing order
* Uses z-ordering (painter's algorithm) to determine the order
* @return Array of face indices in back-to-front order
*/
private int[] calculateFaceVisibility() {
// Calculate center point of each face after rotation
double[][] faceCenters = new double[6][3];
// Find center of each face by averaging its vertices
for (int face = 0; face < 6; face++) {
double[] center = {0, 0, 0};
// Average all 4 corners to get center
for (int i = 0; i < 4; i++) {
center[0] += faceVertices[face][i][0]; // Sum x coordinates
center[1] += faceVertices[face][i][1]; // Sum y coordinates
center[2] += faceVertices[face][i][2]; // Sum z coordinates
}
center[0] /= 4; // Average x
center[1] /= 4; // Average y
center[2] /= 4; // Average z
// Apply current rotation to center point
double[] rotatedCenter = rotatePoint(center);
faceCenters[face] = rotatedCenter;
}
// Sort faces by z-coordinate
// Faces with smaller z (further back) are drawn first
int[] faceOrder = {0, 1, 2, 3, 4, 5};
// Simple sort by z-coordinate
for (int i = 0; i < 5; i++) {
for (int j = i + 1; j < 6; j++) {
if (faceCenters[faceOrder[i]][2] > faceCenters[faceOrder[j]][2]) {
// Swap indices if z-order is incorrect
int temp = faceOrder[i];
faceOrder[i] = faceOrder[j];
faceOrder[j] = temp;
}
}
}
return faceOrder;
}
/**
* Draws a single face of the cube
* @param g2d Graphics context
* @param face Face index to draw
*/
private void drawFace(Graphics2D g2d, int face) {
// Get the projected 2D points for the face after rotation
Point2D.Double[] projectedPoints = new Point2D.Double[4];
// Apply rotation and projection to each vertex
for (int i = 0; i < 4; i++) {
// Rotate the 3D point according to current rotation angles
double[] rotated = rotatePoint(faceVertices[face][i]);
// Apply perspective projection effect
double scale = 1.2 + rotated[2] / 1000.0; // Scale based on z-depth
// Project 3D point to 2D screen space
projectedPoints[i] = new Point2D.Double(
rotated[0] * scale, // Scale X by perspective factor
rotated[1] * scale // Scale Y by perspective factor
);
}
// Create face outline shape
Path2D.Double facePath = new Path2D.Double();
facePath.moveTo(projectedPoints[0].x, projectedPoints[0].y); // Start at first point
// Connect all points to form the face
for (int i = 1; i < 4; i++) {
facePath.lineTo(projectedPoints[i].x, projectedPoints[i].y);
}
facePath.closePath(); // Close the path
// Draw face background
g2d.setColor(new Color(15, 15, 15));
g2d.fill(facePath);
// Draw face border with gradient effect
GradientPaint borderGradient = new GradientPaint(
(float)projectedPoints[0].x, (float)projectedPoints[0].y, new Color(60, 60, 60),
(float)projectedPoints[2].x, (float)projectedPoints[2].y, new Color(30, 30, 30)
);
g2d.setPaint(borderGradient);
g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.draw(facePath);
// Calculate cell size for 3x3 grid
double cellSize = CUBE_SIZE / 3.0;
// Draw each cell in the 3x3 grid
for (int row = 0; row < 3; row++) {
for (int col = 0; col < 3; col++) {
drawCell(g2d, projectedPoints, row, col, cellSize, face);
}
}
}
/**
* Draws a single cell within a face
* @param g2d Graphics context
* @param facePoints The projected 2D points of the face corners
* @param row Cell row (0-2)
* @param col Cell column (0-2)
* @param cellSize Size of each cell
* @param face Face index
*/
private void drawCell(Graphics2D g2d, Point2D.Double[] facePoints, int row, int col, double cellSize, int face) {
// Calculate the normalized position of this cell (0-1 range within the face)
double u1 = (col) / 3.0; // Left edge position (0, 1/3, or 2/3)
double v1 = (row) / 3.0; // Top edge position (0, 1/3, or 2/3)
double u2 = (col + 1) / 3.0; // Right edge position (1/3, 2/3, or 1)
double v2 = (row + 1) / 3.0; // Bottom edge position (1/3, 2/3, or 1)
// Adjust for gap between cells
double gapRatio = CELL_GAP / cellSize;
u1 += gapRatio / 3; // Move right edge inward
v1 += gapRatio / 3; // Move top edge inward
u2 -= gapRatio / 3; // Move left edge inward
v2 -= gapRatio / 3; // Move bottom edge inward
// Array to hold the cell's corner points
Point2D.Double[] cellPoints = new Point2D.Double[4];
for (int i = 0; i < 4; i++) {
cellPoints[i] = new Point2D.Double(0, 0);
}
// Calculate the cell's corners using bilinear interpolation within the face
// Top-left
interpolate(facePoints, u1, v1, cellPoints[0]);
// Top-right
interpolate(facePoints, u2, v1, cellPoints[1]);
// Bottom-right
interpolate(facePoints, u2, v2, cellPoints[2]);
// Bottom-left
interpolate(facePoints, u1, v2, cellPoints[3]);
// Create path for the cell
Path2D.Double cellPath = new Path2D.Double();
cellPath.moveTo(cellPoints[0].x, cellPoints[0].y);
for (int i = 1; i < 4; i++) {
cellPath.lineTo(cellPoints[i].x, cellPoints[i].y);
}
cellPath.closePath();
// Get base colors from cube model
Color baseColor = cubeModel.getCellColor(face, row, col);
Color darkColor = cubeModel.getCellDarkColor(face, row, col);
// Calculate center point for radial gradient
Point2D.Double center = new Point2D.Double();
center.x = (cellPoints[0].x + cellPoints[1].x + cellPoints[2].x + cellPoints[3].x) / 4;
center.y = (cellPoints[0].y + cellPoints[1].y + cellPoints[2].y + cellPoints[3].y) / 4;
// Calculate maximum distance from center to any corner (for gradient radius)
double maxDist = 0;
for (Point2D.Double point : cellPoints) {
double dist = point.distance(center);
if (dist > maxDist) {
maxDist = dist;
}
}
// Create three-color radial gradient
RadialGradientPaint gradient = new RadialGradientPaint(
center,
(float)maxDist * 1.2f,
new float[]{0.0f, 0.7f, 1.0f},
new Color[]{
brightenColor(baseColor), // Lighter in center
baseColor, // Normal color in middle
darkColor // Darker at edges
}
);
// Fill cell with gradient
g2d.setPaint(gradient);
g2d.fill(cellPath);
// Add subtle inner shadow effect
g2d.setColor(new Color(0, 0, 0, 40)); // 40% opacity black
g2d.setStroke(new BasicStroke(5f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND));
g2d.draw(cellPath);
// Add shine effect (highlight from top-left to center)
Path2D.Double shinePath = new Path2D.Double();
shinePath.moveTo(cellPoints[0].x, cellPoints[0].y);
shinePath.lineTo(cellPoints[1].x, cellPoints[1].y);
// Add midpoints to make highlight area look better
double midX = (cellPoints[1].x + cellPoints[2].x) / 2;
double midY = (cellPoints[1].y + cellPoints[2].y) / 2;
shinePath.lineTo(midX, midY);
midX = (cellPoints[0].x + cellPoints[3].x) / 2;
midY = (cellPoints[0].y + cellPoints[3].y) / 2;
shinePath.lineTo(midX, midY);
shinePath.closePath();
// Create highlight gradient from top-left to center
GradientPaint shineGradient = new GradientPaint(
(float)cellPoints[0].x, (float)cellPoints[0].y, new Color(255, 255, 255, 80),
(float)center.x, (float)center.y, new Color(255, 255, 255, 0)
);
// Apply highlight gradient
g2d.setPaint(shineGradient);
g2d.fill(shinePath);
}
private void interpolate(Point2D.Double[] quad, double u, double v, Point2D.Double result) {
// Bilinear interpolation on a quadrilateral
double nu = 1.0 - u;
double nv = 1.0 - v;
// Interpolate along top and bottom edges
double topX = nu * quad[0].x + u * quad[1].x;
double topY = nu * quad[0].y + u * quad[1].y;
double bottomX = nu * quad[3].x + u * quad[2].x;
double bottomY = nu * quad[3].y + u * quad[2].y;
// Interpolate between top and bottom
result.x = nv * topX + v * bottomX;
result.y = nv * topY + v * bottomY;
}
private Color brightenColor(Color color) {
// Create a brighter version of the color for highlights
float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(), color.getBlue(), null);
float brightness = Math.min(1.0f, hsb[2] + 0.2f);
float saturation = Math.max(0.0f, hsb[1] - 0.1f); // Slightly less saturated
return Color.getHSBColor(hsb[0], saturation, brightness);
}
private double[] rotatePoint(double[] point) {
double[] result = new double[3];
double[] temp = new double[3];
// Apply rotations (in radians)
double radX = Math.toRadians(currentRotationX);
double radY = Math.toRadians(currentRotationY);
double radZ = Math.toRadians(currentRotationZ);
// Copy original point
System.arraycopy(point, 0, temp, 0, 3);
// Rotate around X-axis
result[0] = temp[0];
result[1] = temp[1] * Math.cos(radX) - temp[2] * Math.sin(radX);
result[2] = temp[1] * Math.sin(radX) + temp[2] * Math.cos(radX);
// Copy result to temp
System.arraycopy(result, 0, temp, 0, 3);
// Rotate around Y-axis
result[0] = temp[0] * Math.cos(radY) + temp[2] * Math.sin(radY);
result[1] = temp[1];
result[2] = -temp[0] * Math.sin(radY) + temp[2] * Math.cos(radY);
// Copy result to temp
System.arraycopy(result, 0, temp, 0, 3);
// Rotate around Z-axis
result[0] = temp[0] * Math.cos(radZ) - temp[1] * Math.sin(radZ);
result[1] = temp[0] * Math.sin(radZ) + temp[1] * Math.cos(radZ);
result[2] = temp[2];
return result;
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// Run the application on the Event Dispatch Thread
SwingUtilities.invokeLater(() -> {
try {
// Apply a modern look and feel
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
new RubiksCube().setVisible(true);
});
}
}
The Final Result:
More Java Projects:
Download Projects Source Code




