欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

用java Swing做的小游戏"像素鸟"

程序员文章站 2022-06-17 10:27:59
...

最终效果

用java Swing做的小游戏"像素鸟"
用java Swing做的小游戏"像素鸟"
用java Swing做的小游戏"像素鸟"



  整个项目都是基于swing实现的。窗是口将图片加载到JPanel面板,然后将面板添加到到JFrame窗口实现显示。

这个类是选择几只像素鸟的类,也是main函数里执行的方法,代码有详细的注释,这里就不废话了

public class select extends JPanel {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	Image background;//添加到窗口的背景图片
    Image title1;//添加到窗口的游戏名称图片
    JFrame jf; //选择小鸟的窗口
   JButton []b ;//按钮数组
   client t,t1,t2;//主游戏类
	public select(){
		
	    	jf = new JFrame();//实例化窗口
	    	jf.setTitle("请小心选择小鸟数量");//窗口的标题
	       jf.setSize(300, 300);//设置窗口大小
	        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置窗口关闭方式,关闭即退出程序
	        jf.setLocationRelativeTo(null);//设置窗口在屏幕中间显示
	        jf.setResizable(true);//窗口不可更改大小
	        jf.add(this);//将面板加入窗口
	       
        setLayout(null);//设置面板的布局为空,从而可以任意位置放置按钮
        final ImageIcon icon = new ImageIcon("Image/2.png");
        background = ((ImageIcon) icon).getImage();
        title1 = new ImageIcon("Image/title.png").getImage();	
        b = new JButton[3];
        //实例化按钮
        for(int i = 0;i < 3;i++)
       	b[i] = new JButton();
        //为按钮添加照片、设置背景位置
    	b[0].setIcon(new ImageIcon("Image/bird0_0.png"));
    	 b[0].setBounds(120,80,40,30);
    	 this.add(b[0]);
    	 //为第二个按钮添加照片、设置背景位置
        b[1].setIcon(new ImageIcon("bird3_2.png"));
         b[1].setBounds(95,130,100,33);
         this.add(b[1]);
        //外第三个按钮添加照片
        b[2].setIcon(new ImageIcon("bird3_3.png"));
         b[2].setBounds(70,185,146,35);
         this.add(b[2]);  
         //为第一个按钮添加点击事件
         b[0].addActionListener(new ActionListener(){
			public void actionPerformed(final ActionEvent e) {
				
				t = new client();//启动游戏类对象
				jf.dispose();//撤销当前窗口
		    	t.init1();//初始化即进入游戏
			} 
         });
         //为第二个按钮添加点击事件
         b[1].addActionListener(new ActionListener(){
 			public void actionPerformed(final ActionEvent e) {
 				jf.dispose();
 				 t = new client();
 		    	t.init2();
 			} 
          });
         //为第三个按钮添加点击事件
        b[2].addActionListener(new ActionListener(){
 			public void actionPerformed(final ActionEvent e) {
 				jf.dispose();
 				 t = new client();
 		    	t.init3();
 			} 
          });
         jf.setVisible(true);//设置窗口可见   
	}
	//启动窗口后会自动调用这个画画方法,将背景图片画到界面上
	public void paint(final Graphics g){
		super.paint(g);
		g.drawImage(background,0,0,300,300,this);
		g.drawImage(title1,55,20,174,48,this);
	}
}


client类,游戏主类。Main入口方法也放在了这里

