按照教程写了一个Java小游戏,花了19天时间去抄了一遍,今天终于抄完了 。:.゚ヽ(。◕‿◕。)ノ゚.:。+゚
github地址:https://github.com/qq1367212627/kuaidi
此项目是根据尚学堂的马士兵老师的视频教程写的,有兴趣的同学可以搜索一下,以下是代码
坦克游戏主程序
package TankClient;
import Blood.Blood;
import Missile.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import TankClient.Tank.*;
import Wall.Wall;
public class TankClient extends Frame {
public static final int GAME_WIDTH = 800;
public static final int GAME_HEIGHT = 600;
Tank myTank = new Tank(400, 400,true, Direction.STOP,this); //将本身的引用传递过去,实现获取Missile的数据
public ArrayList<Missile> missiles = new ArrayList<Missile>();
public ArrayList<Explode> expelodes =new ArrayList<Explode>();
public ArrayList<Tank> tanks = new ArrayList<Tank>(); //多个坦克
Image offScreenImage = null;
Wall w1=new Wall(100,200,20,150,this);
Wall w2=new Wall(300,100,300,20,this);
private Blood b= new Blood();
public void paint(Graphics g) {
g.drawString("炮弹数量:"+missiles.size(),50,50);
g.drawString("爆炸数量:"+expelodes.size(),50,70);
g.drawString("敌人数量:"+tanks.size(),50,90);
g.drawString("生命值:"+myTank.getLife(),50,110);
if(tanks.size()<=0)addTanks();
for(int i=0;i<missiles.size();i++) { //画出所有的炮弹
Missile m = missiles.get(i);
m.hitTanks(tanks);
m.hitTank(myTank);
m.hitWall(w1);
m.hitWall(w2);
if (m != null) m.draw(g); //判断是否是非空的
}
for(int i = 0;i<expelodes.size();i++){
Explode ex = expelodes.get(i);
if(!ex.isLive()){ //若不存活则移除
expelodes.remove(ex);
}
else
if(ex!=null)ex.draw(g);
}
for(int i = 0;i<tanks.size();i++){
Tank t = tanks.get(i);
t.coollideWithWall(w1);
t.coollideWithWall(w2);
t.coollideWithTanks(tanks);
t.coollideWithTank(myTank); //和玩家的坦克碰撞
if(t.isLive()&&t!=null){
t.draw(g);
}
else{
tanks.remove(t);
}
}
myTank.coollideWithWall(w1);
myTank.coollideWithWall(w2); //添加坦克与墙的碰撞
myTank.draw(g);
w1.draw(g);
w2.draw(g);
b.draw(g);
myTank.Eat(b);
}
public void update(Graphics g) { //重写update方法,双缓冲消除闪烁
if(offScreenImage == null) {
offScreenImage = this.createImage(GAME_WIDTH, GAME_HEIGHT);
}
Graphics gOffScreen = offScreenImage.getGraphics();
Color c = gOffScreen.getColor();
gOffScreen.setColor(Color.GREEN);
gOffScreen.fillRect(0, 0, GAME_WIDTH, GAME_HEIGHT);
gOffScreen.setColor(c);
paint(gOffScreen);
g.drawImage(offScreenImage, 0, 0, null);
}
public void lauchFrame() {
addTanks();
this.setLocation(400, 300);
this.setSize(GAME_WIDTH, GAME_HEIGHT);
this.setTitle("TankWar");
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setResizable(false);
this.setBackground(Color.GREEN);
this.addKeyListener(new KeyMonitor());
setVisible(true);
new Thread(new PaintThread()).start();
}
public static void main(String[] args) {
TankClient tc = new TankClient();
tc.lauchFrame();
}
private class PaintThread implements Runnable {
public void run() {
while(true) {
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private class KeyMonitor extends KeyAdapter {
public void keyReleased(KeyEvent e) {
myTank.keyReleased(e);
}
public void keyPressed(KeyEvent e) {
myTank.keyPressed(e);
}
}
private void addTanks(){
for(int i = 0 ; i<10 ; i++){
tanks.add(new Tank(50+40*i,50, false,Direction.D,this));
}
}
}
package TankClient;
import Blood.Blood;
import Missile.Missile;
import Wall.Wall;
import com.sun.org.apache.bcel.internal.generic.DREM;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Random;
public class Tank {
public static final int XSPEED = 5;
public static final int YSPEED = 5; //坦克速度
public static final int WIDTH = 30;
public static final int HEIGHT = 30;
public TankClient tc = null; //持有TankClient的引用实现数据传输
private Direction ptDir = Direction.D; //炮筒的方向
private int x, y;
private boolean good; //敌我标记
private boolean bL = false, bU = false, bR = false, bD = false; //方向的确定
public enum Direction {L, LU, U, RU, R, RD, D, LD, STOP}; //方向
private static Random r = new Random();
private int step = r.nextInt(8) + 3; //延时标记,使得坦克多移动一些距离
int oldx, oldy;
private boolean Live = true; //记录坦克是否存活
private Direction dir = Direction.STOP; //初始化为停止
private BloodBar bb = new BloodBar();
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
private int life=100;
public boolean isGood() {
return good;
}
public void setGood(boolean good) {
this.good = good;
}
public boolean isLive() {
return Live;
}
public void setLive(boolean live) {
Live = live;
}
public Tank(int x, int y, boolean _good) {
this.x = x;
this.y = y;
this.oldx = x;
this.oldy = y;
this.good = _good;
}
public Tank(int _x, int _y, boolean _good, Direction _dir, TankClient _tc) { //将TankClient 引用传递,实现Missile的交换
this(_x, _y, _good);
this.dir = _dir;
tc = _tc;
}
public void draw(Graphics g) { //画出
if (!Live) {
return;
}
if(this.isGood())bb.draw(g); //若是好坦克,画出血条
Color c = g.getColor();
if (good) g.setColor(Color.RED); //我方坦克为红色
else g.setColor(Color.blue); //敌方的颜色为蓝色
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(c);
switch (ptDir) //画出炮筒的方向
{
case L:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y + Tank.HEIGHT / 2);
break;
case LU:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y);
break;
case U:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH / 2, y);
break;
case RU:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH, y);
break;
case R:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH, y + Tank.HEIGHT / 2);
break;
case RD:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH, y + Tank.HEIGHT);
break;
case D:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x + Tank.WIDTH / 2, y + Tank.HEIGHT);
break;
case LD:
g.drawLine(x + Tank.WIDTH / 2, y + Tank.HEIGHT / 2, x, y + Tank.HEIGHT);
break;
}
if (x < 0) x = 0;
if (y < 30) y = 30;
if (x + Tank.WIDTH > TankClient.GAME_WIDTH) x = TankClient.GAME_WIDTH - Tank.WIDTH;
if (y + Tank.HEIGHT > TankClient.GAME_HEIGHT) y = TankClient.GAME_HEIGHT - Tank.HEIGHT;//判断坦克是否超出边界,如果超出就停下
move();
}
void move() { //运动函数
this.oldx = x;
this.oldy = y;
switch (dir) {
case L:
x -= XSPEED;
break;
case LU:
x -= XSPEED;
y -= YSPEED;
break;
case U:
y -= YSPEED;
break;
case RU:
x += XSPEED;
y -= YSPEED;
break;
case R:
x += XSPEED;
break;
case RD:
x += XSPEED;
y += YSPEED;
break;
case D:
y += YSPEED;
break;
case LD:
x -= XSPEED;
y += YSPEED;
break;
case STOP:
break;
}
if (!good) { //随机产生方向
if (step == 0) {
step = r.nextInt(8) + 3;
Direction[] dirs = Direction.values();
int rn = r.nextInt(dirs.length);
while (dirs[rn] == Direction.STOP)
rn = r.nextInt(dirs.length);
dir = dirs[rn];
ptDir = dir;
}
step--;
if (r.nextInt(40) > 38) this.fire();
}
}
public void keyPressed(KeyEvent e) { //按键被按住的动作
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_LEFT:
bL = true;
break;
case KeyEvent.VK_UP:
bU = true;
break;
case KeyEvent.VK_RIGHT:
bR = true;
break;
case KeyEvent.VK_DOWN:
bD = true;
break;
}
locateDirection();
if (this.dir != Direction.STOP) //保存炮筒的方向
{
ptDir = this.dir;
}
}
void locateDirection() { //判断方向
if (bL && !bU && !bR && !bD) dir = Direction.L;
else if (bL && bU && !bR && !bD) dir = Direction.LU;
else if (!bL && bU && !bR && !bD) dir = Direction.U;
else if (!bL && bU && bR && !bD) dir = Direction.RU;
else if (!bL && !bU && bR && !bD) dir = Direction.R;
else if (!bL && !bU && bR && bD) dir = Direction.RD;
else if (!bL && !bU && !bR && bD) dir = Direction.D;
else if (bL && !bU && !bR && bD) dir = Direction.LD;
else if (!bL && !bU && !bR && !bD) dir = Direction.STOP;
}
public void keyReleased(KeyEvent e) { //按键释放的操作
int key = e.getKeyCode();
switch (key) {
case KeyEvent.VK_CONTROL:
if (this.Live) this.fire(); //添加多个炮弹
break;
case KeyEvent.VK_LEFT:
bL = false;
break;
case KeyEvent.VK_UP:
bU = false;
break;
case KeyEvent.VK_RIGHT:
bR = false;
break;
case KeyEvent.VK_DOWN:
bD = false;
break;
case KeyEvent.VK_A:
if(this.isLive())superFire();
break;
case KeyEvent.VK_F2:
if(!tc.myTank.isLive()){
tc.myTank.setLive(true);
tc.myTank.setLife(100);
}
break;
}
locateDirection();
}
public Missile fire() { //开火方法
int _x = this.x + Tank.WIDTH / 2 - Missile.WIDTH / 2;
int _y = this.y + Tank.HEIGHT / 2 - Missile.HEIGHT / 2; //使子弹从中心发出
Missile m = new Missile(_x, _y, good, ptDir, this.tc); //传递自身引用
this.tc.missiles.add(m);
return m;
}
public Missile fire(Direction Missiledir) { //开火方法
int _x = this.x + Tank.WIDTH / 2 - Missile.WIDTH / 2;
int _y = this.y + Tank.HEIGHT / 2 - Missile.HEIGHT / 2; //使子弹从中心发出
Missile m = new Missile(_x, _y, good, Missiledir, this.tc); //传递自身引用
this.tc.missiles.add(m);
return m;
}
public Rectangle getRect() {
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public boolean coollideWithWall(Wall w) { //判断坦克撞墙
if (this.isLive() && this.getRect().intersects(w.getRect())) {
this.dir = Direction.STOP;
this.stay();
return true;
}
return false;
}
private void stay(){ //回溯到上一次的位置
this.x=this.oldx;
this.y=this.oldy;
}
public boolean coollideWithTank(Tank t){ //与单辆坦克碰撞
if (this!=t&&this.isLive() &&t.isLive() && this.getRect().intersects(t.getRect())) {
this.stay();
t.stay();
return true;
}
return false;
}
public boolean coollideWithTanks(ArrayList<Tank> tanks){ //与多辆坦克碰撞
boolean IscoollideWithTanks=false;
for(int i = 0;i<tanks.size();i++){
Tank t= tanks.get(i);
IscoollideWithTanks=this.coollideWithTank(t);
}
return IscoollideWithTanks;
}
public void superFire(){ //添加超级炮弹功能
Direction[] dirs = Direction.values();
for(int i = 0;i<8;i++){
fire(dirs[i]);
}
}
private class BloodBar{ //血条类
public void draw(Graphics g){
Color c= g.getColor();
g.setColor(Color.red);
g.drawRect(x,y-10,WIDTH,10);
int w = WIDTH*life/100;
g.fillRect(x,y-10,w,10);
g.setColor(c);
}
}
public boolean Eat(Blood b){
if(b.isLive()&&this.isLive()&&this.getRect().intersects(b.getRect())){
this.setLife(100);
b.setLive(false);
return true;
}
return false;
}
}
爆炸类
package TankClient;
import java.awt.*;
/**
* Created by lewis on 2016/10/5.
*/
public class Explode {
int x,y;
private boolean Live=true;
int step=0; //数组下标,记录爆炸的状态
TankClient tc=null;
int [] diameter={4,7,12,18,26,32,49,30,14,6}; //爆炸直径大小
public boolean isLive() {
return Live;
}
public void setLive(boolean live) {
Live = live;
}
public Explode(int _x,int _y,TankClient _tc){
x=_x;
y=_y;
tc=_tc;
}
public void draw(Graphics g){
if(!Live)return ;
if(step==diameter.length){
Live=false;
step=0;
return ;
}
Color c = g.getColor();
g.setColor(Color.ORANGE);
g.fillOval(x,y,diameter[step],diameter[step]);
step++;
}
}
墙类
package Wall;
import TankClient.TankClient;
import java.awt.*;
/**
* Created by lewis on 2016/10/6.
*/
public class Wall{
int x,y,w,h;
TankClient tc;
public Wall(int x, int y, int w, int h, TankClient tc) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.tc = tc;
}
public void draw(Graphics g){
g.fillRect(x,y,w,h);
}
public Rectangle getRect(){
return new Rectangle(x,y,w,h);
}
}
加血血块类
package Blood;
import TankClient.TankClient;
import java.awt.*;
/**
* Created by lewis on 2016/10/6.
* 加血模块
*
*/
public class Blood {
int x,y,w,h,step=0;
TankClient tc;
private boolean Live=true;
private int[][] pos={ //血块 轨迹
{350,300},{360,300},{375,275},{400,200},{360,270},{340,280}
};
public Blood(int x, int y, int w, int h, TankClient tc) {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.tc = tc;
}
public Blood() {
x=pos[0][0];
y=pos[0][1];
w=h=15;
step=0;
}
public void draw(Graphics g){
if(!this.isLive())return;
Color c = g.getColor();
g.setColor( Color.MAGENTA);
g.fillRect(x,y,w,h);
g.setColor(c);
move();
}
private void move(){
step++;
if(step==pos.length) {step=0;}
x=pos[step][0];
y=pos[step][1];
}
public Rectangle getRect(){
return new Rectangle(x,y,w,h);
}
public boolean isLive() {
return Live;
}
public void setLive(boolean live) {
Live = live;
}
}
子弹类
package Missile;
import TankClient.Tank;
import TankClient.TankClient;
import TankClient.Explode;
import Wall.Wall;
import java.awt.*;
import java.util.ArrayList;
public class Missile {
public static final int XSPEED = 10;
public static final int YSPEED = 10;
public static final int WIDTH = 10;
public static final int HEIGHT = 10;
int x, y;
private TankClient tc;
private boolean good;
private boolean Live=true; //判断炮弹是否存活
Tank.Direction dir;
public boolean isLive() {
return Live;
}
public void setLive(boolean live) {
Live = live;
}
public Missile(int x, int y ,Tank.Direction dir) {
this.x = x;
this.y = y;
this.dir = dir;
}
public Missile(int x, int y,boolean _good, Tank.Direction dir,TankClient _tc) {
this(x,y,dir);
this.good=_good;
this.tc=_tc;
}
public void draw(Graphics g) {
if(!Live){
tc.missiles.remove(this);
return ;
}
Color c = g.getColor();
g.setColor(Color.BLACK);
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(c);
move();
}
private void move() {
switch(dir) {
case L:
x -= XSPEED;
break;
case LU:
x -= XSPEED;
y -= YSPEED;
break;
case U:
y -= YSPEED;
break;
case RU:
x += XSPEED;
y -= YSPEED;
break;
case R:
x += XSPEED;
break;
case RD:
x += XSPEED;
y += YSPEED;
break;
case D:
y += YSPEED;
break;
case LD:
x -= XSPEED;
y += YSPEED;
break;
}
if(x<0||y<0||x>TankClient.GAME_WIDTH||y>TankClient.GAME_HEIGHT) { //判断炮弹是否跑出边界
Live=false;
tc.missiles.remove(this); //若炮弹跑出边界则从集合中移除
}
}
public Rectangle getRect(){
return new Rectangle(x,y,WIDTH, HEIGHT);
}
public boolean hitTank(Tank t){ //判断是否相交
if(this.Live&&this.getRect().intersects(t.getRect())&&t.isLive()&&this.good!=t.isGood()) {
if(t.isGood()){ //区分坦克对待
t.setLife(t.getLife()-20);
if(t.getLife()<=0)t.setLive(false);
}
else {
t.setLive(false);
}
this.setLive(false); //炮弹死亡
Explode e = new Explode(x,y,tc);
tc.expelodes.add(e);
return true;
}
return false;
}
public boolean hitTanks(ArrayList<Tank> tanks) { //攻击多个坦克
for (int i = 0; i < tanks.size(); i++){
if(hitTank(tanks.get(i))){
return true;
}
}
return false;
}
public boolean hitWall(Wall w){ //判断子弹撞墙
if(this.isLive()&&this.getRect().intersects(w.getRect())){
this.setLive(false); //撞上墙则设为死亡
return true;
}
return false;
}
}