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

Pong

Features:

- I have created a primitive Pong game that has lots of room for improvement.
- However, I do have some of the important fundamentals squared away in this game. In particular, I have enforced the 1 to 2 player limit. Any new players attempting to connect will immediately disconnect. However, if one of the 2 players disconnects, then a second player can come in.
- Note that because we have a thread running that can be simultaneously pumping out pong game updates this can be tricky. We can have clients who are not quite initialized, but they could be receiving output from a running pong 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 Pong 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 pong;

import java.io.Serializable;

public class MyGameInput implements Serializable{
    static final int CONNECTING=1;
    static final int DISCONNECTING=2;
    static final int MOUSE_PRESSED=3;
    static final int MOUSE_MOVED=4;

    String name;
    int y_location; // location to move to with the paddle
    int command;

    void setName(String name)
    {
        this.name=name;
    }
    void setCmd(int command)
    {
        this.command=command;
    }

    void setLocation(int location)
    {
        y_location = location;
        command=MOUSE_MOVED;
    }
}


MyGameOutput.java


package pong;

import java.io.Serializable;

public class MyGameOutput implements Serializable{
    MyGame myGame = null;
    MyGameOutput(MyGame g)
    {
        myGame =g;
    }
}




MyGame.java


package pong;

import gameNet.GameControl;
import gameNet.GameNet_CoreGame;

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


public class MyGame extends GameNet_CoreGame implements Runnable, Serializable {


    private ArrayList<String> clients = new ArrayList<String>();
    public Box box = new Box();

    transient GameControl gameControl;

    public void startGame(GameControl g)
    {
        gameControl =g;
        Thread t = new Thread(this);
        t.start();
    }

    public int getMyIndex(String name)
    {
        return clients.indexOf(name);
    }

    @Override
    public Object process(Object ob) {
        MyGameInput myGameInput = (MyGameInput)ob;
        if (myGameInput.command == MyGameInput.CONNECTING && clients.size() < 2)
        {
            clients.add(myGameInput.name);
        }

        switch(myGameInput.command)
        {
        case MyGameInput.CONNECTING:
            break;
        case MyGameInput.DISCONNECTING:
            clients.remove(myGameInput.name);
            break;
        case MyGameInput.MOUSE_PRESSED:
             box.setGame(true);
            break;
        case MyGameInput.MOUSE_MOVED:
            int clientIndex = getMyIndex(myGameInput.name);
            if (clientIndex >= 0)
                box.setPaddleY(myGameInput.y_location, clientIndex);
            break;
        }
        MyGameOutput myGameOutput = new MyGameOutput(this);
        return myGameOutput;
    }


    @Override
    public void run() {
        while(true)
        {
            try{
                Thread.sleep(60);
                if (box.isRunning())
                {
                    box.update();
                    MyGameOutput mo = new MyGameOutput(this);
                    gameControl.putMsgs(mo);
                }
            }
            catch (InterruptedException e){}
        }

    }
}



Box.java


package pong;

import java.awt.Point;
import java.io.Serializable;
import java.util.Random;

public class Box implements Serializable{

	//generic size
    static final int box_width = 1000;
    static final int box_height = 500;

    Point boxUpperRight ;
    Point boxUpperLeft  ;
    Point boxLowerRight ;
    Point boxLowerLeft  ;

    Point rightHoleUpper     ;
    Point rightHoleLower     ;

    Point ballLoc       ;

    Point[] paddleLoc     ;

    int paddleWidth ;
    int ballRadius = 20;
    private int ballVx, ballVy;
    private Random rand = new Random();

    int successCount=0;
    private boolean running=false;

    public boolean isRunning()
    {
        return running;
    }


    public Box()
    {
        int box_top =0;
        int box_bottom = box_height;
        int box_left =0;
        int box_right = box_width;

        boxUpperRight= new Point(box_right, box_top);
        boxUpperLeft = new Point(box_left, box_top);
        boxLowerRight= new Point(box_right, box_bottom);
        boxLowerLeft = new Point(box_left, box_bottom);
        rightHoleUpper    = new Point(box_right, box_top +(box_bottom-box_top)/4);
        rightHoleLower    = new Point(box_right, box_top +3*(box_bottom-box_top)/4);

        paddleWidth  = (rightHoleLower.y - rightHoleUpper.y)/3;
        setGame(false);

    }
    void setGame(boolean startRunning)
    {
        int box_top =0;
        int box_bottom = box_height;
        int box_left =0;
        int box_right = box_width;

        // Start the ball out at a random spot
        ballLoc      = new Point(box_left+ rand.nextInt(box_right - box_left),
                box_top+ rand.nextInt(box_bottom - box_top));

        // Heuristic for generating random starting velocities ... maybe not the best
        ballVx = (-50 + (int)(100*Math.random()));
        ballVy = -50 + (int)(100*Math.random());

        paddleLoc = new Point[2];
        paddleLoc[0]     = new Point(box_right,( rightHoleUpper.y+rightHoleLower.y)/2);
        paddleLoc[1]    = new Point(box_left+1,( rightHoleUpper.y+rightHoleLower.y)/2);
        if (startRunning)
            running = true;
    }
    public void setPaddleY(int yLoc, int clientIndex)
    {
        paddleLoc[clientIndex].y =yLoc;
        if (paddleLoc[clientIndex].y - paddleWidth/2 < rightHoleUpper.y)
            paddleLoc[clientIndex].y = rightHoleUpper.y + paddleWidth/2;
        if (paddleLoc[clientIndex].y + paddleWidth/2 > rightHoleLower.y)
            paddleLoc[clientIndex].y = rightHoleLower.y - paddleWidth/2;

    }

