坦克單機版
單機版程式演示
1、能夠四處移動
2、能夠打擊敵人
3、敵人能夠移動
4、能夠模擬爆炸
5、能夠產生障礙
6、能夠增長生命
遊戲測試類
import java.awt.Color;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class TankWar extends Frame{
/**
* 1)設定視窗寬度、高度
* 2)設定子彈、爆炸、坦克陣列
* 3)new Tank\Wall\Blood\
*/
public static final int GAME_WIDTH = 800;
public static final int GAME_HEIGHT = 600;
List<Missile> missiles = new ArrayList();
List<Explode> explodes = new ArrayList();
List<Tank> tanks = new ArrayList();
Tank myTank = new Tank(this,50,50,Direction.STOP,true);
Wall w1 = new Wall(this, 100, 200, 20, 150), w2 = new Wall(this, 300, 100, 300, 20);
Blood b = new Blood();
public static void main(String[] args) {
new TankWar().luanch();
}
/**
* 繪製視窗
*
*/
public void luanch(){
this.setBounds(600, 200, GAME_WIDTH, GAME_HEIGHT);
this.setTitle("TankWar");
this.setBackground(Color.GREEN);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setResizable(false);
this.addKeyListener(new KeyMonitor());
setVisible(true);
new Thread(new PaintThread()).start();
}
public void paint(Graphics g){
/**
* 指明子彈-爆炸-坦克的數量以及坦克的生命值
* 當敵方坦克數量小於或等於0時,自動新增5輛坦克
*/
g.drawString("count missile:" + missiles.size(), 10, 50);
g.drawString("count explodes:" + explodes.size(), 10, 70);
g.drawString("count tanks:" + tanks.size(), 10, 90);
g.drawString("tanks life:" + myTank.getLife(), 10, 110);
if(tanks.size() <= 0){
for(int i=0;i<5;i++){
tanks.add(new Tank(this, 50 + 40*(i+1), 50, Direction.D, false));
}
}
/**繪製子彈
* 遍歷子彈陣列,Missile類得到每一個子彈
* 子彈撞擊敵方坦克、子彈撞擊我方坦克、子彈撞牆
*/
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);
m.draw(g);
}
/**繪製爆炸
* 遍歷爆炸陣列,Explode得到每一個爆炸
*/
for(int i = 0;i<explodes.size();i++){
Explode e = explodes.get(i);
e.draw(g);
}
/**
* 遍歷tanks陣列,繪製每個坦克撞牆的方法
*/
for(int i = 0;i<tanks.size();i++){
Tank t = tanks.get(i);
t.collidesWithWall(w1);
t.collidesWithWall(w2);
t.collidesWithTanks(tanks);
t.draw(g);
}
myTank.draw(g);
myTank.eat(b);
w1.draw(g);
w2.draw(g);
b.draw(g);
}
//雙緩衝
Image offScreenImage = null;
@Override
public void update(Graphics g) {
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);
}
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{
//按下
@Override
public void keyPressed(KeyEvent e) {
myTank.keyPressed(e);
}
//抬起
@Override
public void keyReleased(KeyEvent e) {
myTank.keyReleased(e);
}
}
}
坦克
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;
import java.util.Random;
/**
* 坦克類
* @author Administrator
*
*/
public class Tank {
TankWar tc;
/**一、
* 1)設定坦克座標,寬、高以及移動的間距
* 2)設定坦克方向位置初始化,以及炮筒方向
* 3)設定方向bU\bD\bL\bR為false,
* 4)live(存在)即true,!live(消失)即為false
* 5)good(我方)true、!good(敵方)false
* 6)設定oldX、oldY座標以便為了記錄坦克上一次移動的位置
* 7)設定坦克生命值:100
* 8)設定隨機步數,最小值:3、最大值:14
* 9)new 血條BloodBar
*/
private int x,y;
public static final int WIDTH = 30;
public static final int HEIGHT = 30;
public static final int XSPEED = 5;
public static final int YSPEED = 5;
private Direction dir = null;
private Direction ptDir = Direction.D;
private boolean bU = false, bD = false, bL = false, bR = false;
private boolean live = true;
private boolean good;
private int oldX,oldY;
private int life = 100;
private Random r = new Random();
private int step = r.nextInt(12) + 3;
private BloodBar bb = new BloodBar();
/**二、
* 有參構造
*/
public Tank(TankWar tc, int x, int y, Direction dir, boolean good) {
this.tc = tc;
this.x = x;
this.y = y;
this.dir = dir;
this.good = good;
//記錄第一次的上一步
this.oldX = x;
this.oldY = y;
}
/**三、
* 1)敵方如果死亡就從坦克陣列中移除
* 2)繪製我方坦克顏色以及敵方坦克顏色以及座標、大小
* 3)繪製炮筒八個方向
* 4)我方坦克繪製血條
*/
public void draw(Graphics g){
if(!live){
if(! good){
tc.tanks.remove(this);
}
return;
}
Color c = g.getColor();
if(good) g.setColor(Color.RED);
else g.setColor(Color.BLUE);
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(c);
if(good) bb.draw(g);
switch(ptDir){
case U:
g.drawLine(x + WIDTH/2, y + HEIGHT/2,x + WIDTH/2, y);
break;
case D:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH/2, y + HEIGHT);
break;
case L:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x, y + HEIGHT/2);
break;
case R:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH, y + HEIGHT/2);
break;
case UL:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x, y);
break;
case UR:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH, y);
break;
case DL:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x, y + HEIGHT);
break;
case DR:
g.drawLine(x + WIDTH/2, y + HEIGHT/2, x + WIDTH, y + HEIGHT);
break;
}
move();
}
/**四、
* 1)oldX、oldY還沒有移動之前先記錄坦克xy座標位置
* 2)坦克分別向八個方向移動的距離
* 3)如果坦克不是靜止狀態,那麼炮筒方向就和坦克方向一致
* 4)坦克出界:
* 30是標題欄的高度
* 如果坦克出界就重新定義x、y座標
*/
void move() {
this.oldX = x;
this.oldY = y;
switch (dir) {
case U:
y -= YSPEED;
break;
case D:
y += YSPEED;
break;
case L:
x -= XSPEED;
break;
case R:
x += XSPEED;
break;
case UL:
x -= XSPEED;
y -= YSPEED;
break;
case UR:
x += XSPEED;
y -= YSPEED;
break;
case DL:
x -= XSPEED;
y += YSPEED;
break;
case DR:
x += XSPEED;
y += YSPEED;
break;
}
if (this.dir != Direction.STOP) {
this.ptDir = this.dir;
}
if(x < 0) x = 0;
if(y <30) y =30;
if(x + Tank.WIDTH > TankWar.GAME_WIDTH) x = TankWar.GAME_WIDTH - Tank.WIDTH;
if(y + Tank.HEIGHT > TankWar.GAME_HEIGHT) y = TankWar.GAME_HEIGHT - Tank.HEIGHT;
/**五、
* 隨機指定一個敵方坦克方向,隨機移動的步數最小值3、最大值14
* 每移動一次step步數減1,step步數為零時重新產生一個隨機步數
* 每次產生隨機數大於38就發一次炮彈
*/
if(!good){
Direction [] dirs = Direction.values();
if(step == 0){
step = r.nextInt(12)+3;
int rn = r.nextInt(dirs.length);
dir = dirs[rn];
}
step --;
if(r.nextInt(40) >38)this.fire();
}
}
private void stay(){
x = oldX;
y = oldY;
}
/**
* 坦克開火(發射子彈)
* 如果坦克不存在,直接返回為空
* 設定子彈座標位置:坦克寬度、高度分別除以2,得到坦克中心位置。
* 再減去子彈寬度、高度的一半即子彈位置座標
* fire()用於炮筒方向發射子彈,fire(Dirction dir)用於八個方向超級發射子彈
* @return
*/
public Missile fire() {
if(!live) return null;
int x = this.x + Tank.WIDTH/2 - Missile.WIDTH/2;
int y = this.y + Tank.HEIGHT/2 - Missile.HEIGHT/2;
Missile m = new Missile(tc, x, y, ptDir, good);
tc.missiles.add(m);
return m;
}
public Missile fire(Direction dir) {
if(!live) return null;
int x = this.x + Tank.WIDTH/2 - Missile.WIDTH/2;
int y = this.y + Tank.HEIGHT/2 - Missile.HEIGHT/2;
Missile m = new Missile(tc, x, y, dir, good);
tc.missiles.add(m);
return m;
}
/**
* 鍵盤按下、抬起監聽(方向)
* 1)設定F2,如果live消失即(false),馬上變為ture(存在),並且生命值為100
* 2)如果單單只是設定了keyPressed(按下)監聽,一旦按下某個方向鍵時就永遠為true,也就意味著會一直執行某個鍵的指令
* 3)keyReleased(抬起)存在修正了keyPressed遺留問題,按下為true\抬起為false
* 4)設定抬起鍵盤A,新增超級子彈發射方法
* @param e
*/
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_F2:
if(!this.live){
this.live = true;
this.life = 100;
}
break;
case KeyEvent.VK_UP:
bU = true;
break;
case KeyEvent.VK_DOWN:
bD = true;
break;
case KeyEvent.VK_LEFT:
bL = true;
break;
case KeyEvent.VK_RIGHT:
bR = true;
break;
}
locateDirection();
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_CONTROL:
fire();
break;
case KeyEvent.VK_UP:
bU = false;
break;
case KeyEvent.VK_DOWN:
bD = false;
break;
case KeyEvent.VK_LEFT:
bL = false;
break;
case KeyEvent.VK_RIGHT:
bR = false;
break;
case KeyEvent.VK_A:
superFire();
break;
}
locateDirection();
}
/**設定八個方向
* 當按下朝"上"的鍵時,沒有按下朝"下"、"左"、"右",方向就向上移動
*/
private void locateDirection(){
if(bU && !bD && !bL && !bR) dir = Direction.U;
else if(!bU && bD && !bL && !bR) dir = Direction.D;
else if(!bU && !bD && bL && !bR) dir = Direction.L;
else if(!bU && !bD && !bL && bR) dir = Direction.R;
else if(bU && !bD && bL && !bR) dir = Direction.UL;
else if(bU && !bD && !bL && bR) dir = Direction.UR;
else if(!bU && bD && bL && !bR) dir = Direction.DL;
else if(!bU && bD && !bL && bR) dir = Direction.DR;
else if(!bU && !bD && !bL && !bR) dir = Direction.STOP;
}
/**
* 分別向八個方向發射子彈
*/
private void superFire() {
Direction[] dirs = Direction.values();
for(int i=0; i<8; i++) {
fire(dirs[i]);
}
}
/**
* 如果坦克和牆相撞就回到上一步位置
* @param w
* @return
*/
public boolean collidesWithWall(Wall w){
if(this.live && this.getRect().intersects(w.getRect())){
this.stay();
return true;
}
return false;
}
/**awt和util包中各有List,為了方便區分引數中寫明
* 我方和敵方坦克都存在的情況下,撞上返回true,否則false
* @param tanks
* @return
*/
public boolean collidesWithTanks(java.util.List<Tank> tanks){
for(int i=0;i<tanks.size();i++){
Tank t = tanks.get(i);
if(this != t){
if(this.live && t.isLive() && this.getRect().intersects(t.getRect())){
this.stay();
return true;
}
}
}
return false;
}
/**
* 撞的方法
* @return
*/
public Rectangle getRect(){
return new Rectangle(x,y,WIDTH,HEIGHT);
}
/**血條
* 繪製內框 + 外框
* @author Administrator
*
*/
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);
}
}
/**
* 如果我方坦克和血塊都存在的情況下,並且相撞
* 我方坦克的生命值立即為100,血塊消失
* @param b
* @return
*/
public boolean eat(Blood b){
if(this.live && b.isLive() &&this.getRect().intersects(b.getRect())){
this.life = 100;
b.setLive(false);
return true;
}
return false;
}
public boolean isGood() {
return good;
}
public boolean isLive() {
return live;
}
public void setLive(boolean live) {
this.live = live;
}
public int getLife() {
return life;
}
public void setLife(int life) {
this.life = life;
}
}
子彈
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.net.URI;
import java.util.List;
/**
* 子彈類
* @author Administrator
*
*/
public class Missile {
TankWar tc;
/**
* 定義子彈寬度、高度以及移動距離、方向
* good(我方)true、!good(敵方)false
* live(存在)即true、!live(消失)即為false
*/
public static final int WIDTH = 10;
public static final int HEIGHT = 10;
public static final int XSPEED = 10;
public static final int YSPEED = 10;
int x , y;
Direction dir;
private boolean good ;
private boolean live = true;
public Missile(TankWar tc, int x, int y, Direction dir, boolean good) {
this.tc = tc;
this.x = x;
this.y = y;
this.dir = dir;
this.good = good;
}
/**
* 如果子彈死亡就從Missile陣列中移除
* 繪製子彈顏色形狀大小、以及顏色
* @param g
*/
public void draw(Graphics g){
if(!live) {
tc.missiles.remove(this);
return;
}
Color c = g.getColor();
g.setColor(Color.RED);
g.fillOval(x, y, WIDTH, HEIGHT);
g.setColor(c);
move();
}
/**
* 分別設定子彈移動的八個方向
* 注意子彈類YSPEED、SPEED引數,子彈移動速度須比坦克快
* 子彈越界消亡處理
*/
private void move() {
switch(dir){
case U:
y -= YSPEED;
break;
case D:
y += YSPEED;
break;
case L:
x -= XSPEED;
break;
case R:
x += XSPEED;
break;
case UL:
x -= XSPEED;
y -= YSPEED;
break;
case UR:
y -= YSPEED;
x += XSPEED;
break;
case DL:
x -= XSPEED;
y += YSPEED;
break;
case DR:
x += XSPEED;
y += YSPEED;
break;
case STOP:
break;
}
if(x < 0 || y < 0 || x > tc.GAME_WIDTH || y > tc.GAME_HEIGHT){
live = false;
}
}
/**
* 子彈和坦克碰撞
* hitTank(Tank t)
* 1)如果子彈沒有消失 && 碰撞和坦克碰撞 && 我方子彈不打我方坦克 && 我方坦克存活
* 簡單說就是我方子彈不打我方坦克
* 2)我方坦克被擊中一下減去20的生命值,直到生命值小於或等於零時,我方坦克消失(死亡)
* 3)else反之敵方坦克被子彈擊中立即消失(死亡)
*/
public Rectangle getRect(){
return new Rectangle(x, y, WIDTH, HEIGHT);
}
public boolean hitTank(Tank t){
if(this.live && this.getRect().intersects(t.getRect()) && this.good != t.isGood() && t.isLive()){
if(t.isGood()){
t.setLife(t.getLife()-20);
if(t.getLife() <= 0) t.setLive(false);
}else {
t.setLive(false);
}
this.live = false;
Explode e = new Explode(tc, x, y);
tc.explodes.add(e);
return true;
}
return false;
}
public boolean hitTanks(List<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.live && this.getRect().intersects(w.getRect())){
this.live = false;
return true;//?
}
return false;
}
}
爆炸
import java.awt.Color;
import java.awt.Graphics;
/**
* 爆炸類
* @author Administrator
*
*/
public class Explode {
TankWar tc;
/**
* 1)定義座標,爆炸範圍大小即diameter,步數
* 2)live(存在)即true,!live(消失)即為false
* 3)有參構造
* 4)如果爆炸消失就從explodes移除
* 5)爆炸到最後一步,爆炸消失,step初始化為零
*/
int x,y;
int [] diameter = {4,7,12,18,26,32,49,30,14,6};
int step = 0;
private boolean live = true;
public Explode(TankWar tc, int x, int y) {
this.tc = tc;
this.x = x;
this.y = y;
}
public void draw(Graphics g){
if(!live){
tc.explodes.remove(this);
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]);
g.setColor(c);
step++;
}
}
牆
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
/**
* 牆類
* @author Administrator
*
*/
public class Wall {
TankWar tc;
int x,y,w,h;
public Wall(TankWar tc, int x, int y, int w, int h) {
this.tc = tc;
this.x = x;
this.y = y;
this.w = w;
this.h = h;
}
public void draw(Graphics g){
Color c = g.getColor();
g.setColor(Color.BLACK);
g.fillRect(x, y, w, h);
g.setColor(c);
}
public Rectangle getRect(){
return new Rectangle(x, y, w, h);
}
}
方向
public enum Direction {
U,D,L,R,UL,UR,DL,DR,STOP
}
血塊
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
/**
* 血塊類
* @author Administrator
*
*/
public class Blood {
private int x,y,w,h;
private int step;
private boolean live = true;
private int [][] pos = {
{350, 300}, {360, 300}, {375, 275}, {400, 200}, {360, 270}, {365, 290}, {340, 280}
};
public Blood() {
x = pos[0][0];
y = pos[0][1];
w = h = 15;
}
public void draw(Graphics g){
if(!live) return;
Color c = g.getColor();
g.setColor(Color.MAGENTA);
g.fillOval(x, y, w, h);
g.setColor(c);
move();
}
/**
* 在pos二維陣列中設定點{x,y}座標,每移動一次step +1
* step一直加到最後,step初始化為0
*/
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) {
this.live = live;
}
}
相關文章
- 創領越野新時代,坦克品牌攜坦克400汽油版為中國越野造勢
- springboot + redis(單機版)Spring BootRedis
- zookeeper 單機版 docker部署Docker
- Hadoop單機版安裝Hadoop
- docker安裝單機版 NacosDocker
- 簡單版AC自動機
- Linux安裝Redis單機版LinuxRedis
- Hadoop單機版的安裝Hadoop
- Hbase單機版的安裝
- 坦克世界開發商Wargaming進軍手機遊戲市場GAM遊戲
- kafka環境安裝及簡單使用(單機版)Kafka
- python 坦克大戰原始碼Python原始碼
- Java Swing坦克小遊戲Java遊戲
- Docker 一鍵安裝Nacos 單機版Docker
- 單機版搭建kubernetes(K8s)K8S
- 在Ubuntu上安裝Hadoop單機版UbuntuHadoop
- Flink安裝極簡教程-單機版
- 換個風格闖入二戰 《全面坦克模擬器》內測版試玩
- Oracle運維指令碼-巡檢(單機版)Oracle運維指令碼
- Nacos 本地單機版部署步驟和使用
- Schedule 排程系統設計(單機版)
- 2,ELK安裝--ES安裝(單機版)
- 使用 Docker 快速搭建單機版的 Kubernetes 叢集Docker
- 基於docker 搭建redis環境—redis單機版DockerRedis
- .單機版samba設定 /etc/samba/smb.confSamba
- python版:單機redis實現秒殺,防止超限PythonRedis
- 超簡單的CDH6部署和體驗(單機版)
- 【clickhouse專欄】單機版的安裝與驗證
- Spark大資料處理框架入門(單機版)Spark大資料框架
- CentOS7使用HBase-1.2.6單機版,無hadoopCentOSHadoop
- h5+js實現單機版貪吃蛇H5JS
- hadoop偽分散式叢集的安裝(不是單機版)Hadoop分散式
- milvus 2.1.1單機版佔用磁碟增長特別快?
- Steam測試中國版,單機遊戲也要防沉迷遊戲
- FC紅白機遊戲600合集 for mac(小霸王遊戲) 單機離線版遊戲Mac
- Android:單機版的“你畫我猜”你敢信?(Path的使用)Android
- unity 開發2D坦克大戰教程 系列二Unity
- 5分鐘擁有自己的坦克大戰遊戲遊戲