Maze Board Game (prototype)
in
Contributed Library Questions
•
1 year ago
On the hardware side is a monitor display connected to a rotating mount. Attached to the back of the monitor is a rotary encoder. On the software side is maze processing sketch communicate with arduino which forward the data from rotary encoder to processing sketch.
Boundaries of the maze (full screen mode) would be actually the edges of the screen.
How to ensure that all vertices will be on the right place ? Make all graphics and physics in off-screen buffer and then translate, rotate and place screen buffer in default position ??
BTW, when rotation is faster, green ball penetrates blue fixed rectangle. Is there any way to avoid this?
- import fisica.*;
- public FWorld world;
- public Board board;
- public MazeNode[][] nodes;
- public ArrayList<FBody> rotateUs;
- public FBody body2;
- public float mazeAng;
- public float mouseAng;
- public int offsetX = 0;
- public int offsetY = 0;
- public PFont font48;
- public PFont font36;
- public boolean gamePaused = false;
- public boolean cursorLeftUnpauseCircle = true;
- // constants
- public static final int UI_BAR_HEIGHT = 40;
- public static final float ROT_SPEED = 0.05; // this can be turned up, because the ball is in rotateUs
- public int ROWS = 1;
- public int COLS = 1;
- public int GAP = 500;
- public int rows = ROWS;
- public int cols = COLS;
- public int gap = GAP;
- void setup()
- {
- size(800, 800);
- //size(640,640,P2D); // causes walls to be invisible...?
- smooth();
- // physics stuff
- Fisica.init(this);
- world = new FWorld();
- //world.setGravity(0, 30);
- body2 = new FCircle(50);
- body2.setPosition(width/2, height/4);
- body2.setFill(50, 255, 50);
- body2.setStroke(0);
- body2.setStrokeWeight(3);
- body2.setRestitution(0);
- body2.setFriction(1);
- world.add(body2);
- reset();
- }
- public void reset()
- {
- // stupid hack so changing maze settings in the UI doesn't frak up code (eg - orbiters) that use those settings
- ROWS = rows;
- COLS = cols;
- GAP = gap;
- // end stupid hack
- // offset values describe blank space between applet edges and the edges of the maze
- offsetX = (width - COLS*GAP)/2 + GAP/2;
- offsetY = (height - ROWS*GAP)/2 + GAP/2;
- mazeAng = 0.0;
- mouseAng = 0.0;
- cursorLeftUnpauseCircle = true;
- if (mag(mouseX - (width/2 + width/4 * cos(mazeAng)), mouseY - (height/2 - height/4 * sin(mazeAng))) > 50)
- gamePaused = true;
- else
- gamePaused = false;
- // declare and initialize field of maze nodes/tiles
- nodes = new MazeNode[ROWS][COLS];
- for (int x = 0; x < ROWS; ++x)
- for (int y = 0; y < COLS; ++y)
- nodes[x][y] = new MazeNode();
- world.clear();
- rotateUs = new ArrayList<FBody>();
- board = new Board(nodes);
- board.initTerrain();
- }
- void draw()
- {
- if (!focused) // applet lost focus
- gamePaused = true;
- if (!gamePaused)
- background(255);
- else // if game paused, shade out background and draw unpausing circle
- {
- background(180);
- stroke(0);
- fill(255);
- ellipse(width/2 + width/4 * cos(mazeAng), height/2 - height/4 * sin(mazeAng), 100, 100);
- }
- world.draw();
- if (!gamePaused)
- {
- // calculate angle and rotate maze
- float diffAng = mazeAng - mouseAng;
- // angle adjustments for crossing the 180-degree line
- if (abs(mazeAng - mouseAng + 2*PI) < abs(diffAng))
- diffAng = mazeAng - mouseAng + 2*PI;
- if (abs(mazeAng - mouseAng - 2*PI) < abs(diffAng))
- diffAng = mazeAng - mouseAng - 2*PI;
- board.rotateTerrain(ROT_SPEED*diffAng);
- // end of angle calculation and maze rotation
- // draw difference between maze angle and mouse angle
- float colorScale = abs(diffAng) * 255 / PI;
- fill(colorScale, 0, 255 - colorScale, 60);
- arc(width/2, height/2, width/2, height/2, -mazeAng, -mazeAng + diffAng);
- arc(width/2, height/2, width/2, height/2, -mazeAng + diffAng, -mazeAng);
- // end of draw difference between maze angle and mouse angle
- // fisica functions for drawing and simulating world physics
- world.step();
- }
- // UI bar must be drawn on top, so it's at the bottom
- noStroke();
- fill(0, 80);
- rect(0, 0, width, UI_BAR_HEIGHT);
- }
- void mouseMoved()
- {
- // if mouse is over the UI bar, pause game
- if (mouseY < UI_BAR_HEIGHT)
- gamePaused = true;
- if (!gamePaused) // if game isn't paused rotate maze as normal
- mouseAng = atan2(-(mouseY - height/2), mouseX - width/2);
- else // if game is paused, don't unpause until mouse moves back into highlighted circle
- {
- if (cursorLeftUnpauseCircle && mag(mouseX - (width/2 + width/4 * cos(mazeAng)), mouseY - (height/2 - height/4 * sin(mazeAng))) < 50)
- gamePaused = false;
- else if (!cursorLeftUnpauseCircle && mag(mouseX - (width/2 + width/4 * cos(mazeAng)), mouseY - (height/2 - height/4 * sin(mazeAng))) > 50)
- cursorLeftUnpauseCircle = true;
- }
- }
- class Board
- {
- /* terrain (walls) */
- private MazeNode nodes[][];
- public Board(MazeNode nodes[][])
- {
- this.nodes = nodes;
- }
- public void rotateTerrain(float rotAmt)
- {
- //mazeAng -= rotAmt;
- //mazeAng = mazeAng % (2*PI);
- // linear transformation with matrix T = [[cos, -sin],[sin, cos]]
- // Matrix Theory was a helpful class, yay!
- PVector transX = new PVector(cos(rotAmt), -sin(rotAmt));
- PVector transY = new PVector(sin(rotAmt), cos(rotAmt));
- for (FBody fb : rotateUs)
- {
- fb.adjustRotation(rotAmt);
- PVector v = new PVector(fb.getX() - width/2, fb.getY() - height/2);
- fb.setPosition(v.dot(transX) + width/2, v.dot(transY) + height/2);
- }
- }
- public void initTerrain()
- {
- int row, col;
- // fill in north and west walls for every node
- for (row = 0; row < ROWS; ++row)
- {
- for (col = 0; col < COLS; ++col)
- {
- if (nodes[row][col].walls[0] == 1) // north wall exists
- {
- FBox fb = new FBox(GAP, 10);
- fb.setPosition(col * GAP + offsetX, row * GAP - (GAP/2) + offsetY);
- fb.setStatic(true);
- //fb.setGrabbable(false); // <-- THIS COULD PROVIDE INTERESTING OPPORTUNITIES
- fb.setFill(0);
- rotateUs.add(fb);
- world.add(fb);
- }
- if (nodes[row][col].walls[3] == 1) // west wall exists
- {
- FBox fb = new FBox(10, GAP);
- fb.setPosition(col * GAP - (GAP/2) + offsetX, row * GAP + offsetY);
- fb.setStatic(true);
- //fb.setGrabbable(false); // <-- THIS COULD PROVIDE INTERESTING OPPORTUNITIES
- fb.setFill(0);
- rotateUs.add(fb);
- world.add(fb);
- }
- }
- }
- // fill in the east walls for the last column
- col = COLS - 1;
- for (row = 0; row < ROWS; ++row)
- {
- if (nodes[row][col].walls[1] == 1) // east wall exists
- {
- FBox fb = new FBox(10, GAP);
- fb.setPosition(col * GAP + (GAP/2) + offsetX, row * GAP + offsetY);
- fb.setStatic(true);
- //fb.setGrabbable(false); // <-- THIS COULD PROVIDE INTERESTING OPPORTUNITIES
- fb.setFill(0);
- rotateUs.add(fb);
- world.add(fb);
- }
- }
- // fill in the south walls for the last row
- row = ROWS - 1;
- for (col = 0; col < COLS; ++col)
- {
- if (nodes[row][col].walls[2] == 1) // south wall exists
- {
- FBox fb = new FBox(GAP, 10);
- fb.setPosition(col * GAP + offsetX, row * GAP + (GAP/2) + offsetY);
- fb.setStatic(true);
- //fb.setGrabbable(false); // <-- THIS COULD PROVIDE INTERESTING OPPORTUNITIES
- fb.setFill(0);
- rotateUs.add(fb);
- world.add(fb);
- }
- }
- FBody fb = new FBox(350, 15);
- fb.setPosition(width/2-70, height/2);
- fb.setStatic(true);
- fb.setFill(0, 50, 250);
- fb.setStroke(0);
- fb.setStrokeWeight(3);
- rotateUs.add(fb);
- world.add(fb);
- }
- }
- class MazeEdge
- {
- public int row;
- public int col;
- public int dir; // will be 0 (north) or 3 (west)
- public MazeEdge(int row, int col, int dir)
- {
- this.row = row;
- this.col = col;
- this.dir = dir;
- }
- }
- class MazeNode
- {
- // [0] = north wall
- // [1] = east wall
- // [2] = south wall
- // [3] = west wall
- public int walls[] = {
- 1, 1, 1, 1
- };
- public boolean visited;
- public MazeNode()
- {
- visited = false;
- }
- public String toString()
- {
- return "[" + walls[0] + " " + walls[1] + " " + walls[2] + " " + walls[3] + "]";
- }
- }
1