Title: Quick Click
Course: CPS 261: Advanced Java Concepts ~ DL & MM MASTER

Quick Click

Features:

- The main addition with this program is to have updating output without any user inputs. We have 20 Disks bouncing around.




public class MyGame extends GameNet_CoreGame implements Serializable, Runnable
{
    transient GameControl gameControl ;
    boolean continueToPlay=true;

    public void startGame(GameControl g)
    {
        this.gameControl = g;
        Thread t = new Thread(this);
        t.start();
    }
    public void run()
    {
        while(continueToPlay)
        {
            try
            {
                Thread.sleep(sleepTime);
                .......

                MyGameOutput myGameOutput = new MyGameOutput(this);
                gameControl.putMsgs(myGameOutput);
            } catch (InterruptedException e){}
        }
    }

    // Process commands from each of the game players

    public MyGameOutput process(Object inputs)
    {
        MyGameInput myGameInput = (MyGameInput)inputs;
        .....
    }
}


- This program can allow any number of players to enter or leave the game. The total score of all players is displayed.
- This program also uses generic coordinates. In MyGame you will see some static final numbers which define the generic coordinates to this game.
- Just like the previous program, mouse clicks convert points to generic points, the paint routine converts Disk generic locations to pixel locations.
- The following zip file has the QuickClick program along with gameNet and all of the other games discussed in "Networked Programs"
NetworkedPrograms.zip

MyMain.java

same as everything else including guiChat

MyGameInput.java


package QuickClick;
import java.io.Serializable;

public class MyGameInput implements Serializable
{
// command options
   static final int CONNECTING=1;
   static final int CLICK=2;
   static final int DISCONNECTING=100;
   static final int RESETTING=200;

   int command=CONNECTING;

   String myName;
   DPoint dpoint;

   public void setName(String name)
   {
       myName=name;
   }

}


class DPoint implements Serializable
{
    double x,y;

    DPoint()
    {
        x = MyGame.fieldWidth *Math.random();
        y = MyGame.fieldHeight*Math.random();
    }
    DPoint(double x, double y)
    {
        this.x = x;
        this.y = y;
    }
}



MyGame.java


package QuickClick;

import gameNet.GameControl;
import gameNet.GameNet_CoreGame;


import java.io.Serializable;
import java.util.ArrayList;

class Player implements Serializable
{
    int count=0;
    String name;
    Player(String n)
    {
        name=n;
    }
    public String toString()
    {
        return name + " = "+ count;
    }
}


public class MyGame extends GameNet_CoreGame implements Serializable, Runnable
{
    transient GameControl gameControl ;
    static final int NUM_DISKS = 20;

    static final double fieldHeight =50.0;
    static final double fieldWidth=100.0;
    static final double diskRadius=4.0;

    static final int sleepTime=30;
    static final double OUT_OF_BOUNDS = -fieldWidth;

    Disk[] disks=  new Disk[NUM_DISKS];


    boolean continueToPlay = true;

    ArrayList<Player>players = new ArrayList<Player>();


    public void startGame(GameControl g)
    {
        this.gameControl = g;
        Thread t = new Thread(this);
        restartGame();
        t.start();
    }
    public void run()
    {
        while(continueToPlay)
        {
            try
            {
                Thread.sleep(sleepTime);
                for (int i=0; i < NUM_DISKS; i++)
                {
                    disks[i].update();
                }

                MyGameOutput myGameOutput = new MyGameOutput(this);
                gameControl.putMsgs(myGameOutput);
            } catch (InterruptedException e){}
        }
    }

    // Process commands from each of the game players

    public MyGameOutput process(Object inputs)
    {
        MyGameInput myGameInput = (MyGameInput)inputs;
        switch (myGameInput.command)
        {
        case MyGameInput.CONNECTING:
            // This routine will add a new user if the
            //  player doesn't already exist
            getClientIndex(myGameInput.myName);
            break;
        case MyGameInput.CLICK:
            //System.out.println("checking x="+ myIn.x + " y="+ myIn.y);
            for (int i=0; i < NUM_DISKS; i++)
            {
                if (disks[i].insideDisk(myGameInput.dpoint, diskRadius))
                { // The click nailed a disk

                    int index = getClientIndex(myGameInput.myName);
                    if (index >= 0)
                        players.get(index).count+=1;
                    break; // Only get one ball per click
                }
            }
            break;
        case MyGameInput.DISCONNECTING:
            int index = getClientIndex(myGameInput.myName);
            if (index >= 0)
                players.remove(index);
            break;
        case MyGameInput.RESETTING:
            restartGame();
            break;
        default: /* ignore */
        }
        MyGameOutput myGameOutput = new MyGameOutput();
        myGameOutput.myGame = this;
        return myGameOutput;
    }



