zoukankan      html  css  js  c++  java
  • 用java实现贪吃蛇小游戏

    在本类中目的是做一个背景和画板,实现贪吃蛇游戏的一个动态效果

    package Snake;
    
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class Background {
        //容器对象
        private JFrame sanke_jf = new JFrame("贪吃蛇小游戏");
        private JPanel jPanel = new JPanel();
        private SnakeClass snake;//
        private GetFood.Food food;//食物
        public Background( SnakeClass snake, GetFood.Food food) {
            //构造器
            this.food = food;
            this.snake = snake;
        }
        //背景的大小
        public static final int BACK_WIDTH = 1210;
        public static final int BACK_HEIGHT = 858;
        //游戏相关信息的画布和画笔
        private class DrawArea extends Canvas {
            @Override
            public void paint(Graphics g) {
                if (Is.isOver) {
                    g.setColor(Color.black);
                    g.setFont(new Font("Times", Font.BOLD, 45));
                    g.drawString("游戏结束!", 600, 350);
                    g.drawString("你的分数:"+food.count, 600, 400);
                    g.drawString("历史最高分:"+SaveMaxCount.read(), 600, 450);
                } else {
                    if (food.color==5||food.color==10||food.color==7){
                        g.setColor(Color.orange);
                        g.fillOval(food.foodx, food.foody, Node.NODE_DIA, Node.NODE_DIA);
                    }else if(food.color==4||food.color==8){
                        g.setColor(Color.black);
                        g.fillOval(food.foodx, food.foody, Node.NODE_DIA, Node.NODE_DIA);
                    }else {
                        g.setColor(Color.GREEN);
                        g.fillOval(food.foodx, food.foody, Node.NODE_DIA, Node.NODE_DIA);
                    }
                    //蛇头(黄色)
                    g.setColor(Color.orange);
                    g.fillOval(snake.head.nodex, snake.head.nodey, Node.NODE_DIA, Node.NODE_DIA);
    
                    //蛇的身体(蓝色)
                    g.setColor(Color.BLUE);
                    Node temp = snake.head;
                    while (true) {
                        if (temp.next == null) {
                            g.fillOval(temp.nodex, temp.nodey, Node.NODE_DIA, Node.NODE_DIA);
                            break;
                        }
                        temp = temp.next;
                        g.fillOval(temp.nodex, temp.nodey, Node.NODE_DIA, Node.NODE_DIA);
    
                    }
                }
            }
        }
    
        private Timer timer;//多久自动执行一次相关代码的对象
    
        //创建绘画区域对象
        DrawArea drawArea = new DrawArea();
        //组装显示界面的方法
        public void draw_back() {
            drawArea.setPreferredSize(new Dimension(BACK_WIDTH, BACK_HEIGHT));//为绘画区域设置大小
            //键盘监听器,用键盘控制蛇的移动
           KeyListener listener = new KeyAdapter() {
                @Override
                public void keyPressed(KeyEvent e) {
                    int keyCode = e.getKeyCode();
                    snake.move(keyCode);
                }
            };
    
           //为相关区域添加监听器
           jPanel.addKeyListener(listener);
            sanke_jf.addKeyListener(listener);
            drawArea.addKeyListener(listener);
            //设置JFrame容器的大小
            sanke_jf.setSize(BACK_WIDTH, BACK_HEIGHT);
            //每过指定时间自动执行的任务代码
            ActionListener tack = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    drawArea.repaint();//重画,实现视觉效果
                    snake.autmove();
                    if (Is.isOver) timer.stop();
                }
            };
            timer = new Timer(230, tack);
            timer.start();
            //将绘画区域添加到容器中
            jPanel.add(drawArea);
            sanke_jf.add(jPanel);
            sanke_jf.setResizable(false);//设置JFrame的大小不可变
            sanke_jf.setVisible(true);//设置窗口可见
            //点击右上角“x”号结束程序
            sanke_jf.addWindowListener(new WindowAdapter() {
                @Override
                public void windowClosed(WindowEvent e) {
                    System.exit(0);
                }
            });
        }
    
    //该类是食物相关类,实现同一时间有且仅有一个食物存在,主要利用多线程的通信机制

    package
    Snake; import java.util.Random; public class GetFood { //食物消失与生成的类 //每一个食物也是一个节点 Random rx = new Random();//随机生成食物的x坐标 Random ry = new Random();//随机生成食物的y坐标 Random rc = new Random(); //将背景按节点大小划分为一定的格子,食物只能产生在格子中以保证蛇一定可以吃到 int rowy = Background.BACK_WIDTH/Node.NODE_DIA; int rowx = Background.BACK_HEIGHT/Node.NODE_DIA; //食物类 class Food{ //坐标 public int foodx =-1; public int foody =-1; public int color = 1; //是否需要产生食物 public boolean isGetFood = true; //计算分数 int count=0; } //用多线程实现食物的消亡与产生,利用等待唤醒机制保证食物的同步 class CreateFood extends Thread { //提供锁对象 private Food food; public CreateFood(Food food){ this.food=food; } @Override public void run() { while(true){ synchronized (food){ if(!food.isGetFood){ try { food.wait();//如果有食物进入等待 } catch (InterruptedException e) { e.printStackTrace(); } }else{ //如果没有食物随机生成一个食物(坐标) if(Is.is_Strength){ food.color=(int)(Math.random()*10); } food.foodx=Node.NODE_DIA*(rx.nextInt(rowy-2)+1); food.foody=Node.NODE_DIA*(ry.nextInt(rowx-3));//设置一定范围,增强游戏体验 food.isGetFood=false;//产生食物以后修改食物的状态 food.notify();//唤醒吃食物的线程 } } } } } class EatFood extends Thread{ private Food food;//提供锁对象 private SnakeClass snake;//蛇(与食物发生碰撞) public EatFood(Food food,SnakeClass snake){ //构造器 this.food=food; this.snake=snake; } @Override public void run() { while(true){ synchronized (food){ if(food.isGetFood){ try { food.wait();//如果没有食物,进入等待 } catch (InterruptedException e) { e.printStackTrace(); } }else{ //如果有食物进 if (snake.head.nodex==food.foodx&&snake.head.nodey==food.foody){ //如果蛇头食物发生碰撞 if(food.color==5||food.color==10||food.color==7){ snake.add_Tail(new Node(snake.get_Tail().nodex,snake.get_Tail().nodey)); snake.add_Tail(new Node(snake.get_Tail().nodex,snake.get_Tail().nodey)); food.foodx=-1; food.foody=-1; food.count+=2; }else if(food.color==4||food.color==8){ snake.deleteTail(); food.foodx=-1; food.foody=-1; food.count--; try { Thread.sleep(3500); } catch (InterruptedException e) { e.printStackTrace(); }if(food.count>=SaveMaxCount.read()){ SaveMaxCount.save(food.count); } food.isGetFood=true;//修改食物状态 food.notify();//唤醒产生食物的线程 } else{ snake.add_Tail(new Node(snake.get_Tail().nodex,snake.get_Tail().nodey)); food.foodx=-1; food.foody=-1; food.count++; } // System.out.println(food.color);(在测试时查看随机数) //如果当前分数大于历史最大分数,则将当前分数存入文件 if(!food.isGetFood){ food.isGetFood=true;//修改食物状态 food.notify();//唤醒产生食物的线程 } } } } } } } }
    //游戏入口
    public
    class Inner { public static void main(String[] args) { new StartFrame().start_window(); } }
    //游戏模式和游戏是否结束的开关
    package
    Snake; public class Is { public static boolean isOver = false;//表示游戏是否结束 public static boolean is_nodie=false; public static boolean is_Strength=false; }
    package Snake;
    
    //蛇的没一个节点的基本单位,因为在本游戏中不断地进行删除与增加,所以选择使用链表
    public class Node {
    
        //表示蛇的每一个节点(链表结构)
    
        public  Node next;//指向下一个
        public  int nodex;//节点的x坐标
        public  int  nodey;//节点的y坐标
        public  static final int NODE_DIA = 22;//节点的大小
    
        public Node(int nodex,int nodey){
            //构造器
            this.nodex=nodex;
            this.nodey=nodey;
        }
    }
    package Snake;
    //游戏的初始化信息和模式设置
    public class RunGameMethod {
    
        public static void method1(){//标准模式
            Is.is_nodie=false;
            Is.is_Strength=false;
            original();
        }
        public static void method2(){//无尽模式
            Is.is_Strength=false;
            Is.is_nodie=true;
            original();
        }
        public static void method3(){//无尽模式
            Is.is_nodie=false;
            Is.is_Strength=true;
            original();
        }
    
        private static  void original(){
            SaveMaxCount filecount  = new SaveMaxCount();//创建保存最高分数的对象
    
            //初始化一条小蛇
            Node head = new Node(2 * Node.NODE_DIA, 0);
            Node body1 = new Node(Node.NODE_DIA, 0);
            Node body2 = new Node(0, 0);
            SnakeClass snake = new SnakeClass(head);
            snake.add_Tail(body1);
            snake.add_Tail(body2);
    
            //创建食物的对象
            GetFood.Food food = new GetFood().new Food();
            //显示游戏运行界面
            Background back = new Background(snake, food);
            back.draw_back();
            //开启产生食物和吃食物的两个线程,并将食物对象作为锁对象
            new GetFood().new EatFood(food, snake).start();
            new GetFood().new CreateFood(food).start();
        }
    }
    package Snake;
    //利用文件保存游戏的最高分
    import java.io.*; public class SaveMaxCount { //保存最高分数的文件位置 private static File file_normal = new File("C:\Users\lenovo\IdeaProjects\MyJava\src\Snake\savecount.txt"); private static File file_Strength= new File("C:\Users\lenovo\IdeaProjects\MyJava\src\Snake\save_strength.txt"); private static File file = file_normal; private static File getFile() { if(Is.is_Strength){ return file_Strength; } return file; } //存储分数的方法 public static void save(int count){ FileOutputStream fos = null; try{ fos = new FileOutputStream(SaveMaxCount.getFile()); fos.write(count); }catch(IOException e){ e.getMessage(); }finally { try { fos.close(); } catch (IOException e) { e.printStackTrace(); } } } //得到历史最高分数的方法 public static int read(){ FileInputStream fis = null; int count = 0; try { fis=new FileInputStream(SaveMaxCount.getFile()); count=fis.read(); } catch (IOException e) { e.printStackTrace(); }finally{ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } } return count; } }
    package Snake;
    //实现蛇的构造、移动、游戏结束逻辑的控制。
    public class SnakeClass {
    
        public SnakeClass(){
    
        }
        //蛇的构造器,重点是头节点  IS是为了在整个程序中保证判断结束语句的对象的一致性
        public SnakeClass( Node head) {
            this.head = head;
        }
        public Node head;//头结点
        public Node tail;//尾节点
        //增加蛇的长度(向尾部添加一个节点)
        public void add_Tail(Node node) {
            Node temp = head;
            while (true) {
                if (temp.next == null) {
                    //此时temp为当前的尾节点
                    break;
                }
                temp = temp.next;
            }
            temp.next = node;
        }
    
        //在头结点的后面和原头结点的下一个节点中间插入一个节点(移动的第一步)
        public void add_head(Node node) {
            Node temp = head.next;
            head.next = node;
            node.next = temp;
        }
    
        //得到当前的尾节点(在得分和移动时都需要用到)
        public Node get_Tail() {
            Node temp = head;
            while (true) {
                if (temp.next == null) {
                    tail = temp;
                    return tail;
                }
                temp = temp.next;
            }
        }
    
        //删除尾节点(移动的第二步)
        public void deleteTail() {
            Node temp = head;
            Node temp2 = temp;
            while (true) {
                if (temp.next == null) {
                    temp2.next = null;
                    return;
                }
                temp2 = temp;
                temp = temp.next;
            }
        }
    
        //蛇头撞到了自身,游戏结束逻辑的一方面
        private boolean isOver_Self(){
            boolean b = false;
            Node temp = head.next;
            while(true){
                if(head.nodey==temp.nodey&&head.nodex==temp.nodex){
                    b=true;
                    break;
                }else if(temp.next==null){
                    break;
                }
                temp=temp.next;
            }
            return b;
        }
    
        //游戏结束的逻辑
        public   boolean isOver(){
            return  head.nodex < Node.NODE_DIA || head.nodex > (Background.BACK_WIDTH - 2 * Node.NODE_DIA) ||
                    head.nodey < -0 || head.nodey > (Background.BACK_HEIGHT - 4 * Node.NODE_DIA)||isOver_Self();
        }
    
        //移动的方法(改变方向)(将头结点按指定方法移动一个单位,在其后新增加一个单位,删除尾节点
        //判断蛇是否可以向右移动,正在向左方向移动
        //条件成立不能该方向移动
        private boolean can_moveRight(){
            return head.nodey==head.next.nodey&&head.nodex<head.next.nodex;
        }
        //判断蛇是否可以向左移动,正在向右方向移动
        //条件成立不能该方向移动
        private boolean can_moveLeft(){
            return head.nodey==head.next.nodey&&head.nodex>head.next.nodex;
        }
        //判断蛇是否可以向上移动,正在向下方向移动
        //条件成立不能该方向移动
        private boolean can_moveUp(){
            return head.nodex==head.next.nodex&&head.nodey<head.next.nodey;
        }
        //判断蛇是否可以向下移动,正在向上方向移动
        //条件成立不能该方向移动
        private boolean can_moveDown(){
            return head.nodex==head.next.nodex&&head.nodey>head.next.nodey;
        }
    
        public void move(int ch) {
            boolean b=isOver();
            //撞到边界的判断逻辑,满足条件游戏结束
            int tempx = head.nodex;
            int tempy = head.nodey;
            //新增节点的x和y坐标
            switch (ch) {
                case 37:
                    if(can_moveLeft()) break;
                    if(!Is.is_nodie){
                        if (b) Is.isOver = true;
                    }
                    head.nodex -= Node.NODE_DIA;
                    add_head(new Node(tempx, tempy));
                    deleteTail();
                    break;
                case 40:
                    if(can_moveUp()) break;
                    if(!Is.is_nodie){
                        if (b) Is.isOver = true;
                    }
                    head.nodey += Node.NODE_DIA;
                    add_head(new Node(tempx, tempy));
                    deleteTail();
                    break;
                case 39:
                    if(can_moveRight()) break;
                    if(!Is.is_nodie){
                        if (b) Is.isOver = true;
                    }
                    head.nodex += Node.NODE_DIA;
                    add_head(new Node(tempx, tempy));
                    deleteTail();
                    break;
                case 38:
                    if(can_moveDown()) break;
                    if(!Is.is_nodie){
                        if (b) Is.isOver = true;
                    }
                    head.nodey -= Node.NODE_DIA;
                    add_head(new Node(tempx, tempy));
                    deleteTail();
                    break;
                default:
                    break;
            }
        }
    
        //实现蛇的自动移动(与第一种移动方式有相似的逻辑,但不会改变方向)
        public void autmove(){
            int tempx = head.nodex;
            int tempy = head.nodey;
            boolean b=isOver();
            if(can_moveRight()){
                if(!Is.is_nodie){
                    if (b) Is.isOver = true;
                }
                head.nodex -= Node.NODE_DIA;
                add_head(new Node(tempx, tempy));
                deleteTail();
            }else if(can_moveLeft()){
                if(!Is.is_nodie){
                    if (b) Is.isOver = true;
                }
                head.nodex += Node.NODE_DIA;
                add_head(new Node(tempx, tempy));
                deleteTail();
            }else if (can_moveUp()){
                if(!Is.is_nodie){
                    if (b) Is.isOver = true;
                }
                head.nodey -= Node.NODE_DIA;
                add_head(new Node(tempx, tempy));
                deleteTail();
            }else{
                if(!Is.is_nodie){
                    if (b) Is.isOver = true;
                }
                head.nodey += Node.NODE_DIA;
                add_head(new Node(tempx, tempy));
                deleteTail();
            }
        }
    }
    package Snake;
    //游戏开始界面
    import javax.swing.*;
    import java.awt.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    public class StartFrame implements ActionListener{
    
        private  JFrame start_trame = new JFrame("游戏模式选择");
        private  JPanel start_panle = new JPanel();
        private   JButton but1 = new JButton("标准模式");
        private  JButton but2 = new JButton("无尽模式");
        private   JButton but3 = new JButton("强化模式");
        private   JButton but4 = new JButton("游戏信息");
        private   String str;
        public  void start_window(){
            but1.addActionListener(this);
            but2.addActionListener(this);
            but3.addActionListener(this);
            but4.addActionListener(this);
            start_panle.add(but1);
            start_panle.add(but2);
            start_panle.add(but3);
            start_panle.add(but4);
            start_panle.setLayout(new GridLayout(4,1));
            start_trame.add(start_panle);
            start_trame.setSize(400,500);
            start_trame.setVisible(true);
            start_trame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }
    
        @Override
        public void actionPerformed(ActionEvent e) {
            Is.isOver=false;
            if(e.getSource()==but1){
                RunGameMethod.method1();
            }else if(e.getSource()==but2){
                RunGameMethod.method2();
            }else if(e.getSource()==but3){
                RunGameMethod.method3();
            }else{
                str="你可以通过“↑”“↓”“←”“→”控制一条小蛇去吃食物,注意不要撞到边界和自己的身体!
    " +
                        "在无尽模式中你可以任意移动而不担心死亡,在强化模式中有三种不同的食物各有不同的效果!
    " +
                        "快点开始你的游戏之旅吧!
    " +
                        "
    
    " +
                JOptionPane.showMessageDialog(null,str);
            }
        }
    }
  • 相关阅读:
    【Vijos1067】守望者的烦恼【矩阵乘法】
    【Vijos1067】守望者的烦恼【矩阵乘法】
    【洛谷P3514】LIZ-Lollipop【思维】【模拟】
    【洛谷P3514】LIZ-Lollipop【思维】【模拟】
    【CF617E】XOR and Favorite Number【莫队】
    【CF617E】XOR and Favorite Number【莫队】
    【牛客练习赛46-A】华华教奕奕写几何【二分】
    【牛客练习赛46-A】华华教奕奕写几何【二分】
    【洛谷P1494】【BZOJ2038】小Z的袜子【莫队】
    【洛谷P1494】【BZOJ2038】小Z的袜子【莫队】
  • 原文地址:https://www.cnblogs.com/susexuexi011/p/14301607.html
Copyright © 2011-2022 走看看