今天给大家分享一个使用java编写的坦克大战小游戏,整体还是挺好玩的,通过对这款游戏的简单实现,加深对java基础的深刻理解。
一、设计思路
1.坦克大战小游戏通过java实现,其第一步需要先绘制每一关对应的地图,地图包括河流、草地、砖块、铁块等。
2.需要绘制玩家坦克、敌方坦克、以及坦克移动过程中使用到的碰撞算法,子弹与坦克之间的碰撞,
包括击中敌方坦克后的爆炸效果,通过重绘实现坦克的移动,以及各种道具的随机生成算法。
实际运行效果如下:
二、代码实现
1.首先需要将游戏中涉及到的各种对象梳理清楚,由于Java面向对象的特征,可以将一些对象公共特性抽象出来,比如将坦克抽象出一个超类,代码如下:
public abstract class Tank{
int x=0;
int y=0;
int tempX=0;
int tempY=0;
int size=32;
int direct=Constant.UP;
int speed=1;
int lives=1;
int frame=0;//控制敌方坦克切换方向的时间
boolean isAI=false;//是否自动
boolean hit;
boolean isShooting=false;
boolean isDestroyed=false;
boolean isProtected=false;
Map map;
GameMain gameMain;
Collision collision;
Bullet bullet;
int starNum=0; //星星数
public Tank(int size,int speed,Collision collision,Map map,GameMain gameMain) {
this.size=size;
this.collision=collision;
this.map=map;
this.gameMain=gameMain;
this.speed=speed;
}
public void move() {
//如果是AI坦克,在一定时间或碰撞后切换方法
if(this.isAI && gameMain.enemyStopTime>0) {
return;
}
this.tempX=this.x;
this.tempY=this.y;
if(this.isAI) {
this.frame++;
if(this.frame%100==0 || this.hit) {
this.direct=(int)(Math.random()*4);
this.hit=false;
this.frame=0;
}
}
if(this.direct==Constant.UP) {
this.tempY-=this.speed;
}else if(this.direct==Constant.DOWN) {
this.tempY+=this.speed;
}else if(this.direct==Constant.LEFT) {
this.tempX-=this.speed;
}else if(this.direct==Constant.RIGHT) {
this.tempX+=this.speed;
}
isHit();
if(!this.hit) {
this.x=this.tempX;
this.y=this.tempY;
}
}
public void isHit() {
if(this.direct==Constant.LEFT) {
if(this.x<=map.offsetX) {
this.x=map.offsetX;
this.hit=true;
}
}else if(this.direct==Constant.RIGHT) {
if(this.x>=map.offsetX+map.mapWidth-this.size) {
this.x=map.offsetX+map.mapWidth-this.size;
this.hit=true;
}
}else if(this.direct==Constant.UP) {
if(this.y<=map.offsetY) {
this.y=map.offsetY;
this.hit=true;
}
}else if(this.direct==Constant.DOWN) {
if(this.y>=map.offsetY+map.mapHeight-this.size) {
this.y=map.offsetY+map.mapHeight-this.size;
this.hit=true;
}
}
if(!this.hit) {
if(collision.tankMapCollision(this, map)) {
this.hit=true;
}
}
}
public abstract void drawTank(Graphics2D ctx2);
public void shoot(int type,Graphics2D ctx2) {
if(this.isAI && gameMain.enemyStopTime>0) {
return;
}
if(this.isShooting) {
return;
}
int tempX=this.x;
int tempY=this.y;
this.bullet=new Bullet(tempX, tempY, this.direct, gameMain, type, map, this, collision);
if(!this.isAI) {
if(this.starNum==0) {
this.bullet.speed=3;
this.bullet.fireNum=1;
}
if(this.starNum>0 && this.starNum<=3) {
this.bullet.speed+=this.starNum;
this.bullet.fireNum+=(this.starNum-1);
}
if(this.starNum>3) {
this.bullet.speed+=3;
this.bullet.fireNum+=3;
}
}
if(this.direct==Constant.UP) {
tempX = this.x + this.size/2 - this.bullet.size/2;
tempY=this.y-this.bullet.size;
}else if(this.direct==Constant.DOWN) {
tempX = this.x + this.size/2 - this.bullet.size/2;
tempY=this.y+this.bullet.size;
}else if(this.direct==Constant.LEFT) {
tempX=this.x-this.bullet.size;
tempY=this.y + this.size/2 - this.bullet.size/2;
}else if(this.direct==Constant.RIGHT) {
tempX=this.x+this.bullet.size;
tempY=this.y + this.size/2 - this.bullet.size/2;
}
this.bullet.x=tempX;
this.bullet.y=tempY;
if(!this.isAI) {
//音乐
Constant.executor.execute(new Runnable() {
@Override
public void run() {
Constant.ATTACK_AUDIO.play();
}
});
}
this.bullet.drawBullet(ctx2);
gameMain.bulletArr.add(this.bullet);
this.isShooting=true;
}
public void distroy() {
this.isDestroyed=true;
gameMain.crackArr.add(new CrackAnimation(gameMain, Constant.CRACK_TYPE_TANK, this));
if(this.isAI) {
Constant.executor.execute(new Runnable() {
@Override
public void run() {
Constant.TANK_DESTROY_AUDIO.play();
}
});
gameMain.appearEnemy--;
}else {
Constant.executor.execute(new Runnable() {
@Override
public void run() {
Constant.PLAYER_DESTROY_AUDIO.play();
}
});
this.starNum=0;
}
}
}
2.坦克子类实现
public class PlayTank extends Tank{
int protectedTime = 0;//保护时间
int offsetX=0; //坦克2与坦克1的距离
int type; //玩家类型
public PlayTank(int type,Collision collision, Map map, GameMain gameMain) {
super(32, 2, collision, map, gameMain);
this.lives = 3;//生命值
this.isProtected = true;//是否受保护
this.protectedTime = 500;//保护时间
this.type=type;
}
@Override
public void drawTank(Graphics2D ctx2) {
this.hit = false;
if(this.type==1) {
ctx2.drawImage(Constant.RESOURCE_IMAGE, this.x, this.y,this.x+this.size,this.y+this.size,
Constant.POS.get("player").x+this.offsetX+this.direct*this.size, Constant.POS.get("player").y,
Constant.POS.get("player").x+this.offsetX+this.direct*this.size+this.size, Constant.POS.get("player").y+this.size, null);
}else {
ctx2.drawImage(Constant.RESOURCE_IMAGE, this.x, this.y,this.x+this.size,this.y+this.size,
Constant.POS.get("player").x+128+this.offsetX+this.direct*this.size, Constant.POS.get("player").y,
Constant.POS.get("player").x+128+this.offsetX+this.direct*this.size+this.size, Constant.POS.get("player").y+this.size, null);
}
if(this.isProtected) {
int temp=((500-protectedTime)/5)%2;
ctx2.drawImage(Constant.RESOURCE_IMAGE, this.x, this.y,this.x+this.size,this.y+this.size,
Constant.POS.get("protected").x, Constant.POS.get("protected").y+32*temp,
Constant.POS.get("protected").x+this.size, Constant.POS.get("protected").y+this.size, null);
this.protectedTime--;
if(this.protectedTime==0) {
this.isProtected=false;
}
}
}
/**
* 玩家坦克复活
* @param player
*/
public void renascenc(int playerType) {
this.lives--;
this.direct=Constant.UP;
this.isProtected=true;
this.protectedTime=500;
this.isDestroyed = false;
int temp=0;
if(playerType==1) {
temp=129;
}else {
temp=256;
}
this.x = temp + map.offsetX;
this.y = 385 + map.offsetY;
}
}
3.通过子类继承父类实现玩家坦克和敌方坦克的创建,创建完后,接下来就可让坦克动起来,如下:
public void addEnemyTank(Graphics2D ctx2) {
if(enemyArr == null || enemyArr.size() >= maxAppearEnemy || maxEnemy == 0){
return;
}
appearEnemy++;
Tank objTank=null;
int rand=(int) (Math.random()*4);
if(rand==0) {
objTank=new TankEnemy0(collision, map, this);
}else if(rand==1) {
objTank=new TankEnemy1(collision, map, this);
}else if(rand==2) {
objTank=new TankEnemy2(collision, map, this);
}else if(rand==3) {
objTank=new TankEnemy3(collision, map, this);
}
enemyArr.add(objTank);
this.maxEnemy--;
map.clearEnemyNum(maxEnemy, appearEnemy,ctx2);
}
4.在移动过程中,涉及到坦克与子弹,坦克与地图之间的碰撞问题,实现如下:
/**
* 坦克与地图间的碰撞
**/
public boolean tankMapCollision(Tank tank,Map map) {
//移动检测,记录最后一次的移动方向,根据方向判断+-overlap;
int tileNum=0;
int rowIndex=0;
int colIndex=0;
int overlap=3; //允许重叠的大小
//根据tank的x、y计算map的row和col
if(tank.direct==Constant.UP) {
rowIndex=(tank.tempY+overlap-map.offsetY)/map.tileSize;
colIndex=(tank.tempX+overlap-map.offsetX)/map.tileSize;
}else if(tank.direct==Constant.DOWN) {
rowIndex=(tank.tempY-overlap-map.offsetY+tank.size)/map.tileSize;
colIndex=(tank.tempX+overlap-map.offsetX)/map.tileSize;
}else if(tank.direct==Constant.LEFT) {
rowIndex=(tank.tempY+overlap-map.offsetY)/map.tileSize;
colIndex=(tank.tempX+overlap-map.offsetX)/map.tileSize;
}else if(tank.direct==Constant.RIGHT){
rowIndex=(tank.tempY+overlap-map.offsetY)/map.tileSize;
colIndex=(tank.tempX-overlap-map.offsetX+tank.size)/map.tileSize;
}
if(rowIndex>=map.hTileCount || rowIndex<0 || colIndex>=map.wTileCount || colIndex<0) {
return true;
}
if(tank.direct==Constant.UP || tank.direct==Constant.DOWN) {
int tempWidth=tank.tempX-map.offsetX-colIndex*map.tileSize+tank.size-overlap;
if(tempWidth%map.tileSize==0) {
tileNum=tempWidth/map.tileSize;
}else {
tileNum=tempWidth/map.tileSize+1;
}
for(int i=0;i<tileNum && colIndex+i<map.wTileCount;i++) {
int mapContent=map.mapLevel[rowIndex][colIndex+i];
if(mapContent==Constant.WALL || mapContent==Constant.GRID || mapContent==Constant.WATER || mapContent==Constant.HOME || mapContent==Constant.ANOTHER_HOME) {
if(tank.direct==Constant.UP) {
tank.y=map.offsetY+rowIndex*map.tileSize+map.tileSize-overlap;
}else {
tank.y=map.offsetY+rowIndex*map.tileSize-tank.size+overlap;
}
return true;
}
}
}else {
int tempHeight=tank.tempY-map.offsetY-rowIndex*map.tileSize+tank.size-overlap;
if(tempHeight%map.tileSize==0) {
tileNum=tempHeight/map.tileSize;
}else {
tileNum=tempHeight/map.tileSize+1;
}
for(int i=0;i<tileNum && rowIndex+i<map.hTileCount;i++) {
int mapContent=map.mapLevel[rowIndex+i][colIndex];
if(mapContent==Constant.WALL || mapContent==Constant.GRID || mapContent==Constant.WATER || mapContent==Constant.HOME || mapContent==Constant.ANOTHER_HOME) {
if(tank.direct==Constant.LEFT) {
tank.x=map.offsetX+colIndex*map.tileSize+map.tileSize-overlap;
}else {
tank.x=map.offsetX+colIndex*map.tileSize-tank.size+overlap;
}
return true;
}
}
}
return false;
}
5.绘制界面,通过定时重绘实现,具体代码如下:
public class GameMain extends JPanel{
//int enemyNum=12;
Map map;
Num num;
int level=1;
Level tankLevel;
int gameState=Constant.GAME_STATE_MENU;
private boolean isGameOver=false;
int maxEnemy = 12;//敌方坦克总数
int maxAppearEnemy = 5;//屏幕上一起出现的最大数
int appearEnemy = 0; //已出现的敌方坦克
int enemyStopTime=0;
List<Bullet> bulletArr;
List<Tank> enemyArr;
List<CrackAnimation> crackArr;
List<Integer> keys;
Tank player1 = null;//玩家1
Tank player2 = null;//玩家2
Collision collision;
int mainframe = 0;
Image offScreenImage;
Menu menu;
Stage stage;
Prop prop;
Graphics2D ctx2;
int overX = 176;
int overY = 384;
int propTime = 300; //道具出现频次
int homeProtectedTime = -1;
int winWaitTime=80;
public void initGame(GameMain gameMain) {
this.num=new Num(gameMain);
this.tankLevel=new Level();
this.collision=new Collision(gameMain);
}
public void initObject() {
this.map=new Map(this, num, tankLevel, level);
player1=new PlayTank(1,collision, map, this);
player1.x = 129 + map.offsetX;
player1.y = 385 + map.offsetY;
player2 = new PlayTank(2,collision, map, this);
player2.x = 256 + map.offsetX;
player2.y = 385 + map.offsetY;
bulletArr=new ArrayList<>();
enemyArr=new ArrayList<>();
crackArr=new ArrayList<>();
keys=new ArrayList<>();
menu=new Menu();
stage=new Stage(level, this,this.num);
this.isGameOver=false;
this.propTime=400;
this.homeProtectedTime = -1;
this.maxEnemy=12;
this.winWaitTime=50;
this.appearEnemy=0;
this.overY=384;
}
public void goGameOver() {
this.isGameOver=true;
}
@Override
public void paint(Graphics g) {
//创建和容器一样大小的Image图片
if(offScreenImage==null) {
offScreenImage=this.createImage(Constant.SCREEN_WIDTH,Constant.SCREEN_HEIGHT);
}
//获得该图片的画布
Graphics gImage=offScreenImage.getGraphics();
//填充整个画布
gImage.fillRect(0,0,Constant.SCREEN_WIDTH,Constant.SCREEN_HEIGHT);
if(ctx2==null) {
ctx2=(Graphics2D)gImage;
}
if(gameState==Constant.GAME_STATE_MENU) {
menu.drawMenu(ctx2);
}
if(gameState==Constant.GAME_STATE_INIT) {
stage.setNum(ctx2);
stage.drawStage(ctx2);
}
if(gameState==Constant.GAME_STATE_START || gameState==Constant.GAME_STATE_OVER) {
drawAll(ctx2);
}
if(gameState==Constant.GAME_STATE_OVER) {
gameOver();
}
if(gameState==Constant.GAME_STATE_WIN) {
this.winWaitTime--;
drawAll(ctx2);
if(this.winWaitTime==0) {
nextLevel();
}
}
//将缓冲区绘制好的图形整个绘制到容器的画布中
g.drawImage(offScreenImage,0,0,null);
}
public void initMap(Graphics2D ctx2) {
map.setNum(ctx2);
map.drawMap(ctx2);
}
public void drawAll(Graphics2D ctx2) {
map.setNum(ctx2);
map.drawMap(ctx2);
if(player1.lives>0) {
player1.drawTank(ctx2);
}
if(player2.lives>0) {
player2.drawTank(ctx2);
}
if(appearEnemy<maxEnemy){
if(mainframe % 100 == 0){
addEnemyTank(ctx2);
mainframe = 0;
}
mainframe++;
}
drawLives(ctx2);
drawEnemyTanks(ctx2);
map.drawGrassMap(ctx2);
drawBullet(ctx2);
drawCrack(ctx2);
keyEvent();
if(propTime<=0){
drawProp(ctx2);
}else{
propTime --;
}
if(homeProtectedTime > 0){
homeProtectedTime --;
}else if(homeProtectedTime == 0){
homeProtectedTime = -1;
homeNoProtected(ctx2);
}
}
public void addEnemyTank(Graphics2D ctx2) {
if(enemyArr == null || enemyArr.size() >= maxAppearEnemy || maxEnemy == 0){
return;
}
appearEnemy++;
Tank objTank=null;
int rand=(int) (Math.random()*4);
if(rand==0) {
objTank=new TankEnemy0(collision, map, this);
}else if(rand==1) {
objTank=new TankEnemy1(collision, map, this);
}else if(rand==2) {
objTank=new TankEnemy2(collision, map, this);
}else if(rand==3) {
objTank=new TankEnemy3(collision, map, this);
}
enemyArr.add(objTank);
this.maxEnemy--;
map.clearEnemyNum(maxEnemy, appearEnemy,ctx2);
}
public void drawEnemyTanks(Graphics2D ctx2) {
if(enemyArr!=null && enemyArr.size()>0) {
Iterator<Tank> it=enemyArr.iterator();
while(it.hasNext()) {
Tank enemyTank=it.next();
if(enemyTank.isDestroyed) {
it.remove();
}else {
enemyTank.drawTank(ctx2);
}
}
}
if(enemyStopTime > 0){
enemyStopTime --;
}
}
/**
* 绘制玩家生命数
*/
public void drawLives(Graphics2D ctx2) {
map.drawLives(player1.lives, 1,ctx2);
map.drawLives(player2.lives, 2,ctx2);
}
/**
* 绘制子弹
* @param ctx2
*/
public void drawBullet(Graphics2D ctx2) {
if(bulletArr != null && bulletArr.size() > 0){
Iterator<Bullet> it=bulletArr.iterator();
while(it.hasNext()) {
Bullet bullet=it.next();
if(bullet.isDestroyed) {
it.remove();
bullet.owner.isShooting=false;
}else {
//绘制子弹
bullet.drawBullet(ctx2);
}
}
}
}
public void drawCrack(Graphics2D ctx2) {
if(crackArr != null && crackArr.size() > 0){
Iterator<CrackAnimation> it=crackArr.iterator();
while(it.hasNext()) {
CrackAnimation crackAnimation=it.next();
if(crackAnimation.isOver) {
it.remove();
if(crackAnimation.crackObj instanceof Tank) {
Tank tank=(Tank)crackAnimation.crackObj;
if(tank==player1) {
PlayTank playerTank1=(PlayTank)player1;
playerTank1.renascenc(1);
}else if(tank==player2) {
PlayTank playerTank2=(PlayTank)player2;
playerTank2.renascenc(2);
}
}
}else {
//绘制爆炸效果
crackAnimation.draw(ctx2);
}
}
}
}
public void drawProp(Graphics2D ctx2) {
double rand=Math.random();
if(rand<=0.4 && prop==null) {
prop=new Prop(this, map, collision);
prop.initProp();
}
if(prop!=null) {
prop.drawProp(ctx2);
if(prop.isDestroyed) {
prop=null;
propTime=600;
}
}
}
public void nextLevel() {
level++;
if(level==17) {
level=1;
}
int oldPlayerNum=menu.playNum;
initObject();
menu.playNum = oldPlayerNum;
//只有一个玩家
if(menu.playNum == 1){
player2.lives = 0;
}
map.first=0;
stage.init(level);
gameState = Constant.GAME_STATE_INIT;
}
public void preLevel() {
level--;
if(level == 0){
level = 16;
}
//保存玩家数
int oldPlayerNum = menu.playNum;
initObject();
menu.playNum = oldPlayerNum;
//只有一个玩家
if(menu.playNum == 1){
player2.lives = 0;
}
stage.init(level);
gameState = Constant.GAME_STATE_INIT;
}
public void gameLoop() {
switch (gameState) {
case Constant.GAME_STATE_MENU:
repaint();
break;
case Constant.GAME_STATE_INIT:
//stage.draw();
if(stage.isReady == true){
gameState = Constant.GAME_STATE_START;
}
repaint();
break;
case Constant.GAME_STATE_START:
//drawAll();
if(isGameOver ||(player1.lives <=0 && player2.lives <= 0)){
gameState = Constant.GAME_STATE_OVER;
map.homeHit(ctx2);
Constant.executor.execute(new Runnable() {
@Override
public void run() {
Constant.PLAYER_DESTROY_AUDIO.play();
}
});
}
if(appearEnemy == maxEnemy && enemyArr.size() == 0){
gameState = Constant.GAME_STATE_WIN;
}
repaint();
break;
case Constant.GAME_STATE_WIN:
repaint();
break;
case Constant.GAME_STATE_OVER:
repaint();
break;
}
}
public void gameOver() {
//.clearRect(0, 0, Constant.SCREEN_WIDTH, Constant.SCREEN_HEIGHT);
ctx2.drawImage(Constant.RESOURCE_IMAGE, overX+map.offsetX, overY+map.offsetY,overX+map.offsetX+64,overY+map.offsetY+32,
Constant.POS.get("over").x, Constant.POS.get("over").y,
Constant.POS.get("over").x+64, Constant.POS.get("over").y+32, null);
overY-=2;
if(overY<=map.mapHeight/2) {
initObject();
//if(menu.playNum==1) {
// player2.lives=0;
//}
gameState = Constant.GAME_STATE_MENU;
}
}
public void action() {
KeyAdapter l=new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
switch (gameState) {
case Constant.GAME_STATE_MENU:
if(e.getKeyCode()==KeyEvent.VK_ENTER){
gameState = Constant.GAME_STATE_INIT;
//只有一个玩家
if(menu.playNum==1) {
player2.lives=0;
}
}else {
int n=0;
if(e.getKeyCode()==KeyEvent.VK_DOWN) {
n=1;
}else if(e.getKeyCode()==KeyEvent.VK_UP) {
n=-1;
}
menu.next(n);
}
break;
case Constant.GAME_STATE_START:
if(!keys.contains(e.getKeyCode())){
keys.add(e.getKeyCode());
}
//射击
if(e.getKeyCode()==KeyEvent.VK_SPACE && player1.lives > 0){
player1.shoot(Constant.BULLET_TYPE_PLAYER, ctx2);
}else if(e.getKeyCode()==KeyEvent.VK_ENTER && player2.lives > 0) {
player2.shoot(Constant.BULLET_TYPE_PLAYER, ctx2);
}else if(e.getKeyCode()==KeyEvent.VK_N) { //下一关
nextLevel();
}else if(e.getKeyCode() == KeyEvent.VK_P) {
preLevel();
}
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
//super.keyReleased(e);
if(keys != null && keys.size() > 0){
Iterator<Integer> it=keys.iterator();
while(it.hasNext()) {
Integer key=it.next();
if(key.intValue()==e.getKeyCode()) {
it.remove();
break;
}
}
}
}
@Override
public void keyTyped(KeyEvent e) {
//super.keyTyped(e);
}
};
this.addKeyListener(l);
this.setFocusable(true);
Timer timer=new Timer();
int interval=20;
timer.schedule(new TimerTask() {
@Override
public void run() {
gameLoop();
}
}, interval, interval);
}
public void keyEvent() {
if(keys.contains(KeyEvent.VK_W)){
player1.direct = Constant.UP;
player1.hit = false;
player1.move();
}else if(keys.contains(KeyEvent.VK_S)){
player1.direct = Constant.DOWN;
player1.hit = false;
player1.move();
}else if(keys.contains(KeyEvent.VK_A)){
player1.direct = Constant.LEFT;
player1.hit = false;
player1.move();
}else if(keys.contains(KeyEvent.VK_D)){
player1.direct = Constant.RIGHT;
player1.hit = false;
player1.move();
}
if(keys.contains(KeyEvent.VK_UP)){
player2.direct = Constant.UP;
player2.hit = false;
player2.move();
}else if(keys.contains(KeyEvent.VK_DOWN)){
player2.direct = Constant.DOWN;
player2.hit = false;
player2.move();
}else if(keys.contains(KeyEvent.VK_LEFT)){
player2.direct = Constant.LEFT;
player2.hit = false;
player2.move();
}else if(keys.contains(KeyEvent.VK_RIGHT)){
player2.direct = Constant.RIGHT;
player2.hit = false;
player2.move();
}
}
public void homeNoProtected(Graphics2D ctx2) {
List<Integer[]> mapChangeIndexList=new ArrayList<Integer[]>();
mapChangeIndexList.add(new Integer[] {23,11});
mapChangeIndexList.add(new Integer[] {23,12});
mapChangeIndexList.add(new Integer[] {23,13});
mapChangeIndexList.add(new Integer[] {23,14});
mapChangeIndexList.add(new Integer[] {24,11});
mapChangeIndexList.add(new Integer[] {24,14});
mapChangeIndexList.add(new Integer[] {25,11});
mapChangeIndexList.add(new Integer[] {25,14});
map.updateMap(mapChangeIndexList,Constant.WALL,ctx2);
}
public static void main(String[] args) {
JFrame jf=new JFrame();
jf.setTitle("坦克大战");
jf.setSize(Constant.SCREEN_WIDTH, Constant.SCREEN_HEIGHT);
GameMain gameMain=new GameMain();
jf.add(gameMain);
jf.setLocationRelativeTo(null);
jf.setResizable(false);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.setVisible(true);
gameMain.initGame(gameMain);
gameMain.initObject();
gameMain.action();
}
}
接下来就可运行了。
其中,切换到下一关,按键盘N,上一个按P,空格键射击。
有兴趣的可以试一试。
下载地址:
坦克大战小游戏完整源码