imported from remote update

git-svn-id: svn://anubis/gvsu@97 45c1a28c-8058-47b2-ae61-ca45b979098e
This commit is contained in:
josh 2008-04-13 17:27:05 +00:00
parent a4356f557a
commit 7795f9bc1c
10 changed files with 740 additions and 16 deletions

View File

@ -1,29 +1,174 @@
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.border.*;
import java.net.*;
import java.io.*;
public class BlobWars extends JFrame
{
public static void main(String[] args)
{
BlobWars jt = new BlobWars();
}
private BlobWarsWorld m_world;
private BlobWarsPanel m_panel;
private JTextField m_nameField;
private JTextField m_serverField;
private JButton m_connectButton;
private EventHandler m_handler;
private javax.swing.Timer m_timer;
private Socket m_socket;
private BufferedWriter m_writer;
public BlobWars()
{
super("Josh's Blob Wars Game for CS654");
setSize(400, 500);
m_world = new BlobWarsWorld();
/* TODO: REMOVE */
m_world.addPlayer("Alice");
m_world.getPlayer("Alice").health = 0.8;
m_world.addPlayer("Bob the Bad");
m_world.getPlayer("Bob the Bad").health = 0.6;
m_world.addPlayer("Jo");
m_world.getPlayer("Jo").health = 0.4;
m_world.addPlayer("Triskaidekaphobia");
m_world.getPlayer("Triskaidekaphobia").health = 0.2;
/* END TODO */
m_handler = new EventHandler();
m_panel = new BlobWarsPanel(this, m_world);
setDefaultCloseOperation(EXIT_ON_CLOSE);
// setResizable(false);
setResizable(false);
getContentPane().add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(new JLabel("hi!"));
add(new JLabel("Player name: "));
add(m_nameField = new JTextField());
}});
add(new BlobWarsPanel());
add(new JPanel() {{
setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
add(new JLabel("Server: "));
add(m_serverField = new JTextField());
m_serverField.addKeyListener(m_handler);
add(m_connectButton = new JButton("Connect"));
m_connectButton.addActionListener(m_handler);
}});
// add(new Box.Filler(new Dimension(0, 0),
// new Dimension(0, 10000),
// new Dimension(10000, 10000)));
// add(new JPanel() {{
// setLayout(new BorderLayout());
add(m_panel);
m_panel.addKeyListener(m_handler);
// }});
}});
setSize(getPreferredSize());
setVisible(true);
}
public String getPlayerName()
{
return m_nameField.getText();
}
private void doConnect()
{
try {
m_socket = new Socket(m_serverField.getText(), BlobWarsServer.PORT);
m_writer = new BufferedWriter(
new OutputStreamWriter(m_socket.getOutputStream()));
m_writer.write("NAME:" + m_nameField.getText() + "\n");
} catch (Exception e) {
JOptionPane.showMessageDialog(null,
"Error connecting: " + e.getMessage());
return;
}
(new Thread(new ClientHandler())).start();
m_connectButton.setEnabled(false);
m_nameField.setEnabled(false);
m_serverField.setEnabled(false);
m_panel.requestFocusInWindow();
m_timer = new javax.swing.Timer(50, m_handler);
}
private class ClientHandler implements Runnable
{
public void run()
{
BufferedReader br;
try {
br = new BufferedReader(
new InputStreamReader(m_socket.getInputStream()));
} catch (Exception e) {
return;
}
/* main client loop */
for (;;)
{
String line = "";
try {
line = br.readLine();
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("GOT LINE: " + line);
}
}
}
private class EventHandler implements ActionListener, KeyListener
{
public void actionPerformed(ActionEvent e)
{
if (e.getSource() == m_connectButton)
{
doConnect();
}
}
public void keyPressed(KeyEvent e)
{
if (e.getSource() == m_panel)
{
try {
switch (e.getKeyCode())
{
case KeyEvent.VK_UP:
m_writer.write("UP\n");
break;
case KeyEvent.VK_DOWN:
m_writer.write("DOWN\n");
break;
case KeyEvent.VK_LEFT:
m_writer.write("LEFT\n");
break;
case KeyEvent.VK_RIGHT:
m_writer.write("RIGHT\n");
break;
}
} catch (Exception ex) {}
}
else if (e.getSource() == m_serverField)
{
if (e.getKeyCode() == KeyEvent.VK_ENTER)
{
doConnect();
}
}
}
public void keyReleased(KeyEvent e)
{
}
public void keyTyped(KeyEvent e)
{
}
}
public static void main(String[] args)
{
new BlobWars();
}
}

