多平台统一管理软件接口,如何实现多平台统一管理软件接口
269
2022-11-29
java实现贪吃蛇小游戏
本文实例为大家分享了java实现贪吃蛇小游戏的具体代码,供大家参考,具体内容如下
这是MVC模式的完整Java项目,编译运行SnakeApp.java即可开始游戏。
可扩展功能:
1、积分功能:可以创建得分规则的类(模型类的一部分), 在GameController的run()方法中计算得分
2、变速功能:比如加速功能,减速功能,可以在GameController的keyPressed()方法中针对特定的按键设置每一次移动之间的时间间隔,将Thread.sleep(Settings.DEFAULT_MOVE_INTERVAL);替换为动态的时间间隔即可
3、更漂亮的游戏界面:修改GameView中的drawXXX方法,比如可以将食物渲染为一张图片,Graphics有drawImage方法
View
SnakeApp.java
/*
* 属于View,用来根据相应的类展示出对应的游戏主界面,也是接收控制信息的第一线。
*/
public class SnakeApp {
public void init() {
//创建游戏窗体
JFrame window = new JFrame("一只长不大的蛇");
//初始化500X500的棋盘,用来维持各种游戏元素的状态,游戏的主要逻辑部分
Grid grid = new Grid(50*Settings.DEFAULT_NODE_SIZE,50*Settings.DEFAULT_NODE_SIZE);
//传入grid参数,新建界面元素对象
GameView gameView = new GameView(grid);//绘制游戏元素的对象
//初始化面板
gameView.initCanvas();
//根据棋盘信息建立控制器对象
GameController gameController = new GameController(grid);
//设置窗口大小
window.setPreferredSize(new Dimension(526,548));
//往窗口中添加元素,面板对象被加入到窗口时,自动调用其中的paintComponent方法。
window.add(gameView.getCanvas(),BorderLayout.CENTER);
//画出蛇和棋盘和食物
GameView.draw();
//注册窗口监听器
window.addKeyListener((KeyListener)gameController);
//启动线程
new Thread(gameController).start();
//窗口关闭的行为
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置窗口大小不可变化
window.setResizable(false);
//渲染和显示窗口
window.pack();
window.setVisible(true);
}
//可以忽略,以后每个类中都有这么一个测试模块
public static void main(String[] args) {
SnakeApp snakeApp = new SnakeApp();
snakeApp.init();
}
}
GameView.java
/*
* 属于View,用于绘制地图、蛇、食物
*/
/* Graphics 相当于一个画笔。对象封装了 Java 支持的基本呈现操作所需的状态信息。此状态信息包括以下属性:
要在其上绘制的 Component 对象。
呈现和剪贴坐标的转换原点。
当前剪贴区。
当前颜色。
当前字体。
当前逻辑像素操作函数(XOR 或 Paint)。
当前 XOR 交替颜色
*/
/* java.awt.Component的repaint()方法
作用:更新组件。
如果此组件不是轻量级组件,则为了响应对 repaint 的调用,AWT 调用 update 方法。可以假定未清除背景。
Component 的 update 方法调用此组件的 paint 方法来重绘此组件。为响应对 repaint 的调用而需要其他工作的子类通常重写此方法。重写此方法的 Component 子类应该调用 super.update(g),或者直接从其 update 方法中调用 paint(g)。
图形上下文的原点,即它的(0,0)坐标点是此组件的左上角。图形上下文的剪贴区域是此组件的边界矩形。
*/
public class GameView {
private final Grid grid;
private static JPanel canvas;//画板,用于在这上面制作画面,然后返回。
public GameView(Grid grid) {
this.grid = grid;
}
//重新绘制游戏界面元素http://,不断重新调用paintComponent方法覆盖原本的面板。
public static void draw() {
canvas.repaint();
}
//获取画板对象的接口
public JPanel getCanvas() {
return canvas;
}
//对画板进行初始化
public void initCanvas() {
canvas = new JPanel() {
//指向一个方法被覆盖的新面板子类对象
//paintComponent()绘制此容器中的每个组件,Swing会在合适的时机去调用这个方法,展示出合适的界面,这就是典型的回调(callback)的概念。
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics); //这里必须调用一下父类 也就是 container的重绘方法,否则表现为之前的绘图不会覆盖
drawGridBackground(graphics);//画出背景网格线
drawSnake(graphics, grid.getSnake());//画蛇
drawFood(graphics, grid.getFood());//画食物
}
};
}
//画蛇
public void drawSnake(Graphics graphics, Snake snake) {
for(Iterator
Node bodyNode = (Node)i.next();
drawSquare(graphics, bodyNode,Color.BLUE);
}
}
//画食物
public void drawFood(Graphics graphics, Node food) {
drawCircle(graphics,food,Color.ORANGE);
}
//画格子背景,方便定位Snake运动轨迹,横竖各以10为单位的50个线。
public void drawGridBackground(Graphics graphics) {
graphics.setColor(Color.GRAY);
canvas.setBackground(Color.BLACK);
for(int i=0 ; i < 50 ; i++) {
graphics.drawLine(0, i*Settings.DEFAULT_NODE_SIZE, this.grid.getWidth(), i*Settings.DEFAULT_NODE_SIZE);
}
for(int i=0 ; i <50 ; i++) {
graphics.drawLine(i*Settings.DEFAULT_NODE_SIZE, 0, i*Settings.DEFAULT_NODE_SIZE , this.grid.getHeight());
}
graphics.setColor(Color.red);
graphics.fillRect(0, 0, this.grid.width, Settings.DEFAULT_NODE_SIZE);
graphics.fillRect(0, 0, Settings.DEFAULT_NODE_SIZE, this.grid.height);
graphics.fillRect(this.grid.width, 0, Settings.DEFAULT_NODE_SIZE,this.grid.height);
graphics.fillRect(0, this.grid.height, this.grid.width+10,Settings.DEFAULT_NODE_SIZE);
}
/*
* public abstract void drawLine(int x1,int y1,int x2,int y2)
在此图形上下文的坐标系中,使用当前颜色在点 (x1, y1) 和 (x2, y2) 之间画一条线。
参数:
x1 - 第一个点的 x 坐标。
y1 - 第一个点的 y 坐标。
x2 - 第二个点的 x 坐标。
y2 - 第二个点的 y 坐标。
*/
//提供直接出现游戏结束的选项框的功能。
public static void showGameOverMessage() {
JOptionPane.showMessageDialog(null,"游戏结束","短暂的蛇生到此结束", JOptionPane.INFORMATION_MESSAGE);
}
//画图形的具体方法:
private void drawSquare(Graphics graphics, Node squareArea, Color color) {
graphics.sLHqUpQJetColor(color);
int size = Settings.DEFAULT_NODE_SIZE;
graphics.fillRect(squareArea.getX(), squareArea.getY(), size - 1, size - 1);
}
private void drawCircle(Graphics graphics, Node squareArea, Color color) {
graphics.setColor(color);
int size = Settings.DEFAULT_NODE_SIZE;
graphics.fillOval(squareArea.getX(), squareArea.getY(), size, size);
}
}
Controller
GameController
/*
* 接收窗体SnakeApp传递过来的有意义的事件,然后传递给Grid,让Grid即时的更新状态。
* 同时根据最新状态渲染出游戏界面让SnakeApp显示
*
*/
public class GameController implements KeyListener, Runnable{
private Grid grid;
private boolean running;
public GameController(Grid grid){
this.grid = grid;
this.running = true;
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
switch(keyCode) {
case KeyEvent.VK_UP:
grid.changeDirection(Direction.UP);
break;
case KeyEvent.VK_DOWN:
grid.changeDirection(Direction.DOWN);
break;
case KeyEvent.VK_LEFT:
grid.changeDirection(Direction.LEFT);
break;
case KeyEvent.VK_RIGHT:
grid.changeDirection(Direction.RIGHT);
break;
}
isOver(grid.nextRound());
GameView.draw();
}
private void isOver(boolean flag) {
if(!flag) {//如果下一步更新棋盘时,出现游戏结束返回值(如果flag为假)则
this.running = false;
GameView.showGameOverMessage();
System.exit(0);
}
}
@Override
/*run()函数中的核心逻辑是典型的控制器(Controller)逻辑:
修改模型(Model):调用Grid的方法使游戏进入下一步
更新视图(View):调用GameView的方法刷新页面*/
public void run() {
while(running) {
try {
Thread.sleep(Settings.DEFAULT_MOVE_INTERVAL);
isOver(grid.nextRound());
GameView.draw();
} catch (InterruptedException e) {
break;
}
// 进入游戏下一步
// 如果结束,则退出游戏
// 如果继续,则绘制新的游戏页面
}
running = false;
}
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyReleased(KeyEvent e) {
}
}
Model
Grid
/*
* 随机生成食物,维持贪吃蛇的状态,根据SnakeApp中的用户交互来控制游戏状态。
*/
public class Grid {
private Snake snake;
int width;
int height;
Node food;
private Direction snakeDirection =Direction.LEFT;
public Grid(int length, int high) {
super();
this.width = length;
this.height = high;
initSnake();
food = creatFood();
}
//在棋盘上初始化一个蛇
private void initSnake() {
snake = new Snake();
int x = width/2;
int y = height/2;
for(int i = 0;i<5;i++) {
snake.addTail(new Node(x, y));
x = x+Settings.DEFAULT_NODE_SIZE;
}
}
//棋盘上随机制造食物的功能。
//一直循环获取随机值,直到三个条件都不满足。
private Node creatFood() {
int x,y;
do {
x =(int)(Math.random()*100)+10;
y =(int)(Math.random()*100)+10;
System.out.println(x);
System.out.println(y);
System.out.println(this.width);
System.out.println(this.height);
}while(x>=this.width-10 || y>=this.height-10 || snake.hasNode(new Node(x,y)));
food = new Node(x,y);
return food;
}
//提供下一步更新棋盘的功能,移动后更新游戏和蛇的状态。
public boolean nextRound() {
Node trail = snake.move(snakeDirection);
Node snakeHead = snake.getBody().removeFirst();//将头部暂时去掉,拿出来判断是否身体和头部有重合的点
if(snakeHead.getX()<=width-10 && snakeHead.getX()>=10
&& snakeHead.getY()<=height-10 && snakeHead.getY()>=10
&& !snake.hasNode(snakeHead)) {//判断吃到自己和撞到边界
if(snakeHead.equals(food)) {
//原本头部是食物的话,将move操作删除的尾部添加回来
snake.addTail(trail);
food = creatFood();
}
snake.getBody().addFirst(snakeHead);
return true;//更新棋盘状态并返回游戏是否结束的标志
}
return false;
}
public Node getFood() {
return food;
}
public Snake getSnake() {
return snake;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
//提供一个更改贪吃蛇前进方向的方法
public void changeDirection(Direction newDirection){
snakeDirection = newDirection;
}
}
Snake
/*
* 蛇类,实现了自身数据结构,以及移动的功能
*/
public class Snake implements Cloneable{
public LinkedList
public Node move(Direction direction) {
//根据方向更新贪吃蛇的body
//返回移动之前的尾部Node(为了吃到时候后增加尾部长度做准备)
Node n;//临时存储新头部移动方向的结点
switch (direction) {
case UP:
n = new Node(this.getHead().getX(),this.getHead().getY()-Settings.DEFAULT_NODE_SIZE);
break;
case DOWN:
n = new Node(this.getHead().getX(),this.getHead().getY()+Settings.DEFAULT_NODE_SIZE);
break;
case RIGHT:
n = new Node(this.getHead().getX()+Settings.DEFAULT_NODE_SIZE,this.getHead().getY());
break;
defaultLHqUpQJ:
n = new Node(this.getHead().getX()-Settings.DEFAULT_NODE_SIZE,this.getHead().getY());
}
Node temp = this.body.getLast();
this.body.addFirst(n);
this.body.removeLast();
return temp;
}
public Node getHead() {
return body.getFirst();
}
public Node getTail() {
return body.getLast();
}
public Node addTail(Node area) {
this.body.addLast(area);
return area;
}
public LinkedList
return body;
}
//判断参数结点是否在蛇身上
public boolean hasNode(Node node) {
Iterator
Node n = new Node(0,0);
while(it.hasNext()) {
n = it.next();
if(n.getX() == node.getX() && n.getY() == node.getY()) {
return true;
}
}
return false;
}
}
Direction
/*
* 用来控制蛇的移动方向
*/
public enum Direction {
UP(0),
DOWN(1),
LEFT(2),
RIGHT(3); //调用构造方法对方向枚举实例进行代码初始化
//成员变量
private final int directionCode;
//成员方法
public int directionCode() {
return directionCode;
}
Direction(int directionCode){
this.directionCode = directionCode;
}
}
Node
public class Node {
private int x;
private int y;
public Node(int x, int y) {
this.x = ((int)(x/10))*10;
this.y = ((int)(y/10))*10;
}//使用这种方法可以使得节点坐标不会出现个位数
public int getX() {
return x;
}
public int getY() {
return y;
}
@Override
//判断两个Node是否相同
public boolean equals(Object n) {
Node temp;
if(n instanceof Node) {
temp = (Node)n;
if(temp.getX()==this.getX() && temp.getY()==this.getY())
return true;
}
return false;
}
}
Settings
public class Settings {
public static int DEFAULT_NODE_SIZE = 10;//每一个节点方块的单位
public static int DEFAULT_MOVE_INTERVAL = 200;//蛇移动时间间隔
}
更多有趣的经典小游戏实现专题,分享给大家:
C++经典小游戏汇总
python经典小游戏汇总
python俄罗斯方块游戏集合
javascript经典游戏 玩不停
javascript经典小游戏汇总
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~