2020-09-28

JAVA项目作业——贪吃蛇:


游戏所需要实现的东西:蛇(玩家) 地图(网格) 食物(随机生成)
所需实现的功能:玩家的移动(自动移动与控制方向) 吃食物 食物的生成 死亡判定
需要注意的地方:限制玩家移动方向(防止掉头撞自己)

开始写代码:
1.规定长,宽,高。
    定义一个dir用来控制方向以及lastDir判断移动方向是否符合规则
    定义一个level 用来改变蛇的移动速度 一个bool值 用来实现加速
    写一个Point类 用来模拟地图网格以及构造蛇身
    定义一个foodPoint用来存放食物
    定义一个List来存放所蛇的节点

    static int height=30;
    static int weight=30;
    static int unit=30;
    public int dir;
    public int lastDir;
    public int level=1;
    public boolean isAccelerate=false;

    public List<Point> snakeList=new ArrayList<>();
    public List<Color> colorsList=new ArrayList<Color>();

    Point foodPoint=null;
class Point
{
    int x;
    int y;
    Color color;
    public Point() {}
    public Point(int x,int y)
    {
        this.x=x;
        this.y=y;
    }

    public Point(int x,int y,Color c)
    {
        this.x=x;
        this.y=y;
        color=c;
    }

}

2
遍历List逐个遍历并绘制List中的Point 构成蛇身 (绘制函数中同时也绘制了食物的点)
绘制过程中改变下蛇身的颜色让他看起来花里胡哨些。 显得不那么廉价
同时加个边框 让玩家知道地图的界限在哪,不会莫名其妙的挂了 但是由于地图范围在0-30之间
上边框和左边框不知道怎么绘制到x,y-1的位置(也许不能吧) 就用的浅色做警示线
 protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(foodPoint.color);
        g.fillRect(foodPoint.x*unit,foodPoint.y*unit,weight,height);
        JLabel j1=new JLabel("123");
        for(int i=0;i<snakeList.size();i++)//绘制蛇身
        {
            if(i==0)
            {
                g.setColor(Color.red);
            }else if(i%7==0) {
                g.setColor(Color.magenta);
            }else if (i%7==1){
                g.setColor(Color.ORANGE);
            }else if (i%7==2){
                g.setColor(Color.PINK);
            }else if (i%7==3){
                g.setColor(Color.yellow);
            }else if (i%7==4){
                g.setColor(Color.green);
            }else if (i%7==5){
                g.setColor(Color.cyan);
            }else if (i%7==6){
                g.setColor(Color.BLUE);
            }
            g.fillOval(snakeList.get(i).x*unit,snakeList.get(i).y*unit,weight,height);
        }
        for(int i=-1;i<=31;i++)
        {
            for(int j=-1;j<=31;j++)
            {
                if(i==31||j==31)
                {
                    if(j%2==0||i%2==0)
                    {
                        g.setColor(Color.red);
                    }
                    else
                    {
                        g.setColor(Color.orange);
                    }

                    g.fillArc(i*30,j*30,30,30,30,30);
                }
                else if(i==0||j==0)
                {
                    if(j%2==0||i%2==0)
                    {
                        g.setColor(Color.cyan);
                    }
                    else
                    {
                        g.setColor(Color.pink);
                    }
                    g.fillArc(i*30,j*30,30,30,30,30);
                }
            }
        }
    }

3.

该让蛇摆摆动起来了

   两种方法 一种是模拟蛇的移动方式 头先移动 然后蛇身跟着移动。一种是屁股的节点直接跑到头节点

   这里用的是第一种方法,应为开始我以为如果采用第二种方法会导致蛇身的颜色错位 (之前在Unity3D中用的第二种方法颜色错位了)但写完的时候发现

   我是在绘制的时候根据list的索引绘制的 本身的节点不带颜色。后面也懒得改了

   同时通过判定dir+lastDir是否等于0来判断移动方向是否合法

 //移动3
    public void Move(int dir)
    {
        int newX=snakeList.get(0).x;
        int newY=snakeList.get(0).y;
        if(dir+lastDir==0&&snakeList.size()!=0)
        {
            dir=-dir;
        }else {
            lastDir=dir;
        }
        if (dir==1)
        {newY++;}
        else if (dir==2)
        {newX--;}
        else if(dir==-1)
        {newY--;}
        else
        {newX++;}
        //越界死亡
        if(newX<0||newX>weight||newY<0||newY>height)
        {
            JOptionPane.showMessageDialog(this,"你碰到了墙壁","死亡",JOptionPane.WARNING_MESSAGE);
            System.exit(0);
        }
        //碰撞死亡
        if (IsInSneak(newX,newY))
        {
            JOptionPane.showMessageDialog(this,"你碰到了自己的身体","死亡",JOptionPane.WARNING_MESSAGE);
            System.exit(0);
        }

        //使用传统方法移动
        //如果使用为把跑到头前面的移动方式  蛇身的颜色会错位  之前在Unity3D中做的贪吃蛇就出现过这种问题·1
        //好吧不会  这次是绘制时才给蛇身颜色 蛇本身的Point不带颜色
        Point newP=new Point(newX,newY);
        if(newX==foodPoint.x&&newY==foodPoint.y)
            EatFood();
        for (int i=snakeList.size()-1;i>0;i--)
        {
            snakeList.get(i).x=snakeList.get(i-1).x;
            snakeList.get(i).y=snakeList.get(i-1).y;
        }
        snakeList.get(0).x=newX;
        snakeList.get(0).y=newY;

        repaint();
    }

