Still hooked up by the mobile app game Rolly Vortex since last week’s assignment, I decided to take a shot at creating the game.
I started out by trying to create the grey hoops which give the feeling of you being inside a vortex. I struggled with making them because I wanted to create white spaces between each of them, and because I wanted each hoop to restart from the middle after it expands more than the height of the screen. I wanted to do 3D where the z-dimension increases but I wasn’t comfortable enough at the start.
This was how they looked before fixing the distances between each of them, their thickness, and how they restart.
This is the better version where the hoops actually look like a vortex and are quite similar to the game.
I then started to create the ball and I wanted it to be 3D so a sphere instead of an ellipse. But I struggled at first with making sure the ball doesn’t enter the center of the vortex and did it manually, which was still unsuccessful.
I then did the blocks, where I started out by creating them using rectangles and moving their z-coordinate towards the screen to give the feeling of a vortex. However, after so many trial and error, I realized that the pushMatrix() and popMatrix() are quite dangerous if not used properly and that I had so many issues because of them. or example, I couldn’t move the blocks properly while moving the ball as in the video.
After many attempts I was finally able to create 3D boxes which get closer to the screen and to successfully move the ball without touching the center and to properly make a collide function that checks if the ball touches any block. I was able to end and restart the game without errors and to keep score while playing and at the end of the game.
The code for the overall game:
Hoop[] hoops; //list of grey vortex circles float x, y, z; Ball ball; // ball of the player ArrayList<Block> blocks; //array list of obstacle blocks boolean gameOn; //condition under which the game operates PFont f; //text for ending game int score; //score of user, increases with each block block they void setup () { size(1280, 720, P3D); hoops = new Hoop[200]; //instances of the three main classes ball = new Ball(); blocks = new ArrayList<Block>(); blocks.add(new Block(60)); //initial theta in argument gameOn = true; score = 0; f = createFont("Arial",72,true); for (int i =0; i < hoops.length; i++) { //creates the continuous hoops hoops[i] = new Hoop(); } } void draw () { background(255); if (gameOn == true) { for (int i = 0; i < hoops.length; i+= 20) { //draws the hoops and calls the related functions hoops[i].drawHoop(i*10); hoops[i].update(); hoops[i].checkEdge(); } ball.drawBall(); // draws the ball for (int i = blocks.size()-1; i >= 0; i--) { //draws block for each element in the array list Block block = blocks.get(i); block.drawBlock(); } if (frameCount % 60 == 0){ //creates instances of the blocks of number between 1 and 6 randomly for(int i = 0; i < int(random(1,6)); i++) { blocks.add(new Block(int(random(1,12)*30))); if (gameOn == false) {break;} } } score = blocks.size(); //updates the value of score to be number of elements in array list for (int i = blocks.size()-1; i >= 0; i--) { //checks if the ball collided with any block, if true the game stops if (ball.checkCollide(blocks.get(i).posX, blocks.get(i).posY) == true) { gameOn = false; }; } textAlign(CORNER); textFont(f,24); fill(0); text("Score: "+ score,width -120,height -30); //score text bottom right } else { textFont(f,72); fill(#000080); textAlign(CENTER); text("GAME OVER!",width/2,height/2 - 30); textFont(f,24); fill(0); text("CLICK ANYWHERE TO RESTART",width/2,height/2 +30); //game over text textAlign(CORNER); textFont(f,24); fill(0); text("Score: "+ score,width -120,height -30); //final score text } } void mouseClicked() { if (gameOn == false) { score = 0; gameOn = true; for (int i = blocks.size()-1; i >= 0; i--) { Block block = blocks.remove(i); block.drawBlock(); } } }
Code for the Ball() class:
class Ball { float ballWidth, ballHeight; float locX, locY; color ballColor; float speed; int radius; PVector m; PVector circle; float z; float easing = 0.95; Ball() { locX = width/2; locY = height/2; ballWidth = 100; ballHeight = ballWidth; speed = 15; ballColor = color(random(255), random(255), random(255)); radius = 150; z= 0; } void drawBall() { //idea inspired from ellipse constraint code from https://forum.processing.org/one/topic/ellipse-constrain-shape.html fill(#F5F5F5); noStroke(); m = new PVector(mouseX, mouseY, z); //vector of movement of ball circle = new PVector(width/2, height/2, z); //vector circle around which ball is constrained ellipse(circle.x, circle.y, radius, radius); //circle of cosnstrain if (dist(m.x, m.y, circle.x, circle.y) < radius) { m.sub(circle); m.normalize(); m.mult(radius); m.add(circle); //constrains movement of ball to be everywhere except at a distance from teh center of the vortex } locX = locX + (m.x - locX) * easing; locY = locY + (m.y - locY) * easing; //sets the x and y coordinates such that the ball is updated properly and doesn't disappear or enter middle noStroke(); lights(); pushMatrix(); translate(locX, locY - 30, z); fill(ballColor); sphereDetail(36, 36); sphere(30); popMatrix(); //draws the 3D sphere at the updated location //z+= 0.5; } boolean checkCollide(float posX, float posY) { if (dist(locX, locY - 30, posX - 30, posY + 25) < 55) { //if ball touches the x,y coordinates of the block it collides and returns true to end game gameOn = false; return true; } else { return false; } } }
Code for the Block() class:
class Block { float blockWidth, blockHeight, blockDepth; float locXB, locYB, locZ; color a, g, b; float posX, posY; float theta; float speed; Block(int _theta ) { locXB = width/2; locYB = height/2; locZ = 0; blockWidth = 60; blockHeight = 50; blockDepth = 30; a = int(random(255)); g = int(random(255)); b = int(random(255)); //randomized color posX = width/2; posY = height/2; theta = _theta; speed = 6; //speed of shift } void drawBlock() { fill(a, g, b); noStroke(); pushMatrix(); translate(posX, posY, locZ); rotate(radians(theta)); //rotates blocks before moving posX += speed*sin(theta); // horizontal shift posY += speed*cos(theta); //vertical shift box(blockWidth, blockHeight, blockDepth); locZ+= 8; //z-dimension shift towards the screen popMatrix(); } }
Code for the Hoop() class:
class Hoop { float outerHoopWidth, outerHoopHeight; float innerHoopWidth, innerHoopHeight; float locXH, locYH; float speed, acceleration; Hoop () { locXH = width/2; locYH = height/2; outerHoopWidth = 100; //width of circle outerHoopHeight = outerHoopWidth; speed = 5; } void update() { if (outerHoopHeight + 400 == height) { speed = 10; } outerHoopWidth += speed; outerHoopHeight += speed; } void checkEdge() { if (outerHoopHeight + 300 == height) { //if hoop is out of screen then restart it at the middle of the screen outerHoopWidth = 200; outerHoopHeight = 200; } } void drawHoop(int xFactor) { float circle1w = outerHoopWidth + xFactor; //xFactor is to space out the different hoops float circle1h = outerHoopHeight + xFactor; noFill(); stroke(#F5F5F5); strokeWeight(55); ellipse(locXH, locYH, circle1w, circle1h); } }
great job beethoven.