经典游戏,用java实现的坦克大战小游戏

news2024/12/26 11:39:30

今天给大家分享一个使用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,空格键射击。

有兴趣的可以试一试。
下载地址:
坦克大战小游戏完整源码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054149.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习(5)--正则化之L1和L2正则化

文章目录 正则化一、正则化的基本原理二、L1正则化&#xff08;Lasso&#xff09;三、L2正则化&#xff08;Ridge&#xff09;四、L1与L2正则化的比较 总结 正则化 正则化是一种在机器学习和深度学习中常用的技术手段&#xff0c;旨在提高模型的泛化能力&#xff0c;减少过拟合…

深入探讨C语言中的高级指针操作

目录 指针与内存管理的高级技巧 1. 动态数组的重新分配 2. 内存碎片化的处理 3. 内存对齐 函数指针数组与回调函数的高级用法 1. 基本函数指针用法 2. 函数指针数组 3. 回调函数的使用 指针与数据结构的结合 1. 自定义链表 C语言以其强大的底层操作能力和高效的性能著…

【信创】Linux下EFI引导配置工具efibootmgr _ 统信 _ 麒麟 _ 方德

往期好文&#xff1a;deepin V23 Release 安装与功能介绍&#xff01;&#xff01;&#xff01; Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于在信创操作系统上使用EFI引导管理器配置工具efibootmgr命令详解的文章。efibootmgr是一个在基于UEFI的系统中管理EF…

AI数字员工技能全开,招生、培训、写教案,样样都行

只需要几个AI数字员工&#xff0c;就可以协助您办一所高质量的学校。 教务管理、教师培训、招生咨询、家校沟通、学生评价、资料整理、学习伴侣、写教案、总结、学生评语等。 这些都可以用AI数字员工来完成。 比如&#xff0c;AI培训专员给教师做制度培训、教学培训&#xf…

裴蜀定理相关结论

裴蜀定理: axbygcd(a,b) 必定有解 1. 有无限个数凑不出来 有无限个数凑不出来 2. 最大凑不出的数字 在 的条件下&#xff0c;最大凑不出的数为 推广&#xff1a;若数字数目大于2&#xff0c;gcd仍然为1&#xff0c;最大凑不出来的数字一定小于上面的结论值&#xff0c;即局…

计算机网络——TCP协议与UDP协议详解(上)

一、前言 1.1 再次理解传输层 传输层是计算机网络中的一层&#xff0c;位于网络层和应用层之间。它主要负责在网络中的两个端系统之间提供可靠的、端到端的数据传输服务。简单理解&#xff0c;传输层就是负责在源主机和目标主机之间提供端到端的数据传输。 传输层的两个主要协…

EasyRecovery 16/17数据恢复软件2024最新永久破解版激活码注册码分享

EasyRecovery &#xff08;易恢复中国&#xff09;是由全球著名数据厂商Ontrack 出品的一款数据文件恢复软件。支持恢复不同存储介质数据&#xff1a;硬盘、光盘、U盘/移动硬盘、数码相机、Raid文件恢复等&#xff0c;能恢复包括文档、表格、图片、音视频等各种文件。 开发背…

鸿蒙开发5.0【基于ArkUI的验证码】实现

场景描述 场景一&#xff1a;基于自定义键盘的验证码实现&#xff0c;进入页面后直接输入验证码&#xff0c;第一个验证码输入完后可自动跳到下一个&#xff0c;拉起的键盘是自定义数字键盘&#xff0c;验证码的输入框带选中效果。 场景二&#xff1a;基于系统键盘的验证码实…

顶顶通呼叫中心中间件-一句话识别语音识别安装步骤

顶顶通呼叫中心中间件-一句话模型安装步骤&#xff0c;对接mod_vad。一句话识别&#xff08;http接口提交录音文件识别&#xff09; 一、安装一句话模型 一句话识别&#xff08;http接口提交录音文件识别&#xff09;&#xff0c;比如对接mod_vad(老电话机器人接口) curl -s…