public class client extends JPanel implements KeyListener{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private Image background1,background2;  //定义两张图片作为背景
    private Plane pl;  //定义一个线程
    private pipe P[]=new pipe[300];//定义柱子数组对象
    ArrayList<pipe> list=new ArrayList<pipe>();//存放柱子的集合
    Random ran=new Random();
    public int k=0;
    public int score = 0;
    private bird b1,b2,b3;     //定义一个小鸟
    int flag;//判断调用哪个初始化函数,即创建几个小鸟
    private int x = 0;  //这个变量是用来改变小鸟的飞行状态,起到切换图片的作用
    public static  Music m;//背景音乐
    public static Music m2;//结束时的声音
    JFrame jf;
    public Image gameover =  new ImageIcon("Image/text_game_over.png").getImage();//游戏结束的图片
    //分别获取三只小鸟的散装飞行状态的图片
  	ImageIcon icon1 = new ImageIcon("Image/bird0_0.png");
  	ImageIcon icon2 = new ImageIcon("Image/bird0_1.png");
  	ImageIcon icon3 = new ImageIcon("Image/bird0_2.png");
  	ImageIcon icon4 = new ImageIcon("Image/bird1_0.png");
  	ImageIcon icon5 = new ImageIcon("Image/bird1_1.png");
  	ImageIcon icon6 = new ImageIcon("Image/bird1_2.png");
  	ImageIcon icon7 = new ImageIcon("Image/bird2_0.png");
  	ImageIcon icon8 = new ImageIcon("Image/bird2_1.png");
  	ImageIcon icon9 = new ImageIcon("Image/bird2_2.png");
  	
  	public boolean b = true;//判断是否进入画排行榜的变量
  	Font font = new Font("宋体",Font.BOLD,30);
  //存放从文件中获取的分数
  int ScoreArray[] = new int[300];
	JButton continueButton,outButton;
	RandomAccessFile Score;//定义随机流变量
	int nandu = 1;//游戏难度
    //实例化一个游戏类
    public static void main(String[] args) {
    
       new select();
    }
    
    public int produce() {
   	 return (int)(Math.random()*30 );
     }
    //主类的构造方法
    public client(){	
        
    	jf = new JFrame("请注意!即将开始游戏,控制三只小鸟的按钮依次时是:Q,W,E");//新建一个窗口
        jf.setSize(600, 393);//设置窗口大小
 
        jf.setLocationRelativeTo(null);//设置窗口在屏幕中间显示
        jf.setResizable(false);//窗口不可更改大小
        jf.add(this);//将面板加入窗口
        jf.setVisible(true);//设置窗口可见
        jf.addKeyListener(this);   //为窗口注册按键事件
        
        m=new Music("风中舞.WAV");//因为这个文件太大,在资源中我已经删掉了。想要背景音乐的话下载一个wav格式的音乐放到文件目录下。然后在这里输入资源名称即可
        m2=new Music("小黄人2.WAV");
        //通过ImageIcon类加载背景图片
        ImageIcon icon = new ImageIcon("Image/3.png");
       // ImageIcon icon1=new ImageIcon("Image/pipe_down.png");
     background1 = icon.getImage();
     background2 = icon.getImage();
     //给柱子初始化
     for(int i=0;i<300;i++){
    	 P[i]=new pipe(600+k,produce(),this);
    	 list.add(P[i]);
    	 k+=150;
     }   
    }
    
    //数据初始化方法
    //创建一只小鸟的时候调用
    public void init1()
    {   
       
    	flag  = 1;//设置小鸟数为1,为下面的画小鸟做准备
     b1 = new bird(0,100,this);//创建一个小鸟对象
     b1.setbird(icon1,icon2,icon3);
     pl = new Plane(background1,background2,0,0,this);//创建一个线程对象
     m.play();
    pl.start();  //
    }
    //两只小鸟一起飞时调用
    public void init2()
    {
    	
    	flag = 2;
     b1 = new bird(0,100,this);//创建一个小鸟对象
     b1.setbird(icon1,icon2,icon3);
     b2 = new bird(50,100,this);//创建一个小鸟对象
     b2.setbird(icon4,icon5,icon6);
     pl = new Plane(background1,background2,0,0,this);//创建一个线程对象
     m.play();
    pl.start();  //开始线程
    }
    //三只小鸟一起飞时调用
    public void init3()
    {	
    	flag = 3;
     b1 = new bird(0,100,this);//创建一个小鸟对象
     b1.setbird(icon1,icon2,icon3);
     b2 = new bird(50,100,this);//创建一个小鸟对象
     b2.setbird(icon4,icon5,icon6);
     b3 = new bird(100,100,this);//创建一个小鸟对象
     b3.setbird(icon7,icon8,icon9);
     pl = new Plane(background1,background2,0,0,this);//创建一个线程对象
     m.play();
    pl.start();  //开始线程
    
    }

