0

I made a simple game on a grid in java that involves controlling a white square with the WASD keys. Whenever I press W,S,A, or D, the screen sometimes flickers before drawing the grid again. I am fairly new to coding, so the more you can dumb it down for me, the better.

import java.applet.*;
import java.awt.*;
import java.awt.event.*;
/**
 * DotGame.applet
 * 
 * A simple game where the player controls a white circle with the WASD keys.
 *  - If the user moves his circle over a green circle, his score will go up by 1, and another red circle will spawn.
 *  - If the user moves his circle over a red circle, his score will go down by 1, and one less red circle will be generated.
 *  - There is no win condition, it is just a test game.
 *  
 * @author -----------
 * @version 11-9-2014 
 */

public class DotGame extends Applet
implements KeyListener, MouseListener
{
int width,height;
int powerup = 1;
int click = 0;
int x,y;
final int size = 40;
int ox = size,oy = size;
int rx = 0, ry = 0;
int reddots = 0;
int red[][] = new int[1000][2];
String s = "";
int score = 0;
int DrawGrid = 0;
String sc = "";
int powerupdots = 1;
int yellow[][] = new int[1][2];
int powerupcounter = 0;
int shield = 0;
int blue[][] = new int[1][2];

public void init()
{
    this.setSize(740,500);        
    width = 640;
    height = 480;        
    setBackground( Color.black );
    x = width/2;
    y = height/2;
    s = "CLICK TO START";
    addMouseListener( this );
    addKeyListener( this );
}

public void keyPressed( KeyEvent e ) { }

public void keyReleased ( KeyEvent e ) { }

public void keyTyped( KeyEvent e )
{
    char c = e.getKeyChar();
    String t = c+"";
    //This will change the coordinates of the user-controlled circle by the size of the circle based on what button is pressed
    if(powerupcounter > 0)
    {
        powerup = 2;
    }
    else if(powerupcounter == 0)
    {
        powerup = 1;
    }

    if( t.equalsIgnoreCase("w" )&& oy > 0+((powerup-1)*size))
    {
        oy = oy-(size*powerup);
    }
    else if( t.equalsIgnoreCase("s") && oy < height-(size*powerup))
    {
        oy = oy+(size*powerup);
    }
    else if( t.equalsIgnoreCase("a")&& ox > 0+((powerup-1)*size))
    {
        ox = ox-(size*powerup);
    }
    else if( t.equalsIgnoreCase("d") && ox < width-(size*powerup))
    {
        ox = ox+(size*powerup);
    }
    else if(t.equalsIgnoreCase("w" ) && oy == 0)
    {
        oy = height-(size*powerup);
    }
    else if(t.equalsIgnoreCase("s") && oy == height-size)
    {
        oy = 0+((powerup-1)*size);
    }
    else if(t.equalsIgnoreCase("a") && ox == 0)
    {
        ox = width-(size*powerup);
    }
    else if(t.equalsIgnoreCase("d") && ox == width-size)
    {
        ox = 0+((powerup-1)*size);
    }
    else if(t.equalsIgnoreCase("w") && oy == size && powerup ==2)
    {
        oy = height-size;
    }
    else if(t.equalsIgnoreCase("s") && oy == height -(size*powerup) && powerup ==2)
    {
        oy = 0;
    }
    else if(t.equalsIgnoreCase("a") && ox == size && powerup ==2)
    {
        ox = width-size;
    }
    else if(t.equalsIgnoreCase("d") && ox == width -(size*powerup) && powerup ==2)
    {
        ox = 0;
    }

    if(powerupcounter > 0)
    {
        powerupcounter--;
    }

    repaint();
    e.consume();
}

public void mouseEntered( MouseEvent e) {}

public void mouseExited( MouseEvent e) {}

public void mousePressed( MouseEvent e) {}

public void mouseReleased( MouseEvent e) {}

public void mouseClicked( MouseEvent e) 
{
    if(click == 0)
    {
        randomYellow();
        randomBlue();
        DrawRandom();            
        x = e.getX();
        y = e.getY();
        s = "";
        repaint();
        e.consume();
        click = 1;
    }
}

public void CheckScore()
{
    if(ox == rx && oy == ry)
    {
        score++;
        reddots+=10;
        DrawRandom();
    }
}

public void DrawRandom()
{
    //The reason we divide by the size and then multiply after it is an int is to
    //make sure that the random circle drawn is in the same base as the size of the circle,
    //so that the player's circle can move directly over it, and not be of by a fraction
    //of the predetermined size.

    rx = (int)(Math.random()*width/size)*size;
    ry = (int)(Math.random()*height/size)*size;
    while(rx == ox && ry == oy)
    {
        rx = (int)(Math.random()*width/size)*size;
        ry = (int)(Math.random()*height/size)*size;
    }

    for(int y = 0 ; y < reddots ; y++)
    {
        red[y][0] = (int)(Math.random()*width/size)*size;
        red[y][1] = (int)(Math.random()*height/size)*size;
        while(red[y][0] == rx && red[y][1] == ry || red[y][0] == yellow[0][0] && red[y][1] == yellow[0][1] 
        || red[y][0] == ox && red[y][1] == oy || red[y][0] == blue[0][0] && red[y][1] == blue[0][1])
        {
            red[y][0] = (int)(Math.random()*width/size)*size;
            red[y][1] = (int)(Math.random()*height/size)*size;
        }
    }

}

public void randomYellow()
{
    yellow[0][0] = (int)(Math.random()*width/size)*size;
    yellow[0][1] = (int)(Math.random()*height/size)*size;
    while(yellow[0][0] == rx && yellow[0][1] == ry)
    {
        yellow[0][0] = (int)(Math.random()*width/size)*size;
        yellow[0][1] = (int)(Math.random()*height/size)*size;
    }
}

public void randomBlue()
{
    blue[0][0] = (int)(Math.random()*width/size)*size;
    blue[0][1] = (int)(Math.random()*height/size)*size;
    while(blue[0][0] == rx && blue[0][1] == ry || blue[0][0] == yellow[0][0] && blue[0][1] == yellow[0][1])
    {
        blue[0][0] = (int)(Math.random()*width/size)*size;
        blue[0][1] = (int)(Math.random()*height/size)*size;
    }
}

public void CheckDeath()
{
    for(int y = 0 ; y < reddots ; y++)
    {
        if(ox == red[y][0] && oy == red[y][1] && shield == 0)
        {
            score--;
            reddots--;
            DrawRandom();
        }
        else if(ox == red[y][0] && oy == red[y][1] && shield !=0)
        {
            shield--;
            DrawRandom();
        }
    }
}

public void CheckPowerup()
{
    for(int y = 0 ; y < powerupdots ; y++)
    {
        if(ox == yellow[y][0] && oy == yellow[y][1])
        {
            powerupcounter += 10;
            randomYellow();
        }
    }
}

public void CheckShield()
{
    if(ox == blue[0][0] && oy == blue[0][1] && shield < 5)
    {
        shield++;
        randomBlue();
    }
    else if(ox == blue[0][0] && oy == blue[0][1] && shield >= 5)
    {
        randomBlue();
    }
}

public void CheckWin( Graphics g )
{
    g.setColor(Color.black);
    g.fillRect(0,0,width,height);
    while(1 == 1)
    {
        g.drawString( "YOU WIN" , width/2, height/2);
    }

}

public void paint( Graphics g )
{

    CheckScore();
    if(score == 20)
    {
        CheckWin(g);
    }
    CheckDeath();
    CheckPowerup();
    CheckShield();
    DrawGrid(g);
    g.setColor(Color.yellow);
    g.fillRect(yellow[0][0],yellow[0][1],size+1,size+1);
    g.setColor(Color.red);
    for(int y = 0; y < reddots ; y++)
    {
        g.fillRect(red[y][0],red[y][1],size+1,size+1);
    }
    sc = ""+score;
    //Draw user
    g.setColor(Color.white);
    g.fillRect(ox,oy,size+1,size+1);
    //Draw shield around user if they have shields (max 5)
    if(shield >= 1)
    {
        g.setColor(Color.blue);
        g.fillRect(ox,oy,size+1,5);
        g.fillRect(ox,oy,5,size+1);
        g.fillRect(ox,oy+size-4,size+1,5);
        g.fillRect(ox+size-4,oy,5,size+1);
    }
    //Draw green tile
    g.setColor(Color.green);
    g.fillRect(rx,ry,size+1,size+1);
    //Draw shield tile
    g.setColor(Color.blue);
    g.fillRect(blue[0][0],blue[0][1],size+1,size+1);        
    g.setColor( Color.green );
    g.drawString( s, x, y );
    g.drawString( "Score : "+sc, 650, 20);
    g.drawString( "Powerups : "+powerupcounter, 650, 40);
    g.drawString( "Red Dots : "+reddots, 650,60);
    g.drawString( "Shield : "+shield,650,80);   
}

public void DrawGrid( Graphics g )
{
    g.setColor(Color.orange);
    for(int x = 0 ; x <= width ; x += size)
    {
        g.drawLine(x,0,x,height);
    }
    for(int y = 0 ; y <= height ; y+= size)
    {
        g.drawLine(0,y,width,y);
    }
}

}

