/*press arrow key to move, press space key to shoot*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Rectangle2D;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
/*******game graphics********/
public class MonitorVehicleTrackerDemo {
static final Random rd = new Random();
static final int TOTALENEMIES = 20;
static final int ENEMYMOVINGSPEED = 10;
public static void main(String[] args) {
JFrame mainFrame = new JFrame("Concurrency");
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setBounds(10, 10, 400, 400);
mainFrame.setLayout(new BorderLayout());
JPanel mainPanel = new JPanel();
mainPanel.setBackground(Color.WHITE);
Map<String, MutablePoint> locations = new HashMap<>();
for(int i = 0; i < TOTALENEMIES; i++) {
locations.put("tank" + i, new MutablePoint());
}
final MonitorVehicleTracker mt = new MonitorVehicleTracker(locations);
final GameBoard paintPanel = new GameBoard(mt);
mainFrame.add(mainPanel, BorderLayout.PAGE_START);
mainFrame.add(paintPanel, BorderLayout.CENTER);
mainFrame.setVisible(true);
Thread tankMoveThread = new Thread(
new Runnable(){
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
Map<String, MutablePoint> locations = mt.getLocations();
for(String key: locations.keySet()) {
MutablePoint mp = mt.getLocation(key);
mp.x += rd.nextInt(ENEMYMOVINGSPEED) * (Math.random() > 0.5 ? 1 : -1);
mp.y += rd.nextInt(ENEMYMOVINGSPEED) * (Math.random() > 0.5 ? 1 : -1);
if(mp.x > 400 - 20 || mp.y > 400 - 25 || mp.x < 20 || mp.y < 25)
mp.x = mp.y = 100;
mt.setLocation(key, mp.x, mp.y, mp.alive);
}
paintPanel.repaint();
}
}
});
tankMoveThread.start();
Thread waveThread = new Thread(
new Runnable(){
@Override
public void run() {
while(!Thread.currentThread().isInterrupted()) {
try {
Thread.sleep(10000);
for(int i = 0; i < 50; i++) {
Thread.sleep(100);
Map<String, MutablePoint> locations = mt.getLocations();
for(String key: locations.keySet()) {
MutablePoint mp = mt.getLocation(key);
mp.y += 5;
mt.setLocation(key, mp.x, mp.y, mp.alive);
}
paintPanel.repaint();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
waveThread.start();
}
}
class GameBoard extends JPanel implements KeyListener {
int dx = 200;
int dy = 300;
int lazerBeam = 0;
public Rectangle2D rec = new Rectangle2D.Double(dx , dy, 30, 10);
public Rectangle2D lazer = new Rectangle2D.Double(dx + 15 , 0, 0, 0);
private MonitorVehicleTracker mt;
public GameBoard(MonitorVehicleTracker mt) {
this.addKeyListener(this);
this.setBackground(Color.white);
this.setFocusable(true);
this.mt = mt;
}
public void shoot(KeyEvent evt){
if (evt.getKeyCode() == KeyEvent.VK_SPACE){
System.out.println("space key");
}
lazerBeam = 300;
lazer.setRect(dx + 15 , 0, 0, lazerBeam);
repaint();
}
public void moveRec(KeyEvent evt){
lazerBeam = 0;
switch(evt.getKeyCode()){
case KeyEvent.VK_LEFT:
//System.out.println("test");
dx -= 2;
rec.setRect(dx, dy, 30, 10);
lazer.setRect(dx + 15 , 0, 0, lazerBeam);
repaint();
break;
case KeyEvent.VK_RIGHT:
dx += 2;
rec.setRect(dx, dy, 30, 10);
lazer.setRect(dx + 15 , 0, 0, lazerBeam);
repaint();
break;
}
}
@Override
protected void paintComponent(Graphics grphcs){
cleanDead();
super.paintComponent(grphcs);
Graphics2D gr = (Graphics2D) grphcs;
rec.setRect(dx, dy, 30, 10);
lazer.setRect(dx + 15 , 0, 0, lazerBeam);
gr.draw(rec);
gr.draw(lazer);
Map<String, MutablePoint> locations = mt.getLocations();
for(String key: locations.keySet()) {
MutablePoint mp = mt.getLocation(key);
if(mp.alive)
drawTank(grphcs, mp.x, mp.y);
}
}
private void drawTank(Graphics g, int x, int y) {
g.setColor (Color.yellow);
g.draw3DRect (x, y, 20, 25, true);
g.draw3DRect (x+10, y+12, 2, 25, false);
}
private void cleanDead() {
Map<String, MutablePoint> locations = mt.getLocations();
for(String key: locations.keySet()) {
MutablePoint mp = mt.getLocation(key);
if(!mp.alive) continue;
if(overlaps(mp.x, mp.y, 20, 25, rec)
|| overlaps(mp.x + 10, mp.y + 12, 2, 25, rec)) {
mt.setLocation(key, mp.x, mp.y, false);
lazerBeam = 0;
dx = dy = -100;
}
if(overlaps(mp.x, mp.y, 20, 25, lazer)
|| overlaps(mp.x + 10, mp.y + 12, 2, 25, lazer)) {
mt.setLocation(key, mp.x, mp.y, false);
}
}
}
private boolean overlaps (int x, int y, int width, int height, Rectangle2D r) {
return x < r.getX() + r.getWidth()
&& x + width > r.getX()
&& y < r.getY() + r.getHeight()
&& y + height > r.getY();
}
@Override
public void keyTyped(KeyEvent e) {
shoot(e);
}
@Override
public void keyPressed(KeyEvent e) {
moveRec(e);
}
@Override
public void keyReleased(KeyEvent e) {
lazerBeam = 0;
lazer.setRect(dx + 15 , 0, 0, lazerBeam);
repaint();
int i = 0;
Map<String, MutablePoint> locations = mt.getLocations();
for(String key: locations.keySet()) {
MutablePoint mp = mt.getLocation(key);
if(!mp.alive)
i ++ ;
}
System.out.println(i + " tanks destroied");
}
}
/*********game engine**********/
class MonitorVehicleTracker {
private final Map<String, MutablePoint> locations;
public MonitorVehicleTracker(Map<String, MutablePoint> locations) {
this.locations = deepCopy(locations);
}
public synchronized Map<String, MutablePoint> getLocations() {
return deepCopy(locations);
}
public synchronized MutablePoint getLocation(String id) {
MutablePoint loc = locations.get(id);
return loc == null ? null : new MutablePoint(loc);
}
public synchronized void setLocation(String id, int x, int y, boolean alive) {
MutablePoint loc = locations.get(id);
if (loc == null)
throw new IllegalArgumentException("No such ID: " + id);
loc.x = x;
loc.y = y;
loc.alive = alive;
}
private static Map<String, MutablePoint> deepCopy(Map<String, MutablePoint> m) {
Map<String, MutablePoint> result = new HashMap<String, MutablePoint>();
for (String id : m.keySet())
result.put(id, new MutablePoint(m.get(id)));
return Collections.unmodifiableMap(result);
}
}
class MutablePoint {
public int x, y;
public boolean alive;
public MutablePoint() {
x = 0;
y = 0;
alive = true;
}
public MutablePoint(MutablePoint p) {
this.x = p.x;
this.y = p.y;
this.alive = p.alive;
}
}