软件实习项目二:贪吃蛇的游戏开发——代码

Node.java

package gyt;

//一个点的大小以及坐标位置
class Node
{
	public static final int W = 20;
	public static final int H = 20;
	int x;
	int y;
	
	public Node(int x, int y)
	{
		this.x = x;
		this.y = y;
	}
}

Snake.java

package gyt;

import java.util.ArrayList;
//贪吃蛇的类,包括属性和方法
class Snake
{
	boolean isRun;  //是否在运行
	ArrayList<Node> body;  //身体的列表,里面元素是每一节身体
	Node food;
	int direction; //方向
	int score;  //得分
	int status;//̬状态
	int speed; //速度
	public static final int SLOW = 500;//速度慢/中/快
	public static final int MID = 300;
	public static final int FAST = 100;
	public static final int RUNNING = 1;//状态,运行中/暂停/游戏结束
	public static final int PAUSED = 2;
	public static final int GAMEOVER = 3;
	public static final int LEFT = 1;//贪吃蛇的方向
	public static final int UP = 2;
	public static final int RIGHT = 3;
	public static final int DOWN = 4;
	
	public Snake()//初始化贪吃蛇
	{
		speed = Snake.SLOW;
		score = 0;
		isRun = false;
		status = Snake.PAUSED;
		direction = Snake.RIGHT;
		body = new ArrayList<Node>();
		body.add(new Node(60,20));//最开始蛇的长度只有三格
		body.add(new Node(40,20));
		body.add(new Node(20,20));
		makeFood();//生成食物
	}
	
	//判断吃没吃到食物
	private boolean isEaten()
	{
		Node head = body.get(0);//获取头部位置
		if (direction == Snake.RIGHT && (head.x + Node.W) == food.x//方向向右,且右边一个就是食物(蛇头横坐标加点宽度等于食物横坐标),那么就吃到了,返回true;下面内容意思一样
				&& head.y == food.y)
			return true;
		else if(direction == Snake.LEFT && (head.x - Node.W) == food.x 
				&& head.y == food.y)
			return true;
		else if(direction == Snake.UP && (head.y - Node.H) == food.y 
				&& head.x == food.x)
			return true;
		else if(direction == Snake.DOWN && (head.y + Node.H) == food.y 
				&& head.x == food.x)
			return true;
		else
			return false;			
	}
	
	//判断是否发生碰撞,包括碰到墙壁和自己身体
	public boolean isCollsion() 
	{
		Node head = body.get(0);
		
		//碰到墙返回true
		if(direction == Snake.RIGHT && head.x == 280)//方向向右并且碰到右边界;下面内容意思一样
			return true;
		else if(direction == Snake.UP && head.y == 0)
			return true;
		else if(direction == Snake.LEFT && head.x == 0)
			return true;
		else if(direction == Snake.DOWN && head.y == 380)
			return true;
		
		//碰到身体返回true
		Node temp = null;
		int i;
		for(i =3; i < body.size(); i++)//遍历身体每一格,如果头和身体重合就是碰到;从3开始因为蛇身至少要为四节才有可能咬尾
		{
			temp = body.get(i);
			if (temp.x == head.x && temp.y == head.y)
				return true;
		}
		if(i < body.size())
			return true;
		return false;
	}
	
	//随机产生一个食物
	public void makeFood()
	{
		boolean isInBody = true;//true表示被吃了
		int ax = 0, ay = 0;
		int X = 0, Y = 0;
		while(isInBody)//当食物被蛇吃了,就立刻产生食物
		{
			isInBody = false;
			ax = (int)(Math.random() * 15);//math.random是随机数
			ay = (int)(Math.random() * 20);
			X = ax*Node.W;
			Y = ax*Node.H;
			for(Node temp :body)
			{
				if(X== temp.x && Y == temp.y)
					isInBody = true;
			}
		}
		food = new Node( X, Y); 
	}
	
	//改变方向
	public void changeDerection(int newDer)
	{
		if(direction % 2 !=  newDer % 2) //不能改变为相反的方向,其他都可以
		{
			direction = newDer;
		}
	}
	
