public void launch() {//设置窗口标题setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}
}

1.2 为窗口上色

  • 重写paint()方法,参数g为图形

  • 设置图形颜色

  • 设置图形大小

package com.qf;import java.awt.Color;
import java.awt.Graphics;import javax.swing.JFrame;public class GamePanel extends JFrame {private static final long serialVersionUID = 7471238471259660459L;//窗口宽高int width = 800;int height = 610;//获取画笔(为窗口上色)@Overridepublic void paint(Graphics g) {//设置颜色g.setColor(Color.GRAY);//填充窗口g.fillRect(0, 0, width, height);}public void launch() {setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}}

1.3 添加选项文字

  • 设置字体颜色,不要和背景色一样

  • 设置字体,字体大小

  • 添加文字,及文字位置

package com.qf;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;import javax.swing.JFrame;public class GamePanel extends JFrame {private static final long serialVersionUID = 7471238471259660459L;//窗口宽高int width = 800;int height = 610;//获取画笔@Overridepublic void paint(Graphics g) {g.setColor(Color.GRAY);g.fillRect(0, 0, width, height);//添加游戏选项g.setColor(Color.BLUE);g.setFont(new Font("仿宋", Font.BOLD, 50));g.drawString("选择游戏模式", 220, 100);g.drawString("单人模式", 220, 200);g.drawString("双人模式", 220, 300);}public void launch() {setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}}

1.4 为窗口添加键盘事件

  • 添加内部类,实现KeyAdapter类,重写keyPressed方法,监听按钮

class KeyMonitor extends KeyAdapter {@Overridepublic void keyPressed(KeyEvent e) {System.out.println(e.getKeyChar());}}
  • 窗口添加键盘监视器

this.addKeyListener(new GamePanel.KeyMonitor());
package com.qf;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;import javax.swing.JFrame;public class GamePanel extends JFrame {private static final long serialVersionUID = 7471238471259660459L;//窗口宽高int width = 800;int height = 610;//获取画笔@Overridepublic void paint(Graphics g) {g.setColor(Color.GRAY);g.fillRect(0, 0, width, height);//添加游戏选项g.setColor(Color.BLUE);g.setFont(new Font("仿宋", Font.BOLD, 50));g.drawString("选择游戏模式", 220, 100);g.drawString("单人模式", 220, 200);g.drawString("双人模式", 220, 300);}//添加内部类,实现KeyAdapter类,重写keyPressed方法class KeyMonitor extends KeyAdapter {@Overridepublic void keyPressed(KeyEvent e) {System.out.println(e.getKeyChar());}}public void launch() {setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);this.addKeyListener(new GamePanel.KeyMonitor());}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}}

1.5 键盘控制选择游戏模式

  • 添加指针图片

  • 在项目文件夹下创建文件夹images,关于项目的图片,插件都放在这个文件夹内

  • 创建图片对象

Image select = Toolkit.getDefaultToolkit().getImage("images/mytank_right.gif");
  • int y = 150;

  • g.drawImage(select, 160, y, null);

  • //重绘

  • 设置初始纵坐标为150

  • 在paint()方法,添加此图片

  • 在launch()方法中重绘图形(每隔30毫秒)

        while(true) {repaint();   try {Thread.sleep(25);} catch (InterruptedException e) {e.printStackTrace();}}
  • 重写键盘事件,1选择单人模式,2选择双人模式

//添加内部类,实现KeyAdapter类,重写keyPressed方法

    class KeyMonitor extends KeyAdapter {@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_1 :y = 150;break;case KeyEvent.VK_2 :y = 250;break;case KeyEvent.VK_ENTER :break;default:break;}}}
  • 定义选择相应模式后,点击回车键,显示响应窗口

  • 定义模式state 0:未选择,1:单人 2:双人

    //模式state 0:未选择,1:单人 2:双人

    int state = 0;

    int a = 0;

  • 重写点击事件

//添加内部类,实现KeyAdapter类,重写keyPressed方法

class KeyMonitor extends KeyAdapter {@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_1 :a = 1; // 单人y = 150;break;case KeyEvent.VK_2 :a = 2; //双人y = 250;break;case KeyEvent.VK_ENTER :state = a;break;default:break;}}}
  • 写入图形判断

       if (state == 0 ) {g.drawString("选择游戏模式", 220, 100);g.drawString("单人模式", 220, 200);g.drawString("双人模式", 220, 300);//绘制指针g.drawImage(select, 160, y, null);} else if (state ==1 || state ==2) {g.drawString("游戏开始", 220, 100);if (state ==1) {g.drawString("单人模式", 220, 200);} else if(state ==2) {g.drawString("双人模式", 220, 200);}}
  • 整体代码

 package com.qf;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;import javax.swing.JFrame;public class GamePanel extends JFrame {private static final long serialVersionUID = 7471238471259660459L;//指针图片Image select = Toolkit.getDefaultToolkit().getImage("images/mytank_right.gif");int y =150; //纵坐标//模式state    0:未选择,1:单人   2:双人int state = 0;int a = 0;//窗口宽高int width = 800;int height = 610;//获取画笔@Overridepublic void paint(Graphics g) {g.setColor(Color.GRAY);g.fillRect(0, 0, width, height);//添加游戏选项g.setColor(Color.BLUE);g.setFont(new Font("仿宋", Font.BOLD, 50));if (state == 0 ) {g.drawString("选择游戏模式", 220, 100);g.drawString("单人模式", 220, 200);g.drawString("双人模式", 220, 300);//绘制指针g.drawImage(select, 160, y, null);} else if (state ==1 || state ==2) {g.drawString("游戏开始", 220, 100);if (state ==1) {g.drawString("单人模式", 220, 200);} else if(state ==2) {g.drawString("双人模式", 220, 200);}}}//添加内部类,实现KeyAdapter类,重写keyPressed方法class KeyMonitor extends KeyAdapter {@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_1 :a = 1; // 单人y = 150;break;case KeyEvent.VK_2 :a = 2; //双人y = 250;break;case KeyEvent.VK_ENTER :state = a;break;default:break;}}}public void launch() {setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);this.addKeyListener(new GamePanel.KeyMonitor());//重绘while(true) {repaint();   try {Thread.sleep(25);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}}

1.6 解决闪频

  • //解决闪动问题

Image offScreemImage = null;

  • 创建一个和弹出窗口宽高相同的图片,

  • 获取该图片的图形对象,把所有内容添加到该图片中

//创建和容器一样大小的Image图片

  • 创建一个图片

  • 重写paint()方法

if(offScreemImage == null) {offScreemImage = this.createImage(width,height);}//获该图片的图形Graphics gImage = offScreemImage.getGraphics();gImage.setColor(Color.GRAY);gImage.fillRect(0, 0, width, height);//添加游戏选项gImage.setColor(Color.BLUE);gImage.setFont(new Font("仿宋", Font.BOLD, 50));if (state == 0 ) {gImage.drawString("选择游戏模式", 220, 100);gImage.drawString("单人模式", 220, 200);gImage.drawString("双人模式", 220, 300);//绘制指针gImage.drawImage(select, 160, y, null);} else if (state ==1 || state ==2) {gImage.drawString("游戏开始", 220, 100);if (state ==1) {gImage.drawString("单人模式", 220, 200);} else if(state ==2) {gImage.drawString("双人模式", 220, 200);}}
  • g.drawImage(offScreemImage, 0, 0,null);

  • 把该图片写入到窗口中

package com.qf;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;import javax.swing.JFrame;public class GamePanel extends JFrame {private static final long serialVersionUID = 7471238471259660459L;//解决闪动问题Image offScreemImage = null;//指针图片Image select = Toolkit.getDefaultToolkit().getImage("images/mytank_right.gif");int y =150; //纵坐标//模式state    0:未选择,1:单人   2:双人int state = 0;int a = 0;//窗口宽高int width = 800;int height = 610;//获取画笔@Overridepublic void paint(Graphics g) {//创建和容器一样大小的Image图片if(offScreemImage == null) {offScreemImage = this.createImage(width,height);}//获该图片的图形Graphics gImage = offScreemImage.getGraphics();gImage.setColor(Color.GRAY);gImage.fillRect(0, 0, width, height);//添加游戏选项gImage.setColor(Color.BLUE);gImage.setFont(new Font("仿宋", Font.BOLD, 50));if (state == 0 ) {gImage.drawString("选择游戏模式", 220, 100);gImage.drawString("单人模式", 220, 200);gImage.drawString("双人模式", 220, 300);//绘制指针gImage.drawImage(select, 160, y, null);} else if (state ==1 || state ==2) {gImage.drawString("游戏开始", 220, 100);if (state ==1) {gImage.drawString("单人模式", 220, 200);} else if(state ==2) {gImage.drawString("双人模式", 220, 200);}}g.drawImage(offScreemImage, 0, 0,null);}//添加内部类,实现KeyAdapter类,重写keyPressed方法class KeyMonitor extends KeyAdapter {@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_1 :a = 1; // 单人y = 150;break;case KeyEvent.VK_2 :a = 2; //双人y = 250;break;case KeyEvent.VK_ENTER :state = a;break;default:break;}}}public void launch() {setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);this.addKeyListener(new GamePanel.KeyMonitor());//重绘while(true) {repaint();   try {Thread.sleep(25);} catch (InterruptedException e) {e.printStackTrace();}}}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}}

2. 键盘控制坦克移动

2.1 添加游戏类父类

  • 属性

  • 图片

  • 位置(坐标)

  • 面板

  • 方法

  • 构造方法

  • 在图形中构建自己

  • 获取自身矩形(用于比较中弹)

package com.qf;import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;//游戏父类
public abstract class GameObject {//图片public Image img;//位置(坐标) 纵坐标  竖坐标public int x;public int y;//在哪个面板public GamePanel gamePanel;//有参构造器  img参数为字符串,图片路径public GameObject(String img, int x, int y, GamePanel gamePanel) {super();this.img = Toolkit.getDefaultToolkit().getImage(img);this.x = x;this.y = y;this.gamePanel = gamePanel;}//画自己public abstract void paintSelf(Graphics g);//获取自身矩形public abstract Rectangle getRec();}

2.2 添加坦克类

  • 尺寸(宽高)

  • 速度

  • 方向

  • 不同方向图片

package com.qf;import java.awt.Point;
import java.awt.Toolkit;//坦克父类
public abstract class Tank extends GameObject {//尺寸public int width = 40;public int height = 50;//速度public int speed = 3;//方向public Direction direction = Direction.UP;//四个方向图片public String upImg;public String leftImg;public String rightImg;public String downImg;public Tank(String img, int x, int y, GamePanel gamePanel,String upImg, String leftImg, String rightImg, String downImg) {super(img, x, y, gamePanel);this.upImg = upImg;this.leftImg = leftImg;this.rightImg = rightImg;this.downImg = downImg;}}

2.3 添加玩家类

package com.qf;import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;//玩家
public class PlayerOne extends Tank {public PlayerOne(String img, int x, int y, GamePanel gamePanel, String upImg, String leftImg, String rightImg,String downImg) {super(img, x, y, gamePanel, upImg, leftImg, rightImg, downImg);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(img, x, y, null);}@Overridepublic Rectangle getRec() {return new Rectangle(x, y, width, height);}}

2.4 在窗口中添加玩家

  • 创建玩家对象

  • //添加玩家一到面板

        PlayerOne playerOne = new PlayerOne("images/mytank_up.gif", 125, 510, this, "images/mytank_up.gif", "images/mytank_left.gif", "images/mytank_right.gif", "images/mytank_down.gif");
  • 把玩家对象添加到图形中

    playerOne.paintSelf(g);

package com.qf;import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;import javax.swing.JFrame;/** 已解决闪动*/
public class GamePanel extends JFrame {private static final long serialVersionUID = -9194828502749643640L;//解决闪动问题Image offScreemImage = null;//窗口长宽int width = 800;int height = 610;//指针图片Image select = Toolkit.getDefaultToolkit().getImage("images/mytank.gif");int y =150; //纵坐标//定义游戏模式 0:游戏未开始   1:单人模式   2:双人模式int state = 0;int a = 0; //根据输入的键值,修改a值,再赋值给state//添加玩家一到面板PlayerOne playerOne = new PlayerOne("images/mytank_up.gif", 125, 510, this, "images/mytank_up.gif", "images/mytank_left.gif", "images/mytank_right.gif", "images/mytank_down.gif");//窗口的启动方法public void launch() {setTitle("千锋坦克大战");//设置宽高setSize(width, height);//居中setLocationRelativeTo(null);//差掉窗口,结束setDefaultCloseOperation(3);//窗口不可拉伸setResizable(false);//可见setVisible(true);//添加键盘监视器this.addKeyListener(new GamePanel.KeyMonitor());//重绘while(true) {repaint();   try {Thread.sleep(25);  //间隔时间} catch (InterruptedException e) {e.printStackTrace();}}}//画  图形@Overridepublic void paint(Graphics g) {//创建和容器一样大小的Image图片if(offScreemImage == null) {offScreemImage = this.createImage(width,height);}//获的该图片的画笔Graphics gImage = offScreemImage.getGraphics();//把窗口背景色设置为灰色gImage.setColor(Color.GRAY);//把这个背景色填充整个窗口gImage.fillRect(0, 0, width, height);//设置颜色gImage.setColor(Color.BLUE);//设置字体gImage.setFont(new Font("仿宋", Font.BOLD, 50));if(state == 0 ) {//添加文字gImage.drawString("选择游戏模式", 220, 100);gImage.drawString("单人游戏", 220, 200);gImage.drawString("双人游戏", 220, 300);//绘制指针gImage.drawImage(select, 160, y, null);} else if (state == 1 || state == 2) {gImage.drawString("游戏开始", 220, 100);if(state == 1) {gImage.drawString("单人游戏", 220, 200);} else {gImage.drawString("双人游戏", 220, 200);}//添加玩家playerOne.paintSelf(gImage);}g.drawImage(offScreemImage, 0, 0,null);}//键盘监视器,需要添加到窗口中class KeyMonitor extends KeyAdapter {//按下键盘的回调方法@Overridepublic void keyPressed(KeyEvent e) {//返回按钮的值int key = e.getKeyChar();switch(key) {case KeyEvent.VK_1 :a = 1;y = 150;break;case KeyEvent.VK_2 :a = 2;y = 250;break;case KeyEvent.VK_ENTER :state = a;break;default:}}}public static void main(String[] args) {GamePanel gp = new GamePanel();gp.launch();}}

2.5使用键盘控制坦克移动

  • 不同方向设置不同图片

  • 不同的方向

//移动方法

  • 在坦克类(Tank)中添加上下左右四个方法

    public void leftward() {x -=speed;direction = Direction.LEFT;setImg(leftImg);}public void rightward() {x +=speed;direction = Direction.RIGHT;setImg(rightImg);}public void upward() {y -=speed;direction = Direction.UP;setImg(upImg);}public void downward() {y +=speed;direction = Direction.DOWN;setImg(downImg);}public void setImg(String img) {this.image = Toolkit.getDefaultToolkit().getImage(img);}
  • 在PlayerOne类中按钮点击,松开方法,及移动方法

  • W上,A左,S下,D右

boolean left, right, up, down;

//键盘按下去方法

public void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_A : left=true; break;case KeyEvent.VK_S : down=true; break;case KeyEvent.VK_D : right=true; break;case KeyEvent.VK_W : up=true; break;}}//键盘松开方法public void keyReleased(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_A : left=false; break;case KeyEvent.VK_S : down=false; break;case KeyEvent.VK_D : right=false; break;case KeyEvent.VK_W : up=false; break;}}
  • //移动的方法,每次在绘制的时候移动

 public void move() {if(left) {leftward();} else if (right) {rightward();} else if (up) {upward();} else if(down) {downward();}}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);//每次绘图的时候,根据最新的属性,绘图move();}
  • 在主窗口类中,添加对A,S,D,W按键的监控

    //键盘监控

    class KeyMonitor extends KeyAdapter {//点击键盘的回调方法@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyChar();switch(key) {case KeyEvent.VK_1:y = 150;   a = 1;break;case KeyEvent.VK_2:y = 250;  a = 2;break;case KeyEvent.VK_ENTER :  //点击回车,选择相应的模式state = a;default:playerOne.keyPressed(e);   //这里}}@Overridepublic void keyReleased(KeyEvent e) {  //监听按钮的松开事件playerOne.keyReleased(e);  //这里}}

3. 坦克发射子弹

3.1 创建子弹类

  • 尺寸

  • 速度

  • 方向

  • 属性

  • //尺寸

int width = 10;

int height =10;

//速度

int speed = 7;

//方向,方向和坦克方向一致

Direction direction;

  • 左移,右移,下移,上移

  • 根据坦克方向不同,移动方向不同

  • //移动方法

  • 方法

 public void leftward() {x -=speed;}public void rightward() {x +=speed;}public void upward() {y -=speed;}public void downward() {y +=speed;}//根据方向移动,绘制自己时,调用public void go() {switch(direction) {case LEFT:  leftward(); break;case DOWN:  downward(); break;case RIGHT: rightward();break;case UP:    upward();   break;}}

全部代码:

 package com.qf;import java.awt.Graphics;
import java.awt.Rectangle;public class Bullet extends GameObject {//尺寸int width = 10;int height =10;//速度int speed = 7;//方向,方向和坦克方向一致Direction direction;//移动方法public void leftward() {x -=speed;}public void rightward() {x +=speed;}public void upward() {y -=speed;}public void downward() {y +=speed;}//绘制自己时,调用public void go() {switch(direction) {case LEFT:  leftward(); break;case DOWN:  downward(); break;case RIGHT: rightward();break;case UP:    upward();   break;}}public Bullet(String imageUrl, int x, int y, GamePanal gamePanal,Direction direction) {super(imageUrl, x, y, gamePanal);this.direction = direction;}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);//绘制子弹时,可以移动go();}@Overridepublic Rectangle getRec() {return new Rectangle(x, y, width, height);}}

3.2 实现坦克发射子弹

  • 获取坦克的头部坐标

  • 在坦克类中

       public Point getHeadPoint() {switch(direction) {case LEFT:        return new Point(x, y+height/2);case DOWN: return new Point(x+width/2, y+height);case RIGHT: return new Point(x+width, y+height/2);case UP: return new Point(x+width/2, y);default: return null;}}
  • 添加发射方法

  • 根据坦克头坐标,及坦克方向创建子弹

  • 把创建的子弹添加到面板中创建子弹集合中

//发射子弹

        public void attack() {//获取头坐标Point point = getHeadPoint();//创建子弹Bullet bullet = new Bullet("images/bullet.gif", point.x, point.y, this.gamePanal, this.direction);//可以一次按很多次发射,把产生的子弹存储在面板的子弹集合中this.gamePanal.bulletList.add(bullet);}

//子弹集合 在面板类中定义

List<Bullet> bulletList = new ArrayList<Bullet>();//绘制玩家playerOne.paintSelf(gImage);//绘制子弹  在面板类中操作for(Bullet bullet : bulletList) {bullet.paintSelf(gImage);}
  • 当点击空格按钮,就会调用射击方法

  • 在PlayerOne类中添加键盘事件

//键盘按下去方法

    public void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_A : left=true; break;case KeyEvent.VK_S : down=true; break;case KeyEvent.VK_D : right=true; break;case KeyEvent.VK_W : up=true; break;case KeyEvent.VK_SPACE: attack();           //添加发送子弹方法}}

3.3 添加子弹冷却时间

  • 在坦克类中添加冷却状态,冷却时间

//冷却状态

boolean attackCoolDown = true;

//冷却时间

int attackCoolTime = 1000;

  • 创建冷却线程

//冷却线程

   class AttackCool extends Thread {public void run() {attackCoolDown = false;try {Thread.sleep(attackCoolTime);} catch (InterruptedException e) {e.printStackTrace();}attackCoolDown = true;}}
  • 修改发射方法,每发射一次,启动冷却线程

//发射子弹

    public void attack() {if (attackCoolDown) {//获取头坐标Point point = getHeadPoint();//创建子弹Bullet bullet = new Bullet("images/bullet.gif", point.x, point.y, this.gamePanal, this.direction);//可以一次按很多次发射,把产生的子弹存储在面板的子弹集合中this.gamePanal.bulletList.add(bullet);//启动冷却线程new AttackCool().start();}}

4. 敌方坦克

4.1 随机添加敌方坦克

  • 添加敌方坦克类

//敌方坦克

public class Bot extends Tank{public Bot(String imageUrl, int x, int y, GamePanal gamePanal, String upImg, String leftImg, String rightImg,String downImg) {super(imageUrl, x, y, gamePanal, upImg, leftImg, rightImg, downImg);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);}@Overridepublic Rectangle getRec() {return new Rectangle(x, y, width, height);}}
  • 批量把敌方坦克图片添加到面板上

  • 把敌方坦克的图片添加到项目中(4个方向各一个)

  • 在面板中创建敌方坦克集合

  • 面板每重新加载100次,添加一个敌方坦克,敌方坦克最多有10各

//重绘次数

int count =0;

//敌方坦克个数

int enemyCount = 0;

  • 在重新绘制循环中,添加敌方坦克

//重新载入窗口

                while(true) {if(count%100 ==1 && enemyCount<5 ) {//添加敌方坦克Random r = new Random();int rnum = r.nextInt(800);botList.add(new Bot("images/enemy_up.png", rnum, 110, this, "images/enemy_up.png", "images/enemy_left.png", "images/enemy_right.png", "images/enemy_down.gif"));enemyCount++;}this.repaint();try {Thread.sleep(25);} catch (InterruptedException e) {e.printStackTrace();}}

在开始游戏加载面板中显示敌方坦克并对count自增(paint方法)

                if (state ==0) {//220离左边的距离,  100离上面的距离gImage.drawString("选择游戏模式", 220, 100);gImage.drawString("单人模式", 220, 200);gImage.drawString("双人模式", 220, 300);//画入图像gImage.drawImage(select, 140, y, null);} else {gImage.drawString("开始游戏", 220, 100);if(state == 1) {gImage.drawString("单人模式", 220, 200);} else if (state == 2) {gImage.drawString("双人模式", 220, 200);}//绘制玩家playerOne.paintSelf(gImage);//绘制子弹for(Bullet bullet : bulletList) {bullet.paintSelf(gImage);}//绘制敌方坦克for(Bot bot : botList) {bot.paintSelf(gImage);}count++;}

4.2 敌方坦克随机移动

  • 随机生成方向(Bot)

//随机生成个数,表示方向

       public Direction getRandomDirection() {Random random = new Random();int rnum = random.nextInt(4); //0-3switch(rnum) {case 0 : return Direction.LEFT;case 1 : return Direction.RIGHT;case 2 : return Direction.UP;case 3 : return Direction.DOWN;default: return null;}}
  • 添加运动方法,每20次,转化一次方向(Bot)

//每间隔20,转换方向一次

int moveTime = 20;

//行走方法

    public void go() {if (moveTime >=20) {direction = getRandomDirection();moveTime=0;} else {moveTime++;}switch(direction) {case LEFT:  leftward(); break;case DOWN:  downward(); break;case RIGHT: rightward();break;case UP:    upward();   break;}}

//勿忘把重绘方法添加到绘制自己方法中

    @Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);go();}

4.3 敌方坦克射击

  • 创建敌方子弹类,直接继承Bullet即可

package com.qf;import java.awt.Graphics;
import java.awt.Rectangle;//敌方子弹类
public class EnemyBullet extends Bullet {public EnemyBullet(String imageUrl, int x, int y, GamePanal gamePanal, Direction direction) {super(imageUrl, x, y, gamePanal, direction);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);//在图形绘制自己时移动go();}@Overridepublic Rectangle getRec() {return new Rectangle(x, y, width, height);}}
  • 机器人自行发射,把该方法添加到go()方法中

  • 在机器人坦克类中添加攻击发射方法

//攻击类,添加到go方法中

    public void attack() {Point p = getHeadPoint();Random random = new Random();int num = random.nextInt(100); // [0,99]if(num <4) {  //4%设计概率,可自行调节发射频率   0,1,2,3this.gamePanal.bulletList.add(new EnemyBullet("images/bullet.gif",p.x, p.y, this.gamePanal, this.direction));}}

//机器人坦克自行行走

    public void go() {attack();  // 添加到这里,边走边发射子弹if (moveTime>=20) {direction = getRandomDirection();moveTime =0;} else {moveTime++;}switch(direction) {case LEFT : leftward(); break;case RIGHT : rightward(); break;case DOWN : downward(); break;case UP : upward(); break;}}

5. 碰撞检测

5.1 我方子弹(Bullet)和敌方坦克(Bot)碰撞

  • 在面板类中定义要删除/消失的子弹(GamePanal)

  • 在每次重绘时,把删除的子弹从绘制子弹集合中删除

//碰撞后要删除的子弹

        List<Bullet> removeList = new ArrayList<Bullet>();//绘制子弹for(Bullet bullet : bulletList) {bullet.paintSelf(gImage);}//去除要删除的子弹bulletList.removeAll(removeList);
  • 在绘制每个子弹时,把当前子弹对象和所有计算机坦克比较是否碰撞

  • 该方法要添加到绘制方法中

  • 在子弹类中添加碰撞方法(Bullet)

//碰撞 添加到paintSelf方法中,每次绘制时,检测

        public void hitBot() {List<Bot> bots = this.gamePanal.botList;for(Bot bot : bots) {if (this.getRec().intersects(bot.getRec())) {this.gamePanal.botList.remove(bot);   // 坦克消失this.gamePanal.removeList.add(this);  //子弹消失break;}}}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);//在图形绘制自己时移动go();//每次绘制时,检测碰撞hitBot();}

5.2 敌方子弹和我方坦克碰撞

  • 把玩家都添加到此集合中,在选择游戏模式时添加

  • 不要忘记把原绘制玩家代码删除

  • 添加我方坦克集合(为后续扩展使用)

  • 玩家的绘制,修改成遍历该集合

//玩家坦克集合

List<Tank> playerList = new ArrayList<Tank>();//键盘监控class KeyMonitor extends KeyAdapter {//点击键盘的回调方法@Overridepublic void keyPressed(KeyEvent e) {int key = e.getKeyChar();switch(key) {case KeyEvent.VK_1:y = 150;   a = 1;break;case KeyEvent.VK_2:y = 250;  a = 2;break;case KeyEvent.VK_ENTER :  //点击回车,选择相应的模式state = a;//添加玩家,双人待做playerList.add(playerOne);     //----这里添加default:playerOne.keyPressed(e);   //坦克的移动}}//绘制玩家//        playerOne.paintSelf(gImage);for(Tank player : playerList) {player.paintSelf(gImage);}
  • 该方法添加到绘制方法中

  • 在敌方子弹类中添加碰撞方法

//碰撞 添加到paintSelf方法中,每次绘制时,检测

        public void hitPlayer() {List<Tank> tanks = this.gamePanel.playerList;for(Tank t : tanks) {if (this.getRec().intersects(t.getRec())) {this.gamePanel.playerList.remove(t);   // 玩家坦克消失this.gamePanel.removeList.add(this);  //子弹消失break;}}}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);//在图形绘制自己时移动go();//检测碰撞hitPlayer();}

5.3 与围墙的碰撞检测

5.3.1面板中添加围墙

  • 添加围墙类

package com.qf;import java.awt.Graphics;
import java.awt.Rectangle;public class Wall extends GameObject {//围墙尺寸int length = 60;public Wall(String imageUrl, int x, int y, GamePanel gamePanal) {super(imageUrl, x, y, gamePanel);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);}@Overridepublic Rectangle getRec() {return new Rectangle(x, y, length, length);}}
在面板中添加围墙集合,在lunch方法中添加围墙,然后把集合绘制到面板中
//围墙列表
List<Wall> wallList = new ArrayList<Wall>();
//在lunch方法中//添加围墙for(int i = 0; i<14; i++) {wallList.add(new Wall("images/wall.png", i*60, 170, this));}wallList.add(new Wall("images/wall.png", 305, 560, this));wallList.add(new Wall("images/wall.png", 305, 500, this));wallList.add(new Wall("images/wall.png", 365, 500, this));wallList.add(new Wall("images/wall.png", 425, 500, this));wallList.add(new Wall("images/wall.png", 425, 560, this));//在paint方法中绘制围墙for(Wall wall : wallList) {wall.paintSelf(gImage);}

5.3.2 添加围墙和子弹碰撞检测

  • 把该方法添加到go()方法中,让敌方子弹也可以和围墙碰撞

  • 子弹类添加和围墙碰撞方法(Bullet)

//子弹和围墙碰撞,添加到go方法中,让敌方子弹也可以击破围墙

    public void hitWall() {List<Wall> walls = this.gamePanal.wallList;for(Wall wall : walls) {if (this.getRec().intersects(wall.getRec())) {this.gamePanal.wallList.remove(wall);   // 围墙消失this.gamePanal.removeList.add(this);  //子弹消失break;}}}public void go() {switch(direction) {case LEFT : leftward(); break;case RIGHT : rightward(); break;case DOWN : downward(); break;case UP : upward(); break;}hitWall();       //---------------添加到这里}

5.3.3 坦克和围墙碰撞

  • 当坦克和围墙碰撞时,坦克无法移动

  • 在坦克类中添加围墙碰撞方法

  • 然后在移动类中判断是否会和围墙碰撞,如果碰撞则不移动

//与围墙碰撞检测

                public boolean hitWall(int x, int y) {List<Wall> wallList = this.gamePanal.wallList;//坦克下一步将要移动后的矩形Rectangle next = new Rectangle(x, y, width, height);for(Wall wall : wallList) {if(next.intersects(wall.getRec())) {return true;}}return false;}
  • 修改所有移动的方法

    //移动方法 左移

  public void leftward() {if(!hitWall(x-speed, y)) {x -=speed;}direction = Direction.LEFT;setImg(leftImg);}//移动方法   右移public void rightward() {if(!hitWall(x+speed, y)) {x +=speed;}direction = Direction.RIGHT;setImg(rightImg);}//移动方法   上移public void upward() {if(!hitWall(x, y-speed)) {y -=speed;}direction = Direction.UP;setImg(upImg);}//移动方法   下移public void downward() {if(!hitWall(x, y+speed)) {y +=speed;}direction = Direction.DOWN;setImg(downImg);}

5.4 判断坦克边缘的碰撞

  • 该判断添加到移动方法中

  • 坦克类中添加边缘碰撞判断(Tank)

//判断和边缘的碰撞

        public boolean moveToBorder(int x,int y) {if(x<0) {return true;} else if (x+width > this.gamePanal.width) {return true;} else if (y <0) {return true;} else if (y+height > this.gamePanal.height) {return true;}return false;}//移动方法   左移public void leftward() {if(!hitWall(x-speed, y) && !moveToBorder(x-speed, y)) {x -=speed;}direction = Direction.LEFT;setImg(leftImg);}//移动方法   右移public void rightward() {if(!hitWall(x+speed, y) && !moveToBorder(x+speed, y)) {x +=speed;}direction = Direction.RIGHT;setImg(rightImg);}//移动方法   上移public void upward() {if(!hitWall(x, y-speed)&&!moveToBorder(x, y-speed)) {y -=speed;}direction = Direction.UP;setImg(upImg);}//移动方法   下移public void downward() {if(!hitWall(x, y+speed)&&!moveToBorder(x, y+speed)) {y +=speed;}direction = Direction.DOWN;setImg(downImg);}

5.5判断子弹是否出界

  • 该方法添加到go方法中

  • 判断子弹坐标是否出界,如果出界则删除

//如果子弹出界,该方法添加在go方法中,敌人子弹也可以删除 删除子弹,节省资源

    public void moveToBorder() {if(x<0 || x+width > this.gamePanel.width) {this.gamePanel.removeList.add(this);}if(y<0 || y+height > this.gamePanel.height) {this.gamePanel.removeList.add(this);}}//子弹的移动是根据方向来的public void go() {switch(direction) {case LEFT : leftward(); break;case RIGHT : rightward(); break;case DOWN : downward(); break;case UP : upward(); break;}hitWall(); //子弹撞墙moveToBorder(); //子弹出界删除}

6. 添加基地

6.1 创建并添加基地

  • 创建基地类

package com.qf;import java.awt.Graphics;
import java.awt.Rectangle;//基地类
public class Base extends GameObject {int length = 60;public Base(String imageUrl, int x, int y, gamePanel gamePanal) {super(imageUrl, x, y, gamePanal);}@Overridepublic void paintSelf(Graphics g) {g.drawImage(image, x, y, null);}@Overridepublic Rectangle getRec() {return new Rectangle(x, y, length, length);}}
在面板中添加基地
//基地集合
List<Base> baseList = new ArrayList<Base>();//在lunch方法添加创建一个基地
Base base = new Base("images/base.png", 365, 560, this);
baseList.add(base);//绘制基地
for(Base base : baseList) {base.paintSelf(gImage);
}

6.2 子弹与基地的碰撞测试

  • 该方法添加到go方法中

  • 在子弹类中添加碰撞方法

//与基地碰撞方法

    public void hitBase() {List<Base> bases = this.gamePanel.baseList;for(Base base : bases) {if (this.getRec().intersects(base.getRec())) {this.gamePanel.baseList.remove(base);   // 基地消失this.gamePanel.removeList.add(this);  //子弹消失break;}}}public void go() {switch(direction) {case LEFT : leftward(); break;case RIGHT : rightward(); break;case DOWN : downward(); break;case UP : upward(); break;}hitWall(); //子弹撞墙moveToBorder(); //子弹出界删除hitBase(); //---销毁基地}

7. 游戏规则

  • 把所有的敌人干倒

  • 玩家坦克被干掉

  • 基地被倒了

  • 我方胜利

  • 机器赢了

//判断规则,在每次重绘时

//玩家赢了
if(botList.size() == 0 && enemyCount == 3) {state = 3;
}//机器赢了
if((playerList.size()==0&&(state ==1 || state ==2))  || baseList.size() ==0) {state = 4;
} //获取画笔@Overridepublic void paint(Graphics g) {if(offScreemImage==null) {offScreemImage = this.createImage(width, height);}Graphics gImage = offScreemImage.getGraphics();//设置图形的颜色gImage.setColor(Color.GRAY);//把设置的颜色,填充整个矩形gImage.fillRect(0, 0, width, height);//重新设置字体颜色gImage.setColor(Color.BLUE);gImage.setFont(new Font("楷体", Font.BOLD, 50));if (state ==0) {//220离左边的距离,  100离上面的距离gImage.drawString("选择游戏模式", 220, 100);gImage.drawString("单人模式", 220, 200);gImage.drawString("双人模式", 220, 300);//画入图像gImage.drawImage(select, 140, y, null);} else if (state == 1 || state ==2){gImage.drawString("开始游戏", 220, 100);if(state == 1) {gImage.drawString("单人模式", 220, 200);} else if (state == 2) {gImage.drawString("双人模式", 220, 200);}//绘制玩家//      playerOne.paintSelf(gImage);//绘制玩家列表for(Tank tank : playerList) {tank.paintSelf(gImage);}//绘制子弹for(Bullet bullet : bulletList) {bullet.paintSelf(gImage);}//删除发生碰撞的子弹bulletList.removeAll(removeList);//绘制机器人坦克for (Bot bot : botList) {bot.paintSelf(gImage);}//绘制城墙for (Wall wall : wallList) {wall.paintSelf(gImage);}//绘制基地for (Base base : baseList) {base.paintSelf(gImage);}count++;} else if(state ==3) {gImage.drawString("我赢了", 220, 100);} else if(state == 4) {gImage.drawString("机器赢了", 220, 100);}//把重新绘制的图片放到窗口中(从左上角开始放)g.drawImage(offScreemImage, 0, 0, null);}

单机版坦克大战分步实现项目源码相关推荐

  1. 100行JS代码实现❤坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript )

    坦克大战js小游戏源码 HTML5坦克大战游戏代码(HTML+CSS+JavaScript ) HTML5坦克大战网页小游戏,完美还原小霸王学习机效果,以坦克战斗及保卫基地为主题,属于策略型类游戏. ...

  2. 《游戏学习》JAVA版坦克大战课程设计及源码

    1.功能设计 游戏要有图形用户界面,界面能够反映游戏所有的细节. 界面中要有坦克,墙,树林,河流. 界面中要有一个"家","家"被攻击中则输了游戏. 坦克分两种 ...

  3. 用pygame做经典坦克大战游戏(附源码)

    首先,我们得分析这个项目的结构,设计出它的框架 坦克大战游戏项目开发 需求分析 1.分析项目需要多少个类 2.分析每个类有哪些方法 1.坦克类(敌方坦克,我方坦克) 移动.射击.展示 2.子弹类 移动 ...

  4. 《Java语言程序设计——坦克大战单机游戏》源码以及实验报告

    一.引言 游戏本身是一种娱乐方式,带给人无尽的乐趣,而且游戏行业的发展前景也将会是是带动周边相关行业的发展.为了去满足不同的游戏爱好者的要求,对做游戏开发的人的要求也会越来越高.本次Java语言程序设 ...

  5. 173个Android项目源码及下载地址

    173个Android项目源码及下载地址 注:最近一直没有上CSDN,看到不少想学Android的朋友们想要这几个Android项目源码,所以我把它上传到了CSDN,希望能在Android的学习路上对 ...

  6. part1:推荐一些适合练手、课程设计、毕业设计的python小项目源码,无任何下载门槛

    人生苦短,我用python,随着python这些年的流行,很多人开始使用python来实现各种功能.下面推荐一些适合用来练手.大学生课程设计作业.大学生毕业设计的python小项目,尤其适合新手,源码 ...

  7. Android项目源码分享

    ├─android web应用 │      jqmDemo_static.zip │      jqmMobileDemo-master.zip │      jqmMobileDemo1_1-ma ...

  8. 钢七连实战C3-P2:项目源码结构 面向对象基础 堆分配

    钢七连软件培训 C3-P2  面向对象  第2节 1.怎样阅读一套项目源码 2.面向对象基本技术 https://blog.csdn.net/weixin_42644456 一.通用的学习路线,解决办 ...

  9. c语言循环写回合制小游戏_【资源】60个C语言项目源码免费领取!

    序言 今天的资源特意是为大三.大四的童鞋准备的, 整理了一波有关于C语言开发的游戏.系统.效果.小项目的源码!!源码!!源码!! 小编之前发过一波毕业项目的资源, 还没有获取的伙伴,直接申请进群就能获 ...

最新文章

  1. PHP查看PECL模块包含的函数
  2. 论文笔记 Traffic Data Reconstruction via Adaptive Spatial-Temporal Correlations
  3. 线性代数之矩阵偏导续
  4. Android NDK调试定位错误
  5. js date 前一天
  6. zookeeper环境搭建以及测试
  7. java中date代替_Java:为什么Date构造函数不推荐,我用什么来代替?
  8. php文件上传格式限制,如何在PHP中限制文件上传类型的文件大小?
  9. 音视频和图像相关知识点总结
  10. 大黄蜂vep视频转成MP4格式提取工具的使用
  11. MotoSimEG-VRC软件:安川机器人摆动焊接虚拟仿真操作方法
  12. 区块链专利申请全球过半 厉害了我的国
  13. matlab与测绘数据处理,MATLAB与测绘数据处理
  14. Message: session not created: This version of ChromeDriver only supports Chrome version XX
  15. snipaste截图软件编辑时修改方框粗细
  16. 确定电气间隙和爬电距离
  17. 啊哈C——学习3.6一起来找茬
  18. 怎实施一个ERP项目,需要考虑什么问题
  19. 【Unity】填坑,Unity接入Epic Online Service上架Epic游戏商城
  20. matlab做卡尔曼滤波预测,求Matlab卡尔曼滤波预测股票价格的程序

热门文章

  1. 税收问题的分析:已知税后收入求税前、年终奖一元陷阱的分析
  2. Linux Wi-Fi连接工具,Linux下Wi-Fi配置工具2
  3. 金融机构银行架构变迁
  4. Anderson《空气动力学基础》5th读书笔记导航
  5. [第四章]开发小要点:提高条形码识别率
  6. 快克违禁词检测工具(支持百度搜狗)SEO工具
  7. 热敏电阻NTC103、PT100温度计算公式
  8. AI孙燕姿 ?AI东雪莲 !—— 本地部署DDSP-SVC一键包,智能音频切片,本地训练,模型推理,为你喜欢的角色训练AI语音模型小教程
  9. 《电机学》第四篇 异步电机 第13、14三相异步电动机 原理/结构/特性 第15章 单相异步电动机
  10. 富文本插件 quill