用java写个小游戏 坦克大战

java

1. 窗体绘制

JFrame是指一个计算机语言-java的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化、最小化、关闭。

 

1.1 创建窗口

  • 创建类继承JFrame

  • 创建启动方法launch()

    • setTitle()设置标题

    • setSize(width, height); 设置宽高

    • setLocationRelativeTo(null); 设置位置,null为居中

    • setResizable(); 是否可拉伸

    • setVisible(); 是否可见

    • setDefaultCloseOperation(3); 1,2,3 (点差号,关闭程序)

package com.qf;

import javax.swing.JFrame;

public class GamePanel extends JFrame {

private static final long serialVersionUID = 7471238471259660459L;

//窗口宽高
int width = 800;
int height = 610;

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;

   //获取画笔(为窗口上色)
@Override
public 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;

//获取画笔
@Override
public 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 {

    @Override
    public 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;

//获取画笔
@Override
public 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 {

@Override
public 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");

    • 设置初始纵坐标为150

      • int y = 150;

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

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

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

    • //重绘
      while(true) {
      repaint();  
      try {
      Thread.sleep(25);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

  • 重写键盘事件,1选择单人模式,2选择双人模式

    //添加内部类,实现KeyAdapter类,重写keyPressed方法
    class KeyMonitor extends KeyAdapter {

    @Override
    public 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 {

      @Override
      public 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;

//获取画笔
@Override
public 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 {

@Override
public 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;

  • 重写paint()方法

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

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

    //创建和容器一样大小的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);

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;

//获取画笔

@Override

public 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 {

@Override

public 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);

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(img, x, y, null);

}

@Override

public 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();

}

}

}

//画 图形

@Override

public 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 {

//按下键盘的回调方法

@Override

public 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();

    }

    }

    @Override

    public void paintSelf(Graphics g) {

    g.drawImage(image, x, y, null);

    //每次绘图的时候,根据最新的属性,绘图

    move();

    }

  • 在主窗口类中,添加对A,S,D,W按键的监控

    	//键盘监控

    class KeyMonitor extends KeyAdapter {

    //点击键盘的回调方法

    @Override

    public 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); //这里

    }

    }

    @Override

    public 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;

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(image, x, y, null);

//绘制子弹时,可以移动

go();

}

@Override

public 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 AttackCool() {

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);

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(image, x, y, null);

}

@Override

public Rectangle getRec() {

return new Rectangle(x, y, width, height);

}

}

  • 批量把敌方坦克图片添加到面板上

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

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

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

	//重绘次数

int count =0;

//敌方坦克个数

int enemyCount = 0;

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

		//重新载入窗口

while(true) {

while(count%100 ==1 && enemyCount<10 ) {

//添加敌方坦克

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.png"));

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-3

    switch(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;

    }

    }

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

    @Override

    public 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);

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(image, x, y, null);

//在图形绘制自己时移动

go();

}

@Override

public 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);

if(num <4) { //4%设计概率,可自行调节发射频率

this.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;

}

}

}

	@Override

public void paintSelf(Graphics g) {

g.drawImage(image, x, y, null);

//在图形绘制自己时移动

go();

//每次绘制时,检测碰撞

hitBot();

}

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

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

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

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

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

//玩家坦克集合

List<Tank> playerList = new ArrayList<Tank>();

	//键盘监控

class KeyMonitor extends KeyAdapter {

//点击键盘的回调方法

@Override

public 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.gamePanal.playerList;

for(Tank t : tanks) {

if (this.getRec().intersects(t.getRec())) {

this.gamePanal.playerList.remove(t); // 玩家坦克消失

this.gamePanal.removeList.add(this); //子弹消失

break;

}

}

}

	@Override

public 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, GamePanal gamePanal) {

super(imageUrl, x, y, gamePanal);

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(image, x, y, null);

}

@Override

public 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));

	//绘制围墙

for(Wall wall : wallList) {

wall.paintSelf(gImage);

}

 

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

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

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

	//子弹和围墙碰撞,添加到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.gamePanal.width) {

