练习:简单实现坦克大战

选择这个项目作为swing部分的总结

  • 1.添加窗体,设计图型界面
  • 2.设计一个绘制坦克的类
  • 3.设计一个绘制子弹的类
  • 3.编写一个坦克主类,子类敌方坦克,我方坦克
  • 4.编写一个子弹类
  • 5.考虑窗体的重绘,实现坦克子弹的移动(判断子弹的存活情况,坦克的重叠情况)
  • 6.添加监听事件,设置键盘案件
  • 7.添加爆炸效果,音效

效果:





package study1019;

import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JFrame;

/**
 * 创建主要图形界面
 * 
 * @author SUMMER
 *
 */
public class TanksWarFrame extends JFrame implements Runnable {
	
	/**
	 * 创建一个我方坦克实例
	 */
	private MyTank myTanks = MyTank.getMyTankInstance();
	
	/**
	 * 生成随机数值
	 */
	private Random random = new Random();

	
	/**
	 * 创建一个敌方坦克,调试使用
	 */
//	private EnemyTank enemyTank1 = new EnemyTank(2, 20, 50, 4, 15);
//	private EnemyTank enemyTank2 = new EnemyTank(2, 320, 50, 2, 15);
//	private EnemyTank enemyTank3 = new EnemyTank(2, 620, 50, 1, 15);
//	private EnemyTank enemyTank4 = new EnemyTank(2, 920, 50, 3, 15);
//	private EnemyTank enemyTank5 = new EnemyTank(2, 1220, 50, 4, 15);
	
	/**
	 * 创建一个敌方坦克集合
	 */
	private List<EnemyTank> enemyTanksList = Collections.synchronizedList(new ArrayList<EnemyTank>());
	
	/**
	 * 创建一个我方子弹,调试使用
	 */
//	private Bullet myBullet = new Bullet(1, 652, 950, 4, 45);
	
	List<BombPicture> bombList = new ArrayList<BombPicture>();
	
	//炸弹图片
	Image img1 = new ImageIcon("E:\\workspace\\Test\\JavaTest\\study1019\\images\\1.jpg").getImage();
	Image img2 = new ImageIcon("E:\\workspace\\Test\\JavaTest\\study1019\\images\\2.gif").getImage();
	Image img3 = new ImageIcon("E:\\workspace\\Test\\JavaTest\\study1019\\images\\3.gif").getImage();
	
	
	/**
	 * 创建窗体:设置窗体属性
	 */
	public TanksWarFrame() {
		Container container = this.getContentPane();		//取得容器实例
		container.setBackground(Color.WHITE);				//设置背景颜色为白色
		container.setFocusable(true);								//设置交点事件
		
		new Thread(this).start();										//启动本类线程
		
		new Thread(new Audio("E:"+File.separator+"workspace"+File.separator+"Test"+File.separator+"JavaTest"+File.separator+"study1019"+File.separator+"music"+File.separator+"background.wav")).start();
		
		/**
		 * 设置键盘监听事件:W,S,A,D,小键盘上下左右控制我方坦克位移;L,ctrl控制子弹发射
		 */
		container.addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent e) {
				if (e.getKeyCode()==e.VK_W) {
					myTanks.moveUp();
				}
				if (e.getKeyCode()==e.VK_S) {
					myTanks.moveDown();
				}
				if (e.getKeyCode()==e.VK_A) {
					myTanks.moveLeft();
				}
				if (e.getKeyCode()==e.VK_D) {
					myTanks.moveRight();
				}
				if (e.getKeyCode()==e.VK_UP ) {
					myTanks.moveUp();
				}
				if (e.getKeyCode()==e.VK_DOWN) {
					myTanks.moveDown();
				}
				if (e.getKeyCode()==e.VK_LEFT) {
					myTanks.moveLeft();
				}
				if (e.getKeyCode()==e.VK_RIGHT ) {
					myTanks.moveRight();
				}
				if (e.getKeyCode()==e.VK_L) {
					if (myTanks.getBulletList().size()<10) {//如果我方坦克中子弹集合中长度小于10,则允许发射子弹
						myTanks.fire();
						myTanks.getBulletList().add(myTanks.getBullet());
					}
				}
				if (e.getKeyCode()==e.VK_CONTROL) {
					if (myTanks.getBulletList().size()<10) {//如果我方坦克中子弹集合中长度小于10,则允许发射子弹
						myTanks.fire();
						myTanks.getBulletList().add(myTanks.getBullet());
					}
				}
			}
		});
		
		this.setTitle("坦克大战");					//设置窗体标题
		this.setVisible(true);						//设置窗体可见
		this.setSize(1320, 900);						//设置窗体尺寸
		this.setResizable(false);					//设置窗体不可调整
		this.setLocationRelativeTo(null);		//设置窗体居中
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置默认关闭方式
		this.setIconImage(Toolkit.getDefaultToolkit().createImage("F:\\下载\\坦克车.png"));//设置程序标题Icon
		
		/**
		 * 创建敌方坦克对象,设置属性,添加至敌方坦克集合
		 */
		for(int i = 0;i<5;i++) {
			EnemyTank enemyTank = new EnemyTank(2, i*312+15, 40, random.nextInt(4)+1, 2);
			new Thread(enemyTank).start();				//开启线程
			enemyTanksList.add(enemyTank);			//添加至集合
		}
		
		/**
		 * 添加敌方坦克子弹
		 */