	public void move()//移动蛇
	{
		if(isEaten())    
		{
			body.add(0,food);//吃了的话身体加一格,加分,随机产生食物
			score += 10;
			makeFood();
		}
		else if(isCollsion())
		{
			isRun = false;
			status = Snake.GAMEOVER;//碰撞的话游戏结束
		}
		else if(isRun)//正在运行的话,要时刻判断是否改变了方向
		{
			Node head = body.get(0);
			int X = head.x;
			int Y = head.y;
			switch(direction)
			{
			case RIGHT:
				X += Node.W;
				break;
			case LEFT:
				X -= Node.W;
				break;
			case UP:
				Y -= Node.H;
				break;
			case DOWN:
				Y += Node.H;
				break;
			}
			body.add(0,new Node(X,Y));//用前面多一节,后面少一节的方式来表示移动
			body.remove(body.size()-1);   
		}
	}
}


SnakeFrame.java

package gyt;

import java.awt.Color;
import java.awt.Component;

import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.util.ArrayList;

import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;

public class SnakeFrame extends JFrame
{
	private JLabel statusLabel;
	private JLabel speedLabel;
	private JLabel scoreLabel;
	private JPanel snakePanel;
	private Snake snake;
	private JMenuBar bar;		
	private JMenu gameMenu;		
	private JMenu helpMenu;
	private JMenu speedMenu;
	private JMenuItem newItem;
	private JMenuItem pauseItem;
	private JMenuItem beginItem;
	private JMenuItem aboutItem;		
	private JMenuItem slowItem;
	private JMenuItem midItem;
	private JMenuItem fastItem;
	
	public SnakeFrame()
	{
		init();//初始化
		ActionListener actionListener = event ->
		{
			if(event.getSource() == pauseItem)
				snake.isRun = false;
			else if(event.getSource() == beginItem)
				snake.isRun = true;
			else if(event.getSource() == newItem)
				newGame();
			else if(event.getSource() == slowItem)
			{
				snake.speed = Snake.SLOW;
				speedLabel.setText("slow");
			}
			else if(event.getSource() == midItem)
			{
				snake.speed = Snake.MID;
				speedLabel.setText("mid");
			}
			else if(event.getSource() == fastItem)
			{
				snake.speed = Snake.FAST;
				speedLabel.setText("fast");
			}
		};
		
		pauseItem.addActionListener(actionListener);//各种监听
		beginItem.addActionListener(actionListener);
		newItem.addActionListener(actionListener);
		slowItem.addActionListener(actionListener);
		midItem.addActionListener(actionListener);
		fastItem.addActionListener(actionListener);
		aboutItem.addActionListener(actionListener);
		
		addKeyListener(new KeyAdapter()
			{
				public void keyPressed(KeyEvent event)
				{
					switch(event.getKeyCode())
					{
					case KeyEvent.VK_DOWN:
						snake.changeDerection(Snake.DOWN);
						break;
					case KeyEvent.VK_UP:
						snake.changeDerection(Snake.UP);
						break;
					case KeyEvent.VK_LEFT:
						snake.changeDerection(Snake.LEFT);
						break;
					case KeyEvent.VK_RIGHT:
						snake.changeDerection(Snake.RIGHT);
						break;
					case KeyEvent.VK_SPACE:
						if(snake.isRun == true)
						{
							snake.isRun = false;
							snake.status = Snake.PAUSED;
							break;
						}
						else
						{
							snake.isRun = true;
							snake.status = Snake.RUNNING;
							break;
						}
					}
				}
			});
		
	}
	private void init()//初始化
	{
		snake = new Snake();
		setSize(380,460);//面板大小
		setLayout(null);//将容器的布局设为绝对布局	
		this.setResizable(false);//用户不可以自由改变该窗体的大小
		
		bar = new JMenuBar();//菜单栏
		gameMenu = new JMenu("Game");		
		gameMenu.add((newItem = new JMenuItem("New Game")));
		gameMenu.add((pauseItem = new JMenuItem("Pause")));
		gameMenu.add((beginItem = new JMenuItem("continue")));
		
		helpMenu = new JMenu("help");		
		helpMenu.add((aboutItem = new JMenuItem("about")));
		
		speedMenu = new JMenu("speed");
		speedMenu.add(( slowItem = new JMenuItem("slow")));
		speedMenu.add(( midItem  = new JMenuItem("mid")));
		speedMenu.add(( fastItem = new JMenuItem("fast")));
		
		bar.add(gameMenu);
		bar.add(helpMenu);
		bar.add(speedMenu);
		setJMenuBar(bar);
		
		statusLabel = new JLabel();//状态栏
		speedLabel = new JLabel();//速度栏
		scoreLabel = new JLabel();//分数栏
		snakePanel = new JPanel();//贪吃蛇运行的区域
		
		snakePanel.setBounds(0, 0, 300, 400);// 从左上角(0,0)开始 ,大小 300 * 400	
		snakePanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));
		add(snakePanel);
		//设置位置和大小
		statusLabel.setBounds(310,25,60,20);//四个参数依次是该组件在JFrame中的x坐标、y坐标、组件宽度、组件高度
		add(statusLabel);
		speedLabel.setBounds(310,75,60,20);
		add(speedLabel);
		scoreLabel.setBounds(310,125,60,20);
		add(scoreLabel);
		
		JLabel temp = new JLabel("状态");
		temp.setBounds(310, 5, 60, 20);
		add(temp);
		temp = new JLabel("速度");
		temp.setBounds(310,55,60,20);
		add(temp);
		temp = new JLabel("分数");
		temp.setBounds(310, 105, 60, 20);
		add(temp);			
	}
	private void newGame()
	{
		this.remove(snakePanel);//移除原来的状态、分数等
		this.remove(statusLabel);
		this.remove(scoreLabel);
		speedLabel.setText("slow");
		statusLabel = new JLabel();//新建状态、分数等
		scoreLabel = new JLabel();
		snakePanel = new SnakePanel(snake);
		snakePanel.setBounds(0,0,300,400);
		snakePanel.setBorder(BorderFactory.createLineBorder(Color.DARK_GRAY));  
		//两个线程,一个负责贪吃蛇的运行,另一个负责计算它的状态分数等
		Runnable r1 = new SnakeRunnable(snake,snakePanel);
		Runnable r2 = new StatusRunnable(snake,statusLabel,scoreLabel);
		Thread t1 = new Thread(r1);
		Thread t2 = new Thread(r2);
		t1.start();
		t2.start();
		add(snakePanel);
		statusLabel.setBounds(310,25,60,20);
		add(statusLabel);
		scoreLabel.setBounds(310,125,60,20);
		add(scoreLabel);
	}
}