4. 转向与自动移动
通过定时器让蛇自动动起来 并且每次在按键检测时从新设定延迟
本来想在生成食物中的方法中从新设定 但是访问不到timer 所以在键盘检车中调用了setDely
 mainPanle()
    {
        this.setBackground(Color.LIGHT_GRAY);
        //初始化蛇
        Point p1=new Point(15,15,Color.ORANGE);
        snakeList.add(p1);
        foodPoint=SpawnFood();

        ActionListener actionListener=new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Move(dir);
            }
        };
        Timer timer = new Timer(1000/level,actionListener);

        KeyListener keyListener=new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode())
                {
                    case KeyEvent.VK_UP:
                        System.out.println("UP");
                        dir=-1;
                        break;
                    case KeyEvent.VK_DOWN:
                        System.out.println("DOWN");
                        dir=1;
                        break;
                    case KeyEvent.VK_LEFT:
                        System.out.println("LEFT");
                        dir=2;
                        break;
                    case KeyEvent.VK_RIGHT:
                        System.out.println("RIGHT");
                        dir=-2;
                        break;
                    case KeyEvent.VK_SPACE:
                        Move(dir);
                        break;
                    default:
                        isAccelerate=false;
                        break;
                }
                timer.setDelay(500/(level));
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }
        };
        timer.start();
        this.addKeyListener(keyListener);
    }

5 生成食物,吃到食物时level++
Random类来随机x,y 并判断该Point是否在蛇身上来判断该点是否符合规则
 //生成食物
    public Point SpawnFood()
    {

        Random random=new Random();


        Point foodPoint=new Point(random.nextInt(31),random.nextInt(31));

        while (IsInSneak(foodPoint))
        {
            foodPoint.x=random.nextInt(30);
            foodPoint.y=random.nextInt(30);

        }
        return foodPoint;
    }
    //吃到食物
    public void EatFood()
    {
        level++;

        snakeList.add(foodPoint);
        foodPoint=SpawnFood();
        repaint();
    }

6.死亡判定
判断下一个点是否碰到蛇身 (在move方法中判断)





