实验二贪吃蛇的游戏开发

一、实验目的
本实验的目的是使学生了解一个小游戏开发的流程,贪吃蛇游戏的开发代码量较大,考验学生的编程能力。
二、实验器材
通过Java运行输出
三、实验内容

1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子。玩家能利用上下左右键控制的移动,“蛇”吃到“豆子”后“蛇”身体加长一节,得分增加,“蛇”碰到边界或蛇头与蛇身相撞,“蛇”死亡,游戏结束。

2)进行交互界面的设计,要有开始键、暂停键和停止退出的选项,能够控制游戏进程。对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐等拓展元素。

四、实验要点

①生成图形面板,建立墙、蛇、豆子

②如何通过代码控制蛇吃到豆子后蛇长度增加

③如何控制蛇前进速度

④背景音乐的插入(待实现)

⑤用界面上的按键响应键盘(经改进)
五、实现代码和运行界面

建立package snake

类GluttonousSnake

package snake;

import java.awt.*;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JMenu;

import javax.swing.JMenuBar;

import javax.swing.JMenuItem;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JTextField;

import javax.swing.border.TitledBorder;


public class GluttonousSnake extends JFrame implements ActionListener {

    private JButton upButton, downButton, leftButton, rightButton;//控制方向按钮

    private JTextField score;//分数

    private SnakeCanvas snake;//蛇的模型



    public GluttonousSnake() {
        super("贪吃蛇");//设置标题
        this.setSize(725, 515);//设置大小
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);//设置退出按键
        this.setLocationRelativeTo(null);//设置窗口居中
        JPanel p = new JPanel();//控制按钮和显示分数面板
        p.setBorder(new TitledBorder("控制和显示区"));//设置这个面板的标题
        this.getContentPane().add(p, "East");//设置此面板的位置
        p.setLayout(new GridLayout(4, 1));//设置此面板的布局方式,为网格布局方式
        JPanel p2 = new JPanel();//在此面板中添加显示分数的面板
        p2.setLayout(new FlowLayout());//设置为流布局方式
        p2.add(new JLabel("得分:"));
        score = new JTextField("0");
        score.setEditable(false);
        p2.add(score);
        p.add(p2);
        //添加按钮,有图片的并添加事件监听
        upButton = new JButton("   up   " );
        upButton.setActionCommand("up");
        upButton.addActionListener(this);
        downButton = new JButton( "   down   ");
        downButton.setActionCommand("down");
        downButton.addActionListener(this);
        leftButton = new JButton("   left    ");
        leftButton.setActionCommand("left");
        leftButton.addActionListener(this);
        rightButton = new JButton( "   right   ");
        rightButton.setActionCommand("right");
        rightButton.addActionListener(this);
        p.add(upButton);
        JPanel p1 = new JPanel();
        p1.setLayout(new GridLayout(1, 2));
        p1.add(leftButton);
        p1.add(rightButton);
        p.add(p1);
        p.add(downButton);

        addMenu();//添加菜单
        start();
        this.setResizable(false);
        this.setVisible(true);

    }

    private void start() {
        snake = new SnakeCanvas();
        this.getContentPane().add(snake);
    }

    private void addMenu() {
        JMenuBar menubar = new JMenuBar();
        this.setJMenuBar(menubar);
        JMenu game = new JMenu("游戏");
        JMenu help = new JMenu("帮助");
        JMenuItem jitemNew = new JMenuItem("新游戏");
        jitemNew.setActionCommand("new");
        jitemNew.addActionListener(this);
        JMenuItem jitemPause = new JMenuItem("暂停");
        jitemPause.setActionCommand("pause");
        jitemPause.addActionListener(this);
        JMenuItem jitemExit = new JMenuItem("退出");
        jitemExit.setActionCommand("exit");
        jitemExit.addActionListener(this);
        game.add(jitemNew);
        game.add(jitemPause);
        game.addSeparator();//菜单里设置分隔线
        game.add(jitemExit);
        menubar.add(game);
        menubar.add(help);
    }

    public static void main(String[] args) {
        new GluttonousSnake();
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getActionCommand().equalsIgnoreCase("exit")) {
            System.exit(EXIT_ON_CLOSE);
        }
        if (e.getSource() instanceof JButton) {
            if (e.getActionCommand().equalsIgnoreCase("up")) {//响应向上按钮按下事件
                snake.setDirect(1);//设置蛇头运动方向
                snake.repaint();//对蛇模型重新画
                snake.timer.start();//定时器开始
                return;
            }
            if (e.getActionCommand().equalsIgnoreCase("down")) {
                snake.setDirect(2);
                snake.repaint();
                snake.timer.start();
                return;
            }
            if (e.getActionCommand().equalsIgnoreCase("left")) {
                snake.setDirect(3);
                snake.repaint();
                snake.timer.start();
                return;
            }
            if (e.getActionCommand().equalsIgnoreCase("right")) {
                snake.setDirect(4);
                snake.repaint();
                snake.timer.start();
                return;
            }
        }
        if (e.getSource() instanceof JMenuItem) {
            if (e.getActionCommand().equalsIgnoreCase("new")) {
                //this.getContentPane().remove(snake);
                snake.init();
                snake.repaint();
                snake.timer.start();
            }
            if (e.getActionCommand().equalsIgnoreCase("pause")) {
                snake.timer.stop();
                JOptionPane.showMessageDialog(this, "继续请按“确定”");
                snake.timer.start();
            }
        }
    }






}

类MapCanvas

package snake;

import java.awt.Canvas;

import java.awt.Color;

import java.awt.Graphics;

//蛇运行的地图

public class MapCanvas extends Canvas{