SnakeGame.java

package gyt;

import java.awt.EventQueue;
import javax.swing.JFrame;

public class SnakeGame
{
	public static void main(String[] args) 
	{
		EventQueue.invokeLater(()->//使事件派发线程上的可运行对象排队
		{
			SnakeFrame frame = new SnakeFrame();
			frame.setTitle("̰贪吃蛇");
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//使用 System exit 方法退出应用程序
			frame.setVisible(true);//可以运行开始画图了
		});
	}
}


SnakePanel.java

package gyt;

import java.awt.EventQueue;
import javax.swing.JFrame;

public class SnakeGame
{
	public static void main(String[] args) 
	{
		EventQueue.invokeLater(()->//使事件派发线程上的可运行对象排队
		{
			SnakeFrame frame = new SnakeFrame();
			frame.setTitle("̰贪吃蛇");
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//使用 System exit 方法退出应用程序
			frame.setVisible(true);//可以运行开始画图了
		});
	}
}


SnakeRunnable.java

package gyt;

import java.awt.EventQueue;
import javax.swing.JFrame;

public class SnakeGame
{
	public static void main(String[] args) 
	{
		EventQueue.invokeLater(()->//使事件派发线程上的可运行对象排队
		{
			SnakeFrame frame = new SnakeFrame();
			frame.setTitle("̰贪吃蛇");
			frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//使用 System exit 方法退出应用程序
			frame.setVisible(true);//可以运行开始画图了
		});
	}
}


StatusRunnable.java

package gyt;

import javax.swing.JLabel;

class StatusRunnable implements Runnable
{
	private JLabel statusLabel;
	private JLabel scoreLabel;
	private Snake snake;
	
	//另一个线程,负责计算蛇的状态、分数
	public StatusRunnable(Snake snake, JLabel statusLabel, JLabel scoreLabel)
	{
		this.statusLabel = statusLabel;
		this.scoreLabel = scoreLabel;
		this.snake = snake;
	}
	
	public void run()
	{
		String sta = "";
		String spe = "";
		
		while(true)
		{
			switch(snake.status)
			{
			case Snake.RUNNING:
				sta = "running";
				break;
			case Snake.PAUSED:
				sta = "Paused";
				break;
			case Snake.GAMEOVER:
				sta = "GameOver";
				break;
			}
			statusLabel.setText(sta);//显示状态
			scoreLabel.setText("" + snake.score);//显示分数
			try {
				Thread.sleep(100);
			}catch(Exception e) {}//如果运行代码出现异常,什么也不做		
		}
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值