Java實現貪喫蛇遊戲【代碼】

Java實現貪喫蛇遊戲【代碼】

花了兩個下午寫了一個貪喫蛇小遊戲,本人想寫這遊戲很長時間了。作爲以前諾基亞手機上的經典遊戲,貪喫蛇和俄羅斯方塊一樣,都曾經在我們的童年給我們帶來了很多樂趣。世間萬物斗轉星移,諾基亞曾經作爲手機業的龍頭老大,現如今也一步步走向衰落,被收購,再過不久估計就要退出手機業務了,而貪喫蛇這款遊戲也基本上沒人玩了,甚至在新一代人的印象中都已毫無記憶了。。。但是,這款遊戲在它基礎上經過改造其實可以弄出很多花樣,也確實可以在一定程度上鍛鍊自己的編程能力。前不久十分火熱的貪喫蛇大作戰其實就可以看做是在這款遊戲的基礎上進行的改造。所以,我也希望自己可以嘗試以下,做個有意思的版本。

目前這個版本只是爲了後期版本的一個測試版本,所以只有一些基本功能,本來是打算這個版本實現了移動,喫食物增長,判斷撞牆和撞自己的身體就行了,無奈覺得有點單調,於是在此基礎上加上了一個計時器,記分功能,重新開始,開始暫停以及音效。白白又多了幾百行代碼。原來的基本代碼也就300行。

遊戲界面圖如下:





代碼:

import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.util.Random;
import javax.sound.sampled.*;
import javax.swing.*;

class Tile{
    int x;
    int y;
    
    public Tile(int x0,int y0){
        x = x0;
        y = y0;
    }
}

public class SnakeDemo extends JComponent{
    /**
     * 
     */
    private static final long serialVersionUID = 3794762291171148906L;
    private final int MAX_SIZE = 400;//蛇身體最長爲400節
    private Tile temp = new Tile(0,0);
    private Tile temp2 = new Tile(0,0);
    private Tile head = new Tile(227,100);//頭部的位置初始化爲(227,100)
    private Tile[] body = new Tile[MAX_SIZE];
    private String direction = "R";//默認向右走
    private String current_direction = "R";//當前方向
    private boolean first_launch = false;
    private boolean iseaten = false;
    private boolean isrun = true;
    private int randomx,randomy;
    private int body_length = 5;//身體長度初始化爲5
    private Thread run;
    private JLabel label = new JLabel("當前長度:");
    private JLabel label2 = new JLabel("所花時間:");
    private JLabel label3 = new JLabel("說          明:");
    private JTextArea explain = new JTextArea("此遊戲是一個貪喫蛇Demo版本,實現簡單地移動,得分,判斷撞牆和撞自己的功能,"
            + "初始長度爲6,頭部爲紅色,身體的顏色漸變。遊戲本身代碼只有300行,加上一些顯示,計時和音效後多了幾百行。\n"
            + "遊戲界面按上下左右鍵實現移動,按ESC重新開始,按空格鍵可以實現暫停和開始");
    private JLabel Score = new JLabel("6");
    private JLabel Time = new JLabel("");
    private Font f = new Font("微軟雅黑",Font.PLAIN,15);
    private Font f2 = new Font("微軟雅黑",Font.PLAIN,13);
    private JPanel p = new JPanel();
    private int hour =0;
    private int min =0;
    private int sec =0 ;
    private boolean pause = false;
    