    // Find index of existing player.  If he doesn't exist add him.
    // There is no limit to the number of clients to this game
    private int getClientIndex(String name)
    {
        for (int i=0; i < players.size(); i++)
        {
            if (name.equals(players.get(i).name) )
            {
                return i;
            }
        }
        players.add(new Player(name));


        return players.size() -1;
    }


    private void restartGame()
    {
        for (int i=0; i < players.size(); i++)
        {
            players.get(i).count=0;
        }
        for (int i=0; i < NUM_DISKS; i++)
        {
            disks[i] = new Disk(); // Generates Random Disks
        }
    }


    public String getScore()
    {
        String retStr="";
        for (int i=0; i < players.size(); i++)
            retStr += players.get(i).toString()+"   ";

        return retStr;
    }
}






Disk.java


package QuickClick;

import java.awt.Color;
import java.io.Serializable;

public class Disk implements Serializable
{
    double vx,vy;
    DPoint dp;
    Color color;
    Disk()
    {
        dp = new DPoint();// generates random location
        vx =-0.5 + Math.random();
        vy = -1.0 + 2*Math.random();
        color = new Color((float)Math.random(),(float)Math.random(),(float)Math.random());
    }
    boolean isInPlay()
    {
        if (dp.x < 0)
            return false;
        else
            return true;
    }
    boolean insideDisk(DPoint dp_click , double radius)
    {
        if ( dp_click.x <= (dp.x + radius)  &&
             dp_click.x >=    (dp.x - radius) &&
             dp_click.y <=    (dp.y + radius) &&
             dp_click.y >= (dp.y - radius))
        {
            dp.x= MyGame.OUT_OF_BOUNDS; // Take this disk out of play
            return true;  // the click is inside a box that surrounds the disk
        }
        else
            return false;
    }
    void update()
    {
        if (dp.x <= MyGame.OUT_OF_BOUNDS ) return;
        dp.x += vx;
        dp.y += vy;

        // Bounce off top wall
        if (dp.y < MyGame.diskRadius)
        {
            vy = -vy;
            dp.y= MyGame.diskRadius;
        }
        // Bounce off bottom wall
        if (dp.y > MyGame.fieldHeight-MyGame.diskRadius)
        {
            vy = - vy;
            dp.y= MyGame.fieldHeight-MyGame.diskRadius;
        }

        // Check Right Wall
        if (dp.x > MyGame.fieldWidth-MyGame.diskRadius)
        {
            vx = -vx;
            dp.x = MyGame.fieldWidth-MyGame.diskRadius;
        }


        // Check Left Wall
        if (dp.x < MyGame.diskRadius)
        {
            vx = -vx;
            dp.x = MyGame.diskRadius;
        }
    }
}



MyUserInterface.java


package QuickClick;

import gameNet.GameNet_UserInterface;
import gameNet.GamePlayer;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;




public class MyUserInterface extends JFrame implements  GameNet_UserInterface
{
    GamePlayer  myGamePlayer=null;

    String myName=null;
    JLabel statusLabel = new JLabel("");
    MyGameInput myGameInput = new MyGameInput();
    PaintPanel paintPanel=null;

    public MyUserInterface()
    {
        super("Quick Click");

    }

    public void receivedMessage(Object ob)
    {
        MyGameOutput myGameOutput = (MyGameOutput)ob;
        if (paintPanel != null)
            paintPanel.updatePaint(myGameOutput.myGame);
        else
            System.out.println("Thread is already sending  stuff before I am ready");
    }


    void sendMessage(int command)
    {
        myGameInput.command = command;
        myGamePlayer.sendMessage(myGameInput);
    }


    public void startUserInterface (GamePlayer gamePlayer) {
        myGamePlayer = gamePlayer;
        myName=gamePlayer.getPlayerName();
        myGameInput.setName(myName);

        mylayout();

        sendMessage(MyGameInput.CONNECTING);

        addWindowListener(new Termination());

        setVisible(true);
    }
    private void mylayout()
    {
        setLayout(new BorderLayout());
        paintPanel = new PaintPanel( statusLabel,  myName, myGamePlayer);
        add(paintPanel, BorderLayout.CENTER);

        JPanel topPanel = new JPanel();
        topPanel.setLayout(new FlowLayout());
        JButton b = new JButton("Reset");
        topPanel.add(b);
        b.addActionListener(new ActionMonitor());
        statusLabel.setText(myName);
        topPanel.add(statusLabel);
        add(topPanel, BorderLayout.NORTH);


        setSize(500,300);
    }


