赋料扬雄敌,诗看子建亲。这篇文章主要讲述坦克大战(上)相关的知识,希望能为你提供帮助。
项目建设
文章图片
在IDEA下新建一个项目TankGame文件,文件下新建TankGame类和MyPanel类
TankGame类主要用于游戏入口和窗口的相关配置
MyPanel类主要用于绘画坦克、子弹、移动、爆炸效果等
背景显示TankGame继承JFrame并重写构造器,给(main)启动入口
import javax.swing.*;
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class TankGame extends JFrame {
MyPanel mp = null;
public TankGame() {//重写构造器
mp = new MyPanel();
//初始化属性
this.setSize(1100, 800);
//设置界面大小
this.add(mp);
//添加mp
this.setVisible(true);
//设置可见
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置关闭窗口结束程序
}public static void main(String[] args) {
TankGame tankGame = new TankGame();
//启动游戏入口
}
}
MyPanel继承JPanel并重写paint()方法
import javax.swing.*;
import java.awt.*;
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class MyPanel extends JPanel {
@Override
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);
//设置背景大小
}
}
测试结果
文章图片
画出坦克模型在MyPanel添加drawTank( ) 方法
/**
* @param x坦克的横坐标
* @param y坦克的纵坐标
* @param g画笔
* @param direct 坦克的方向
* @param type坦克的颜色
*/
public void drawTank(int x, int y, int direct, int type, Graphics g) {//设置坦克模板switch (type) {//坦克颜色区分敌我坦克
case 0:
g.setColor(Color.CYAN);
break;
case 1:
g.setColor(Color.YELLOW);
break;
}switch (direct) {//坦克方向
case 0://上
g.fill3DRect(x, y, 10, 40, false);
//坦克左轮
g.fill3DRect(x + 30, y, 10, 40, false);
//坦克右轮
g.fill3DRect(x + 10, y + 5, 20, 30, false);
//坦克身子
g.fillOval(x + 10, y + 10, 20, 20);
//坦克盖子
g.fill3DRect(x + 18, y - 2, 4, 4, false);
//
g.drawLine(x + 20, y + 20, x + 20, y);
//坦克炮膛
for (int i = 2;
i <
40;
i += 4) {
g.drawLine(x + 1, y + i, x + 9, y + i);
g.drawLine(x + 31, y + i, x + 39, y + i);
}
break;
case 1://右
g.fill3DRect(x, y, 40, 10, false);
g.fill3DRect(x, y + 30, 40, 10, false);
g.fill3DRect(x + 5, y + 10, 30, 20, false);
g.fillOval(x + 10, y + 10, 20, 20);
g.fill3DRect(x + 38, y + 18, 4, 4, false);
g.drawLine(x + 20, y + 20, x + 40, y + 20);
for (int i = 2;
i <
40;
i += 4) {
g.drawLine(x + i, y + 1, x + i, y + 9);
g.drawLine(x + i, y + 31, x + i, y + 39);
}
break;
case 2://下
g.fill3DRect(x, y, 10, 40, false);
g.fill3DRect(x + 30, y, 10, 40, false);
g.fill3DRect(x + 10, y + 5, 20, 30, false);
g.fillOval(x + 10, y + 10, 20, 20);
g.fill3DRect(x + 18, y + 38, 4, 4, false);
g.drawLine(x + 20, y + 20, x + 20, y + 40);
for (int i = 2;
i <
40;
i += 4) {
g.drawLine(x + 1, y + i, x + 9, y + i);
g.drawLine(x + 31, y + i, x + 39, y + i);
}
break;
case 3://左
g.fill3DRect(x, y, 40, 10, false);
g.fill3DRect(x, y + 30, 40, 10, false);
g.fill3DRect(x + 5, y + 10, 30, 20, false);
g.fillOval(x + 10, y + 10, 20, 20);
//坦克盖子
g.fill3DRect(x - 2, y + 18, 4, 4, false);
g.drawLine(x + 20, y + 20, x, y + 20);
for (int i = 2;
i <
40;
i += 4) {
g.drawLine(x + i, y + 1, x + i, y + 9);
g.drawLine(x + i, y + 31, x + i, y + 39);
}
break;
}
}
在MyPanel的paint( )内传参测试
@Override
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);
//设置背景大小
drawTank(100, 100, 1, 0, g);
//测试
}
测试结果
文章图片
画出敌我坦克添加Tank类(父类)、Hero类(我方坦克继承Tank)、Enemy类(敌方坦克继承Tank)
Tank类:
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class Tank {
private int x;
//x坐标
private int y;
//有坐标
private int direct;
//方向public Tank(int x, int y, int direct) {
this.x = x;
this.y = y;
this.direct = direct;
}public int getX() {
return x;
}public void setX(int x) {
this.x = x;
}public int getY() {
return y;
}public void setY(int y) {
this.y = y;
}public int getDirect() {
return direct;
}public void setDirect(int direct) {
this.direct = direct;
}
}
Hero类
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class Hero extends Tank{
public Hero(int x, int y, int direct) {
super(x, y, direct);
}
}
Enemy类
/**
* @author 谢阳
* @version 1.8.0_131
*/
public class Enemy extends Tank {
public Enemy(int x, int y, int direct) {
super(x, y, direct);
}
}
在MyPanel中添加敌我坦克属性,并添加构造器初始化敌我坦克
Hero hero = null;
//创建hero属性
int enemyNum = 10;
//创建敌方坦克数量
Vector<
Enemy>
enemies = new Vector<
>
();
//创建敌方坦克集合public MyPanel() {//创建无参构造器
hero = new Hero(500, 500, 0);
//初始化我方坦克for (int i = 0;
i <
enemyNum;
i++) {//初始化敌方坦克
Enemy enemy = new Enemy(100*(i+0),0,2);
enemies.add(enemy);
}
}
在MyPanel的paint( ) 方法中画出敌我坦克
public void paint(Graphics g) {
super.paint(g);
g.fill3DRect(0, 0, 1000, 750, false);
//设置背景大小drawTank(hero.getX(), hero.getY(), hero.getDirect(), 0, g);
//画出我方坦克for (int i = 0;
i <
enemies.size();
i++) {//遍历画出敌方坦克
Enemy enemy = enemies.get(i);
drawTank(enemy.getX(),enemy.getY(),enemy.getDirect(),1,g);
}
}
测试结果
文章图片
我方坦克改变方向让MyPanel类实现KeyListener并在其方法内监听WDSA键,对应键可以改变对应方向
注: this.repaint(); 每改变一次方向可以刷新一次,后面可以通过多线程自动刷新
public class MyPanel extends JPanel implements KeyListener {@Override
public void keyTyped(KeyEvent e) {}@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//上
hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_D){//右
hero.setDirect(1);
}else if (e.getKeyCode() == KeyEvent.VK_S){//下
hero.setDirect(2);
}else if (e.getKeyCode() == KeyEvent.VK_A){//左
hero.setDirect(3);
}
this.repaint();
//刷新画布
}@Override
public void keyReleased(KeyEvent e) {}
在TankGame的构造器内添加监听键盘方法
public TankGame() {//重写构造器
mp = new MyPanel();
//初始化属性
this.setSize(1100, 800);
//设置界面大小
this.add(mp);
//添加mp
this.setVisible(true);
//设置可见
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置关闭窗口结束程序
this.addKeyListener(mp);
//监听键盘输入
}
测试结果(我方坦克可以上下左右切换方向)
文章图片
我方坦克可以移动【坦克大战(上)】在Tank类中添加速度speed属性 (给set和get方法) ,并添加上下左右移动方法
private int speed = 1;
//速度public void moveUp() {
y -= speed;
}public void moveDown() {
y += speed;
}public void moveRight() {
x += speed;
}public void moveLeft() {
x -= speed;
}public int getSpeed() {
return speed;
}public void setSpeed(int speed) {
this.speed = speed;
}
在MyPanel的监听方法中给其WDSA对应的坦克(hero)的移动方法,并且可以在构造器中设置移动速度
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_W) {//上
hero.moveUp();
hero.setDirect(0);
} else if (e.getKeyCode() == KeyEvent.VK_D){//右
hero.setDirect(1);
hero.moveRight();
}else if (e.getKeyCode() == KeyEvent.VK_S){//下
hero.setDirect(2);
hero.moveDown();
}else if (e.getKeyCode() == KeyEvent.VK_A){//左
hero.setDirect(3);
hero.moveLeft();
}
this.repaint();
}public MyPanel() {//创建无参构造器
hero = new Hero(500, 500, 0);
//初始化我方坦克
hero.setSpeed(5);
//设置我方移动速度for (int i = 0;
i <
enemyNum;
i++) {//初始化敌方坦克
Enemy enemy = new Enemy(100*(i+0),0,2);
enemies.add(enemy);
}
}
测试结果
文章图片
敌方坦克向下移动Enemy类实现Runnable接口,并重写run方法
public class Enemy extends Tank implements Runnable {
public Enemy(int x, int y, int direct) {
super(x, y, direct);
}@Override
public void run() {//重写run方法
while (true) {
moveDown();
//可以向下移动
try {//捕获异常
Thread.sleep(20);
//休眠20ms
} catch (InterruptedException e) {
e.printStackTrace();
}}
}
}
在MyPanel的构造器中启动enemy线程
public MyPanel() {//创建无参构造器
hero = new Hero(500, 500, 0);
//初始化我方坦克
hero.setSpeed(5);
//设置我方移动速度for (int i = 0;
i <
enemyNum;
i++) {//初始化敌方坦克
Enemy enemy = new Enemy(100*(i+0),0,2);
enemy.setSpeed(2);
//设置敌人移动速度
enemies.add(enemy);
//添加至敌人坦克集合
new Thread(enemy).start();
//启动敌人坦克线程
}
}
这时敌方坦克可以移动,但窗口不会自动刷新画板,只有当我方坦克移动时,才能看见敌方坦克移动
同理,在MyPanel类实现Runnable接口,重写run()方法添加repaint使其自动刷新画板
public void run() {
while(true) {this.repaint();
//刷新画板
try {
Thread.sleep(15);
//每15ms刷新一次
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
在TankGame的构造器中启动MyPanel的线程
public TankGame() {//重写构造器
mp = new MyPanel();
//初始化属性
new Thread(mp).start();
//启动Mypanel的线程
this.setSize(1100, 800);
//设置界面大小
this.add(mp);
//添加mp
this.setVisible(true);
//设置可见
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置关闭窗口结束程序
this.addKeyListener(mp);
//监听键盘输入
}
验证结果
文章图片
敌方坦克随机移动在Enemyl类中重写run方法,补充一点细节即可
@Override
public void run() {//重写run方法
while (true) {
int random = (int)(Math.random()*60);
//获取随机移动距离
switch (getDirect()){//获取方向
case 0://上
for (int i = 0;
i <
random;
i++) {
moveUp();
//向上移动random步
try {
Thread.sleep(50);
//休眠50ms
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 1://右
for (int i = 0;
i <
random;
i++) {
moveRight();
//向右移动random步
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 2://下
for (int i = 0;
i <
random;
i++) {
moveDown();
//向下移动random步
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
case 3://左
for (int i = 0;
i <
random;
i++) {
moveLeft();
//向左移动random步
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
break;
}
setDirect((int)(Math.random()*4));
//设置随机方向
}
}
验证结果
文章图片
推荐阅读
- OpenHarmony 3.0 LTS全解析(首个真正意义上全量长期支持版本)
- Web宝塔面板 安装Mongo 启动服务 创建用户
- 静态路由原理与配置
- Veeam BR 常见问题
- 国产开源网络编程框架t-io的炸裂性能介绍之30W长连接并发
- Android技术分享| 自习室自定义View代替通知动画
- Java技术指南「编译器专题」深入分析探究“静态编译器”(JAVAIDEAECJ编译器)
- Spring Data JPA 参考文档二
- 一文搞懂Hive的存储格式与压缩格式