//		for (int i = 0; i < 10; i++) {
//			EnemyTank.enemyTankBulletsList.add(new Bullet(enemyTanksList.get(i).getTanksType(), enemyTanksList.get(i).getCoordinateX(), enemyTanksList.get(i).getCoordinateY(), enemyTanksList.get(i).getDirection(), 5));
//		}
		
		
	}
	/**
	 * 绘制坦克图案
	 * 设定:1为我方坦克,设定四个方向分别为1,2,3,4;
	 * 如果类型为1则绘制主体红色,如果类型为2则绘制主体浅灰色
	 * @param g
	 * @param t
	 */
	public void paintTanks(Graphics g,Tanks t) {
		if (t.getTanksType()==1) {
			g.setColor(Color.RED);
		}else {
			g.setColor(Color.LIGHT_GRAY);
		}
		
		/**
		 * 坦克初始化的方向设定为上,1;
		 */
		if (t.getDirection()==1) {
			g.fillRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);
			g.setColor(Color.BLACK);		//置设画笔颜色
			g.drawRect(t.getCoordinateX() + 10,t.getCoordinateY() + 10, 20, 20);//车身边框--小
			g.setColor(Color.BLACK);		//置设画笔颜色
			g.drawRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);//车身边框--大
			g.drawRect(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 10, 50);//左侧履带边框
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 5, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 15, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 25, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 35, 11, 10);//左侧履带车轮
			g.drawRect(t.getCoordinateX() + 35, t.getCoordinateY() - 5, 10, 50);//右侧履带边框
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() - 5, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 5, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 15, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 25, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 35, 11, 10);//右侧履带车轮
			g.setColor(Color.DARK_GRAY);	//置设画笔颜色
			g.fillRect(t.getCoordinateX() + 15, t.getCoordinateY() - 15, 11, 40); //炮口
		}
		/**
		 * 坦克初始化的方向设定为左,2;
		 */
		if (t.getDirection()==2) {
			g.fillRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);
			g.setColor(Color.BLACK);//置设画笔颜色
			g.drawRect(t.getCoordinateX() + 10,t.getCoordinateY() + 10, 20, 20);//车身边框--小
			g.setColor(Color.BLACK);//置设画笔颜色
			g.drawRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);//车身边框--大
			g.drawRect(t.getCoordinateX() - 5, t.getCoordinateY() + 35, 50, 10);//左侧履带边框
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 5, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 15, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 25, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.drawRect(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 50, 10);//右侧履带边框
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 5, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 15, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 25, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.setColor(Color.DARK_GRAY);//置设画笔颜色
			g.fillRect(t.getCoordinateX() - 15, t.getCoordinateY() + 15, 40, 11); //炮口
		}
		/**
		 * 坦克初始化的方向设定为右,3;
		 */
		if (t.getDirection()==3) {
			g.fillRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);
			g.setColor(Color.BLACK);//置设画笔颜色
			g.drawRect(t.getCoordinateX() + 10,t.getCoordinateY() + 10, 20, 20);//车身边框--小
			g.setColor(Color.BLACK);//置设画笔颜色
			g.drawRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);//车身边框--大
			g.drawRect(t.getCoordinateX() - 5, t.getCoordinateY() + 35, 50, 10);//左侧履带边框
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 5, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 15, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 25, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 35, 10, 11);//左侧履带车轮
			g.drawRect(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 50, 10);//右侧履带边框
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 5, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 15, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 25, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() - 5, 10, 11);//右侧履带车轮
			g.setColor(Color.DARK_GRAY);//置设画笔颜色
			g.fillRect(t.getCoordinateX() + 15, t.getCoordinateY() + 15, 40, 11); //炮口
		}
		/**
		 * 坦克初始化的方向设定为下,4;
		 */
		if (t.getDirection()==4) {
			g.fillRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);
			g.setColor(Color.BLACK);//置设画笔颜色
			g.drawRect(t.getCoordinateX() + 10,t.getCoordinateY() + 10, 20, 20);//车身边框--小
			g.setColor(Color.BLACK);//置设画笔颜色
			g.drawRect(t.getCoordinateX(), t.getCoordinateY(), 40, 40);//车身边框--大
			g.drawRect(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 10, 50);//左侧履带边框
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() - 5, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 5, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 15, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 25, 11, 10);//左侧履带车轮
			g.fillOval(t.getCoordinateX() - 5, t.getCoordinateY() + 35, 11, 10);//左侧履带车轮
			g.drawRect(t.getCoordinateX() + 35, t.getCoordinateY() - 5, 10, 50);//右侧履带边框
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() - 5, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 5, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 15, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 25, 11, 10);//右侧履带车轮
			g.fillOval(t.getCoordinateX() + 35, t.getCoordinateY() + 35, 11, 10);//右侧履带车轮
			g.setColor(Color.DARK_GRAY);//置设画笔颜色
			g.fillRect(t.getCoordinateX() + 15, t.getCoordinateY() + 15, 11, 40); //炮口
		}
	}
	
	/**
	 * 绘制子弹图案,规定不同方向子弹图案
	 * @param g
	 * @param t
	 */
	public void paintBullet(Graphics g,Bullet t) {
			
			/**
			 * 设定不同子弹类型不同颜色
			 */
			if (t.getBulletType()==1) {
				g.setColor(Color.RED);
			}else {
				g.setColor(Color.GRAY);
			}
			/**
			 * 子弹初始化的方向设定为上,1;
			 */
			if (t.getBulletDirection()==1) {
				g.draw3DRect(t.getBulletCoordinateX(), t.getBulletCoordinateY(), 6, 22,true);
			}
			
			/**
			 * 子弹初始化的方向设定为左,2;
			 */
			if (t.getBulletDirection()==2) {
				g.draw3DRect(t.getBulletCoordinateX(), t.getBulletCoordinateY(), 22, 6,true);
			}
			
			/**
			 * 子弹初始化的方向设定为右,3;
			 */
			if (t.getBulletDirection()==3) {
				g.draw3DRect(t.getBulletCoordinateX(), t.getBulletCoordinateY(), 22, 6,true);
			}
			
			/**
			 * 子弹初始化的方向设定为下,4;
			 */
			if (t.getBulletDirection()==4) {
				g.draw3DRect(t.getBulletCoordinateX(), t.getBulletCoordinateY(), 6, 22,true);
			}
	}
	
	/* 
	 * (non-Javadoc)
	 * @see java.awt.Window#paint(java.awt.Graphics)
	 */
	public void paint(Graphics g) {
		
		super.paint(g);
		/**
		 * 调用paintTanks()绘制坦克方法
		 */
		this.paintTanks(g,myTanks);
		
		/**
		 * 循环绘制敌方坦克以及子弹
		 */
		for (int i = 0; i < enemyTanksList.size(); i++) {
			EnemyTank et = enemyTanksList.get(i);
			if(et.isIslive()) {
				this.paintTanks(g, et);					//绘制敌方坦克
				if (et.getEnemyTankBulletsList().size()>=0) {
					for (int j = 0; j < et.getEnemyTankBulletsList().size(); j++) {
						Bullet bullet = et.getEnemyTankBulletsList().get(j);
						if (bullet.isLive()) {
//							System.out.println("绘制子弹"+j);
//							System.out.println(bullet.toString());
							paintBullet(g, bullet);		//绘制敌方坦克子弹
						}
					}
				}
			}
		}
		
		/**
		 * 绘制爆炸效果图
		 */
		for(int i = 0; i < bombList.size(); i++) {
			BombPicture bomb = bombList.get(i);
			if(bomb.isIslive()) {
				if(bomb.getLife() > 6) {
					g.drawImage(img1, bomb.getCoordinateX(), bomb.getCoordinateY(), 60,60,null);
				}else if(bomb.getLife() > 3) {
					g.drawImage(img2, bomb.getCoordinateX(), bomb.getCoordinateY(), 60,60,null);
				}else{
					g.drawImage(img3, bomb.getCoordinateX(), bomb.getCoordinateY(), 60,60,null);
				}
				bomb.lifeDown();
			}
		}
		
		/**
		 * 集合中获取我方坦克子弹
		 */
		for (int i = 0; i < myTanks.getBulletList().size(); i++) {
			Bullet bullet = myTanks.getBulletList().get(i);
			if (bullet.isLive()) {
				paintBullet(g, bullet);//如果子弹存活,则调用
			}else {
				MyTank.getBulletList().remove(i);//如果子弹不是存活状态,则从集合中移除
			}
		}
		
 	}
	
	/**
	 * 重写Runnable接口run方法----每五十毫秒重构一次窗体
	 */
	public void run() {
		while (true) {
			this.EnemyTankCoordinatesCoincide();//敌方坦克是否碰撞
			this.enemyTankMyTankCooddinatesCoincide();//敌方坦克是否碰撞我方坦克
			this.hitMe();//敌方击中我方
			this.hitEnemy();//我方击中敌方
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			repaint();
		}
		
	}
	
	/**
	 * 判断坦克坐标是否重合的方法
	 */
	public boolean coordinatesCoincide(Tanks t1 , Tanks t2) {//坐标重合
//		System.out.println("判断坦克坐标是否重合的方法");
		if ((Math.abs(t1.getCoordinateX()-t2.getCoordinateX())<=50)&&(Math.abs(t1.getCoordinateY()-t2.getCoordinateY())<=50)) {
			return true ;
		}else {
			return false ;
		}
	}
	
	/**
	 * 调用cooddinatesCoincide()
	 * 判断敌方坦克是否重合,并转换方向
	 */
	public void EnemyTankCoordinatesCoincide() {
		for(int i = 0; i < enemyTanksList.size(); i++) {
			EnemyTank e1 = enemyTanksList.get(i);
			if(e1.isIslive()) {
				for(int j = 0; j < enemyTanksList.size(); j++) {
					if(i == j) {
						continue;
					}
					EnemyTank e2 = enemyTanksList.get(j);
					if(coordinatesCoincide(e1, e2)) {
						switch(e1.getDirection()) {
							case 1:{
								try {
									Thread.sleep(20);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
								for (int k = 0; k < 20; k++) {
									try {
										Thread.sleep(5);
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									e1.moveDown();
								}
								break;
					 		}
							case 2:{
								try {
									Thread.sleep(20);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
								for (int k = 0; k < 20; k++) {
									try {
										Thread.sleep(5);
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									e1.moveLeft();
								}
								break;
							}
							case 3:{
								try {
									Thread.sleep(20);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
								for (int k = 0; k < 20; k++) {
									try {
										Thread.sleep(5);
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									e1.moveUp();
								}
								break;
							}
							case 4:{
								try {
									Thread.sleep(20);
								} catch (InterruptedException e) {
									e.printStackTrace();
								}
								for (int k = 0; k < 20; k++) {
									try {
										Thread.sleep(5);
									} catch (InterruptedException e) {
										// TODO Auto-generated catch block
										e.printStackTrace();
									}
									e1.moveRight();
								}
								break;
							}
						}
						switch(e2.getDirection()) {
						case 1:{
							try {
								Thread.sleep(20);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							for (int k = 0; k < 20; k++) {
								try {
									Thread.sleep(5);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								e2.moveDown();
							}
							break;
						}
						case 2:{
							try {
								Thread.sleep(20);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							for (int k = 0; k < 20; k++) {
								try {
									Thread.sleep(5);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								e2.moveLeft();
							}
							break;
						}
						case 3:{
							try {
								Thread.sleep(20);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							for (int k = 0; k < 20; k++) {
								try {
									Thread.sleep(5);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								e2.moveUp();
							}
							break;
						}
						case 4:{
							try {
								Thread.sleep(20);
							} catch (InterruptedException e) {
								e.printStackTrace();
							}
							for (int k = 0; k < 20; k++) {
								try {
									Thread.sleep(5);
								} catch (InterruptedException e) {
									// TODO Auto-generated catch block
									e.printStackTrace();
								}
								e2.moveRight();
							}
							break;
						}
					}
					}
				}
			}
		}
		}
	
	/**
	 * 调用cooddinatesCoincide()
	 * 判断敌方坦克是否与我方坦克碰撞
	 */
	public void enemyTankMyTankCooddinatesCoincide() {
		for (int i = 0; i < enemyTanksList.size(); i++) {
			EnemyTank enemyTank = enemyTanksList.get(i);
			if (enemyTank.isIslive()&&myTanks.isIslive()) {
				if (this.coordinatesCoincide(enemyTank, myTanks)) {
					myTanks.setIslive(false);
					new Thread(new Audio("E:"+File.separator+"workspace"+File.separator+"Test"+File.separator+"JavaTest"+File.separator+"study1019"+File.separator+"music"+File.separator+"bomb.wav")).start();
					BombPicture bombPicture = new BombPicture(myTanks.getCoordinateX(), myTanks.getCoordinateY());
					bombList.add(bombPicture);
					//添加爆炸图片,声音并开启线程
					myTanks.setCoordinateY(10000);
					enemyTank.setIslive(false);
					enemyTanksList.remove(enemyTank);
				}
			}
		}
	}
	
	/**
	 * 判断子弹是否击中坦克
	 */
	private boolean hitTank(Bullet bullet,Tanks tank) {
		if(bullet.getBulletCoordinateX() > tank.getCoordinateX()
				&& bullet.getBulletCoordinateX() < tank.getCoordinateX() + 60
				&& bullet.getBulletCoordinateY() > tank.getCoordinateY()
				&& bullet.getBulletCoordinateY() < tank.getCoordinateY() + 60) {
			/**
			 * 如果敌方坦克子弹或者是我方坦克子弹攻击到对方
			 * 结果为:子弹死亡,坦克死亡
			 * 如果敌方坦克子弹打到敌方坦克
			 * 结果为:子弹和坦克都不死亡
			 */
			if(bullet.getBulletType() != tank.getTanksType()) {
				bullet.setLive(false);
				tank.setIslive(false);
				//添加爆炸图片,声音并开启线程
				BombPicture bombPicture = new BombPicture(tank.getCoordinateX(), tank.getCoordinateY());
				bombList.add(bombPicture);
				new Thread(new Audio("E:"+File.separator+"workspace"+File.separator+"Test"+File.separator+"JavaTest"+File.separator+"study1019"+File.separator+"music"+File.separator+"bomb.wav")).start();
			}
			return true;
		}
		return false;
	}
	
	/**
	 * 敌方坦克子弹是否击中我方坦克
	 * 判断敌方哪个坦克发的那颗子弹击中了我方坦克
	 */
	private void hitMe() {
		if(enemyTanksList.size() > 0) {
			for(int i = 0; i < enemyTanksList.size(); i++) {
				EnemyTank enemyTank = enemyTanksList.get(i);
				if(enemyTank.isIslive()) {
					List<Bullet> bullets = enemyTank.getEnemyTankBulletsList();
					for(int j = 0; j < bullets.size(); j++) {
						Bullet bullet = bullets.get(j);
						if(bullet.isLive()) {
							if(hitTank(bullet,myTanks)){
								bullets.remove(bullet);
								myTanks.setCoordinateY(100000);
							}
						} 
					}
				}
			}
		}
	}
	
	/**
	 * 判断我方坦克子弹是否击中敌方坦克
	 */
	private void hitEnemy() {
		if(myTanks.isIslive()) {
			for(int i = 0; i < myTanks.getBulletList().size(); i++) {
				Bullet bullet = myTanks.getBulletList().get(i);
//			for(Bullet bullet : myTanks.getBulletList()) {
				if(bullet.isLive()) {
					if(enemyTanksList.size() > 0) {
						for(int j = 0; j < enemyTanksList.size(); j++) {
							EnemyTank enemyTank = enemyTanksList.get(j);
//					for(EnemyTank enemyTank : enemyTanksList) {
							if(enemyTank.isIslive()) {
								if(hitTank(bullet, enemyTank)){
									bullet.setLive(false);
									bullet.shutDown();
									myTanks.getBulletList().remove(bullet);
									enemyTank.setIslive(false);
									enemyTanksList.remove(enemyTank);
								}
							}
						}
					}
				}
			}
		}
	}
	
	
	
	
}
























package study1019;

import java.beans.ExceptionListener;

/**
 * 坦克类
 * @author SUMMER
 */
public class Tanks {
	
	/**
	 * 坦克初始化的类型
	 * 设定:我方坦克为1,敌方坦克为2
	 */
	private int tanksType ;
	
	/**
	 * 坦克初始化的X坐标
	 */
	private int coordinateX ;
	
	/**
	 * 坦克初始化的Y坐标
	 */
	private int coordinateY ;
	
	/**
	 * 坦克初始化的方向
	 * 设定:上为1;左为2;右为3;下为4
	 */
	private int direction ;
	
	/**
	 * 坦克初始化的速度
	 */
	private int speed ;
	
	/**
	 * 坦克是否发射子弹
	 */
	private Bullet bullet = null ;
	
	/**
	 * 判断敌方坦克是否生存
	 */
	private boolean islive = true ;
	
	/**
	 * 坦克初始化的类型/X坐标/Y坐标/方向/速度
	 * @param tanksType
	 * @param coordinateX
	 * @param coordinateY
	 * @param direction
	 * @param speed
	 */
	public Tanks(int tanksType, int coordinateX, int coordinateY, int direction, int speed) {
		super();
		this.tanksType = tanksType;
		this.coordinateX = coordinateX;
		this.coordinateY = coordinateY;
		this.direction = direction;
		this.speed = speed;
	}

	/**
	 * 设置坦克向上移动
	 */
	public void moveUp( ){
		if (this.coordinateY>50) {
			this.coordinateY-=this.speed;
			this.setDirection(1);
		}else {
			this.setDirection(4);//设定:上为1;左为2;右为3;下为4
		}
	}
	
	/**
	 * 设置坦克向下移动
	 */
	public void moveDown( ){
		if (this.coordinateY<835) {
			this.coordinateY+=this.speed;
			this.setDirection(4);
		}else {
			this.setDirection(1);//设定:上为1;左为2;右为3;下为4
		}
	}
	
	/**
	 * 设置坦克向左移动
	 */
	public void moveLeft( ){
		if (this.coordinateX>30) {
			this.coordinateX-=this.speed;
			this.setDirection(2);
		}else {
			this.setDirection(3);//设定:上为1;左为2;右为3;下为4	
		}
	}

	/**
	 * 设置坦克向右移动
	 */
	public void moveRight( ){
		if (this.coordinateX<1260) {
			this.coordinateX+=this.speed;
			this.setDirection(3);
		}else {
			this.setDirection(2);//设定:上为1;左为2;右为3;下为4	
		}
	}
	
	/**
	 * 坦克发射子弹的方法,判断坦克方向指定子弹方向及属性,开启子弹对象线程
	 */
	public void fire() {
		switch (this.direction) {
		case 1:
			bullet = new Bullet(this.tanksType, this.coordinateX+17, this.coordinateY-40, this.direction	, this.speed);
			break;
		case 2:
			bullet = new Bullet(this.tanksType, this.coordinateX-40, this.coordinateY+17, this.direction	, this.speed);
			break;	
		case 3:
			bullet = new Bullet(this.tanksType, this.coordinateX+56, this.coordinateY+17, this.direction	, this.speed);
			break;
		case 4:
			bullet = new Bullet(this.tanksType, this.coordinateX+17, this.coordinateY+58, this.direction	, this.speed);
			break;	
		}
		new Thread(bullet).start();//开启子弹对象线程
	}
	
	/**
	 * @return the tanksType
	 */
	public int getTanksType() {
		return tanksType;
	}

	/**
	 * @param tanksType the tanksType to set
	 */
	public void setTanksType(int tanksType) {
		this.tanksType = tanksType;
	}

	/**
	 * @return the coordinateX
	 */
	public int getCoordinateX() {
		return coordinateX;
	}

	/**
	 * @param coordinateX the coordinateX to set
	 */
	public void setCoordinateX(int coordinateX) {
		this.coordinateX = coordinateX;
	}

	/**
	 * @return the coordinateY
	 */
	public int getCoordinateY() {
		return coordinateY;
	}

	/**
	 * @param coordinateY the coordinateY to set
	 */
	public void setCoordinateY(int coordinateY) {
		this.coordinateY = coordinateY;
	}

	/**
	 * @return the direction
	 */
	public int getDirection() {
		return direction;
	}

	/**
	 * @param direction the direction to set
	 */
	public void setDirection(int direction) {
		this.direction = direction;
	}

	/**
	 * @return the speed
	 */
	public int getSpeed() {
		return speed;
	}

	/**
	 * @param speed the speed to set
	 */
	public void setSpeed(int speed) {
		this.speed = speed;
	}

	/**
	 * @return the bullet
	 */
	public Bullet getBullet() {
		return bullet;
	}

	/**
	 * @param bullet the bullet to set
	 */
	public void setBullet(Bullet bullet) {
		this.bullet = bullet;
	}

	/**
	 * @return the islive
	 */
	public boolean isIslive() {
		return islive;
	}

	/**
	 * @param islive the islive to set
	 */
	public void setIslive(boolean islive) {
		this.islive = islive;
	}
	
	
}



package study1019;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class EnemyTank extends Tanks implements Runnable {
	
	/**
	 * 创建敌方坦克子弹集合
	 */
	private static List<Bullet> enemyTankBulletsList = Collections.synchronizedList(new ArrayList<>()); 
	
	/**
	 * 判断敌方坦克是否生存
	 */
	private boolean islive = true ;
	
	/**
	 * 生成随机数值
	 */
	private Random random = new Random();

	
	/**
	 * @param tanksType
	 * @param coordinateX
	 * @param coordinateY
	 * @param direction
	 * @param speed
	 */
	public EnemyTank(int tanksType, int coordinateX, int coordinateY, int direction, int speed) {
		super(tanksType, coordinateX, coordinateY, direction, speed);
		// TODO Auto-generated constructor stub
	}

	/**
	 * @return the islive
	 */
	public boolean isIslive() {
		return islive;
	}

	/**
	 * @param islive the islive to set
	 */
	public void setIslive(boolean islive) {
		this.islive = islive;
	}

	/**
	 * @return the enemyTankBulletsList
	 */
	public static List<Bullet> getEnemyTankBulletsList() {
		return enemyTankBulletsList;
	}

	/**
	 * @param enemyTankBulletsList the enemyTankBulletsList to set
	 */
	public static void setEnemyTankBulletsList(List<Bullet> enemyTankBulletsList) {
		EnemyTank.enemyTankBulletsList = enemyTankBulletsList;
	}

	/**
	 * 重写父类中的run方法,设定敌方坦克随机运动
	 */
	@Override
	public void run() {
		while (true) {
			fire();
			getEnemyTankBulletsList().add(getBullet());
			try {
				Thread.sleep(20);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			super.setDirection(random.nextInt(4)+1);
			switch (super.getDirection()) {
			case 1:
				for (int i = 0; i < 100; i++) {
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					super.moveUp();
				}
				break;
			case 2:
				for (int i = 0; i < 100; i++) {
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					super.moveLeft();
				}
				break;
			case 3:
				for (int i = 0; i < 100; i++) {
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					super.moveRight();
				}
				break;
			case 4:
				for (int i = 0; i < 100; i++) {
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					super.moveDown();
				}
				break;
				default:
					break;
			}
			

			
		}
	}
	

	
	
}











package study1019;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

/**
 * 我方坦克类
 * 
 * @author SUMMER
 */
public class MyTank extends Tanks{
	
	/**
	 * 创建一个我方坦克子弹的集合
	 */
	public static List<Bullet>bulletList = Collections.synchronizedList(new ArrayList<Bullet>());
	
	/**
	 * 判断敌方坦克是否生存
	 */
	private boolean islive = true ;

	/**
	 * @param tanksType
	 * @param coordinateX
	 * @param coordinateY
	 * @param direction
	 * @param speed
	 */
	private MyTank(int tanksType, int coordinateX, int coordinateY, int direction, int speed) {
		super(tanksType, coordinateX, coordinateY, direction, speed);
		// TODO Auto-generated constructor stub
	}
	
	public static MyTank getMyTankInstance() {
		MyTank myTank = new MyTank(1, 635, 850, 1, 25);
		return myTank;
	}

	/**
	 * @return the bulletList
	 */
	public static List<Bullet> getBulletList() {
		return bulletList;
	}

	/**
	 * @param bulletList the bulletList to set
	 */
	public static void setBulletList(List<Bullet> bulletList) {
		MyTank.bulletList = bulletList;
	}

	/**
	 * @return the islive
	 */
	public boolean isIslive() {
		return islive;
	}

	/**
	 * @param islive the islive to set
	 */
	public void setIslive(boolean islive) {
		this.islive = islive;
	}
	
	

}



package study1019;

/**
 * 坦克大战系统子弹类
 * 
 * @author SUMMER
 *
 */
public class Bullet implements Runnable{
	
	/**
	 * 引入共享变量,该变量可以被多个执行相同任务的线程用来作为是否中断的信号,通知中断线程的执行
	 */
	private volatile boolean shutDownExit = false; 
	
	/**
	 * 子弹初始化的类型
	 * 设定:我方子弹为1,敌方子弹为2
	 */
	private int bulletType ;
	
	/**
	 * 子弹初始化的X坐标
	 */
	private int bulletCoordinateX ;
	
	/**
	 * 子弹初始化的Y坐标
	 */
	private int bulletCoordinateY ;
	
	/**
	 * 子弹初始化的方向
	 * 设定:上为1;左为2;右为3;下为4
	 */
	private int bulletDirection ;
	
	/**
	 * 子弹初始化的速度
	 */
	private int bulletSpeed ;
	
	/**
	 * 判断子弹是否存活
	 */
	private boolean isLive = true ;
	
	/**
	 * 子弹初始化的类型/X坐标/Y坐标/方向/速度
	 * @param bulletType
	 * @param bulletCoordinateX
	 * @param bulletCoordinateY
	 * @param bulletDirection
	 * @param bulletSpeed
	 */
	public Bullet(int bulletType, int bulletCoordinateX, int bulletCoordinateY, int bulletDirection, int bulletSpeed) {
		super();
		this.bulletType = bulletType;
		this.bulletCoordinateX = bulletCoordinateX;
		this.bulletCoordinateY = bulletCoordinateY;
		this.bulletDirection = bulletDirection;
		this.bulletSpeed = bulletSpeed;
	}
	
	/**
	 * 重写Runnable接口run方法,设定子弹指定方向移动,并设定子弹运动边界
	 */
	public void run() {
		while (!shutDownExit) {
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			switch (bulletDirection) {
			case 1:
				if (this.getBulletCoordinateY()>50) {
//					System.out.println("子弹发射坐标:X坐标"+this.getBulletCoordinateX()+";Y坐标"+this.getBulletCoordinateY());
					this.bulletCoordinateY-=this.bulletSpeed;//子弹向上移动
				}else {
					this.isLive = false ;//设定子弹生存状态为false
					this.shutDown();
				}
				break;
			case 2:
				if (this.getBulletCoordinateX()>20) {
//					System.out.println("子弹发射坐标:X坐标"+this.getBulletCoordinateX()+";Y坐标"+this.getBulletCoordinateY());
					this.bulletCoordinateX-=this.bulletSpeed;//子弹向左移动
				}else {
					this.isLive = false ;//设定子弹生存状态为false
					this.shutDown();
				}
				break;	
			case 3:
				if (this.getBulletCoordinateX()<1280) {
//					System.out.println("子弹发射坐标:X坐标"+this.getBulletCoordinateX()+";Y坐标"+this.getBulletCoordinateY());
					this.bulletCoordinateX+=this.bulletSpeed;//子弹向右移动
				} else {
					this.isLive = false ;//设定子弹生存状态为false
					this.shutDown();
				}
				break;
			case 4:
				if (this.getBulletCoordinateY()<850) {
//					System.out.println("子弹发射坐标:X坐标"+this.getBulletCoordinateX()+";Y坐标"+this.getBulletCoordinateY());
					this.bulletCoordinateY+=this.bulletSpeed;//子弹向下移动
				} else {
					this.isLive = false ;//设定子弹生存状态为false
					this.shutDown();
				}
				break;	

			}
		}
	}
	
	/**
	 * 提供一个shutdownexit方法给外部使用
	 */
	public final void shutDown() {
		this.shutDownExit = true ;
		Thread.interrupted();
	}
	
	/**
	 * @return the bulletType
	 */
	public int getBulletType() {
		return bulletType;
	}
	/**
	 * @param bulletType the bulletType to set
	 */
	public void setBulletType(int bulletType) {
		this.bulletType = bulletType;
	}
	/**
	 * @return the bulletCoordinateX
	 */
	public int getBulletCoordinateX() {
		return bulletCoordinateX;
	}
	/**
	 * @param bulletCoordinateX the bulletCoordinateX to set
	 */
	public void setBulletCoordinateX(int bulletCoordinateX) {
		this.bulletCoordinateX = bulletCoordinateX;
	}
	/**
	 * @return the bulletCoordinateY
	 */
	public int getBulletCoordinateY() {
		return bulletCoordinateY;
	}
	/**
	 * @param bulletCoordinateY the bulletCoordinateY to set
	 */
	public void setBulletCoordinateY(int bulletCoordinateY) {
		this.bulletCoordinateY = bulletCoordinateY;
	}
	/**
	 * @return the bulletDirection
	 */
	public int getBulletDirection() {
		return bulletDirection;
	}
	/**
	 * @param bulletDirection the bulletDirection to set
	 */
	public void setBulletDirection(int bulletDirection) {
		this.bulletDirection = bulletDirection;
	}
	/**
	 * @return the bulletSpeed
	 */
	public int getBulletSpeed() {
		return bulletSpeed;
	}
	/**
	 * @param bulletSpeed the bulletSpeed to set
	 */
	public void setBulletSpeed(int bulletSpeed) {
		this.bulletSpeed = bulletSpeed;
	}

	/**
	 * @return the isLive
	 */
	public boolean isLive() {
		return isLive;
	}

	/**
	 * @param isLive the isLive to set
	 */
	public void setLive(boolean isLive) {
		this.isLive = isLive;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "Bullet [bulletType=" + bulletType + ", bulletCoordinateX=" + bulletCoordinateX + ", bulletCoordinateY="
				+ bulletCoordinateY + ", bulletDirection=" + bulletDirection + ", bulletSpeed=" + bulletSpeed
				+ ", isLive=" + isLive + "]";
	}
	

}



package study1019;

/**
 * 设置爆炸效果图
 * @author SUMMER
 */
public class BombPicture {
	
	private int coordinateX ;
	
	private int coordinateY ;
	
	private boolean islive = true ;
	
	private int life = 9 ;

	/**
	 * @param coordinateX
	 * @param coordinateY
	 */
	public BombPicture(int coordinateX, int coordinateY) {
		super();
		this.coordinateX = coordinateX;
		this.coordinateY = coordinateY;
	}

	/**
	 * @return the coordinateX
	 */
	public int getCoordinateX() {
		return coordinateX;
	}

	/**
	 * @param coordinateX the coordinateX to set
	 */
	public void setCoordinateX(int coordinateX) {
		this.coordinateX = coordinateX;
	}

	/**
	 * @return the coordinateY
	 */
	public int getCoordinateY() {
		return coordinateY;
	}

	/**
	 * @param coordinateY the coordinateY to set
	 */
	public void setCoordinateY(int coordinateY) {
		this.coordinateY = coordinateY;
	}

	/**
	 * @return the islive
	 */
	public boolean isIslive() {
		return islive;
	}

	/**
	 * @param islive the islive to set
	 */
	public void setIslive(boolean islive) {
		this.islive = islive;
	}

	/**
	 * @return the life
	 */
	public int getLife() {
		return life;
	}

	/**
	 * @param life the life to set
	 */
	public void setLife(int life) {
		this.life = life;
	}

	/**
	 * 炸弹逐渐死亡
	 */
	public void lifeDown() {
		if(life < 0) {
			islive = false;
		}
		life--;
	}
	
}


package study1019;

import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
import javax.sound.sampled.UnsupportedAudioFileException;

/**
 * 导入声音的类
 * @author SUMMER
 */
public class Audio extends Thread {
	
	/**
	 * 设置一个声音文件路径
	 */
	private String audioFileName ;
	
	/**
	 * 实例化时传入声音路径
	 * @param audioFileName
	 */
	public Audio(String audioFileName) {
		this.audioFileName = audioFileName ;
	}
	
	/**
	 * 设置线程启动内容,覆写父类中的run方法
	 */
	public void run() {
		/**
		 * 创建一个指定路劲的声音文件
		 */
		File file = new File(this.audioFileName);
		
		/**
		 * 设置一个输入流的引用
		 */
		AudioInputStream audioInputStream = null ;
		
		try {
			audioInputStream = AudioSystem.getAudioInputStream(file); //从提供的 File 获得音频输入流
		} catch (UnsupportedAudioFileException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		/**
		 *  获得此音频输入流中声音数据的音频格式
		 */
		AudioFormat format = audioInputStream.getFormat();
		SourceDataLine auline = null;
		DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
		try {
			auline = (SourceDataLine) AudioSystem.getLine(info);
			auline.open(format);
		} catch (Exception e) {
			e.printStackTrace();
			return;
		}

		auline.start();
		int nBytesRead = 0;
		byte[] abData = new byte[512];

		try {
			while (nBytesRead != -1) {
				nBytesRead = audioInputStream.read(abData, 0, abData.length);
				if (nBytesRead >= 0)
					auline.write(abData, 0, nBytesRead);
			}
		} catch (IOException e) {
			e.printStackTrace();
			return;
		} finally {
			auline.drain();
			auline.close();
		}
		
	}

	
}


package study1019;

/**
 * 启动程序
 * @author SUMMER
 */
public class TanksWarGame {
	/**
	 * 启动程序主方法
	 * @param args
	 */
	public static void main(String[] args) {
		
		new TanksWarFrame();//实例化主界面
		
	}
}


组件:







  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
这是一个用java编写的坦克大战的游戏毕业设计! 目 录 摘 要 - I - Abstract - II - 引  言 - 3 - 第一章  绪 论 - 1 - 1.1 手机软件现状 - 1 - 1.2 游戏业务及J2ME概况 - 1 - 1.3 任天堂(Nintendo)的8位FC机器和Battle City背景介绍 - 3 - 1.4 本章小结 - 3 - 第二章 开发环境及相关技术的介绍 - 4 - 2.1 开发环境 - 4 - 2.2 Java语言的特点 - 4 - 2.3 关于JBuilder9 - 4 - 2.4 关于Wireless Tool Kit - 5 - 2.5 Java Appication Manager - 5 - 2.6 本章小结 - 5 - 第三章 程序结构、思想和相关技术 - 6 - 3.1 本程序需解决的有关技术问题 - 6 - 3.2 程序流程 - 7 - 3.3 绘图与MIDP2.0新增的GameCanvas包 - 9 - 3.3.1 提供低级绘制的Canvas类 - 9 - 3.3.2 Graphics类 - 9 - 3.3.3 PNG格式 - 9 - 3.3.4 Game包中的新功能 - 10 - 3.3.5 有关绘图的一些技术 - 11 - 3.4 坦克的控制和敌方的智能运行 - 11 - 3.5 子弹的运行和控制 - 12 - 3.6 RMS数据库系统 - 13 - 3.7 内存使用的最佳化 - 14 - 3.8 混淆器(Obfuscator)的使用 - 15 - 3.9 模拟器的相关调试 - 15 - 3.10 本章小结 - 16 - 第四章 程序分析和具体实现 - 17 - 4.1 游戏进入前的选择 - 17 - 4.2 主游戏逻辑及其涉及到的若干类 - 18 - 4.3 坦克的共同行为 - 20 - 4.4 玩家坦克的功能属性 - 21 - 4.5 敌人坦克的功能属性 - 21 - 4.6 子弹的运行和控制 - 23 - 4.7 记分系统 - 24 - 4.8 本章小结 - 26 - 第五章 总 结 - 27 - 5.1 本程序的总结和展望 - 27 - 5.2 经验和感想 - 27 - 致 谢 - 29 - 参考文献 - 30 - 附录 源程序代码 - 31 -
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值