    //*******************************************
    // Another Inner class
    //*******************************************
    class ActionMonitor implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            sendMessage(MyGameInput.RESETTING);
        }
    }

    //*******************************************************
    // Inner Class
    //*******************************************************

    class Termination extends WindowAdapter
    {
        public void windowClosing(WindowEvent e)
        {
            sendMessage(MyGameInput.DISCONNECTING);

            myGamePlayer.doneWithGame();
            System.exit(0);
        }
    }



}





PaintPanel.java


package QuickClick;

import gameNet.GamePlayer;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JLabel;
import javax.swing.JPanel;

public    class PaintPanel extends JPanel
    {
        Image gOffScreenImage=null;
        int lastWidth=-1, lastHeight=-1;
        MyGame myGame=null;
        JLabel statusLabel;
        String myName;
        MyGameInput myGameInput= new MyGameInput();
        GamePlayer myGamePlayer;

        BoardDimensions boardDimensions = new BoardDimensions();

        PaintPanel(JLabel statusLabel, String myName, GamePlayer gamePlayer)
        {
            this.statusLabel = statusLabel;
            this.myName = myName;
            myGameInput.setName(myName);
            myGamePlayer= gamePlayer;
            addMouseListener(new MouseClickMonitor());
        }
        public void updatePaint(MyGame g)
        {
            myGame =g;
            repaint();
        }



        public void paint(Graphics g)
        {
            if (myGame == null) return;

            Insets insets = super.getInsets();
            Dimension d = getSize();
            if (lastWidth != d.width || lastHeight != d.height)
            {
                gOffScreenImage = createImage(getBounds().width, getBounds().height);
                lastWidth = d.width;
                lastHeight = d.height;
            }
            Graphics offScreenGraphics = gOffScreenImage.getGraphics();

            offScreenGraphics.setColor(Color.white);
            offScreenGraphics.fillRect(0, 0, d.width, d.height);

            statusLabel.setText(myName + "'s Screen: " +myGame.getScore());

            boardDimensions.setParms(insets.top, insets.left,
                    d.width-insets.left -insets.right , d.height - insets.top -insets.bottom);

            offScreenGraphics.setColor(Color.black);

            // Draw Disks
            for (int i=0; i < MyGame.NUM_DISKS; i++)
            {
                Disk disk = myGame.disks[i];
                if (disk.isInPlay())
                {
                    offScreenGraphics.setColor(disk.color);
                    DPoint dp = boardDimensions.toPaintPoint(disk.dp);
                    int x = (int)dp.x;
                    int y = (int)dp.y;
                    int r= (int)(boardDimensions.toPaintScaleX(MyGame.diskRadius));
                    offScreenGraphics.fillOval(x-r, y-r, 2*r, 2*r);
                }
            }
            g.drawImage(gOffScreenImage, 0, 0, this);

        }

        //*******************************************
        // Another Inner class of PaintPanel
        //*******************************************
        class MouseClickMonitor extends MouseAdapter
        {
            public void mousePressed(MouseEvent e)
            {
                DPoint dpoint = boardDimensions.toGenericPoint( e.getPoint());
                if (dpoint != null)
                {
                    myGameInput.dpoint = dpoint;
                    myGameInput.command = MyGameInput.CLICK;
                    myGamePlayer.sendMessage(myGameInput);
                }
            }

        }



    }



BoardDimensions.java


package QuickClick;

import java.awt.Point;


public class BoardDimensions {

    private int left=-1, top=-1;
    int width=-1, height=-1;
    double x_scale=1.0, y_scale=1.0;

    // note that width and height are the effective width and height
    public void setParms(int top, int left, int width , int height)
    {
        this.top = top;
        this.left = left;
        this.width = width;
        this.height = height;
        x_scale = width /MyGame.fieldWidth;
        y_scale = height/MyGame.fieldHeight;
    }

    DPoint toGenericPoint(Point p)
    {
        double dx = (p.x - left)/x_scale;
        double dy = (p.y - top)/y_scale;
        if (dx < 0.0 || dy < 0.0 || dx > MyGame.fieldWidth || dy > MyGame.fieldHeight)
            return null;
        else
            return new DPoint(dx, dy);
    }
    double toPaintScaleX(double x)
    {
        return x*x_scale;
    }
    DPoint toPaintPoint(DPoint dp)
    {
        int x=left + (int)(dp.x*x_scale);
        int y=top+ (int)(dp.y*y_scale);
        return new DPoint(x,y);
    }
}




October 19, 2013 10:53 AM