大概用了兩天半的課餘,一共四五個多小時的時間做的,一千行代碼的小遊戲。先實現了尚學堂版坦克大戰,一邊看PPT一邊自己寫,不會實現的地方看視頻,一點點做了來以後,然後根據自己的想法進行了修改:
1. 加強AI,優化了坦克撞牆不回頭的問題
2. 敵我使用兩種顏色子彈
3. 敵方坦克死光後,隨機生成十輛坦克,並避免卡牆。
代碼:
TankClient.java
import java.awt.*;
import java.util.*;
import java.awt.event.*;
public class TankClient extends Frame {
Image offScreenImage = null;
Tank tank = new Tank(600,325,this,Tank.Direction.STOP,true);
LinkedList<Missile> missiles = new LinkedList<Missile>();
LinkedList<Explode> explodes = new LinkedList<Explode>();
LinkedList<Tank> tanks = new LinkedList<Tank>();
LinkedList<Missile> eMissiles = new LinkedList<Missile>();
Blood b = new Blood();
Random r = new Random(); //添加隨機數,用於隨機生成坦克
Wall w=new Wall(500, 200, 20, 250, this);
public static final int WINDOW_HEIGHT = 600,WINDOW_WIDTH = 800;
public static void main(String[] args) {
new TankClient().launchFrame();
}
public void launchFrame(){
for(int i=0;i<10;i++){
tanks.add(new Tank(50, (50*i+120), this, Tank.Direction.D, false));
}
setBounds(600,300,WINDOW_WIDTH,WINDOW_HEIGHT);
setVisible(true);
this.setResizable(false);
this.addKeyListener(new KeyMonitor());
setBackground(Color.lightGray);
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e)
{
setVisible(false);
System.exit(0);
}
});
new Thread(new rePaint()).start();
}
public void paint(Graphics g)
{
if(tanks.size()<=0){
for(int i=0;i<10;i++){
int newX,newY;
Tank t = new Tank(newX=r.nextInt(500),newY=r.nextInt(600), this, Tank.Direction.D, false); //用於隨機生成坦克
while(new Rectangle(newX,newY,30,30).intersects( w.getRect())){ //與牆進行碰撞檢測
t = new Tank(newX=r.nextInt(500),newY=r.nextInt(600), this, Tank.Direction.D, false);
}
tanks.add(t);
}
}
Color c = g.getColor();
/*
for(Missile m:missiles) //用此種循環會出現Exception,故放棄
{
if(!m.getExist())
missiles.remove(m);
m.drawMissile(g);
m.hitTank(eTank);
}
*/
for(int i=0;i<missiles.size();i++){
Missile m = missiles.get(i);
m.hitTanks(tanks);
m.hitTank(tank);
m.drawMissile(g);
m.hitWall(w);
}
for(int i=0;i<tanks.size();i++){
Tank t = tanks.get(i);
t.collidesWall(w);
t.drawTank(g);
t.collidesTanks(tanks);
}
tank.collidesWall(w);
tank.collidesTanks(tanks);
tank.eat();
for(int i=0;i<explodes.size();i++)
{
Explode e = explodes.get(i);
e.draw(g);
}
w.drawWall(g);
b.draw(g);
g.drawString("missiles count:"+missiles.size(), 30, 60);
g.drawString("explodes count:"+explodes.size(), 30, 75);
g.drawString("enemy tanks count:"+tanks.size(), 30, 90);
g.drawString("tank life:"+tank.getLife(), 30, 105);
tank.drawTank(g);
g.setColor(c);
}
public void update(Graphics g){
if(offScreenImage==null){
offScreenImage = this.createImage(WINDOW_WIDTH, WINDOW_HEIGHT);
}
Graphics gOffScreen = offScreenImage.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.lightGray);
gOffScreen.fillRect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
gOffScreen.setColor(c);
paint(gOffScreen);
g.drawImage(offScreenImage, 0, 0, null);
}
private class rePaint implements Runnable{
public void run(){
while(true)
{
repaint();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class KeyMonitor extends KeyAdapter{
public void keyPressed(KeyEvent e)
{
tank.keyPressed(e);
}
public void keyReleased(KeyEvent e)
{
tank.keyReleased(e);
}
}
}
Tank.java
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Tank {
enum Direction {L,LU,U,UR,R,RD,D,LD,STOP};
private static final int XSPEED = 5;
private static final int YSPEED = 5;
private static final int WIDTH = 30;
private static final int HEIGHT = 30;
private boolean good = true;
private boolean live = true;
private int life = 100;
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
private int x,y;
private int oldX,oldY;
private static Random r = new Random();
private boolean bL = false;
private boolean bU = false;
private boolean bR = false;
private boolean bD = false;
private boolean pL = false;
private boolean pU = false;
private boolean pR = false;
private boolean pD = false;
private Direction direc = Direction.STOP;
private Direction ptDirec = Direction.D;
private BloodBar bb = new BloodBar();
private int step = r.nextInt(12)+3;
TankClient tc;
Tank(int x,int y, TankClient tc,Direction dir,Boolean good)
{
this.x = x;
this.y = y;
this.tc = tc;
this.direc = dir;
this.good = good;
this.direc = dir;
this.oldX = x;
this.oldY = y;
new Thread(new Runnable(){
public void run() {
}
}).start();
}
public void drawTank(Graphics g){
if(this.live==false) {
if(!good){
tc.tanks.remove(this);
}
return;
}
Color c = g.getColor();
if(good==true)
g.setColor(Color.RED);
else
g.setColor(Color.BLUE);
g.fillOval(x, y, 30, 30);
g.setColor(Color.BLACK);
bb.draw(g);
switch(ptDirec){
case D:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH/2, y+HEIGHT);
break;
case L:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x, y+HEIGHT/2);
break;
case LD:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x, y+HEIGHT);
break;
case LU:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x, y);
break;
case R:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH, y+HEIGHT/2);
break;
case RD:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH, y+HEIGHT);
break;
case U:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH/2, y);
break;
case UR:
g.drawLine(x+WIDTH/2, y+HEIGHT/2, x+WIDTH, y);
break;
}
g.setColor(c);
move();
}
private synchronized void stay(){
x = oldX;
y = oldY;
if(!this.good){
switch(this.direc){ //坦克不會傻傻的頂着牆跑了
case D:
this.direc = Direction.U;
break;
case L:
this.direc = Direction.R;
break;
case LD:
this.direc = Direction.UR;
break;
case LU:
this.direc = Direction.RD;
break;
case R:
this.direc = Direction.L;
break;
case RD:
this.direc = Direction.LU;
break;
case U:
this.direc = Direction.D;
break;
case UR:
this.direc = Direction.LD;
break;
default:
step=r.nextInt(12)+3; //優化:翻身撞牆後不會立即調整方向
}
}
}
private void move()
{
oldX = x;
oldY = y;
switch(direc){
case D:
y += YSPEED;
break;
case L:
x -= XSPEED;
break;
case LD:
x -= XSPEED;
y += YSPEED;
break;
case LU:
x -= XSPEED;
y -= YSPEED;
break;
case R:
x += XSPEED;
break;
case RD:
x += XSPEED;
y += YSPEED;
break;
case STOP:
break;
case U:
y -= YSPEED;
break;
case UR:
x += XSPEED;
y -= YSPEED;
break;
}
if(this.direc != Direction.STOP){
ptDirec = direc;
}
while(x<0) x=0;
while(y<30) y=30;
while(x+Tank.WIDTH>TankClient.WINDOW_WIDTH ) x=TankClient.WINDOW_WIDTH-Tank.WIDTH;
while(y+Tank.HEIGHT>TankClient.WINDOW_HEIGHT ) y=TankClient.WINDOW_HEIGHT-Tank.HEIGHT;
if(!good){
if(step==0){
Direction[] dirs = Direction.values();
int ranNum = r.nextInt(dirs.length);
direc = dirs[ranNum];
step=r.nextInt(12)+3;
}
step--;
if(r.nextInt(40)>36){
this.fire();
}
}
}
public void keyPressed(KeyEvent e)
{
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_DOWN:
bD = true;
pD = true;
break;
case KeyEvent.VK_LEFT:
bL = true;
pL = true;
break;
case KeyEvent.VK_UP:
bU = true;
pU = true;
break;
case KeyEvent.VK_RIGHT:
bR = true;
pR = true;
break;
}
locate();
}
public void fire() {
if(!live) return;
int x = this.x+this.WIDTH/2-Missile.WIDTH/2;
int y = this.y+this.HEIGHT/2-Missile.HEIGHT/2;
tc.missiles.add(new Missile(x,y,good,ptDirec,tc,this)); //修改構造函數
}
public void fire(Direction dir) {
if(!live) return;
int x = this.x+this.WIDTH/2-Missile.WIDTH/2;
int y = this.y+this.HEIGHT/2-Missile.HEIGHT/2;
tc.missiles.add(new Missile(x,y,good,dir,tc,this)); //修改構造函數
}
public void superFire(){
Direction[] dirs = Direction.values();
for(int i=0;i<dirs.length-1;i++){
fire(dirs[i]);
}
}
public Direction getPtDirec() {
return ptDirec;
}
public void setPtDirec(Direction ptDirec) {
this.ptDirec = ptDirec;
}
public boolean isGood() {
return good;
}
public void locate()
{
if(!bD && bL && !bU && !bR) direc = Direction.L;
else if(!bD && bL && bU && !bR) direc = Direction.LU;
else if(!bD && !bL && bU && !bR) direc = Direction.U;
else if(!bD && !bL && bU && bR) direc = Direction.UR;
else if(!bD && !bL && !bU && bR) direc = Direction.R;
else if(bD && !bL && !bU && bR) direc = Direction.RD;
else if(bD && !bL && !bU && !bR) direc = Direction.D;
else if(bD && bL && !bU && !bR) direc = Direction.LD;
else if(!bD && !bL && !bU && !bR) direc = Direction.STOP;
/*
if(!pD && bL && !pU && !pR) ptDirec = Direction.L;
else if(!pD && pL && pU && !pR) ptDirec = Direction.LU;
else if(!pD && !pL && pU && !pR) ptDirec = Direction.U;
else if(!pD && !pL && pU && pR) ptDirec = Direction.UR;
else if(!pD && !pL && !pU && pR) ptDirec = Direction.R;
else if(pD && !pL && !pU && pR) ptDirec = Direction.RD;
else if(pD && !pL && !pU && !pR) ptDirec = Direction.D;
else if(pD && pL && !pU && !pR) ptDirec = Direction.LD;
太麻煩!!!
*/
// move();
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_F2:{
this.live = true;
this.life = 100;
}
case KeyEvent.VK_DOWN:
bD = false;
pD = false;
break;
case KeyEvent.VK_LEFT:
bL = false;
pL = false;
break;
case KeyEvent.VK_UP:
bU = false;
pU = false;
break;
case KeyEvent.VK_RIGHT:
bR = false;
pR = false;
break;
case KeyEvent.VK_Z:
this.fire();
break;
case KeyEvent.VK_X:
superFire();
break;
}
locate();
}
public boolean getLive()
{
return this.live;
}
public void setLive(boolean live)
{
this.live = live;
}
public Rectangle getRect()
{
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public boolean collidesWall(Wall w){
if(this.getRect().intersects(w.getRect())){
stay();
return true;
}
return false;
}
public boolean collidesTanks(java.util.List<Tank> tanks){
for(int i=0;i<tanks.size();i++){
Tank t = tanks.get(i);
if(t!=this && this.live == true && t.getLive() == true &&this.getRect().intersects(t.getRect())){
this.stay();
t.stay();
return true;
}
}
return false;
}
public boolean eat(){
if(this.live && tc.b.isLive() && tc.b.getRect().intersects(this.getRect())){
this.life = 100;
tc.b.setLive(false);
return true;
}
return false;
}
private class BloodBar{
protected void draw(Graphics g){
Color c = g.getColor();
int w = WIDTH*life/100;
g.setColor(Color.red);
g.drawRect(x, y-10, WIDTH, 5);
g.fillRect(x, y-10, w, 5);
g.setColor(c);
}
}
}
Missile.java
import java.awt.*;
import java.util.ArrayList;
import java.util.LinkedList;
public class Missile {
int x,y;
TankClient tc;
Tank.Direction direc;
public static final int XSPEED = 12;
public static final int YSPEED = 12;
public static final int WIDTH = 10;
public static final int HEIGHT = 10;
private boolean exist = true;
private boolean good;
private Tank from;
/*
Missile(int x, int y,Tank.Direction direc){
this.x = x;
this.y = y;
this.direc = direc;
}
Missile(int x, int y,Tank.Direction direc,TankClient tc){
this.x = x;
this.y = y;
this.direc = direc;
this.tc = tc;
}
*/
Missile(int x, int y,boolean good,Tank.Direction direc,TankClient tc,Tank from){
this.x = x;
this.y = y;
this.direc = direc;
this.tc = tc;
this.good = good;
this.from = from;
}
public void drawMissile(Graphics g){
if(this.exist==false){
tc.missiles.remove(this);
return;
}
Color c = g.getColor();
if(!this.from.isGood()){
g.setColor(Color.BLUE);
}
else
g.setColor(Color.BLACK);
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(c);
move();
}
public void move(){
switch(direc){
case D:
y += YSPEED;
break;
case L:
x -= XSPEED;
break;
case LD:
x -= XSPEED;
y += YSPEED;
break;
case LU:
x -= XSPEED;
y -= YSPEED;
break;
case R:
x += XSPEED;
break;
case RD:
x += XSPEED;
y += YSPEED;
break;
case U:
y -= YSPEED;
break;
case UR:
x += XSPEED;
y -= YSPEED;
break;
}
if(x <0 || y<0 || x>TankClient.WINDOW_WIDTH ||y>TankClient.WINDOW_HEIGHT)
this.exist = false;
}
public Rectangle getRect()
{
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public boolean getExist()
{
return this.exist;
}
public boolean hitTank(Tank t)
{
if(this.exist &&this.getRect().intersects(t.getRect()) && t.getLive() && this.good != t.isGood()) //碰撞檢測
{
if(t.isGood()){
t.setLife(t.getLife()-10);
if(t.getLife()<=0)
t.setLive(false);
}else{
t.setLife(t.getLife()-25);
if(t.getLife()<=0)
t.setLive(false);
}
this.exist = false;
tc.explodes.add(new Explode(x,y,tc));
return true;
}
return false;
}
public boolean hitTanks(LinkedList<Tank> tanks)
{
Tank t = null;
for(int i=0;i<tc.tanks.size();i++){
t = tanks.get(i);
if(hitTank(t))
{
return true;
}
}
return false;
}
public boolean hitWall(Wall w){
if(this.exist == true && this.getRect().intersects(w.getRect())){
this.exist = false;
}
return true;
}
}
Wall.java
import java.awt.*;
/*
* 坦克不能穿過
* 子彈碰撞會消失
*/
public class Wall {
private int x,y,width,height;
TankClient tc;
public Wall(int x,int y,int width,int height,TankClient tc){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.tc = tc;
}
public void drawWall(Graphics g)
{
Color c = g.getColor();
g.fillRect(x, y, width, height);
g.setColor(c);
}
public Rectangle getRect()
{
return new Rectangle(x,y,width,height);
}
}
Explode.java
import java.awt.*;
public class Explode {
private int x,y;
private boolean live = true;
private int[] diameter = {4 ,7 ,12 ,18 ,26 ,32 ,49 ,30 ,14 ,6};
private int step = 0;
private TankClient tc;
public Explode(int x,int y,TankClient tc){
this.x = x;
this.y = y;
this.tc = tc;
}
public void draw(Graphics g){
if(live==false){
tc.explodes.remove(this);
return;
}
if(step==diameter.length){
live = false;
return;
}
Color c = g.getColor();
g.setColor(Color.orange);
g.fillOval(x, y, diameter[step], diameter[step]);
g.setColor(c);
step++;
}
}
Blood.java
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
public class Blood {
private int[][] loc = {
{120,150},{130,170},{140,165},{150,135},{125,145},{123,147}};
private static int width = 10;
private static int height = 10;
private int step = 0;
private boolean live=true;
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
public void draw(Graphics g){
if(!this.live) return;
Color c = g.getColor();
g.setColor(Color.MAGENTA);
g.fillRect(loc[step][0], loc[step][1], width, height);
g.setColor(c);
step++;
if(step==loc.length)
step=0;
}
public Rectangle getRect(){
return new Rectangle(loc[step][0], loc[step][1], width, height);
}
}