package game.client;
import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.swing.*;
import game.ClientRemovedEvent;
import game.FireEvent;
import game.GameEvent;
import game.GameListener;
import game.GameObjectLocation;
import game.GameObjectLocation.Type;
import game.NewClientEvent;
import game.ObjectMoveEvent;
import game.ObjectMoveEvent.Directions;
import game.ObjectMoveEvent.Turns;
import game.ObjectsUpdateEvent;
import game.RemoveClientEvent;
import game.impl.AbstractInputSource;
import game.impl.NetworkGameControllerClient;
import game.impl.SimpleGameController;
@SuppressWarnings("serial")
public class Client extends JFrame {
Image tank;
NetworkGameControllerClient client;
KeyboardInputSource inputSource = new KeyboardInputSource();
SwingListener listener = new SwingListener();
JPanel panel;
private Map<String, GameObjectLocation> objects = new HashMap<String, GameObjectLocation>();
private String id;
public Client() throws Exception {
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu menu = new JMenu("File");
menuBar.add(menu);
JMenuItem menuItem = new JMenuItem("Connect");
menu.add(menuItem);
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
connect();
}
});
menuItem = new JMenuItem("Dicsonnect");
menuItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
disconnect();
}
});
menu.add(menuItem);
tank = getToolkit().getImage(getClass().getClassLoader().getResource("tank.png"));
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
panel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
synchronized (objects) {
for (GameObjectLocation gameObject : objects.values()) {
if (gameObject.getType() == Type.BULLET) {
g.setColor(Color.RED);
g.fillOval(gameObject.getX(), gameObject.getY(), 5, 5);
} else {
double angle = (90 - gameObject.getHeading()) * Math.PI / 180.0;
int tankWidth = tank.getWidth(null) / 2;
Graphics2D gg = (Graphics2D) g;
gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
AffineTransform affn = new AffineTransform();
affn.rotate(angle, gameObject.getX(), gameObject.getY());
affn.translate(gameObject.getX() - tankWidth, gameObject.getY() - tankWidth);
gg.drawImage(tank, affn, this);
}
}
}
}
};
addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
if (client != null) {
client.onRemoveClient(new RemoveClientEvent(id));
client.shutdown();
}
System.exit(0);
}
});
new Thread(listener).start();
getContentPane().add(panel);
setSize(640, 480);
}
private void disconnect() {
removeKeyListener(inputSource);
client.shutdown();
client = null;
synchronized (objects) {
objects.clear();
}
repaint();
}
private void connect() {
if (client != null) {
return;
}
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
try {
client = new NetworkGameControllerClient(listener);
Thread.sleep(1000);
id = "" + System.currentTimeMillis();
addKeyListener(inputSource);
inputSource.setGameCommands(client);
inputSource.onNewClient(new NewClientEvent(id));
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
public static void main(String[] args) throws Exception {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
new Client().setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private class KeyboardInputSource extends AbstractInputSource implements KeyListener {
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
Directions direction = null;
Turns turn = null;
switch (e.getKeyCode()) {
case KeyEvent.VK_UP:
direction = Directions.FORWARD;
break;
case KeyEvent.VK_DOWN:
direction = Directions.BACKWARD;
break;
case KeyEvent.VK_LEFT:
turn = Turns.LEFT;
break;
case KeyEvent.VK_RIGHT:
turn = Turns.RIGHT;
break;
case KeyEvent.VK_SPACE:
onFire(new FireEvent(id));
break;
}
if (direction != null || turn != null) {
ObjectMoveEvent event = new ObjectMoveEvent(id, direction, turn);
onUserControl(event);
}
}
public void keyReleased(KeyEvent e) {
}
}
private class SwingListener implements GameListener, Runnable {
private List<GameEvent> events = Collections.synchronizedList(new ArrayList<GameEvent>());
public void onObjectsUpdate(final ObjectsUpdateEvent e) {
events.add(e);
}
@Override
public void onClientRemoved(ClientRemovedEvent e) {
events.add(e);
}
@Override
public void run() {
while (true) {
try {
Thread.sleep(SimpleGameController.STEP_DELAY);
} catch (InterruptedException e) {
break;
}
synchronized (events) {
if (events.isEmpty()) {
continue;
}
for (GameEvent e : events) {
if (e instanceof ObjectsUpdateEvent) {
synchronized (objects) {
for (GameObjectLocation location : ((ObjectsUpdateEvent) e).getObjects()) {
objects.put(location.getId(), location);
}
}
} else if (e instanceof ClientRemovedEvent) {
synchronized (objects) {
objects.remove(e.getSource());
}
}
}
events.clear();
}
panel.repaint();
}
}
}
}