View File

@ -2,21 +2,107 @@
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import java.util.*;
public class BlobWarsPanel extends JPanel
{
public BlobWarsPanel()
private BlobWarsWorld m_world;
private BlobWars m_gui;
public BlobWarsPanel(BlobWars gui, BlobWarsWorld world)
{
Dimension sz = new Dimension(400, 400);
Dimension sz = new Dimension(500, 500);
setMinimumSize(sz);
setPreferredSize(sz);
setMaximumSize(sz);
m_world = world;
m_gui = gui;
}
public void paint(Graphics g)
{
// System.out.println("Width: " + getWidth() + " Height: " + getHeight());
g.setColor(Color.RED);
g.fillRect(0, 0, 40, 20);
Graphics2D g2d = (Graphics2D) g;
/* draw background */
g2d.setColor(Color.BLACK);
g2d.fillRect(0, 0, getWidth(), getHeight());
/* draw players */
for (Player p : m_world.getPlayers().values())
{
drawPlayer(p, g);
}
}
private void drawPlayer(Player p, Graphics g)
{
double xscl = p.x * getWidth();
double yscl = p.y * getHeight();
double rxscl = p.radius * getWidth();
double ryscl = p.radius * getHeight();
/* draw the blob circle */
g.setColor(p.name.equals(m_gui.getPlayerName())
? new Color(0.7f, 1.0f, 1.0f)
: Color.CYAN);
g.fillOval((int) (xscl - rxscl),
(int) (getHeight() - (yscl + ryscl)),
(int) (2 * rxscl),
(int) (2 * ryscl));
g.setColor(Color.BLUE);
g.drawOval((int) (xscl - rxscl),
(int) (getHeight() - (yscl + ryscl)),
(int) (2 * rxscl),
(int) (2 * ryscl));
/* draw the health bar */
Color hcol;
if (p.health >= 0.9)
hcol = Color.GREEN;
else if (p.health >= 0.5)
hcol = new Color((float) ((0.9 - p.health) / 0.4), 1.0f, 0.0f);
else if (p.health >= 0.1)
hcol = new Color(1.0f, (float) ((p.health - 0.1) / 0.4), 0.0f);
else
hcol = Color.RED;
int hbarwidth = (int) (rxscl * 1.4);
int hbarheight = (int) (ryscl * 0.2);
int hbarx = (int) (xscl - hbarwidth/2);
int hbary = (int) (getHeight() - (p.r < Math.PI
? (yscl - 3*hbarheight/2)
: (yscl + 5*hbarheight/2)));
g.setColor(hcol);
g.fillRect(hbarx, hbary, (int) (hbarwidth * p.health), hbarheight);
g.setColor(Color.BLUE);
g.drawRect(hbarx, hbary, hbarwidth, hbarheight);
/* draw the shooter triangle */
int[] s_pointsx = new int[3];
int[] s_pointsy = new int[3];
s_pointsx[0] = (int) (xscl + rxscl * Math.cos(p.r));
s_pointsy[0] = getHeight() -
(int) (yscl + ryscl * Math.sin(p.r));
s_pointsx[1] = (int) (xscl + rxscl * 0.3 * Math.cos(p.r + Math.PI / 2));
s_pointsy[1] = getHeight() -
(int) (yscl + ryscl * 0.3 * Math.sin(p.r + Math.PI / 2));
s_pointsx[2] = (int) (xscl + rxscl * 0.3 * Math.cos(p.r - Math.PI / 2));
s_pointsy[2] = getHeight() -
(int) (yscl + ryscl * 0.3 * Math.sin(p.r - Math.PI / 2));
g.setColor(Color.WHITE);
g.fillPolygon(s_pointsx, s_pointsy, 3);
g.setColor(Color.BLACK);
g.drawPolygon(s_pointsx, s_pointsy, 3);
/* draw the player's name */
char[] chars = new char[p.name.length()];
p.name.getChars(0, p.name.length(), chars, 0);
int width = g.getFontMetrics().charsWidth(chars, 0, p.name.length());
int height = g.getFontMetrics().getHeight();
g.setColor(Color.WHITE);
g.drawString(p.name,
(int) (xscl - width/2),
getHeight() - 4 - (p.y >= 0.5
? ((int) (yscl - ryscl - height))
: ((int) (yscl + ryscl)) ));
}
}

View File