C#中的多线程案例

使用Task写一个进度条 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.For…

【有手就行】:从无到有在win10上用docker搭建svn服务器

前言 之所以要搭建svn服务器&#xff0c;是因为在用docker打包项目时方便&#xff0c;如果没有svn就需要手动拷贝项目到容器内&#xff0c;用svn直接update就可以轻松拿到最新代码&#xff0c;岂不快哉 准备工作 1、先安装docker&#xff0c;请移步 docker安装 2、选择svn-s…

【每日力扣中医养生】力扣2608. 图中的最短环

2608. 图中的最短环 文章目录 【每日力扣&中医养生】力扣2608. 图中的最短环题目描述示例示例 1示例 2 输入输出说明解题思路Python代码复杂度分析总结 【每日力扣&中医养生】力扣2608. 图中的最短环 《黄帝内经》阴阳应象大论篇第五&#xff0c;提到“秋伤于湿&…

Leetcode 209,713,3 滑动窗口 C++实现

Leetcode 209. 长度最小的子数组 问题&#xff1a;给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c…

redis 遍渐进式历

1.scan cursor [match pattern] [coutn] [type]:以渐进式的方式进行建的遍历 cursor:是光标 指向当前遍历的位置 设置成0表示当前从0开始获取 math parttern &#xff1a;和keys命令一样的 keys * count: 限制一次遍历能够获取到多少个 元素默认是10 type :这次遍历只想获取…

数据库原理--关系模型简述

目录 一、关系模型研究什么 二、关系模型的三要素 三、关系模型与关系数据库语言的关系 一、关系模型研究什么 一个关系(relation)就是一个表(Table),关系模型就是处理Table的&#xff0c;它由三个部分组成: 描述DB各种数据的基本结构(Table/Relation)描述Table与Table之间…

Docker安装Redis集群记录

redis集群整体的安装效果 备注&#xff1a;本机docker容器的宿主机ip为192.168.0.200&#xff0c;下面的配置全部基于当前IP进行配置&#xff1b; 1 docker镜像下载使用的国内地址 vi /etc/docker/daemon.json{"registry-mirrors": ["https://ustc-edu-cn.mir…

苹果手机怎么还原删除的照片?4个【独门秘籍】都在这里了

苹果手机的拍照功能深受广大用户的喜爱&#xff0c;大家出行旅游也大都选择苹果手机拍照记录&#xff0c;因此手机相册也就成为用户们的【生活回忆录】。但是&#xff0c;我们总是会因为各种各样的原因导致相册里的照片消失不见&#xff0c;对此&#xff0c;我们要怎么还原删除…

《计算机组成原理》(第3版)课后习题答案

第1篇 概 论 1&#xff0e;什么是计算机系统、计算机硬件和计算机软件&#xff1f;硬件和软件哪个更重要&#xff1f; 答&#xff1a;计算机系统&#xff1a;由计算机硬件和软件两部分组成&#xff0c;计算机系统具有接收和存储信息、按程序快速计算和判断并输出处理结果等功…

武汉流星汇聚:亚马逊迎来中国力量,中国卖家推动跨境电商繁荣

随着全球化进程的加速和跨境电商的蓬勃发展&#xff0c;中国卖家正以前所未有的速度和规模涌入亚马逊这一全球领先的电商平台。他们的入驻不仅为亚马逊平台注入了新的活力与多样性&#xff0c;更在全球范围内产生了深远的积极影响与变革。 中国作为世界工厂&#xff0c;拥有庞…

一段式端到端vs两段式端到端,到底哪个好

在智能汽车领域&#xff0c;端到端自动驾驶技术正迅速成为行业焦点&#xff0c;不同的玩家实现路径也有差别。目前主流的端到端智驾方案有两类&#xff1a;一段式和两段式&#xff0c;针对这两种方案优缺点的讨论&#xff0c;也从未停止过。 “两段式”端到端和“一段式”端到端…