    public SnakeDemo(){
        String lookAndFeel =UIManager.getSystemLookAndFeelClassName();
        try {
            UIManager.setLookAndFeel(lookAndFeel);
        } catch (ClassNotFoundException e1) {
            // TODO 自動生成的 catch 塊
            e1.printStackTrace();
        } catch (InstantiationException e1) {
            // TODO 自動生成的 catch 塊
            e1.printStackTrace();
        } catch (IllegalAccessException e1) {
            // TODO 自動生成的 catch 塊
            e1.printStackTrace();
        } catch (UnsupportedLookAndFeelException e1) {
            // TODO 自動生成的 catch 塊
            e1.printStackTrace();
        }
        
        //佈局
        add(label);
        label.setBounds(500, 10, 80, 20);
        label.setFont(f);
        add(Score);
        Score.setBounds(500, 35, 80, 20);
        Score.setFont(f);
        add(label2);
        label2.setBounds(500, 60, 80, 20);
        label2.setFont(f);
        add(Time);
        Time.setBounds(500, 85, 80, 20);
        Time.setFont(f);
        add(p);
        p.setBounds(498, 110, 93, 1);
        p.setBorder(BorderFactory.createLineBorder(Color.black));
        
        add(label3);
        label3.setBounds(500, 115, 80, 20);
        label3.setFont(f);
        add(explain);
        explain.setBounds(498, 138, 100, 350);
        explain.setFont(f2);
        explain.setLineWrap(true);
        explain.setOpaque(false); 
        
        for(int i = 0; i < MAX_SIZE;i++)
        {
            body[i] = new Tile(0,0);
        }
        
        addKeyListener(new KeyAdapter() {
            public void keyPressed(KeyEvent e) {
                super.keyPressed(e);
                if(e.getKeyCode() == KeyEvent.VK_RIGHT)
                {
                    if(isrun && current_direction != "L")
                    {
                        direction = "R";
                    }
                }
                if(e.getKeyCode() == KeyEvent.VK_LEFT)
                {
                    if(isrun && current_direction != "R")
                    {
                        direction = "L";
                    }
                }
                if(e.getKeyCode() == KeyEvent.VK_UP)
                {
                    if(isrun && current_direction != "D")
                    {
                        direction = "U";
                    }
                }
                if(e.getKeyCode() == KeyEvent.VK_DOWN)
                {
                    if(isrun && current_direction != "U")
                    {
                        direction = "D";
                    }
                }
                if(e.getKeyCode() == KeyEvent.VK_ESCAPE)
                {
                    direction = "R";//默認向右走
                    current_direction = "R";//當前方向
                    first_launch = false;
                    iseaten = false;
                    isrun = true;
                    body_length = 5;
                    head = new Tile(227,100);
                    Score.setText("6");
                    hour =0;
                    min =0;
                    sec =0 ;
                    for(int i = 0; i < MAX_SIZE;i++)
                    {
                        body[i].x = 0;
                        body[i].y = 0;
                    }
                    
                    run = new Thread();
                    run.start();
                    System.out.println("Start again");
                }
                if(e.getKeyCode() == KeyEvent.VK_SPACE)//按空格鍵開始和暫停暫時沒做,還在思考中
                {
                    if(!pause)//暫停
                    {
                        pause = true;
                        isrun = false;
                    }
                    else//開始
                    {
                        pause = false;
                        isrun = true;
                    }
                }
            }
        });
        
        new Timer();
        
        setFocusable(true);
    }
    
    public void paintComponent(Graphics g1){
        super.paintComponent(g1);
        Graphics2D g = (Graphics2D) g1;
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_NORMALIZE);
        
        //畫頭部
        g.setColor(Color.red);
        g.fillRoundRect(head.x, head.y, 20, 20, 10, 10);
        