Woohoojin
  • 674
  • 1
  • 4
  • 19
  • 1
    I think it might be the delay of calculation when calculating your random red dots and then filling them in; it flashes much more often as the number of red dots gets bigger. You also redraw the whole board each time a move happens, despite the fact that unless one of your special conditions triggers the only thing that should change is the position of the white dot. Try instead, only drawing a black square over the last position and redrawing the white dot (with shields if necessary) if the special conditions aren't triggered. – Steve K Nov 12 '14 at 22:59
  • You may also need to set up some sort of BufferStrategy. There are many tutorials on it. Just google something like "java double buffering graphics" or something and you should find video and written tutorials everywhere. – vedi0boy Nov 13 '14 at 00:50
  • Buffering might be good, but I think paring down your algorithm might be better. For example, define your game board as a single matrix of integers, and assign values for colors - 0 for black, 1 for red, 2 for yellow, 3 for green, 4 for white, etc. Then to check your collisions 'on move', you just check the color of the square you're moving to. You don't have to do checks through multiple arrays of colors and store lists of coordinates. Also, draw items from back to front. First the black board, then the yellow grid lines, then everything else, to minimize the flash. – Steve K Nov 13 '14 at 04:25
  • 1) Why code an applet? If it is due to the teacher specifying it, please refer them to [Why CS teachers should **stop** teaching Java applets](http://programmers.blogoverflow.com/2013/05/why-cs-teachers-should-stop-teaching-java-applets/). 2) Why use AWT? See [this answer](http://stackoverflow.com/questions/6255106/java-gui-listeners-without-awt/6255978#6255978) for many good reasons to abandon AWT using components in favor of Swing. – Andrew Thompson Nov 13 '14 at 22:25

1 Answers1

0

My advice is to move as much of your calculation as possible into methods called from your keypress events, and keep your paint() method as short and direct as possible. Don't do math inside your paint() method if you can help it - use your keypress method to build the picture of everything you need to paint before you call repaint(), and make your paint() method's only job to be to draw the current state of the board. Also, don't redraw the whole board anytime you don't have to. For instance, when moving from the current square to an empty square, all you should draw is a black square over your previous position, and a new user square in the new position. When hitting a yellow or blue square, all you need to draw is the new yellow or blue square (and update the appropriate status messages). You only need to redraw the whole board when hitting a red or green square.

Steve K
  • 4,863
  • 2
  • 32
  • 41