    public void paint(Graphics g) {
        g.setColor(Color.pink);
        for(int i=30;i<=450;i+=30){
            g.drawLine(0,i,450,i);
        }
        for(int i=30;i<=450;i+=30){
            g.drawLine(i,0,i,450);
        }
        g.drawLine(0, 0, 450, 0);
        g.drawLine(0, 450, 450, 450);
        g.drawLine(0, 0, 0, 450);
        g.drawLine(450, 0, 450, 450);
    }



}

类SnakeCanvas

package sanke;

import java.awt.Color;

import java.awt.Graphics;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.util.Random;

import javax.swing.JOptionPane;

import javax.swing.Timer;

//蛇模型

public class SnakeCanvas extends MapCanvas implements ActionListener {

    private int number = 5;//蛇身的初始长度

    public Timer timer;//定时器

    private Body[] bodys;//蛇身

    private Body food;//食物

    public int score=0;//分数

    private int speed=250;//定时器延时事件

    int direct = 3;//蛇头初始方向

    private int[][] mapflag = new int[455][455];//地图标记

    //初始化

    public void init(){

        this.direct=3;

        this.number=5;

        this.bodys = new Body[this.number];

        mapflag = new int[455][455];

        for (int i = 0, x = 300; i < this.number; i++, x += 30) {

            bodys[i] = new Body(x, 180);

            mapflag[bodys[i].x][bodys[i].y] = 2;//如果是蛇体  设标记为2

        }

        food = creatFood();//创建食物



    }
    public SnakeCanvas() {
        init();
        timer = new Timer(speed, this);//创建定时器对象
        timer.start();//定时器启动
    }

    private class Body {//蛇头成员
        int x, y;

        Body(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public void paint(Graphics g) {//画图
        super.paint(g);
        if(bodys==null){
            return ;
        }
        for (int i = 0; i < this.number; i++) {
            if(i==0){//设置蛇头颜色不同
                g.setColor(Color.pink);
            }else{
                g.setColor(Color.white);
            }
            mapflag[bodys[i].x][bodys[i].y] = 2;
            g.fillOval(bodys[i].x, bodys[i].y, 30, 30);//画蛇体
        }

        g.setColor(Color.red);
        g.fillOval(food.x, food.y, 30, 30);//画食物
    }

    public Body creatFood() {
        int x = 0, y = 0;
        do {//随机生成食物位置

            Random r = new Random();//创建随机数对象
            x = r.nextInt(450);//在0到所给的数中随机产生一个伪随机数
            y = r.nextInt(450);
            //System.out.println(mapflag[x][y]+"!");
        } while (x % 30 != 0 || y % 30 != 0 ||  mapflag[x][y]==2 );//保证位置不是蛇身的部分,并且确保整齐性
        //System.out.println(x + " " + y);
        mapflag[x][y] = 1;//将食物标记为1,下面就可以通过标记的不同来判断是吃到食物还是自身,从而进行不同的操作
        return new Body(x, y);
    }

    public void actionPerformed(ActionEvent e) {
        if(bodys==null){
            return ;
        }
        if(!isMove()){//如果移动失败,游戏结束
            JOptionPane.showMessageDialog(this, "Game Over !");
            bodys=null;
            timer.stop();
            return ;
        }
        repaint();
    }
    //蛇移动,原理:仅需对蛇头进行操作,然后将蛇头之前的位置赋值给现在蛇身的第二个部分,
//让之前的第二个部分复制个现在的第三个部分。。。。以此类推,模拟蛇运动(这是关键)
    public void move(int x,int y) {
        Body[] b=new Body[bodys.length];
        for(int i=0;i<this.number;i++){
            b[i]=new Body(bodys[i].x,bodys[i].y);
        }
        this.bodys[0].x=x;
        this.bodys[0].y=y;
        for(int i=1;i<this.number;i++){
            this.bodys[i]=b[i-1];
        }
        setMapflag();

    }

    private void setMapflag() {//地图标记的刷新
        mapflag=new int[455][455];
        mapflag[food.x][food.y]=1;
        for(int i=0;i<this.number;i++){
            mapflag[bodys[i].x][bodys[i].y]=2;
        }
    }
    //判断是否移动成功
    public boolean isMove() {
        if(bodys==null){
            return false;
        }
        int x=bodys[0].x;
        int y=bodys[0].y;
        switch (this.direct) {//通过方向的不同对蛇头进行不同的操作
            case 1:
                y -= 30;
                break;
            case 2:
                y += 30;
                break;
            case 3:
                x -= 30;
                break;
            case 4:
                x += 30;
                break;
        }
        if(x<0||y>=450||x>=450||y<0){//越界问题
            return false;
        }
        if(mapflag[x][y]==1){//标记为1 ,则为蛇头,要添加蛇身长度
            this.number++;
            addSnake(x,y);//添加蛇长


//          System.out.println("*");

            return true;

        }else if(mapflag[x][y]==2){//标记为2,则为蛇体,即自己吃到自己,游戏结束

//          System.out.println("^");

            return false;

        }else{

//          System.out.println("%");

            move(x,y);

            return true;

        }

    }

    //添加蛇身,类似move();

    private void addSnake(int x, int y) {

        this.score++;

        Body[] b=new Body[bodys.length];

        for(int i=0;i<this.number-1;i++){

            b[i]=new Body(bodys[i].x,bodys[i].y);

        }

        bodys=new Body[this.number];

        this.bodys[0]=new Body(x,y);

        for(int i=1;i<this.number;i++){

            this.bodys[i]=b[i-1];

        }

        setMapflag();

        food = creatFood();

    }



    public void setDirect(int i) {//设置蛇头方向
        this.direct = i;
    }



}

 点击游戏含暂停,重新开始新游戏的选择

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值