        g.setPaint(new GradientPaint(115,135,Color.CYAN,230,135,Color.MAGENTA,true));
        if(!first_launch)
        {
            //初始化身體
            int x = head.x;
            for(int i = 0;i < body_length;i++)
            {
                x -= 22;//相鄰兩個方塊的間距爲2個像素,方塊寬度都爲20像素
                body[i].x = x;
                body[i].y = head.y;
                g.fillRoundRect(body[i].x, body[i].y, 20, 20, 10, 10);
            }
            //初始化食物位置
            ProduceRandom();
            g.fillOval(randomx, randomy, 19, 19);
        }
        else
        {
            //每次刷新身體
            for(int i = 0;i < body_length;i++)
            {
                g.fillRoundRect(body[i].x, body[i].y, 20, 20, 10, 10);
            }
            
            if(EatFood())//被吃了重新產生食物
            {
                ProduceRandom();
                g.fillOval(randomx, randomy, 19, 19);
                iseaten = false;
            }
            else
            {
                g.fillOval(randomx, randomy, 19, 19);
            }
        }
        first_launch = true;
        //牆
        g.setStroke( new BasicStroke(4,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
        g.setBackground(Color.black);
        g.drawRect(2, 7, 491, 469);
        
        //網格線
        for(int i = 1;i < 22;i++)
        {
            g.setStroke( new BasicStroke(1,BasicStroke.CAP_BUTT,BasicStroke.JOIN_BEVEL));
            g.setColor(Color.black);
            g.drawLine(5+i*22,9,5+i*22,472);
            if(i <= 20)
            {
                g.drawLine(4,10+i*22,491,10+i*22);
            }
        }
    }
    
    public void ProduceRandom(){
        boolean flag = true;
        Random rand = new Random();
        randomx = (rand.nextInt(21) + 1) * 22 + 7;
        randomy = (rand.nextInt(20) + 1) *22 + 12;
        while(flag)
        {
            for(int i = 0;i < body_length; i++)
            {
                if(body[i].x == randomx && body[i].y == randomy)
                {
                    randomx = (rand.nextInt(21) + 1) * 22 + 7;
                    randomy = (rand.nextInt(20) + 1) *22 + 12;
                    flag = true;
                    break;
                }
                else
                {
                    if(i == body_length - 1)
                    {
                        flag = false;
                    }
                }
            }
        }
    }
    
    public void HitWall(){//判斷是否撞牆
        if(current_direction == "L")
        {
            if(head.x < 7)
            {
                new AePlayWave("over.wav").start();
                isrun = false;
                int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
                if(result==JOptionPane.YES_NO_OPTION)
                {
                    direction = "R";//默認向右走
                    current_direction = "R";//當前方向
                    first_launch = false;
                    iseaten = false;
                    isrun = true;
                    body_length = 5;
                    head = new Tile(227,100);
                    Score.setText("6");
                    hour =0;
                    min =0;
                    sec =0 ;
                    for(int i = 0; i < MAX_SIZE;i++)
                    {
                        body[i].x = 0;
                        body[i].y = 0;
                    }
                    
                    run = new Thread();
                    run.start();
                    System.out.println("Start again");
                }
                else
                {
                    run.stop();
                }        
            }
        }
        if(current_direction == "R")
        {
            if(head.x > 489)
            {
                new AePlayWave("over.wav").start();
                isrun = false;
                int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
                if(result==JOptionPane.YES_NO_OPTION)
                {
                    direction = "R";//默認向右走
                    current_direction = "R";//當前方向
                    first_launch = false;
                    iseaten = false;
                    isrun = true;
                    body_length = 5;
                    head = new Tile(227,100);
                    Score.setText("6");
                    hour =0;
                    min =0;
                    sec =0 ;
                    for(int i = 0; i < MAX_SIZE;i++)
                    {
                        body[i].x = 0;
                        body[i].y = 0;
                    }
                    
                    run = new Thread();
                    run.start();
                    System.out.println("Start again");
                }
                else
                {
                    run.stop();
                }
            }
        }
        if(current_direction == "U")
        {
            if(head.y < 12)
            {
                new AePlayWave("over.wav").start();
                isrun = false;
                int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
                if(result==JOptionPane.YES_NO_OPTION)
                {
                    direction = "R";//默認向右走
                    current_direction = "R";//當前方向
                    first_launch = false;
                    iseaten = false;
                    isrun = true;
                    body_length = 5;
                    head = new Tile(227,100);
                    Score.setText("6");
                    hour =0;
                    min =0;
                    sec =0 ;
                    for(int i = 0; i < MAX_SIZE;i++)
                    {
                        body[i].x = 0;
                        body[i].y = 0;
                    }
                    
                    run = new Thread();
                    run.start();
                    System.out.println("Start again");
                }
                else
                {
                    run.stop();
                }
            }
        }
        if(current_direction == "D")
        {
            if(head.y > 472)
            {
                new AePlayWave("over.wav").start();
                isrun = false;
                int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
                if(result==JOptionPane.YES_NO_OPTION)
                {
                    direction = "R";//默認向右走
                    current_direction = "R";//當前方向
                    first_launch = false;
                    iseaten = false;
                    isrun = true;
                    body_length = 5;
                    head = new Tile(227,100);
                    Score.setText("6");
                    hour =0;
                    min =0;
                    sec =0 ;
                    for(int i = 0; i < MAX_SIZE;i++)
                    {
                        body[i].x = 0;
                        body[i].y = 0;
                    }
                    
                    run = new Thread();
                    run.start();
                    System.out.println("Start again");
                }
                else
                {
                    run.stop();
                }
            }
        }
    }
    
    public void HitSelf(){//判斷是否撞到自己身上
        for(int i = 0;i < body_length; i++)
        {
            if(body[i].x == head.x && body[i].y == head.y)
            {
                new AePlayWave("over.wav").start();
                isrun = false;
                int result=JOptionPane.showConfirmDialog(null, "Game over! Try again?", "Information", JOptionPane.YES_NO_OPTION);
                if(result==JOptionPane.YES_NO_OPTION)
                {
                    direction = "R";//默認向右走
                    current_direction = "R";//當前方向
                    first_launch = false;
                    iseaten = false;
                    isrun = true;
                    body_length = 5;
                    head = new Tile(227,100);
                    Score.setText("6");
                    hour =0;
                    min =0;
                    sec =0 ;
                    for(int j = 0; j < MAX_SIZE;j++)
                    {
                        body[j].x = 0;
                        body[j].y = 0;
                    }
                    
                    run = new Thread();
                    run.start();
                    System.out.println("Start again");
                }
                else
                {
                    run.stop();
                }
                break;
            }
        }
    }
    
    public boolean  EatFood(){
        if(head.x == randomx && head.y == randomy)
        {
            iseaten = true;
            return true;
        }
        else
        {
            return false;
        }
    }
    
    public void Thread(){
        long millis = 300;//每隔300毫秒刷新一次
        run = new Thread() {
            public void run() {
                while (true) 
                {
                    try {
                        Thread.sleep(millis);
                    } catch (InterruptedException ex) {
                        ex.printStackTrace();
                    }
                    
                    if(!pause)
                    {    
                        temp.x = head.x;
                        temp.y = head.y;
                        //頭部移動
                        if(direction == "L")
                        {
                            head.x -= 22;
                        }
                        if(direction == "R")
                        {
                            head.x += 22;
                        }
                        if(direction == "U")
                        {
                            head.y -= 22;
                        }
                        if(direction == "D")
                        {
                            head.y += 22;
                        }
                        current_direction = direction;//刷新當前前進方向
                        //身體移動
                        for(int i = 0;i < body_length;i++)
                        {
                            temp2.x = body[i].x;
                            temp2.y = body[i].y;
                            body[i].x = temp.x;
                            body[i].y = temp.y;
                            temp.x = temp2.x;
                            temp.y = temp2.y;
                        }
                        
                        if(EatFood())
                        {
                            body_length ++;
                            body[body_length-1].x = temp2.x;
                            body[body_length-1].y = temp2.y;
                            Score.setText("" + (body_length+1) );
                            new AePlayWave("eat.wav").start();
                        }
                        
                        repaint();
                        
                        HitWall();
                        HitSelf();
                    }
                }
            }
        };
        
        run.start();
    }
    
    public static void main(String[] args) {
        SnakeDemo t = new SnakeDemo();
        t.Thread();
        
        JFrame game = new JFrame();
        Image img=Toolkit.getDefaultToolkit().getImage("title.png");//窗口圖標
        game.setIconImage(img);
        game.setTitle("Snake By XJX");
        game.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//        game.setSize(502, 507);
        game.setSize(602, 507);
        game.setResizable(false);
        game.setLocationRelativeTo(null);
       
        game.add(t);
        game.setVisible(true);
    }
    
    //計時器類
    class Timer extends Thread{  
            public Timer(){
                this.start();
            }
            @Override
            public void run() {
                // TODO Auto-generated method stub
                while(true){
                    if(isrun){
                        sec +=1 ;
                        if(sec >= 60){
                            sec = 0;
                            min +=1 ;
                        }
                        if(min>=60){
                            min=0;
                            hour+=1;
                        }
                        showTime();
                    }
         
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                     
                }
            }

            private void showTime(){
                String strTime ="" ;
                if(hour < 10)
                    strTime = "0"+hour+":";
                else
                    strTime = ""+hour+":";
                 
                if(min < 10)
                    strTime = strTime+"0"+min+":";
                else
                    strTime =strTime+ ""+min+":";
                 
                if(sec < 10)
                    strTime = strTime+"0"+sec;
                else
                    strTime = strTime+""+sec;
                 
                //在窗體上設置顯示時間
                Time.setText(strTime);
            }
        }    
}

class AePlayWave extends Thread {      
    private String filename;
    private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb 

    public AePlayWave(String wavfile) { 
        filename = wavfile;
    } 
            
    public void run() { 
        File soundFile = new File(filename); 
        AudioInputStream audioInputStream = null;
        try { 
            audioInputStream = AudioSystem.getAudioInputStream(soundFile);
        } catch (UnsupportedAudioFileException e1) { 
            e1.printStackTrace();
            return;
        } catch (IOException e1) { 
            e1.printStackTrace();
            return;
        } 
 
        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 (LineUnavailableException e) { 
            e.printStackTrace();
            return;
        } catch (Exception e) { 
            e.printStackTrace();
            return;
        } 

        auline.start();
        int nBytesRead = 0;
        byte[] abData = new byte[EXTERNAL_BUFFER_SIZE];
 
        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();
        } 
    } 
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章