贪吃蛇是一个大家耳熟能详的小游戏,有很多语言的版本,游戏玩法很简单。
这里使用canvas画板实现。
首先定义一个Snake类,该类是一个列表,存放了蛇上的坐标点,以及蛇的节点的绘制、清除、蛇的移动方向等
class Snake extends Arraylist<Point>{
...........
}
接着创建画板GameCanvas类继承Canvas类,该类是程序主要构成,大部分操作放在该类中,包括监听键盘按键,游戏的开始、结束、暂停等操作
class GameCanvas extends Canvas{
...........
}
对于程序的窗口也需要一个类SnakeGame类,该类继承了JFrame,显示程序的主界面,同时显示开始按钮和分数提示等等信息,在窗体中把GameCanvas类添加到窗体中
public class SnakeFrame extends JFrame{
.......
public SnakeFrame(){
JPanel pane=new JPanel(null);
canvas = new GameCanvas(this);
pane.add(canvas);
}
}
运行效果图如下:
程序完整代码如下:
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;
public class SnakeFrame extends JFrame{
/**
*
*/
private static final long serialVersionUID = 2487843782670565160L;
static Color BGCOLOR =Color.BLACK;//定义背景色
static Color SNAKECOLOR =Color.BLUE;//定义蛇的颜色
static Color BEANCOLOR =Color.RED;//食物的颜色
static Color EATEDBEANCOLOR =Color.CYAN;//吃的时候食物的颜色
private String info="请使用键盘上的<上下左右>按钮控制方向-空格暂停-ESC退出";
private JLabel helplab=new JLabel(info);
private JLabel scorelab=new JLabel("得分:0");
private JButton beginbnt=new JButton("开始游戏");
private GameCanvas canvas;
public void setLable(String str){
scorelab.setText(str);
}
public SnakeFrame() {
setTitle("-贪吃蛇-");//设置标题
this.setSize(600,400);//设置窗体大小
JPanel pane=new JPanel(null);//定义窗体面板
beginbnt.setBounds(430, 150, 100, 50);//设置开始按钮
pane.add(beginbnt);
beginbnt.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
canvas.resetGame();
beginbnt.setFocusable(false);//按钮失去焦点
canvas.requestFocus();//画布获得焦点
}
});
//设置帮助信息
helplab.setBounds(10, 320, 400, 30);
pane.add(helplab);
//设置分数显示标签
scorelab.setBounds(430, 250, 200, 30);
pane.add(scorelab);
//创建游戏面板
canvas = new GameCanvas(this);
canvas.setBounds(10, 10, 400, 300);
//添加到窗体
pane.add(canvas);
setContentPane(pane);
//窗体不可变大小
this.setResizable(false);
//居中
this.setLocationRelativeTo(null);
//关闭窗体程序结束
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
SnakeFrame sFrame=new SnakeFrame();
sFrame.setVisible(true);
}
}
/**
*
* @author cslg.yao
*
*/
class GameCanvas extends Canvas{
/**
*
*/
private static final long serialVersionUID = 8444419077424283797L;
private int horizontalCount,verticalCount;//明确横向和纵向大小
private int x,y;
private Snake snake;//蛇列表
private LinkedList<Point> eatedBean = new LinkedList<>();
private Iterator<Point> snakeSq;
public Timer timer;//定时器,自动移动
private int direction=2;//方向
private int score;//得分
private Point bean= new Point(), eatBean;
private boolean mark;
private Graphics2D g;
private boolean hasStoped =true;
private SnakeFrame game;
public GameCanvas(SnakeFrame gamefrm) {
this();
game=gamefrm;
}
public GameCanvas() {
//设置绘制的尺寸范围
this.horizontalCount=25;
this.verticalCount=20;
this.x=400/25;
this.y=300/20;
this.addKeyListener(new KeyHandler());
//开始
timer = new Timer(180, new TimerHandler());
snake = new Snake();
hasStoped =false;
setBackground(SnakeFrame.BGCOLOR);
}
private class KeyHandler extends KeyAdapter{
public void keyPressed(KeyEvent e){
if (e.getKeyCode()==10) {
resetGame();
}else if (e.getKeyCode() == 27) {
timer.stop();
if (JOptionPane.showConfirmDialog(null, "你确定退出吗?")==0) {
System.exit(0);
}
timer.start();
}
else if (e.getKeyCode()==37 && snake.snakeDirection !=2) {
direction=4;
}
else if (e.getKeyCode()==39 && snake.snakeDirection !=4) {
direction=2;
}
else if (e.getKeyCode()==38 && snake.snakeDirection !=3) {
direction=1;
}
else if (e.getKeyCode()==40 && snake.snakeDirection !=1) {
direction=3;
}else if (e.getKeyCode()==32) {
if (!hasStoped) {
if (!mark) {
timer.stop();
mark=true;
}else {
timer.start();
mark=false;
}
}
}
}
}
private class TimerHandler implements ActionListener{
@Override
public synchronized void actionPerformed(ActionEvent e) {
Point temp=(Point)snake.get(snake.size()-1);
snakeSq=snake.iterator();
while (snakeSq.hasNext()) {
Point tempPoint = (Point)snakeSq.next();
if (temp.equals(tempPoint)&&snakeSq.hasNext()!=false) {
timer.stop();
stopGame();
JOptionPane.showMessageDialog(null,"游戏结束!");
}
}
//判断游戏结束
if ((temp.x ==0 &&direction==4)||(temp.x==horizontalCount-1 &&direction==2)||(temp.y==0&&direction==1)||(temp.y==verticalCount-1&&direction==3) ) {
timer.stop();
stopGame();
JOptionPane.showMessageDialog(null,"游戏结束!");
}
if (direction!=snake.snakeReDirection) {
moveSnake(direction);
}
snake.drawSnake(getGraphics(),x,y);
drawBeanAndEBean(getGraphics());
}
}
/**
* 游戏结束
*/
public void stopGame(){
this.hasStoped = true;
this.timer.stop();
Graphics2D g=(Graphics2D)GameCanvas.this.getGraphics();
g.setColor(SnakeFrame.BGCOLOR);
super.paint(g);
}
/**
* 游戏开始
*/
public void resetGame(){
System.gc();
this.hasStoped=false;
Graphics2D g=(Graphics2D)GameCanvas.this.getGraphics();
g.setColor(SnakeFrame.BGCOLOR);
super.paint(g);
this.snake = new Snake();
this.createBean(bean);
this.eatedBean.clear();
snake.drawSnake(getGraphics(),x,y);
this.timer.start();
this.direction=2;
this.score=0;
}
/**
* 蛇的移动
* @param direction
*/
private void moveSnake(int direction){
//判断是否吃到食物
if (snake.checkBeanIn(this.bean)) {
this.score+=100;
game.setLable("得分:"+this.score+" ");
//添加到吃过的食物列表
this.eatedBean.add(new Point(this.bean));
//创建一个新的食物
this.createBean(this.bean);
}
//
snake.changeDirection((Point)snake.get(snake.size()-1),direction);
Point p=(Point)snake.get(0);
if (eatedBean.size()!=0) {
if (eatedBean.getFirst().equals(p)) {
eatedBean.remove(0);
}else {
snake.clearEndSnakePiece(getGraphics(),p.x,p.y,x,y);
snake.removeTail();
}
}else {
snake.clearEndSnakePiece(getGraphics(),p.x,p.y,x,y);
snake.removeTail();
}
}
/**
* 绘制食物
* @param g
*/
private void drawBeanAndEBean(Graphics g){
//设置食物的颜色
g.setColor(SnakeFrame.BEANCOLOR);
this.drawPiece(g,this.bean.x,this.bean.y);
//设置正在吃的食物颜色
g.setColor(SnakeFrame.EATEDBEANCOLOR);
snakeSq =eatedBean.iterator();
while (snakeSq.hasNext()) {
Point tempPoint = (Point) snakeSq.next();
this.drawPiece(g,tempPoint.x,tempPoint.y);
}
}
/**
* 绘制填充的矩形块
* @param g
* @param x
* @param y
*/
private void drawPiece(Graphics g,int x,int y){
g.fillRect(this.x*x+1, this.y*y+1, this.x-2, this.y-2);
}
/**
* 随机创建食物
* @param temp
*/
private void createBean(Point temp){
while(true){
temp.x =(int)(Math.random()*this.horizontalCount);
temp.y =(int)(Math.random()*this.verticalCount);
snakeSq =snake.iterator();
while (snakeSq.hasNext()) {
if (snakeSq.next().equals(new Point(temp.x,temp.y))) {
break;
}
}
break;
}
}
}
class Snake extends ArrayList<Point>{
/**
*
*/
private static final long serialVersionUID = -2545954212854332230L;
public int snakeDirection=2;
public int snakeReDirection=4;
public Snake() {
/**
* 添加默认节点
*/
this.add(new Point(3, 3));
this.add(new Point(4, 3));
this.add(new Point(5, 3));
}
/**
* 根据方向添加蛇的节点
* @param temp
* @param direction
*/
public void changeDirection(Point temp,int direction){
this.snakeDirection =direction;
switch (direction) {
case 1://向上
this.snakeReDirection =3;
this.add(new Point(temp.x, temp.y-1));
break;
case 2://向右
this.snakeReDirection =4;
this.add(new Point(temp.x+1, temp.y));
break;
case 3://向下
this.snakeReDirection =1;
this.add(new Point(temp.x, temp.y+1));
break;
case 4://向左
this.snakeReDirection =2;
this.add(new Point(temp.x-1, temp.y));
break;
default:
break;
}
}
/**
* 清除
* @param bean
* @return
*/
public boolean checkBeanIn(Point bean) {
Point temp =(Point)this.get(this.size()-1);
if (temp.equals(bean)) {
return true;
}
return false;
}
/**
* 删除
*/
public void removeTail(){
this.remove(0);
}
/**
* 绘制蛇
* @param g
* @param x
* @param y
*/
public void drawSnake(Graphics g,int x,int y){
g.setColor(SnakeFrame.SNAKECOLOR);
Iterator<Point> snakeSq = this.iterator();
while (snakeSq.hasNext()) {
Point p = (Point) snakeSq.next();
g.fillRect(x*p.x+1, y*p.y+1, x-2, y-2);
}
}
/**
* 清除节点
* @param g
* @param x1
* @param y1
* @param x2
* @param y2
*/
public void clearEndSnakePiece(Graphics g,int x1,int y1,int x2,int y2){
g.setColor(SnakeFrame.BGCOLOR);
g.fillRect(x1*x2+1, y1*y2+1, x2-2, y2-2);
}
}