Java实现贪吃蛇游戏详解:JSwing代码与关键技术

1 下载量 98 浏览量 更新于2024-09-01 收藏 73KB PDF 举报
Java实现贪吃蛇游戏是一种经典的编程挑战,它结合了基本的图形用户界面设计、数据结构和逻辑控制。本文将深入探讨如何在Java环境中利用JSwing库开发一款贪吃蛇游戏。 首先,文章的核心在于使用Java的面向对象特性,特别是单链表来构建蛇的身体结构。每个蛇的身体部分作为一个节点,通过`next`指针相连,形成一个动态的数据结构。地图被划分成一个二维格子(lattice),这些格子存放在一个`Map`中,其中存储了蛇头的位置,通过更新蛇头的坐标来模拟蛇的移动。 移动机制是关键,游戏的主体部分。在Java实现中,蛇的移动分为两个步骤:头部移动和尾巴移动。头部移动根据用户的输入(例如键盘上的wasd键)来决定方向,这涉及到键盘事件监听。当蛇头移动时,需要检查是否吃到食物,若成功则游戏状态改变(`getFood`标记为true),并更新地图。同时,尾部移动则涉及更新`next`指针,确保蛇身的连续性,当蛇头到达尾巴的位置时,将尾巴移到下一个格子,同时更新尾部的指针。 为了保证游戏的流畅性,引入了一个`directionChange`标志,防止在一次运动周期内频繁转向。当用户改变方向时,这个标志会在新的方向确定后变为false,等待下一次移动时再更新蛇头的方向。 在窗口设计方面,游戏视图继承自`JPanel`,负责渲染地图和蛇的形状。`Graphics.draw()`方法被用来绘制每个格子以及蛇的轮廓。核心部分的代码展示了如何初始化地图大小(`MAP_SIZE`)、管理游戏状态(如食物获取、游戏结束)以及自动移动蛇的逻辑。 Java实现的贪吃蛇游戏通过巧妙地利用数据结构、事件驱动的控制流程和图形用户界面组件,提供了一次实践面向对象编程和基本游戏机制的良好机会。这个项目不仅锻炼了开发者对Java语言的理解,也加深了对图形用户界面编程和算法设计的认识。对于希望学习Java或提升编程能力的人来说,这篇文章提供了实用的参考和实践案例。
2018-03-05 上传
可以运行! (以下代码只是其中的一个类) package chy.snake.entities; import java.awt.Color; import java.awt.Graphics; import java.awt.Point; import java.util.HashSet; import java.util.LinkedList; import java.util.Set; import chy.snake.listener.SnakeListener; import chy.snake.util.Global; public class Snake { public static final int up = 1; public static final int down = -1; public static final int left = -2; public static final int right = 2; private int oldDirection,newDirection; //newDirection:一次时间 间隔内输入的最后方向 private Point oldTail; private boolean life; //life 为 true或者false,初始为true, 用于118行 private LinkedList<Point> body = new LinkedList<Point> (); //需要经常访问蛇的第一个和最后一个节点,使用链表LinkedList存放蛇的身体节点,因为它有getFirst(),getLast(),removeLast(),方法 private Set<SnakeListener> listeners = new HashSet<SnakeListener>(); public Snake(){ init(); } public void init(){ //初始化 int x = Global.WIDTH/2; int y = Global.HEIGHT/2; for(int i=0;i<3;i++){ //初始长度3 body.addLast(new Point(x-i,y)); //是addLast } oldDirection = newDirection = right; //初始方向 右 life = true; } public void die(){ life = false; } public void move(){ System.out.println("Snake's move"); if (!(oldDirection + newDirection == 0)){ oldDirection = newDirection; } //1.去尾 oldTail = body.removeLast(); int x = body.getFirst().x; int y = body.getFirst().y; //蛇头的x,y坐标 switch(oldDirection){ case up: y--; break; case down: y++; break; case left: x--; break; case right: x++; break; } Point newHead = new Point(x,y); //2.加头 body.addFirst(newHead); } public void changeDirection(int direction){ /*无效方向:在蛇的这一次移动之后和下一次移动之前的 这个时间间隔内输入了多个方向,只有最后一个方向 是 有效方向,其余的都为无效方向*/ System.out.println("Snake's changeDirection"); newDirection = direction; //将一个时间间隔内按得最后方向,赋给 newDirection } public void eatFood(){ System.out.println("Snake's eatFood"); body.addLast(oldTail); //后面的节点不去掉 } public boolean isEatFood(){ System.out.println("Snake's isEatFood"); return false; } public boolean isEatBody(Snake snake){ //比较蛇是否吃到身体 System.out.println("snake's isEatBody"); for(int i= 1;i<body.size();i++){ //i 从蛇头结点的下一个节点开始,排除蛇头结点 if(body.get(i).equals(this.getHead())){ //如果i 的节点 和 头结点 相同 return true; } } return false; } public void drawMe(Graphics g){ System.out.println("Snake's drawMe"); g.setColor(Color.GREEN); //设置蛇的颜色 for(Point p : body){ g.fill3DRect(p.x * Global.CELL_SIZE, p.y * Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true); } } public Point getHead(){ //得到蛇头节点,判断吃食物 return body.getFirst(); } private class SnakeDriver implements Runnable{ //线程,不停的调用move方法 @Override public void run() { // TODO 自动生成的方法存根 while(life){ // 42和46行,life为true 或者false move(); for(SnakeListener l : listeners){ l.snakeMoved(Snake.this); //循环,依次调用SnakeMoved方法 } try { Thread.sleep(300); } catch (InterruptedException e) { // TODO 自动生成的 catch 块 e.printStackTrace(); } } } } public void start(){ new Thread(new SnakeDriver()).start(); //启动线程的方法 } public void addSnakeListener(SnakeListener l){ if(l != null){ this.listeners.add(l); } } }