2025-02-23 23:18:27 -05:00

531 lines
14 KiB
Java

import java.util.ArrayList;
import java.util.Random;
import processing.core.PApplet;
import processing.core.PFont;
/*
* To-Do
* Finish Options Menu
* Create animations - Create a before and after grid to compare the movements? Need to animate the new piece too
* Game mode: Timer
*
* */
public class runner extends PApplet{
Random r = new Random();
int[] values = {2, 2, 2, 2, 2, 2, 2, 2, 2, 4};
final double uiy = 0.25;
int yq;
int gridSize = 4;
boolean hasWon = false;
tile grid[][], tempGrid[][];
variables v;
PFont BOLD, REGULAR;
public void settings() {
size(600,800);
}
public void setup() {
surface.setResizable(true); // Is it possible for an "onResize" function?
surface.setTitle("2048");
BOLD = createFont("Arial Bold", 16, true);
REGULAR = createFont("Arial", 16, true);
v = new variables();
resetVars();
frameRate(30);
}
public void draw() {
background(255);
drawGame();
drawUI();
}
public void drawUI() {
int r = 16;
yq = (int) (uiy * height);
fill(250,248,238);
rect(0, 0, width, yq, r, r, r, r);
textAlign(CENTER);
textFont(BOLD);
fill(119,110,101);
drawText("2048", (int) (width * 0.1875), (int) (height * uiy * 0.5), (int) (width / 9.375));
drawText("Score: " + v.gameScore, (int) (width * 0.1875), (int) (height * uiy * 0.7), (int) (width / 15));
fill(255);
v.buttons.get(1).setValues((int) (width * 0.5), (int)(height * uiy * 0.25), (int) (width / 4.8), (int) (height / 10.667), (int) (width / 30)); // This would be better with a window resized listener if the game is ported to a better engine
drawButton(v.buttons.get(1)); // Make this a for loop later.
fill(255);
v.buttons.get(2).setValues((int) ((width * 0.525) + (width / 4.8)), (int)(height * uiy * 0.25), (int) (width / 4.8), (int) (height / 10.667), (int) (width / 30));
drawButton(v.buttons.get(2)); // Make this a for loop later.
if (v.gameOver) {
drawGameOverUI();
}
else if (v.showOptionsUI) {
drawOptionsUI();
}
else if (v.showGameWonUI) {
drawGameWonUI();
}
}
public void drawGameOverUI() {
noStroke();
fill(0,0,0,100);
rect(0, yq, width, height);
drawText("Game Over!", width / 2, height / 2, (int) (width / 12.5), 255);
fill(237,197, 63);
v.buttons.get(0).setValues((int) (width * 0.25), (int) (height * 0.55), (int) (width * 0.5), (int) (height * 0.125), (int) (width / 18.75));
drawButton(v.buttons.get(0));
}
public void drawGameWonUI() {
noStroke();
fill(0,0,0,100);
rect(0, yq, width, height);
drawText("2048!", width / 2, height / 2, (int) (width / 12.5), 255);
fill(237,197, 63);
v.buttons.get(0).setValues((int) (width * 0.25), (int) (height * 0.55), (int) (width * 0.5), (int) (height * 0.125), (int) (width / 18.75));
drawButton(v.buttons.get(0));
fill(237,197, 63);
v.buttons.get(3).setValues((int) (width * 0.25), (int) (height * 0.7), (int) (width * 0.5), (int) (height * 0.125), (int) (width / 18.75));
drawButton(v.buttons.get(3));
}
public void drawOptionsUI() {
noStroke();
// Hidden buttons for the UI
fill(0,0,0,100);
rect(0, yq, width, height);
int xPadding = (int) (width * 0.1);
int yPadding = (int) (height * 0.05);
int r = 16;
int xOptionsArea = (int) (width * 0.05) + xPadding;
int yOptionsArea = (int) (height * 0.1) + yq + yPadding;
fill(255);
rect(xPadding, yq + yPadding, width - (int) (xPadding * 2), (int) (height - yq - yPadding * 2), r, r, r, r);
drawText(v.language[2], xPadding + (int) (width * 0.15), yPadding + yq + (int) (height * 0.05), (int) (width / 18.75), 0);
stroke(5);
line(xPadding + (int) (width * 0.05), yPadding + yq + (int) (height * 0.1), width - (xPadding + (int) (width * 0.05)), yPadding + yq + (int) (height * 0.1));
updateOptionsContext();
// For loop of each option
for (int i = 0; i < v.optionsLanguage.length; i++) {
textAlign(LEFT, TOP);
drawText(v.optionsLanguage[i], xOptionsArea, yOptionsArea + (int) (i * (height * 0.05)), (int) (width * 0.04), 0);
textAlign(RIGHT, TOP);
drawText(v.optionsContext[i], width - xOptionsArea, yOptionsArea + (int) (i * (height * 0.05)), (int) (width * 0.04), 0);
}
fill(0);
for (int i = 0; i < v.optionMenuButtons.size(); i++) {
v.optionMenuButtons.get(i).setValues(xOptionsArea, yOptionsArea + (int) (i * (height * 0.05)), (int) (width - xOptionsArea * 2), (int) (height * 0.04), 1);
}
}
public void updateOptionsContext() {
v.optionsContext[0] = gridSize + " x " + gridSize;
}
/*
* Parameters: Area start X, Area Start Y, Area end X, Area end Y
*/
public boolean isMouseInArea(int x1, int y1, int x2, int y2) {
return (mouseX >= x1 && mouseY >= y1 && mouseX <= x2 && mouseY <= y2);
}
public void mouseClicked() {
for(button x : v.buttons) {
if(isMouseInArea(x.x1, x.y1, x.x2, x.y2)) {
buttonHandler(x);
}
}
for (button x : v.optionMenuButtons) {
if(isMouseInArea(x.x1, x.y1, x.x2, x.y2)) {
buttonHandler(x);
}
}
}
public void buttonHandler(button x) {
if (x.activated) {
if(x.action == "Retry") {
resetVars();
}
else if (x.action == "New Game") {
resetVars();
}
else if (x.action == "Options") {
v.showOptionsUI = !v.showOptionsUI;
}
else if (x.action == "Continue") {
v.showGameWonUI = false;
}
else if (x.action == "Grid Size") {
flipGridSize();
}
}
}
public void flipGridSize() {
if(gridSize == 4) {
setGridSize(5);
}
else {
setGridSize(4);
}
resetVars();
}
public void drawButton(button x) {
rect(x.x1, x.y1, x.xLength, x.yLength, x.r, x.r, x.r, x.r);
textAlign(CENTER, CENTER);
drawText(x.text, (int) ((x.x2 + x.x1)/2), (int) ((x.y1 + x.y2)/2.025), (int) x.fontSize, 0);
}
public void drawGame() {
v.gameXSize = width / gridSize;
v.gameYSize = (height - yq) / gridSize;
double spacing = 0.1;
int xSpacing = (int) (v.gameXSize * spacing);
int ySpacing = (int) (v.gameYSize * spacing);
noStroke();
fill(187, 173, 160);
rect(0, 0, width, height);
strokeWeight(v.gameStrokeSize);
stroke(1);
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
tile temp = grid[i][k];
int cl = tileColor(temp);
fill(v.colors[cl].r, v.colors[cl].g, v.colors[cl].b); // Figure out how Processing generates color code to simplify this.
rect((int) (v.gameXSize * i + xSpacing * 0.5), (int) ((v.gameYSize * k) + yq + ySpacing * 0.5), v.gameXSize - xSpacing, v.gameYSize - ySpacing, 8, 8, 8, 8);
if(!temp.isEmpty()) {
fill(0);
textAlign(CENTER);
drawText(temp.value + "", (int) (v.gameXSize * i + v.gameXSize * 0.5 + xSpacing * 0.5), (int) ((v.gameYSize * k + v.gameYSize * 0.5) + yq + ySpacing * 0.5), 32);
}
}
}
}
public void checkWinConditions() {
for (int i = 0; i < grid.length; i++) {
for (int k = 0; k < grid[0].length; k++) {
if (grid[i][k].value == 2048 && !hasWon && true) {// Replace true with the game mode
hasWon = true;
v.showGameWonUI = true;
}
}
}
}
public int tileColor(tile temp) {
int cl = temp.colorLevel();
if(cl >= v.colors.length)
cl = v.colors.length - 1;
return cl;
}
public int isZero(int x) {
if(x == 0)
return 1;
else
return 0;
}
public void drawText(String stringText, int x, int y, int size) {
textSize(size);
text(stringText, x, y);
}
public void drawText(String stringText, int x, int y, int size, int color) {
fill(color);
textSize(size);
text(stringText, x, y);
}
// Gamey Stuff \/
public void keyPressed() {
if (key == 'r' || key == 'R') {
resetVars();
}
else if (key == 'f' || key == 'F') {
undoMove();
}
else if (key == 't') {
v.showGameWonUI = true;
}
else {
if(!v.gameOver)
moveTiles();
}
}
public void resetVars() {
v.gameScore = 0;
hasWon = false; // Used for checking if win condition has been met before
setGridSize(gridSize);
fillGrid();
resetTempGrid();
createNewTile();
v.gameOver = false;
v.showGameWonUI = false;
v.buttons = new ArrayList<button>();
v.optionMenuButtons = new ArrayList<button>();
for(int i = 0; i < 10; i++) {
if (i < v.language.length) {
v.buttons.add(new button(v.actions[i], v.language[i]));
}
else
v.buttons.add(new button());
}
for(int i = 0; i < v.optionsLanguage.length; i++) {
v.optionMenuButtons.add(new button(v.optionsLanguage[i], ""));
}
v.buttons.get(0).deactivate();
}
public void setGridSize(int x) {
gridSize = x;
grid = new tile[x][x];
}
public void fillGrid() {
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
grid[i][k] = new tile(i, k, 0);
}
}
}
public void resetTempGrid() {
tempGrid = new tile[grid.length][grid[0].length];
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
tempGrid[i][k] = new tile(i, k, 0);
}
}
}
public void undoMove() {
if(grid == tempGrid) {
System.out.println(tempGrid[0][0].value);
}
grid = tempGrid;
}
public void createNewTile() {
int value = values[r.nextInt(values.length)];
ArrayList<tile> possibleTiles = new ArrayList<>();
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
if(grid[i][k].isEmpty()) {
possibleTiles.add(grid[i][k]);
}
}
}
int selectedTile = r.nextInt(possibleTiles.size());
int i = possibleTiles.get(selectedTile).x;
int k = possibleTiles.get(selectedTile).y;
setTile(i, k, value);
}
public boolean canMove() {
return canMoveUp() || canMoveDown() || canMoveRight() || canMoveLeft();
}
public boolean canMoveUp() {
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
if (grid[i][k].moveUp(grid, 0, grid[i][k].value) != 0)
return true;
}
}
return false;
}
public boolean canMoveDown() {
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
if (grid[i][k].moveDown(grid, 0, grid[i][k].value) != 0)
return true;
}
}
return false;
}
public boolean canMoveRight() {
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
if (grid[i][k].moveRight(grid, 0, grid[i][k].value) != 0)
return true;
}
}
return false;
}
public boolean canMoveLeft() {
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
if (grid[i][k].moveLeft(grid, 0, grid[i][k].value) != 0)
return true;
}
}
return false;
}
public void setTile(int i, int k, int val) {
grid[i][k].value = val;
}
public void moveTileUp(int x, int y, int moves, int val) {
setTile(x, y - moves, val);
setTile(x, y, 0);
}
public void moveTileDown(int x, int y, int moves, int val) {
setTile(x, y + moves, val);
setTile(x, y, 0);
}
public void moveTileRight(int x, int y, int moves, int val) {
setTile(x + moves, y, val);
setTile(x, y, 0);
}
public void moveTileLeft(int x, int y, int moves, int val) {
setTile(x - moves, y, val);
setTile(x, y, 0);
}
public void moveTiles() {
boolean moved = false;
int moves = 0;
// Redo this later, Make two tempGrid, if a move is made make this the new temp grid... u know what i mean
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
tempGrid[i][k].value = grid[i][k].value;
}
}
if(keyCode == UP) {
if (canMoveUp())
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
moves = grid[i][k].moveUp(grid, 0, grid[i][k].value);
if(moves != 0 && grid[i][k].value != 0) {
moved = true;
if(moves > 0) {
moveTileUp(i, k, moves, grid[i][k].value);
}
else {
v.gameScore += grid[i][k].value * 2;
moveTileUp(i, k, -moves, grid[i][k].value * 2);
}
}
}
}
}
if (canMoveDown())
if (keyCode == DOWN) {
for(int i = grid.length - 1; i >= 0; i--) {
for(int k = grid[0].length - 1; k >= 0; k--) {
moves = grid[i][k].moveDown(grid, 0, grid[i][k].value);
if(moves != 0 && grid[i][k].value != 0) {
moved = true;
if(moves > 0) {
moveTileDown(i, k, moves, grid[i][k].value);
}
else {
v.gameScore += grid[i][k].value * 2;
moveTileDown(i, k, -moves, grid[i][k].value * 2);
}
}
}
}
}
if (canMoveRight())
if (keyCode == RIGHT) {
for(int i = grid.length - 1; i >= 0; i--) {
for(int k = grid[0].length - 1; k >= 0; k--) {
moves = grid[i][k].moveRight(grid, 0, grid[i][k].value);
if(moves != 0 && grid[i][k].value != 0) {
moved = true;
if(moves > 0) {
moveTileRight(i, k, moves, grid[i][k].value);
}
else {
v.gameScore += grid[i][k].value * 2;
moveTileRight(i, k, -moves, grid[i][k].value * 2);
}
}
}
}
}
if (canMoveLeft())
if (keyCode == LEFT) {
for(int i = 0; i < grid.length; i++) {
for(int k = 0; k < grid[0].length; k++) {
moves = grid[i][k].moveLeft(grid, 0, grid[i][k].value);
if(moves != 0 && grid[i][k].value != 0) {
moved = true;
if(moves > 0) {
moveTileLeft(i, k, moves, grid[i][k].value);
}
else {
v.gameScore += grid[i][k].value * 2;
moveTileLeft(i, k, -moves, grid[i][k].value * 2);
}
}
}
}
}
if (moved) {
createNewTile();
checkWinConditions();
}
if(!canMove()) {
v.gameOver = !canMove();
v.buttons.get(0).activate();
}
}
public static void main(String[] args) {
PApplet.main("runner");
}
}