所有代码

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class mainPanle extends JPanel {

    static int height=30;
    static int weight=30;
    static int unit=30;
    public int dir;
    public int lastDir;
    public int level=1;
    public boolean isAccelerate=false;

    public List<Point> snakeList=new ArrayList<>();
    public List<Color> colorsList=new ArrayList<Color>();

    Point foodPoint=null;

    mainPanle()
    {
        this.setBackground(Color.LIGHT_GRAY);
        //初始化蛇
        Point p1=new Point(15,15,Color.ORANGE);
        snakeList.add(p1);
        foodPoint=SpawnFood();

        ActionListener actionListener=new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Move(dir);
            }
        };
        Timer timer = new Timer(1000/level,actionListener);

        KeyListener keyListener=new KeyListener() {
            @Override
            public void keyTyped(KeyEvent e) {
            }
            @Override
            public void keyPressed(KeyEvent e) {
                switch (e.getKeyCode())
                {
                    case KeyEvent.VK_UP:
                        System.out.println("UP");
                        dir=-1;
                        break;
                    case KeyEvent.VK_DOWN:
                        System.out.println("DOWN");
                        dir=1;
                        break;
                    case KeyEvent.VK_LEFT:
                        System.out.println("LEFT");
                        dir=2;
                        break;
                    case KeyEvent.VK_RIGHT:
                        System.out.println("RIGHT");
                        dir=-2;
                        break;
                    case KeyEvent.VK_SPACE:
                        Move(dir);
                        break;
                    default:
                        isAccelerate=false;
                        break;
                }
                timer.setDelay(500/(level));
            }
            @Override
            public void keyReleased(KeyEvent e) {
            }
        };
        timer.start();
        this.addKeyListener(keyListener);
    }

    public boolean IsInSneak(Point p) {
        int flag=0;
        for(int i=0;i<snakeList.size();i++)
        {
            if(p.x==snakeList.get(i).x&&p.y==snakeList.get(i).y)
            {
                return true;
            }
        }
        return false;
    }

    public boolean IsInSneak(int x,int y) {
        int flag=0;
        for(int i=0;i<snakeList.size();i++)
        {
            if(x==snakeList.get(i).x&&y==snakeList.get(i).y)
            {
                return true;
            }
        }
        return false;
    }
    ///绘制
    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        g.setColor(foodPoint.color);
        g.fillRect(foodPoint.x*unit,foodPoint.y*unit,weight,height);
        JLabel j1=new JLabel("123");
        for(int i=0;i<snakeList.size();i++)//绘制蛇身
        {
            if(i==0)
            {
                g.setColor(Color.red);
            }else if(i%7==0) {
                g.setColor(Color.magenta);
            }else if (i%7==1){
                g.setColor(Color.ORANGE);
            }else if (i%7==2){
                g.setColor(Color.PINK);
            }else if (i%7==3){
                g.setColor(Color.yellow);
            }else if (i%7==4){
                g.setColor(Color.green);
            }else if (i%7==5){
                g.setColor(Color.cyan);
            }else if (i%7==6){
                g.setColor(Color.BLUE);
            }
            g.fillOval(snakeList.get(i).x*unit,snakeList.get(i).y*unit,weight,height);
        }
        for(int i=-1;i<=31;i++)
        {
            for(int j=-1;j<=31;j++)
            {
                if(i==31||j==31)
                {
                    if(j%2==0||i%2==0)
                    {
                        g.setColor(Color.red);
                    }
                    else
                    {
                        g.setColor(Color.orange);
                    }

                    g.fillArc(i*30,j*30,30,30,30,30);
                }
                else if(i==0||j==0)
                {
                    if(j%2==0||i%2==0)
                    {
                        g.setColor(Color.cyan);
                    }
                    else
                    {
                        g.setColor(Color.pink);
                    }
                    g.fillArc(i*30,j*30,30,30,30,30);
                }
            }
        }
    }
    //移动3
    public void Move(int dir)
    {
        int newX=snakeList.get(0).x;
        int newY=snakeList.get(0).y;
        if(dir+lastDir==0&&snakeList.size()!=0)
        {
            dir=-dir;
        }else {
            lastDir=dir;
        }
        if (dir==1)
        {newY++;}
        else if (dir==2)
        {newX--;}
        else if(dir==-1)
        {newY--;}
        else
        {newX++;}
        //越界死亡
        if(newX<0||newX>weight||newY<0||newY>height)
        {
            JOptionPane.showMessageDialog(this,"你碰到了墙壁","死亡",JOptionPane.WARNING_MESSAGE);
            System.exit(0);
        }
        //碰撞死亡
        if (IsInSneak(newX,newY))
        {
            JOptionPane.showMessageDialog(this,"你碰到了自己的身体","死亡",JOptionPane.WARNING_MESSAGE);
            System.exit(0);
        }

        //使用传统方法移动
        //如果使用为把跑到头前面的移动方式  蛇身的颜色会错位  之前在Unity3D中做的贪吃蛇就出现过这种问题·1
        //好吧不会  这次是绘制时才给蛇身颜色 蛇本身的Point不带颜色
        Point newP=new Point(newX,newY);
        if(newX==foodPoint.x&&newY==foodPoint.y)
            EatFood();
        for (int i=snakeList.size()-1;i>0;i--)
        {
            snakeList.get(i).x=snakeList.get(i-1).x;
            snakeList.get(i).y=snakeList.get(i-1).y;
        }
        snakeList.get(0).x=newX;
        snakeList.get(0).y=newY;

        repaint();
    }
    //生成食物
    public Point SpawnFood()
    {

        Random random=new Random();


        Point foodPoint=new Point(random.nextInt(31),random.nextInt(31));

        while (IsInSneak(foodPoint))
        {
            foodPoint.x=random.nextInt(30);
            foodPoint.y=random.nextInt(30);

        }
        return foodPoint;
    }
    //吃到食物
    public void EatFood()
    {
        level++;

        snakeList.add(foodPoint);
        foodPoint=SpawnFood();
        repaint();
    }

    public static void main(String[] args) {
        JFrame jFrame=new JFrame();
        jFrame.setVisible(true);
        jFrame.setBounds(0,0,900,900);
        jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        mainPanle mainPanel=new mainPanle();
        jFrame.add(mainPanel);

        mainPanel.requestFocus();
    }
}


class Point
{
    int x;
    int y;
    Color color;
    public Point() {}
    public Point(int x,int y)
    {
        this.x=x;
        this.y=y;
    }

    public Point(int x,int y,Color c)
    {
        this.x=x;
        this.y=y;
        color=c;
    }

}


©️2020 CSDN 皮肤主题: 1024 设计师:上身试试 返回首页