this.gamePanal.removeList.add(this);

}

if(y<0 || y+height > this.gamePanal.height) {

this.gamePanal.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, GamePanal gamePanal) {

super(imageUrl, x, y, gamePanal);

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(image, x, y, null);

}

@Override

public Rectangle getRec() {

return new Rectangle(x, y, length, length);

}

}

  • 在面板中添加基地

//基地集合

List<Base> baseList = new ArrayList<Base>();

//创建一个基地

Base base = new Base("images/base.png", 365, 560, this);

//在lunch方法添加

baseList.add(base);

//绘制基地

for(Base base : baseList) {

base.paintSelf(gImage);

}

6.2 子弹与基地的碰撞测试

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

    • 该方法添加到go方法中

	//与基地碰撞方法

public void hitBase() {

List<Base> bases = this.gamePanal.baseList;

for(Base base : bases) {

if (this.getRec().intersects(base.getRec())) {

this.gamePanal.baseList.remove(base); // 基地消失

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(); //子弹撞墙

moveToBorder(); //子弹出界删除

hitBase(); //---销毁基地

}

7. 游戏规则

  • 我方胜利

    • 把所有的敌人干倒

  • 机器赢了

    • 玩家坦克被干掉

    • 基地被倒了

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

//玩家赢了

if(botList.size() == 0 && enemyCount == 3) {

state = 3;

}

//机器赢了

if((playerList.size()==0&&(state ==1 || state ==2))

|| baseList.size() ==0) {

state = 4;

}

 

	//获取画笔

@Override

public 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. 窗体绘制

JFrame是指一个计算机语言-java的GUI程序的基本思路是以JFrame为基础,它是屏幕上window的对象,能够最大化、最小化、关闭。

 

1.1 创建窗口

  • 创建类继承JFrame

  • 创建启动方法launch()

    • setTitle()设置标题

    • setSize(width, height); 设置宽高

    • setLocationRelativeTo(null); 设置位置,null为居中

    • setResizable(); 是否可拉伸

    • setVisible(); 是否可见

    • setDefaultCloseOperation(3); 1,2,3 (点差号,关闭程序)

package com.qf;

import javax.swing.JFrame;

public class GamePanel extends JFrame {

private static final long serialVersionUID = 7471238471259660459L;

//窗口宽高
int width = 800;
int height = 610;

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;

   //获取画笔(为窗口上色)
@Override
public 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;

//获取画笔
@Override
public 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 {

    @Override
    public 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;

//获取画笔
@Override
public 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 {

@Override
public 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");

    • 设置初始纵坐标为150

      //初始纵坐标为150
      int y = 150;

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

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

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

    • //重绘
      while(true) {
      repaint();  
      try {
      Thread.sleep(25);
      } catch (InterruptedException e) {
      e.printStackTrace();
      }
      }

  • 重写键盘事件,1选择单人模式,2选择双人模式

    //添加内部类,实现KeyAdapter类,重写keyPressed方法
    class KeyMonitor extends KeyAdapter {

    @Override
    public 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 {

      @Override
      public 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;

//获取画笔
@Override
public 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 {

@Override
public 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;

  • 重写paint()方法

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

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

    //创建和容器一样大小的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);

     

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;

//获取画笔

@Override

public 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 {

@Override

public 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();

}

方向枚举类:

package com.qf;

public enum Direction {

UP,LEFT,RIGHT,DOWN

}

 

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);

}

@Override

public void paintSelf(Graphics g) {

g.drawImage(img, x, y, null);

}

@Override

public 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();

}

}

}

//画 图形

@Override

public 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 {

//按下键盘的回调方法

@Override

public 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:

playerOne.keyPressed(e); //玩家按

}

}

@Override

public void keyReleased(KeyEvent e) {

playerOne.keyReleased(e); //玩家松

}

}

public static void main(String[] args) {

GamePanel gp = new GamePanel();

gp.launch();

}

}

 

 

以上是 用java写个小游戏 坦克大战 的全部内容, 来源链接: utcz.com/z/392267.html

回到顶部