GAMES TWO: LESSON Fourteen: Cantris: Dealing with Multiple Cans

Dealing with more than one can at a time requires some way of storing many cans. In this applet we will use an array. (A better choice would be a linked list.) In order to deal with this change, the class structure of the game presented in the last lesson was altered a bit. Instead of two classes, there are now three, with many of the responsibilities of the original two classes moved around a bit.

First of all, lets take a look at the revised CAN class (now called CAN3).

import java.awt.*; class CAN3{ Color[] cr={Color.white, Color.white, Color.white}; int x, y; CAN3(Color A, Color B, Color C){ cr[0] = A; cr[1] = B; cr[2] = C; y = 10; x = 60; } public void moveX(int n){ if(x>30 && n == -1){ x-=10; } else if(x<80 && n == 1){ x+=10; } } public void moveY(){ y+=3; } public void draw(Graphics g){ g.setColor(cr[0]); g.fillRect(x,y,10,10); g.setColor(cr[1]); g.fillRect(x,y+10,10,10); g.setColor(cr[2]); g.fillRect(x,y+20,10,10); } }
The CAN class has been simplified to deal only with those functions which are needed by an individual can.

The GRID class created to deal with all the cans involved in the modified game. The array which stores all the cans is contained in this class. The applet class communicates only with the GRID class which, in turn, communicates with the CAN3 class, as necessary.

import java.awt.*; import java.util.*; public class GRID{ CAN3[] cans = new CAN3[40]; CAN3 can = null; int col=3; int bottom[] = {180,180,180,180,180,180}; Color sel[] = { Color.red, Color.blue, Color.cyan, Color.green, Color.magenta, Color.yellow }; int next=0; Random r = new Random(); int cnt; boolean gameOn = true; GRID(){ spawn(); } public void moveX(int m){ if(col>0 && m==-1){ if(test_bottom(m)){ col--; can.moveX(m); } } else if(col<5 && m==1){ if(test_bottom(m)){ col++; can.moveX(m); } } } public void moveY(){ can.moveY(); } //MAKES SURE THAT ARRAY HAS SPACE FOR MORE CANS //THIS IS NOT NECESSARY IF LINKED LIST IS USED public boolean keepPlaying(){ if(cnt>cans.length-1) return false; return gameOn; } //CREATES NEW CAN public void spawn(){ if(cnt<cans.length){ Color c[] = new Color[3]; col = 3; int x = 0; do{ for(int i = 0; i<c.length; i++){ x = Math.abs(r.nextInt()%sel.length); c[i]=sel[x]; } }while(c[0].equals(c[1]) || c[1].equals(c[2]) || c[2].equals(c[0]) ); can = new CAN3(c[0],c[1],c[2]); } cnt++; } //CHECKS TO SEE IF CAN HAS HIT BOTTOM public boolean hit_bottom(){ if(cnt>=cans.length) return true; if(can.y >= bottom[col]){ can.y=bottom[col]; bottom[col]-=30; cans[next]=can; next++; return true; } if(bottom[col]<10) gameOn=false; return false; } //CHECKS TO SEE IF ADJACENT COLUMN IS POPULATED //USED BEFORE MOVING CAN SIDEWAYS //--REMEMBER THAT n CAN BE A NEGATIVE VALUE public boolean test_bottom(int n){ if(can.y < bottom[col+n]) return true; return false; } public void draw(Graphics g){ if(next>0){ for(int i=0; i<next; i++){ cans[i].draw(g); } } can.draw(g); } }
The applet class should only deal with managing the game. There is some stuff in the paint method that should be moved to the GRID class draw method.
import java.awt.*; import java.applet.*; import java.awt.event.*; import java.util.*; public class CC3 extends Applet implements Runnable{ Dimension d; Thread tm; Random r = new Random(); Image offI; int speed = 200; //The array sel should not be part of the applet class Color sel[] = { Color.red, Color.blue, Color.cyan, Color.green, Color.magenta, Color.yellow }; String title[] = { "C", "A", "N", "T", "R", "I", "S" }; GRID grid = new GRID(); public void init(){ d = getSize(); offI=createImage(d.width,d.height); reset(); tm = new Thread(this); tm.start(); requestFocus(); this.addKeyListener(new KeyAdapter(){ public void keyPressed(KeyEvent k) { if(grid.keepPlaying()){ if(k.getKeyCode() == KeyEvent.VK_RIGHT){ grid.moveX(1); } else if(k.getKeyCode() == KeyEvent.VK_LEFT){ grid.moveX(-1); } else if(k.getKeyCode() == KeyEvent.VK_DOWN){ speed=20; } else if(k.getKeyCode() == KeyEvent.VK_UP){ speed=100; } } else{ reset(); } repaint(); } }); } public void reset(){ grid=new GRID(); } public void run(){ while(true){ while(grid.keepPlaying()){ grid.moveY(); if(grid.hit_bottom()){ grid.spawn(); } repaint(); try{ Thread.sleep(speed); }catch(InterruptedException e){}; } } } public void update(Graphics g){ paint(g); } public void paint(Graphics g){ Graphics offG = offI.getGraphics(); offG.setColor(Color.white); offG.fillRect(0,0,d.width,d.height); grid.draw(offG); //should be part of grid class: for(int i=0; i<sel.length; i++){ offG.setColor(sel[i]); offG.fillRect(30+i*10,210,10,10); } offG.setColor(Color.black); offG.drawRect(30,10,60,210); //end of stuff that should be in grid class. offG.setFont(new Font("sansserif", Font.BOLD, 24)); for(int i = 0; i<title.length; i++){ offG.drawString(title[i], 5, 30+30*i); } offG.setFont(new Font("sansserif", Font.PLAIN, 12)); if( grid.keepPlaying() ) offG.drawString("Keep playing.",20,d.height-5); else offG.drawString("Press 'r'.", 20, d.height-5); g.drawImage(offI, 0, 0, this); } }


ASSIGNMENT:

Move all functions necessary for drawing the grid over to the GRID class.