@ -1,20 +1,52 @@
import java.io.*;
import java.util.*;
import java.net.*;
public class BlobWarsServer extends Thread
public class BlobWarsServer
{
public static final int PORT = 38491;
private ServerSocket m_socket;
private BlobWarsWorld m_world;
private Vector<ClientUpdate> m_clientUpdates;
private HashMap<Socket, String> m_socketToPlayerName;
private HashMap<String, Player> m_lastPlayers;
private HashMap<Integer, Shot> m_lastShots;
public void run()
public static void main(String[] args)
{
BlobWarsServer bws = new BlobWarsServer();
bws.mainloop();
}
public BlobWarsServer()
{
m_world = new BlobWarsWorld();
m_clientUpdates = new Vector<ClientUpdate>();
m_socketToPlayerName = new HashMap<Socket, String>();
try {
m_socket = new ServerSocket(PORT);
} catch (Exception e) {
e.printStackTrace();
return;
}
}
private class ClientUpdate
{
public Socket socket;
public String message;
}
public void mainloop()
{
if (m_socket == null)
return;
new Thread(new ServerGameLoop()).start();
/* listen loop to accept new connections */
for (;;)
{
Socket client;
@ -22,6 +54,7 @@ public class BlobWarsServer extends Thread
client = m_socket.accept();
} catch (Exception e) {
System.out.println("Socket error!");
e.printStackTrace();
break;
}
@ -31,6 +64,127 @@ public class BlobWarsServer extends Thread
}
}
private void processClientUpdate(ClientUpdate cu)
{
StringTokenizer st = new StringTokenizer(cu.message, ":");
Vector<String> tokens = new Vector<String>();
while (st.hasMoreTokens())
{
tokens.add(st.nextToken());
}
String[] arr = tokens.toArray(new String[1]);
if (arr.length < 2)
return;
if (arr[0].equals("NAME"))
{
m_world.addPlayer(arr[1]);
m_socketToPlayerName.put(cu.socket, arr[1]);
return;
}
/* the rest of the commands all require a player to be registered */
if (!m_socketToPlayerName.containsKey(cu.socket))
return;
String playerName = m_socketToPlayerName.get(cu.socket);
if (arr[0].equals("SHOOT")) {
m_world.shoot(playerName);
} else if (arr[0].equals("UP")) {
m_world.moveUp(playerName);
} else if (arr[0].equals("DOWN")) {
m_world.moveDown(playerName);
} else if (arr[0].equals("LEFT")) {
m_world.moveLeft(playerName);
} else if (arr[0].equals("RIGHT")) {
m_world.moveRight(playerName);
}
}
private class ServerGameLoop implements Runnable
{
public void run()
{
for (;;)
{
try {
Thread.sleep(45);
} catch (InterruptedException ie) {
System.out.println("ServerGameLoop: interrupted!");
return;
}
/* apply changes from clients */
synchronized (m_clientUpdates)
{
for (ClientUpdate cu : m_clientUpdates)
{
processClientUpdate(cu);
}
m_clientUpdates.clear();
}
m_world.step();
/* push updates to clients */
HashMap<String, Player> pushPlayers =
new HashMap<String, Player>();
HashMap<Integer, Shot> pushShots =
new HashMap<Integer, Shot>();
if (m_lastPlayers == null)
pushPlayers.putAll(m_world.getPlayers());
else
{
HashMap<String, Player> players = m_world.getPlayers();
for (String name : players.keySet())
{
if (!m_lastPlayers.containsKey(name))
pushPlayers.put(name, players.get(name));
else if (!players.get(name).equals(
m_lastPlayers.get(name)))
pushPlayers.put(name, players.get(name));
}
}
if (m_lastShots == null)
pushShots.putAll(m_world.getShots());
else
{
HashMap<Integer, Shot> shots = m_world.getShots();
for (Integer shotid : shots.keySet())
{
if (!m_lastShots.containsKey(shotid))
pushShots.put(shotid, shots.get(shotid));
else if (!shots.get(shotid).equals(
m_lastShots.get(shotid)))
pushShots.put(shotid, shots.get(shotid));
}
}
/* write updated info to each client */
String sendLine = "";
for (Player p : pushPlayers.values())
{
sendLine += "PLAYER:" + p + "\n";
}
for (Shot s : pushShots.values())
{
sendLine += "SHOT:" + s + "\n";
}
synchronized (m_socketToPlayerName)
{
for (Socket client : m_socketToPlayerName.keySet())
{
try {
BufferedWriter br = new BufferedWriter(
new OutputStreamWriter(
client.getOutputStream()));
br.write(sendLine, 0, sendLine.length());
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
private class ClientHandler implements Runnable
{
private Socket m_socket;
@ -38,11 +192,54 @@ public class BlobWarsServer extends Thread
public ClientHandler(Socket socket)
{
m_socket = socket;
System.out.println("Incoming connection from " + m_socket.getInetAddress().getAddress());
System.out.println("Incoming connection from " +
m_socket.getInetAddress().getHostAddress());
}
public void run()
{
BufferedReader br;
try {
br = new BufferedReader(
new InputStreamReader(m_socket.getInputStream()));
} catch (IOException ioe) {
ioe.printStackTrace();
return;
}
for (;;)
{
String line;
try {
line = br.readLine();
} catch (IOException ioe) {
// TODO: remove this line to not print stack trace for
// a client that disconnects, and remove socket from
// HashMap after for() loop
ioe.printStackTrace();
break;
}
System.out.println("SERVER GOT LINE: " + line);
if (line.equals("QUIT"))
{
synchronized (m_socketToPlayerName)
{
if (m_socketToPlayerName.containsKey(m_socket))
m_socketToPlayerName.remove(m_socket);
try {
m_socket.close();
} catch (Exception e) {}
}
break;
}
ClientUpdate cu = new ClientUpdate();
cu.socket = m_socket;
cu.message = line;
synchronized (m_clientUpdates)
{
m_clientUpdates.add(cu);
}
}
}
}
}

View File

@ -0,0 +1,206 @@
import java.util.*;
public class BlobWarsWorld
{
public static final double SHOT_SPEED = 0.3;
public static final double PLAYER_SPEED = 0.2;
public static final double PLAYER_SPIN_SPEED = Math.PI / 2;
private HashMap<String, Player> m_players;
private HashMap<Integer, Shot> m_shots;
private long m_lastStepTime;
private Integer m_shotID;
public BlobWarsWorld()
{
m_players = new HashMap<String, Player>();
m_shots = new HashMap<Integer, Shot>();
}
public boolean playerExists(String name)
{
return m_players.containsKey(name);
}
public Player getPlayer(String name)
{
return m_players.get(name);
}
public boolean addPlayer(String name)
{
if (playerExists(name))
return false;
Player p = new Player(name);
m_players.put(name, p);
do
{
p.x = (1.0 - 2 * Player.DEFAULT_RADIUS) * Math.random()
+ Player.DEFAULT_RADIUS;
p.y = (1.0 - 2 * Player.DEFAULT_RADIUS) * Math.random()
+ Player.DEFAULT_RADIUS;
} while (collidesWith(p).size() != 0);
return true;
}
public void shoot(String playerName)
{
if (!m_players.containsKey(playerName))
return;
/* TODO: check validity of shot, create Shot object */
Player p = m_players.get(playerName);
long curtime = (new Date()).getTime();
if ( ((curtime - p.lastShotTime) / 1000.0)
< Player.SHOT_DELAY)
{
/* calculate X & Y coordinates of shot */
double x = p.x + Math.cos(p.r) * (p.radius + Shot.DEFAULT_RADIUS);
double y = p.y + Math.sin(p.r) * (p.radius + Shot.DEFAULT_RADIUS);
m_shotID++;
Shot s = new Shot(m_shotID, curtime, x, y);
s.dx = Math.cos(p.r) * SHOT_SPEED;
s.dy = Math.sin(p.r) * SHOT_SPEED;
m_shots.put(m_shotID, s);
}
}
public void moveUp(String playerName)
{
if (!m_players.containsKey(playerName))
return;
Player p = m_players.get(playerName);
p.dx = Math.cos(p.r) * PLAYER_SPEED;
p.dy = Math.cos(p.r) * PLAYER_SPEED;
}
public void moveDown(String playerName)
{
if (!m_players.containsKey(playerName))
return;
Player p = m_players.get(playerName);
p.dx = 0;
p.dy = 0;
}
public void moveLeft(String playerName)
{
if (!m_players.containsKey(playerName))
return;
Player p = m_players.get(playerName);
p.dr = PLAYER_SPIN_SPEED;
}
public void moveRight(String playerName)
{
if (!m_players.containsKey(playerName))
return;
Player p = m_players.get(playerName);
p.dr = -PLAYER_SPIN_SPEED;
}
public Vector<GameItem> collidesWith(GameItem gi)
{
Vector<GameItem> collideList = new Vector<GameItem>();
for (Player p : m_players.values())
{
if (p != gi && p.health > 0.0 && collidesWith(gi, p))
collideList.add(p);
}
for (Shot s : m_shots.values())
{
if (s != gi && collidesWith(gi, s))
collideList.add(s);
}
return collideList;
}
public boolean collidesWith(GameItem i1, GameItem i2)
{
double dx = i2.x - i1.x;
double dy = i2.y - i1.y;
double d2 = dx*dx + dy*dy;
double r = i1.radius + i2.radius;
double r2 = r*r;
return (d2 < r2);
}
public HashMap<String, Player> getPlayers()
{
return m_players;
}
public HashMap<Integer, Shot> getShots()
{
return m_shots;
}
public void step()
{
long curtime = (new Date()).getTime();
double elapsed = (curtime - m_lastStepTime) / 1000.0;
if (m_lastStepTime == 0)
elapsed = 0.001;
for (Player p : m_players.values())
{
p.x += p.dx * elapsed;
p.y += p.dy * elapsed;
p.r += p.dr * elapsed;
if (p.x < 0.0) p.x += 1.0;
if (p.x > 1.0) p.x -= 1.0;
if (p.y < 0.0) p.y += 1.0;
if (p.y > 1.0) p.y -= 1.0;
if (p.r < 0.0) p.r += Math.PI*2;
if (p.r > Math.PI*2) p.r -= Math.PI*2;
}
Vector<Integer> shotIDs = new Vector<Integer>();
shotIDs.addAll(m_shots.keySet());
for (Integer i : shotIDs)
{
Shot s = m_shots.get(i);
if (((curtime - s.createTime) / 1000.0) >= Shot.SHOT_DURATION)
{
m_shots.remove(i);
i++;
}
else
{
s.x += s.dx * elapsed;
s.y += s.dy * elapsed;
}
}
/* calculate damage against players */
for (Player p : m_players.values())
{
Vector<GameItem> objs = collidesWith(p);
for (GameItem gi : objs)
{
if (gi instanceof Player)
{
p.health -= Player.COLLIDE_DAMAGE;
}
if (gi instanceof Shot)
{
p.health -= Shot.SHOT_DAMAGE;
Integer ifound = null;
for (Integer i : m_shots.keySet())
{
if (m_shots.get(i) == gi)
{
ifound = i;
break;
}
}
if (ifound != null)
m_shots.remove(ifound);
}
if (p.health < 0.0)
p.health = 0.0;
}
}
m_lastStepTime = curtime;
}
}

View File

@ -0,0 +1,9 @@
public class GameItem
{
public double radius;
public double x;
public double y;
public double dx;
public double dy;
}

View File

@ -0,0 +1,41 @@
public class Player extends GameItem
{
public static final double DEFAULT_RADIUS = 0.06;
public static final double COLLIDE_DAMAGE = 0.002;
public static final double SHOT_DELAY = 4.0;
public String name;
public double health;
public double r;
public double dr;
public long lastShotTime;
public Player(String name)
{
this.name = name;
this.radius = DEFAULT_RADIUS;
this.health = 1.0;
this.r = Math.random() * Math.PI * 2;
this.dr = 0;
this.dx = 0;
this.dy = 0;
}
public boolean equals(Player other)
{
return this.name.equals(other.name) &&
this.radius == other.radius &&
this.health == other.health &&
this.r == other.r &&
this.dr == other.dr &&
this.dx == other.dx &&
this.dy == other.dy;
}
public String toString()
{
return String.format("%s:%.3f:%.3f:%.3f:%.3f:%.3f:%.3f:%.3f:%.3f",
name, radius, health, x, y, r, dr, dx, dy);
}
}

View File

@ -0,0 +1,37 @@
public class Shot extends GameItem
{
public static final double DEFAULT_RADIUS = 0.03;
public static final double SHOT_DURATION = 3.0;
public static final double SHOT_DAMAGE = 0.27;
public long createTime;
public Integer id;
public Shot(Integer id, long createTime, double x, double y)
{
this.id = id;
this.createTime = createTime;
this.radius = DEFAULT_RADIUS;
this.x = x;
this.y = y;
this.dx = 0;
this.dy = 0;
}
public boolean equals(Shot other)
{
return this.createTime == other.createTime &&
this.radius == other.radius &&
this.x == other.x &&
this.y == other.y &&
this.dx == other.dx &&
this.dy == other.dy;
}
public String toString()
{
return String.format("%d:%.3f:%.3f:%.3f:%.3f:%.3f",
id, radius, x, y, dx, dy);
}
}

1
cs654/final-proj/make.bat Executable file
View File

@ -0,0 +1 @@
javac *.java

1
cs654/final-proj/run.bat Executable file
View File

@ -0,0 +1 @@
java BlobWars

1
cs654/final-proj/runserver.bat Executable file
View File

@ -0,0 +1 @@
java BlobWarsServer