    //JPanel面板的画图方法-------这个方法需不断地被执行,我们放在自己创建的一个线程里执行
    public void paint(Graphics g){
        super.paint(g); 
        g.drawImage(pl.background1, pl.x, pl.y, 600, 393, this);//画第一张背景图
        g.drawImage(pl.background2,599+pl.x, pl.y, 600, 393, this);//画第二张背景图
        //通过判断flag值来确定画几个小鸟
        String s = Integer.toString(score);
        String n = Integer.toString(nandu);
        this.drawBirdAndJump(g);
        //画柱子和柱子的移动
        for(int i=0;i<list.size();i++){
        	list.get(i).drawDown(g);
        	list.get(i).drawUp(g);
        	list.get(i).move();
        }  
        
        g.setColor(Color.RED);
        g.setFont(font);
        g.drawString("得分:"+s, 150, 25);   //画分数 
        g.setColor(Color.PINK);
        g.drawString("难度:"+n, 380, 25);
        this.isDead(g);
	       try {
     	 		this.showScore(g);
     	 	} catch (IOException e) {
     	 		// TODO Auto-generated catch block
     	 		e.printStackTrace();
     	 	}

    }
    public void   isDead(Graphics g){
    	//柱子和1只小鸟碰撞  
    	  if(flag==1){
          	for(int i = 0;i < list.size();i++){
          		if(b1.Getrect().intersects(list.get(i).GetDOWNrect()) ||//第一只鸟与上边界柱子相碰
          				b1.Getrect().intersects(list.get(i).GetUPrect())//第一只鸟与下边界柱子相碰
          				|| b1.gety() < 0 || b1.gety() > 393)//小鸟往上飞出窗口或者往下掉出窗口
          		{
          			 pl.setFlag(false);//柱子停止移动
          		 m.stop();//游戏结束时停止背景音乐
          			 g.drawImage(gameover,200,180,204,54,this);//画出游戏结束图片
          
          		}
          		
          	}
      
      }
          //2只小鸟时,小鸟与柱子的碰撞
          else if(flag==2){
          	for(int i = 0;i < list.size();i++){//
          		if(b1.Getrect().intersects(list.get(i).GetDOWNrect()) ||   
          				b1.Getrect().intersects(list.get(i).GetUPrect())
          				|| b2.Getrect().intersects(list.get(i).GetDOWNrect())
          				|| b2.Getrect().intersects(list.get(i).GetUPrect())
          				|| b1.gety() < 0 || b1.gety() > 393
          				|| b2.gety() < 0 || b2.gety() > 393)
          		{
          			 pl.setFlag(false);
          			 m.stop();//游戏结束时停止背景音乐
          			 g.drawImage(gameover,200,180,204,54,this);
          		}

          }
          }
          //三只小鸟时候的小鸟与柱子碰撞
          else if(flag==3){
            	for(int i = 0;i < list.size();i++){
          		if(b1.Getrect().intersects(list.get(i).GetDOWNrect()) ||
          				b1.Getrect().intersects(list.get(i).GetUPrect())
          				|| b2.Getrect().intersects(list.get(i).GetDOWNrect())
          				|| b2.Getrect().intersects(list.get(i).GetUPrect())
          				|| b3.Getrect().intersects(list.get(i).GetDOWNrect())
          				|| b3.Getrect().intersects(list.get(i).GetUPrect())
          				|| b1.gety() < 0 || b1.gety() > 393
          				|| b2.gety() < 0 || b2.gety() > 393
          				|| b3.gety() < 0 || b3.gety() > 393)
          				{
          			 pl.setFlag(false);
          			  m.stop();	//游戏结束时停止背景音乐
          			 g.drawImage(gameover,200,180,204,54,this);
          				}
            	}
      }
    	  if(pl.getFlag())
    	  {
          for(int i = 0;i < list.size();i++){
          	if(list.get(i).getUppipex() < 0){
          		//每十根柱子更改移动速度
          		if(score % 10 == 0 && score != 0){
          			pipe.setMoveSp();
          			nandu++;
          		}
          		list.remove(i);
          		  Music mus=new Music("小黄人1.WAV"); ;//定义多个过柱子时的笑声
          		mus.play();   	
          		score++ ;   		
          	}
          }
    	  }
    }
    /*
     * 画出排行榜
     * 画出当前分数的排行
     */
    public void showScore(Graphics g) throws IOException{
    	int max,sedmax,threemax;//三个变量保存分数的前三名
    	if(!pl.getFlag()&&b){
    		b = false;//避免线程刷新画面时重新进入浪费资源,设置为false
    		int i;
    		//创建随机流访问文件
    		//判断是几只小鸟,然后将分数存到不同的文件中
    		if(flag == 1)
    		 Score = new RandomAccessFile("scoreOneBird.dat","rw");
    		else if(flag == 2)
    			Score = new RandomAccessFile("scoreTwoBird.dat","rw");
    		else
    			Score = new RandomAccessFile("scoreThreeBird.dat","rw");
    		//将位置跳到文件末,存放分数
    		Score.seek(Score.length());
				Score.writeInt(score);
				//关闭文件
				Score.close();	
			 i =0;
				while(true){
					       //判断是在玩几只小鸟,然后打开不同的存分数文件
					if(flag == 1)
						  	Score = new RandomAccessFile("scoreOneBird.dat","rw");
					else if(flag == 2)
		    			Score = new RandomAccessFile("scoreTwoBird.dat","rw");
		    		else
		    			Score = new RandomAccessFile("scoreThreeBird.dat","rw");
							//每隔四个字节读取一个整形数
						  	Score.seek(i*4);
					//将分数保存到数组中
						ScoreArray[i] = Score.readInt();
						i++;
						//如果到文件末尾,退出循环
						if(Score.length() == i*4){
							break;
						
					}
				}
				//关闭文件
					Score.close();
			//初始化三个变量
			max = sedmax = threemax = 0;
			//将数组按顺序排序
			Arrays.sort(ScoreArray);
			//轻松获取前三大值
			max = ScoreArray[ScoreArray.length-1];
			sedmax = ScoreArray[ScoreArray.length-2];
			threemax = ScoreArray[ScoreArray.length-3];
			//记录排名,从末尾往前
			int count = ScoreArray.length;  
             for(i = 0;i < ScoreArray.length;i++)
             {
            	 //如果分数比数组里的数大,排名往前一位
            	 if(ScoreArray[i] < score )
            		 count--;
            	 //如果等0,说明是第一名
            	 if(count == 0)
            		 count = 1;
             }
             //三个整形转换成字符型
			String ScMax = Integer.toString(max);
			String ScSeMax = Integer.toString(sedmax);
			String ScThMax = Integer.toString(threemax);
			//设置字体大小、改变颜色、画出排名
		        g.setFont(font);
		        g.setColor(Color.MAGENTA);
		        g.drawString("当前排名:"+count,150, 90);
		        g.setColor(Color.ORANGE);
		        g.drawString("得分排名第一:"+ScMax, 150, 120);
		        g.setColor(Color.CYAN);
		        g.drawString("得分排名第二:"+ScSeMax, 150, 150);
		        g.setColor(Color.GREEN);
		        g.drawString("得分排名第三:"+ScThMax, 150, 180);
		        //实例两个按钮
		        continueButton = new JButton("重新开始");
		        outButton = new JButton("退出游戏");
		   //将按钮添加到面板上、设置背景颜色、出现的位置以及大小
		        this.add(continueButton);
		        this.add(outButton);
		        continueButton.setBackground(Color.green);
		        continueButton.setBounds(140,240,100,50);
		        outButton.setBackground(Color.CYAN);
		        outButton.setBounds(350,240,100,50);
		        
		        //为继续按钮添加点击事件
		        continueButton.addActionListener(new ActionListener(){
		 			public void actionPerformed(ActionEvent e) {
		 				jf.dispose();
		 		       new select();
		 			} 
		          });
		   //     为退出游戏按钮添加点击事件
		        outButton.addActionListener(new ActionListener(){
		    
					public void actionPerformed(ActionEvent e) {
						// TODO Auto-generated method stub
						jf.dispose();
					}
		        });
		        
    	}
    }
    public void drawBirdAndJump(Graphics g){
        //画一只小鸟
        if(flag == 1)
        {
        	jf.setTitle("单飞像素鸟        跳跃键:Q");
        	b1.draw(g,x);//调用小鸟对象的画图方法画一个小鸟
        }
        //flag=2 画2只小鸟
      else if(flag == 2)
      {
    	  jf.setTitle("双飞像素鸟      跳跃键:Q、W");
        b1.draw(g,x);
        b2.draw(g,x);
      }
        //画三只小鸟
      else
      {
    	  jf.setTitle("三飞像素鸟         跳跃键:Q、W、E");
        b1.draw(g,x);//调用小鸟对象的画图方法画一个小鸟
        b2.draw(g,x);
        b3.draw(g,x);
      }
        x++;//每次跑都改变小鸟飞行的图片
        if(flag == 1)
          b1.move();//小鸟往下掉的方法
        else if(flag == 2)
        {
        b1.move();
        b2.move();
        }
        else if(flag == 3){
        b1.move();//小鸟往下掉的方法
        b2.move();
        b3.move();
        }
        if(x == 3)//小鸟飞行有三张图片,循环变换
        	x = 0; 
    }
    //按下键盘时自动调用的方法
	public void keyPressed(KeyEvent e) {
	
	}
	//按下并且释放键盘时自动调用的方法
	public void keyReleased(KeyEvent e) {
		//通过flag值判断调用多少个小鸟的按键函数
		if(flag == 1)
		 b1.keyPressed1(e);//调用小鸟类的按键方法
		else if(flag == 2){
		 b1.keyPressed1(e);
		 b2.keyPressed2(e);
		}
		else{
		 b1.keyPressed1(e);//调用小鸟类的按键方法
		 b2.keyPressed2(e);
		 b3.keyPressed3(e);
		}
		
	}

线程类非常简单。只要一个死循环就行

public class Plane extends Thread {
	public Image background1, background2; // 定义两张背景