    public void update()
    {
        if ( !running)
            return;
        ballLoc.x = ballLoc.x + ballVx;
        ballLoc.y = ballLoc.y + ballVy;

        // check against right wall
        if (ballLoc.x + ballRadius > boxUpperRight.x)
        {
            if (ballLoc.y <= rightHoleUpper.y || ballLoc.y >= rightHoleLower.y )
            {
                // hits wall
                ballVx *= -1;
                ballLoc.x = boxUpperRight.x - ballRadius;
            }
            else if (ballLoc.y >= paddleLoc[0].y-paddleWidth/2 &&
                    ballLoc.y <= paddleLoc[0].y + paddleWidth/2)
            {
                successCount +=1;  // In hole but bounces off right paddle
                ballVx *= -1;
                ballLoc.x = boxUpperRight.x - ballRadius;
                System.out.println("In Hole and hits paddle");
            }
            else
            {
                // In hole and missed by paddle
                running= false;
                System.out.println("In Hole and missed by paddle");
            }
        }

		 // check against the left wall
        if (ballLoc.x - ballRadius < boxUpperLeft.x)
        {
            ballVx *= -1;
            ballLoc.x = boxUpperLeft.x + ballRadius;
        }
		
		 // check against the bottom wall
        if (ballLoc.y + ballRadius > boxLowerRight.y)
        {
            ballVy *= -1;
            ballLoc.y = boxLowerRight.y - ballRadius;
        }

		 // check against the top wall
        if (ballLoc.y - ballRadius < boxUpperRight.y)
        {
            ballVy *= -1;
            ballLoc.y = boxUpperRight.y + ballRadius;
        }

    }

}





MyUserInterface.java


package pong;

import gameNet.GameNet_UserInterface;
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.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;

