Please review this code

Takwas

Honorable
Nov 15, 2012
8
0
10,510
I'm learning Java and this is what I've been able to come up with.

Please take a look at my code and tell me about the wrong approaches I've employed
(Apart from the lack of comments).

Also:
--tell me the good habits I should keep-up with.
--What does line 163 do?
--How do I make the keyboard control the player (My **keyPressed()** method doesn't work)

There are five Classes: Is it OO enough?



Class 1:
Code:
    //SpaceInvaders.java    
    //This is the main class that runs the Applet
	
    package space_game;
	
	import acm.program.*;
	import acm.graphics.*;
	import acm.util.*;
	
	import java.applet.AudioClip;
	import java.awt.Color;
	import java.awt.event.*;
	import java.util.ArrayList;
	
	public class SpaceInvaders extends GraphicsProgram{
	
		private static final int APP_WIDTH = 1100;
		private static final int APP_HEIGHT = 600;
		
		private static final int GAME_BOARD_WIDTH = 800;
		private static final int GAME_BOARD_HEIGHT = 400;
		
		
		private static final double BULLET_DIM = 3;
		private static final double PLAYER_WIDTH = 15;
		private static final double PLAYER_HEIGHT = 5;
		private static final double INVADER_WIDTH = 9;
		private static final double INVADER_HEIGHT = 12;
		private static final int PADDING = 5;
		
		
		private static final Color BG_COLOR = Color.WHITE;
		private static final Color BULLET_COLOR = Color.ORANGE;
		private static final Color PLAYER_COLOR = Color.GREEN;
		
		//private static final Color INVADER_COLOR = Color.LIGHT_GRAY;
		
		private GameBoard board;
		private GRect[] backGround;
		private GRect playArea;
		private Color[] boardCols;
		private Player player = new Player(PLAYER_WIDTH, PLAYER_HEIGHT,PLAYER_COLOR);
		private ArrayList<Bullet> bullet = new ArrayList<Bullet>();
		private Invader invader[];
		private int curBullet = 0;
		private double totalBullets = 0.0;
		private int level = 0;
		private double score = 0;
		private double speed;
		
		private Invader.Type type;
		private Bullet.Type bType;
		
		private RandomGenerator rgen = new RandomGenerator();
		private double yCord;
		private int invadersRemovalCount = 0;
		private int totalInvadersRemoved = 0;
		private boolean gamePaused;
		private boolean gameOver;
		
		private AudioClip coming;
		private AudioClip invaded;
		private AudioClip shoot;
		private AudioClip killed;
		
		public void init(){
			resize(APP_WIDTH, APP_HEIGHT);
			setBackground(BG_COLOR);
			
			addMouseListeners();
			
			backGround = new GRect[4];
			
			boardCols = new Color[4];
			boardCols[0] = Color.BLACK;
			boardCols[1] = Color.BLUE;
			boardCols[2] = Color.GRAY;
			boardCols[3] = Color.WHITE;
			
			speed = 0.3;
			bType = Bullet.Type.BALLER;
			
			coming = MediaTools.loadAudioClip("audio/CrayonRock.au");
			invaded = MediaTools.loadAudioClip("audio/OnTheHunt.au");
			shoot = MediaTools.loadAudioClip("audio/gun.au");
			killed = MediaTools.loadAudioClip("audio/tweeters.au");
			
			gamePaused = false;
			gameOver = false;
		}
		
		public void run(){
			
			setup();
			int scoreChecker;
			
			while(true){
				
				if(level_1()){
					type = Invader.Type.PAWN;
					bType = Bullet.Type.BALLER;
					scoreChecker = 1;
				}			
				else if(level_2()){
					type = Invader.Type.KNIGHT;
					bType = Bullet.Type.BALLER;
					speed = 0.2;
					scoreChecker = 2;
				}
				else if(level_3()){
					type = Invader.Type.QUEEN;
					bType = Bullet.Type.SNIPER;
					speed = 0.1;
					scoreChecker = 3;
				}
				else {
					coming.stop();
					coming = MediaTools.loadAudioClip("audio/BussaMove.au");
					coming.loop();
						break;
				}
				score *= scoreChecker;
				board.updateInfo(1, String.valueOf((int) score));
				
				createInvaders(new GPoint((playArea.getX()+playArea.getWidth())-PADDING, playArea.getY()+PADDING), playArea.getWidth(), playArea.getHeight()-PADDING, type, rgen.nextInt((int) (APP_HEIGHT*0.03), (int) (APP_HEIGHT*0.05)));
				
				board.updateInfo(2, String.valueOf(level+1).concat(" / 10"));
				
				invadersRemovalCount = 0;
				moveInvaders(invader);
				
				level++;
							
			}
			gameOver = true;
			reset();
	
		}
	
		private void setup(){
	
			board = new GameBoard(GAME_BOARD_WIDTH, GAME_BOARD_HEIGHT, boardCols ,">>>SP4C3 INV4D3RS<<<", PADDING, 13, "Invaders Exterminated: ", "Bullets Used: ");
			add(board, (getWidth()-board.getWidth())/2, (getHeight()-board.getHeight())/2);
			playArea = new GRect(board.getX(), board.getY()+(board.getHeight()*0.15), board.getWidth(), board.getPlayArea().getHeight());
			
			backGround[0] = new GRect(APP_WIDTH, APP_HEIGHT);
			backGround[0].setFilled(true);
			backGround[0].setColor(boardCols[2]);
			add(backGround[0], 0, 0);
			
			backGround[1] = new GRect(APP_WIDTH, APP_HEIGHT);
			backGround[1].setFilled(true);
			backGround[1].setColor(getBackground());
			add(backGround[1], 0, playArea.getY());
			
			backGround[2] = new GRect(APP_WIDTH, APP_HEIGHT);
			backGround[2].setFilled(true);
			backGround[2].setColor(boardCols[2]);
			add(backGround[2], 0, getYEnd(playArea));
	
			
			add(playArea);
			playArea.setVisible(false);
			playArea.addMouseMotionListener(this);
			board.sendToFront();
			
			add(player, board.getX()+PADDING, (playArea.getY()+(playArea.getHeight()*0.5)));
			
			backGround[3] = new GRect(0,0);
			backGround[3].setBounds(board.getPauseButton().getBounds());
			backGround[3].setLocation(playArea.getX()+((playArea.getWidth()-backGround[3].getWidth())/2), (playArea.getY()-((board.getStatusArea().getHeight()-backGround[3].getHeight())/2)-backGround[3].getHeight()));
			add(backGround[3]);
			//backGround[3].setVisible(false);
			           
			coming.loop();
			
		}
		
		private void createInvaders(GPoint pos, double wdt, double hgt, Invader.Type type, int numInvaders){
			invader = new Invader[numInvaders];
			for(int i=0; i<numInvaders; i++){
				invader[i] = new Invader(INVADER_WIDTH, INVADER_HEIGHT, type);
				add(invader[i], pos.getX()+rgen.nextDouble(0.0, wdt*0.25), pos.getY()+((hgt/numInvaders)*i));
				invader[i].setVisible(false);
			}
			
		}
		
		private void moveInvaders(Invader[] inv){
			int i ;
			while(true){
				if(gamePaused){
					board.changeState();
					waitForClick();
					board.changeState();
				}
				
				gamePaused = false;
				if (!bullet.isEmpty())
					for(int j=0; j<bullet.size(); j++){
						bullet.get(j).move(2, 0);
						
						if(collides(bullet.get(j), inv) || bullet.get(j).getX()>=getXEnd(playArea))
							remove(bullet.get(j));
				}
				
				if(invadersExited(inv, invadersRemovalCount)){
					invaded.play();	
						if(levelChanging()){
							reset();	
						}
					break;
				}
				
				for(i=0; i<inv.length; i++){
					inv[i].move(-1, 0);
					
					if(xIsInPlayArea(inv[i].getX(), inv[i].getWidth())){
						inv[i].setVisible(true);
					}
					
					if(!inv[i].isDead() && inv[i].getX()<=playArea.getX()){
						inv[i].changeState();
						remove(inv[i]);
	
						invadersRemovalCount++;
					}
					
				}
				
				pause(100*speed);
				animatebottomBar();
			}
			for(i=0; i<inv.length; i++){
				remove(inv[i]);
			}
			
		}
		private void animatebottomBar() {
			board.name.move(-1, 0);
			if(board.name.getX()<board.getPlayArea().getX())
				board.name.setLocation(getXEnd(board.getPlayArea()), board.name.getY());
		}
		
		
		private boolean levelChanging(){
			return (level==2||level==5||level==9);
		}
		
		private boolean collides(Bullet b, Invader[] inv){		
			
			for(int i =0; i<inv.length; i++){
				if(!inv[i].isDead() && (inv[i].contains(b.getX()+b.getWidth()*0.9, b.getY()+b.getHeight()) || inv[i].contains(b.getX()+b.getWidth()*0.9, b.getY()+b.getHeight()))){
					inv[i].hit();
					
					if(inv[i].maxHitReached()){
						inv[i].changeState();
						killed.play();
						
						remove(inv[i]);
						invadersRemovalCount++;
						
						totalInvadersRemoved++;
						score = ((totalInvadersRemoved/totalBullets)*1000);
						board.updateInfo(3, "Invaders Exterminated: "+totalInvadersRemoved);
						board.updateInfo(1, String.valueOf((int) score));
					}
					return true;
				}
			}	
			return false;
		}
		
		private boolean invadersExited(Invader[] inv, int count){
			return count == inv.length;
			
		}
		
	
		private boolean level_1(){
			return level<3;
		}
		
		private boolean level_2(){
			return level<6;
		}
		
		private boolean level_3(){
			return level<10;
		}
		
		public void keyPressed(KeyEvent k){
			if(k.getKeyCode() == KeyEvent.VK_ENTER)
				shoot();
			if(k.getKeyCode() == KeyEvent.VK_UP)
				player.move(0,-1);
			if(k.getKeyCode() == KeyEvent.VK_DOWN)
				player.move(0,1);
			
			shoot();
			showStatus("..."+k.getKeyCode());
		}
		
		public void mouseClicked(MouseEvent e){
			
			if(backGround[3].contains(e.getX(), e.getY())){
				
				gamePaused = true;
				//((GCompound) getElementAt(e.getX(), e.getY())).scale(50);
			}
		}
		
		public void mousePressed(MouseEvent e){
			if(!gameOver){
				shoot();
			}
		}
		
		public void mouseMoved(MouseEvent e){
		
			if(yIsInPlayArea(player.getY(), player.getHeight())){
				player.move(0, e.getY()-yCord);
				yCord = e.getY();
			}
			
			if(outUpwards(player.getY())){
				player.move(0, 2);
			}
			if(outDownwards(getYEnd(player))){
				player.move(0, -2);
			}		
			
		}
		
		public void mouseEntered(MouseEvent e){
			player.setLocation(player.getX(), e.getY());
		}
		
		private void shoot(){
			switch(bType){
			case SNIPER:
				bullet.add(new Bullet(BULLET_DIM,Color.WHITE, bType));
				break;
			default:
				bullet.add(new Bullet(BULLET_DIM,BULLET_COLOR, bType));
				break;
			}
			
			add(bullet.get(curBullet), player.getX()+player.getWidth(), player.getY());
			
			if(yIsInPlayArea((bullet.get(curBullet).getY()), bullet.get(curBullet).getHeight())){	
				shoot.play();
				curBullet++;
				totalBullets++;
				score = ((totalInvadersRemoved/totalBullets)*1000);
				board.updateInfo(4, "Bullets Used: ".concat(String.valueOf((int) totalBullets)));
				board.updateInfo(1, String.valueOf((int) score));
			}
	
			else{
				bullet.get(curBullet).sendToBack();
			}
				
		}
		
		private boolean xIsInPlayArea(double x, double wdt){
			return  (playArea.getX()<=x)&&((playArea.getX()+playArea.getWidth()>=x+wdt));
		}
		
		private boolean yIsInPlayArea(double y, double hgt){
			return  (playArea.getY()<=y)&&((playArea.getY()+playArea.getHeight()>=y+hgt));
		}
		
		private boolean outUpwards(double y){
			return playArea.getY()>y;
		}
	
		private boolean outDownwards(double y){
			return playArea.getY()+playArea.getHeight()<y;
		}
		
		private double getXEnd(GObject g){
			return g.getX()+g.getWidth();
		}
		
		private double getYEnd(GObject g){
			return (g.getY()+g.getHeight());
		}
		
		private void reset(){
			for(int j=0; j<bullet.size(); j++){
				remove(bullet.get(j));
			}
			bullet.clear();
			curBullet = 0;
			board.name.setLocation((board.getPlayArea().getX()+(board.getPlayArea().getWidth()-board.name.getWidth())/2), board.name.getY());
			
			showStatus("RESET CARRIED OUT!");
		}
	}



Class 2:
Code:
    //Player.java creates a shooting object [a Gun]
	
    package space_game;
	
	import acm.graphics.*;
	import java.awt.Color;
	
	public class Player extends GCompound{
	
		private GRect player;
		
		public Player(double wdt, double hgt, Color col1, Color col2){
			player = new GRect(wdt, hgt);
			player.setFilled(true);
			player.setColor(col1);
			player.setFillColor(col2);
			add(player, 0,0);
			
			player = new GRect(wdt*0.4, hgt*0.7);
			player.setFilled(true);
			player.setColor(col1);
			player.setFillColor(col2);
			add(player, 0,hgt);
			
			player = new GRect(wdt*0.2, hgt*0.5);
			player.setFilled(true);
			player.setColor(col1);
			player.setFillColor(col2);
			add(player, 0,hgt*1.7);
		}
		
		public Player(double wdt, double hgt, Color col){
			this(wdt, hgt, col, col);
		}
		
		public Player(double wdt, Color col){
			this(wdt,wdt,col);
		}
	}


Class 3:
Code:
    //Bullet.java creates the bullet fired by the gun above
	
    package space_game;
	
	import acm.graphics.*;
	import java.awt.Color;
	
	public class Bullet extends GCompound{
	
		private GOval bullet;
		private GOval[] bulletArr = new GOval[4];
		private Type type;
		
		public Bullet(double dia, Color col){
			this(dia, col, col, Type.BALLER);
		}
		
		public Bullet(double dia, Color col, Type t){
			this(dia, col, col, t);
		}
		
		public Bullet(double dia, Color col1, Color col2, Type t){
			type = t;
			
			
			switch(type){
			case BALLER:
				bullet = new GOval(dia,dia);
				bullet.setFilled(true);
				bullet.setColor(col1);
				bullet.setFillColor(col2);
				add(bullet, 0 ,0);
				
				break;
			
			case SNIPER:
				
				dia*=2;
				for(int i = 0; i<4; i++){
					bulletArr[i] = new GOval(dia*((i+1)*(0.55)),dia*((i+1)*(0.2)));
					bulletArr[i].setFilled(true);
					bulletArr[i].setColor(col1);
					bulletArr[i].setFillColor(col2);
					
					switch(i){
					case 0:
						add(bulletArr[0], 0 ,0);
						break;
					default:
						add(bulletArr[i], bulletArr[i-1].getWidth()*0.9 , -bulletArr[i-1].getHeight()*0.5);
						break;
					}
					
				}
				break;
			}
		}
		
		public enum Type{
			BALLER, SNIPER
		} 
	}


Class 4:
Code:
    //Invader.java creates an enemy object
	
    package space_game;
	
	import acm.graphics.*;
	import acm.util.ErrorException;
	
	import java.awt.Color;
	
	public class Invader extends GCompound{
	
		private GPolygon invader;
		private Color bodyColor;
		private Color skinColor;
		private int hits;
		private Type type;
		private State state;
		
		public Invader(double wdt, double hgt, Color col1, Type t){
			switch(t){
			case PAWN:
				type = Type.PAWN;
				bodyColor = Color.PINK;
				break;
			case KNIGHT:
				type = Type.KNIGHT;
				bodyColor = Color.MAGENTA;
				break;
			case QUEEN: 
				type = Type.QUEEN;
				bodyColor = Color.RED;
				wdt*=1.5;
				hgt*=1.5;
				break;
			default: throw new ErrorException("Invalid Type!");
			}
			
			hits = 0;
			state = State.ALIVE;
			skinColor = col1;
			invader = new GPolygon();
			
			invader.addVertex(-wdt, hgt*0.125);
			invader.addEdge(wdt*0.5, hgt*0.125);
			invader.addEdge(-wdt*0.5, hgt*0.125);
			invader.addEdge(wdt*0.5, hgt*0.125);
			invader.addEdge(-wdt*0.5, hgt*0.125);
			invader.addEdge(wdt*0.5, hgt*0.125);
			invader.addEdge(-wdt*0.5, hgt*0.125);
			invader.addEdge(wdt, hgt*0.125);
			invader.addVertex(0,0);
			
			
			invader.setFilled(true);
			invader.setColor(skinColor);
			invader.setFillColor(bodyColor);
			add(invader, 0,0);
		}
		
		public Invader(double wdt, double hgt, Type t){
			this(wdt, hgt, Color.BLACK, t);
		}
		
		public Invader(double wdt, Color col, Type t){
			this(wdt,wdt,Color.BLACK,t);
		}
		
		public void setType(Type t){
			
			switch(t){
			case PAWN:
				bodyColor = Color.PINK;
				type = Type.PAWN;
				break;
			case KNIGHT:
				bodyColor = Color.MAGENTA;
				type = Type.KNIGHT;
				break;
			case QUEEN: 
				bodyColor = Color.RED;
				type = Type.QUEEN;
				break;
			default: throw new ErrorException("Invalid Type!");
			}
		
		}
		
		public void hit(){
			this.hits++;
		}
	
		public int getHits(){
			return hits;
		}
		
		public boolean maxHitReached(){
			switch (this.type){
			case PAWN:
				return(this.hits==2);
			case KNIGHT:
				return(this.hits==4);
			case QUEEN:
				return(this.hits==4);
			default:
				return false;
			}
		}
		
		public void changeState(){
			if(state == State.ALIVE)
				state = State.DEAD;
			else{
				state = State.ALIVE;
			}
		}
		
		public boolean isDead(){
			return (state == State.DEAD);
		}
	
		public enum Type{
			PAWN, KNIGHT, QUEEN
		}
		
		public enum State{
			ALIVE, DEAD
		}
	}



Class 5:
Code:
    //GameBoard.java creates a game-board that can be used by other 2d 'arcade' games
	package space_game;
	
	/**
	 * >>>[File: GameBoard.java]<<<
	 * [=======================]
	 * 
	 * Creates a Game-Board Template
	 * 
	 * [=======================]
	 * 
	 * This is an arcade-style-GameBoard Java class.
	 * The Game-Board objects created from here can
	 * be used by various game objects from other 
	 * classes
	 * 
	 * [================================================]
	 * 
	 * @author ac3Takwas
	 * 
	 */
	import acm.graphics.*;
	
	import java.awt.Color;
	
	public class GameBoard extends GCompound{
	
		/*Declaration of instance variables*/
	
		private GRect statusArea;
		private GRect pauseButton;
		private GRoundRect playArea;
		private GRoundRect bottom;
		public GLabel name;
		private GLabel scoreArea;
		private GLabel level;
		private GLabel info_1;
		private GLabel info_2;
		private GLabel pauseLabel;
		private int padding;
		
		
		
		/**
		 * Constructs a Game-Board given the listed parameters.
		 * @param width
		 * @param height
		 * @param col
		 * @param gameName
		 * @param padding
		 * @param statusFont
		 * @param info_1
		 * @param info_2
		 */
		public GameBoard(double width, double height, Color[] col, String gameName, int padding, int statusFont, String info_1, String info_2){
		
			playArea = new GRoundRect(width, height*0.75);
			statusArea = new GRect(playArea.getWidth()-(playArea.getArcWidth()*2), height*0.15);
			bottom = new GRoundRect(playArea.getWidth(), height*0.1);
			
			pauseLabel = new GLabel("PAUSE");
			this.padding = padding;
			createCanvas(height, col);
	
			addBoardElements(col, gameName, padding, statusFont, info_1, info_2);
			
			addPauseButton(col, width, padding, statusFont);
		}
	
		
		/**
		 * Creates the Game-Board canvas when called by a Constructor
		 * [========================================================]
		 * 
		 * @param hgt
		 * @param colorPack
		 */
		private void createCanvas(double hgt, Color[] colorPack){
			statusArea.setFilled(true);
			statusArea.setFillColor(colorPack[1]);
			statusArea.setColor(colorPack[0]);
			
			playArea.setFilled(true);
			playArea.setFillColor(colorPack[0]);
			playArea.setColor(colorPack[1]);
			
			bottom.setFilled(true);
			bottom.setFillColor(colorPack[1]);
			bottom.setColor(colorPack[0]);
			
			add(statusArea, playArea.getArcWidth(), 0);
	
			add(playArea, 0, hgt*0.15);
			
			add(bottom, 0, playArea.getY()+playArea.getHeight());
	
		}
			
		/**
		 * Adds the various screen elements to the already drawn canvas.
		 * For instance the element that displays the game score is created
		 * by this method
		 * [===============================================================]
		 * 
		 * @param colorPack
		 * @param gameName
		 * @param padding
		 * @param statusFont
		 * @param info_1
		 * @param info_2
		 */
		private void addBoardElements(Color colorPack[], String gameName, int padding, int statusFont, String info_1, String info_2) {
			addTopLevelElements(colorPack, padding, statusFont, info_1, info_2);
			
			addBottomLevelElements(colorPack, gameName);
					
		}
		
		/*Adds the Game-Board elements displayed at the top of the Playing-Area*/
		private void addTopLevelElements(Color[] colorPack, int padding, int statusFont, String info_1, String info_2) {
			scoreArea = new GLabel("SCORE: 0");
			scoreArea.setFont("Courier-BOLD-"+statusFont);
			scoreArea.setColor(colorPack[3]);
			add(scoreArea, ((statusArea.getY()+statusArea.getWidth())-((scoreArea.getWidth())+padding)), statusArea.getY()+padding+scoreArea.getAscent());
			
			level = new GLabel("LEVEL: 1");
			level.setFont("Courier-BOLD-"+statusFont);
			level.setColor(colorPack[3]);		
			add(level, ((statusArea.getY()+statusArea.getWidth())-((level.getWidth())+padding)), (statusArea.getY()+statusArea.getHeight())-(padding/2));
			
			if(info_1 != null){
				this.info_1 = new GLabel(""+info_1);
				this.info_1.setFont("Courier-BOLD-"+statusFont);
				this.info_1.setColor(colorPack[3]);
				add(this.info_1, (playArea.getArcWidth())+padding, statusArea.getY()+padding+this.info_1.getAscent());
			}
			
			if(info_2 != null){
				this.info_2 = new GLabel(""+info_2);
				this.info_2.setFont("Courier-BOLD-"+statusFont);
				this.info_2.setColor(colorPack[3]);
				add(this.info_2, (playArea.getArcWidth())+padding, (statusArea.getY()+statusArea.getHeight())-(padding/2));
			}
	
		}
	
		/*Adds the Game-Board elements displayed at the bottom of the Playing-Area*/
		private void addBottomLevelElements(Color[] colorPack, String gameName) {
			name = new GLabel(gameName);
			name.setFont("Courier-BOLD-15");
			name.setColor(colorPack[2]);
			
			add(name, (getWidth()-name.getWidth())/2, (bottom.getY()+bottom.getHeight())-bottom.getArcHeight());
	
			
		}
		
		
		/**
		 * Creates and adds the button that pauses and resumes the game
		 * [==========================================================]
		 * 
		 * @param col
		 * @param width
		 * @param padding
		 * @param statusFont
		 */
		private void addPauseButton(Color[] col, double width, int padding, int statusFont) {
			pauseLabel.setFont("Courier-BOLD-"+statusFont);
			pauseLabel.setColor(col[3]);
			
			pauseButton = 	new GRect(pauseLabel.getWidth()+padding*2, pauseLabel.getAscent()+padding*2);
			pauseButton.setFilled(true);
			pauseButton.setFillColor(col[2]);
			pauseButton.setColor(col[0]);
			add(pauseButton, (getWidth()-pauseButton.getWidth())/2, (statusArea.getHeight() - pauseButton.getHeight())/2);
			
			add(pauseLabel, pauseButton.getX()+padding, pauseButton.getY()+padding+pauseLabel.getAscent());
			
		}
		
		@Override
		public void repaint(){
			
		}
	
		public boolean isInPlayArea(GObject g){
			return  contains(playArea, g);
		}
		
		/**
		 * @param g1
		 * @param g2
		 * @return true if g1 contains g2
		 */
		private boolean contains(GObject g1, GObject g2){
			return  (g1.getY()<=g2.getY())&&((g1.getY()+g1.getHeight()>=g2.getY()+g2.getHeight())) 
					&&
					(g1.getX()<=g2.getX())&&((g1.getX()+g1.getWidth()>=g2.getX()+g2.getWidth()));
		}
		
		public boolean yIsInPlayArea(double y, double hgt){
			return  (this.playArea.getY()<=y)&&((this.playArea.getY()+this.playArea.getHeight()>=y+hgt));
		}
		
		public boolean xIsInPlayArea(double x, double wdt){
			return  (this.playArea.getX()<=x)&&((this.playArea.getX()+this.playArea.getWidth()>=x+wdt));
		}
		
		public boolean outUpwards(double y){
			return this.playArea.getY()>y;
		}
	
		public boolean outDownwards(double y){
			return this.playArea.getY()+this.playArea.getHeight()<y;
		}
		
		public GObject getPlayArea(){
			return this.playArea;
		}
		public GObject getPauseButton(){
			return this.pauseButton;
		}
		public GObject getStatusArea(){
			return this.statusArea;
		}
		
		public void changeState(){
			if(pauseLabel.getLabel().equalsIgnoreCase("Start")){
				pauseLabel.setLabel("PAUSE");
			}
			else{
				pauseLabel.setLabel("START");
			}
			
			repaint();
		}
		
		
		public void updateInfo(int index, String str){
			
			switch(index){
			case 1:
				scoreArea.setLabel("SCORE: "+str);
				scoreArea.setLocation((statusArea.getY()+statusArea.getWidth())-((scoreArea.getWidth())+padding), scoreArea.getY());
				break;
			case 2:
				level.setLabel("LEVEL: "+str);
				level.setLocation((statusArea.getY()+statusArea.getWidth())-((level.getWidth())+padding), level.getY());
				break;
			case 3:
				info_1.setLabel(""+str);
				break;
			default:
				info_2.setLabel(""+str);
				break;
			}
			
			repaint();
		}
		
	
	}
 
Solution


It can be improved. You have a class Invader which has several different types, each which behave slightly differently (eg. they all have different max hits and different colours). You are using an enum to switch the behaviour of the class when you should be extending Invader instead. Each derived class can then override the methods and fields of the Invader class which differ depending on the type, while the common members will only be defined once in the parent class.

The rest of your application can then, for the most part, continue to work with Invader objects since derived classes are still valid Invader instances. It won't have to keep using switches and other checks to see what...

Sunius

Distinguished
Dec 19, 2010
390
0
19,060
No idea what that means, because GRect class isn't defined in your source code. However, in the future I'd advice naming variables so it would be clear what they are made for from their names.
 

Takwas

Honorable
Nov 15, 2012
8
0
10,510


Sorry, I don't quite understand you.

GRect (which creates a rectangle) is not defined by me. It's defined in the ACM package which I imported.

What's wrong with my naming convention?
 

Sunius

Distinguished
Dec 19, 2010
390
0
19,060
For example, take Player class. It's confusing it has field 'player'. Also, there are some variable in GCompound that uses shortenings of words and it's hard to understand them (like bulletArr). And generally, I don't think you want to define same objects inside of class (like bullet inside Bullet class). Bullet class should consist of fields about one bullet and when you write
Code:
Bullet bullet = new Bullet()
then a single bullet is created.
 

Takwas

Honorable
Nov 15, 2012
8
0
10,510



Thanks. That's noted.
 

randomizer

Distinguished


It can be improved. You have a class Invader which has several different types, each which behave slightly differently (eg. they all have different max hits and different colours). You are using an enum to switch the behaviour of the class when you should be extending Invader instead. Each derived class can then override the methods and fields of the Invader class which differ depending on the type, while the common members will only be defined once in the parent class.

The rest of your application can then, for the most part, continue to work with Invader objects since derived classes are still valid Invader instances. It won't have to keep using switches and other checks to see what type it's working with because it doesn't care, since each derived class of Invader takes care of its own peculiarities internally.

This also applies to any other similar usages of enums to define types, like the Bullet class.
 
Solution

Takwas

Honorable
Nov 15, 2012
8
0
10,510



Thanks for pointing that out randomizer. I would like to ask if the new Invader superClass is what is called an Abstract class.

Also, if you were to run the updated version of my code which is posted as one of the comments (NOT THE ORIGINAL POST!) in here:

http://www.dreamincode.net/forums/topic/302496-im-unable-to-access-a-member-from-an-object-properly/

You will find out that as the levels get increased the game speed gets slower instead of the contrary. I've looked at my code but nothing seems to be wrong with. Could it be a problem with my CPU or an increased number of computations.
 

randomizer

Distinguished


Only if you declare it as such. Abstract classes are classes that can't be instantiated; that is, you can't call the constructor for one. you are only able to call the constructor for its derived classes (unless they are also marked as abstract and have their own derived classes). A class that has derived classes does not necessarily need to be abstract, there are uses for both abstract and normal classes. A common example for needing an abstract class would be if you want to force all derived classes to provide their own implementation of one or more methods. The method would need to be abstract as well as the parent class that declares it.



I don't have the Java compiler installed so I can't actually run it myself. If you have a notably faster or slower computer available you could test it on that to see if it is getting slower because your game speed logic is wrong or due to performance problems (a slow PC will slow down more quickly and vice versa for a faster PC). You might also want to run it against a performance profiler and look for locations in the code where the CPU is spending too much time.
 

Takwas

Honorable
Nov 15, 2012
8
0
10,510



Alright thanks.

BTW, I'm already building in more functionality into the game and yes most of the superclasses are declared abstract (cos I wrote some abstract methods).

Also I'm learning about simulating multiple inheritance with Interfaces, so I've also used a few interfaces like Killable, Shooter...

Indeed, it looks a lot more Object - Oriented with all these new implementations. I really appreciate the fact that you pointed-out about the need for more classes.


In general, it's fun!




----------------------******************------------------
Code:
while (ALIVE) {
    idea ++;
    implement (idea);
}

----------------------******************-----------------