	public int x = 0; // 背景图片x坐标
	public int y = 0;// 背景图片y坐标
	public JPanel jp;// 定义一个面板
	public int movesp = 5;// 背景图的移动速度
	public boolean flag = true;
	public Music m = new Music("风中舞.WAV");
	public Music m2 = new Music("小黄人2.WAV");

	// 构造方法
	public Plane(Image background1, Image background2, int x, int y, JPanel jp) {
		m.play();
		this.background1 = background1;
		this.background2 = background2;
		this.x = x;
		this.y = y;
		this.jp = jp;// 将面板传进来主要是为了在线程中调用窗口面板的repaint
		// 方法,重画游戏窗口
	}

	public boolean setFlag(boolean flag) {
		this.flag = flag;
		return flag;
	}

	public boolean getFlag() {
		return flag;
	}

	public void run() {
		// 在线程中循环调用背景图的move方法,并且重画面板

		while (true) {
			if (flag) {
                                //移动就是通过不断刷新更改x,y值实现的
				jp.repaint();

			} else {
				m.stop();
				m2.play();
			}
			try {
				Thread.sleep(100);// 线程睡眠0.1秒
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}

还有一个柱子类、封装的调用播放音乐的类非常非常简单这里就不放占用资源了。下载地址

像素鸟源代码下载下载后直接导入到myeclipse中就可以运行了噢