public class MyUserInterface extends JFrame
implements GameNet_UserInterface
{

    Box box = null;
    Image offScreenImage=null;
    Dimension previousSize=null;

    GamePlayer myGamePlayer;
    String myName;
    MyGameInput myGameInput = new MyGameInput();
    int game_top, game_bottom, game_left, game_right;
    Color[] paddleColors = {Color.green, Color.red};
    BoardDimensions boardDimensions = new BoardDimensions();

    @Override
    public void receivedMessage(Object ob) {
        MyGameOutput myGameOutput = (MyGameOutput)ob;

        if (myGamePlayer != null)
        {
            // Check to see we were accepted and connected
            if (myGameOutput.myGame.getMyIndex(myName) < 0)
            {
                System.out.println("Not allowed to connect to the game");
                exitProgram();
            }
            else
            {
                // connected and ready to run
                box = myGameOutput.myGame.box;
                repaint();
            }
        }
        else
            System.out.println("Getting outputs before we are ready");
    }


    @Override
    public void startUserInterface(GamePlayer player) {
        myGamePlayer = player;
        myName = myGamePlayer.getPlayerName();
        myGameInput.setName( myName);
        myGameInput.setCmd(MyGameInput.CONNECTING);
        myGamePlayer.sendMessage(myGameInput);
    }



    public MyUserInterface()
    {
        super("My Pong Game");
        setSize(800, 400);
        // setResizable(false);
        addWindowListener(new Termination());

        Mouser m = new Mouser();
        addMouseMotionListener(m);
        addMouseListener(m);
        setVisible(true);
    }


    public void paint(Graphics theScreen)
    {
        Dimension d = getSize();
        if (offScreenImage==null || !d.equals(previousSize))
        {
            offScreenImage = createImage(d.width, d.height);
            previousSize = d;
        }
        Graphics g = offScreenImage.getGraphics();

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

        Insets insets = getInsets();
        int pad=10;
        boardDimensions.setParms(insets.top+pad, insets.left+pad,
                d.width-insets.left-insets.right -2*pad,
                d.height-insets.top-insets.bottom -2*pad);
        if (box == null)
        {
            g.drawString("Click Mouse to start", 100,100);
        }
        else
        {

            if (!box.isRunning())
            {
                String str ="Success count="+
                        box.successCount+ " Click Mouse to restart";
                g.drawString(str, 100, 100);
            }

            Point bur = boardDimensions.toPixels(box.boxUpperRight);
            Point bul = boardDimensions.toPixels(box.boxUpperLeft);
            Point blr = boardDimensions.toPixels(box.boxLowerRight);
            Point bll = boardDimensions.toPixels(box.boxLowerLeft);
            Point hu  = boardDimensions.toPixels(box.rightHoleUpper);
            Point hl  = boardDimensions.toPixels(box.rightHoleLower);

            g.drawLine(bll.x, bll.y, blr.x, blr.y); // lower line
            g.drawLine(bll.x, bll.y, bul.x, bul.y); // left side
            g.drawLine(bul.x,bul.y, bur.x, bur.y);  // top side
            g.drawLine(bur.x, bur.y, hu.x, hu.y);   // above hole on right
            g.drawLine(blr.x, blr.y, hl.x, hl.y);   // below hole on right

            Point pball = boardDimensions.toPixels(box.ballLoc);
            int r = boardDimensions.toPixels(box.ballRadius);
            g.fillOval(pball.x-r, pball.y-r, 2*r, 2*r);


            int paddleWidth = boardDimensions.toPixels(box.paddleWidth);
            for (int i=0; i < 2; i++)
            {
                Point pPaddle =boardDimensions.toPixels( box.paddleLoc[i]);
                g.setColor(paddleColors[i]);
                g.drawLine(pPaddle.x, pPaddle.y-paddleWidth/2,
                        pPaddle.x, pPaddle.y+paddleWidth/2);
            }
        }

        theScreen.drawImage(offScreenImage, 0,0, this);
    }

    private void exitProgram()
    {
        if (myGamePlayer != null)
        {
            myGameInput.setCmd(MyGameInput.DISCONNECTING);
            myGamePlayer.sendMessage(myGameInput); // Let the game know that we are leaving

            myGamePlayer.doneWithGame(); // clean up sockets
        }
        System.exit(0);
    }

    //*******************************************
    // An Inner class
    //*******************************************
    class Mouser extends MouseAdapter
    {
        public void mouseMoved(MouseEvent e)
        {
            int y= e.getY();

            if (box != null)
            {
                myGameInput.setLocation(boardDimensions.toGenericY(y));
                if (myGamePlayer != null)
                    myGamePlayer.sendMessage(myGameInput);

            }

        }
        public void mousePressed(MouseEvent e)
        {
            myGameInput.setCmd(MyGameInput.MOUSE_PRESSED);
            if (myGamePlayer != null)
                myGamePlayer.sendMessage(myGameInput);

        }

    }
    //*******************************************
    // Another Inner class
    //*******************************************
    class Termination extends WindowAdapter
    {
        public void windowClosing(WindowEvent e)
        {
            System.out.println("Client is exitting game");
            exitProgram();
        }
    }

    //****** Done with Inner Classes ***************
}



BoardDimensions.java


package pong;

import java.awt.Point;

public class BoardDimensions {

    private int top=-1, left=-1;
    private double scale_width=0.0, scale_height=0.0;

    public void setParms(int top, int left , int width, int height)
    {
        this.top = top;
        this.left = left;
        scale_width = Box.box_width/(double)width;
        scale_height = Box.box_height/(double)height;
    }
    // Used to translate MouseMoved locations to Paddle Locations
    int toGenericY(int y)
    {
        int yGeneric = (int)((y-top) * scale_height);
        return yGeneric;
    }
    // Used for translating Box Points to the Screen
    Point toPixels(Point p)
    {
        int x = left + (int)(p.x / scale_width);
        int y = top + (int)(p.y / scale_height);
        return new Point(x,y);
    }
    // Used to resize the Ball
    int toPixels(int y)
    {
        int yPixels = (int)(y / scale_height);
        return yPixels;
    }



}



If you were to do a project similar to Pong, here are some ideas of things you could do:

- Note that the current logic only has the first player's paddle fully working ... fix this.
- Put the current paint screen in a JPanel that is placed in the center of a BorderLayout. Then you could have a North panel to provide status update information like: Name, Scores, ResetButton, etc.
- Create an up to 4 player pong game, with each new player having a side of the box to defend
- If you are good with math, you might want to create a round paddle (like in air hockey) to allow the user more variety on his shot.
- Prettier screen.
- Anything else that you can think of.

October 19, 2013 1:50 PM