java控制台贪食蛇_java中的贪食蛇例程
最近要重新学习Java,找个例子来实践,在网上找了很多例程来看,自己重新编写了一个贪食蛇的例子,记在这里。
1.SnakeModel.java
import java.util.Observable;
import java.util.LinkedList;
import java.util.Arrays;
import java.util.Random;
import javax.swing.*;
//Observable类一般代表数据,实现接口Runnable表明创建一个进程
public class SnakeModel extends Observable implements Runnable {
boolean[][] matrix;//指示位置上是否有蛇体或食物;
LinkedList nodeArray = new LinkedList(); //蛇体
Node food;
int maxX;//X轴边线,即为画布中X轴个数
int maxY;//y轴边线,即为画布中Y轴个数
int direction = UP; //蛇运行的方向,初始为向上(UP)
boolean isRunning = false; //运行状态
int timeInterval = 200; //时间间隔,毫秒级
double speedChangeRate = 0.75; //每次的速度变化率
boolean isPaused = false ;//暂停标志
int score = 0; //得分
int countMove = 0; //吃到食物前移动的次数
public static final int UP = 2;
public static final int DOWN =4;
public static final int LEFT= 1;
public static final int RIGHT =3;
public SnakeModel(int maxX, int maxY){
this.maxX = maxX;
this.maxY = maxY;
reset();
}
public void reset(){
direction = SnakeModel.UP;
timeInterval = 200;
isPaused = false;
score = 0;
countMove = 0;
//初始化矩阵
matrix = new boolean[maxX][];
for(int i = 0; i < maxX; ++i){
//关于数组的新建
matrix[i] = new boolean[maxY];
Arrays.fill(matrix[i],false);
}
//初始化蛇体
//初始蛇体长度按照横轴的长度,若横轴>20,则蛇体长度为10,否则为横轴一半
int initArrayLength = maxX > 20 ? 10 : maxX / 2;
nodeArray.clear();
for(int i = 0; i < initArrayLength; ++i){
int x = maxX / 2;
int y = maxY / 2;
nodeArray.addLast(new Node(x, y));
matrix[x][y] = true;
}
//创建食物
food = createFood();
matrix[food.x][food.y] = true;
}
public void changeDirection(int newDirection){
//改变方向不能与原方向同向或反向
if((direction & 1) != (newDirection & 1)){
direction = newDirection;
}
}
//移动一格
public boolean moveOn(){
Node n = (Node) nodeArray.getFirst();
int x = n.x;
int y = n.y;
//根据方向增减坐标,这里的增减是以数组平面的,而不是普通的坐标轴
switch(direction){
case UP:
y--;break;//向上时,数组的y变小
case DOWN:
y++;break;//向下时,数组的y变大
case LEFT:
x--;break;
case RIGHT:
x++;break;
}
//如果新坐标落在有效范围内,则进行处理
if((0<=x && x
if(matrix[x][y]){//如果新坐标的点上有东西(蛇体或食物)
if( x==food.x && y==food.y){//吃到食物,成功
nodeArray.addFirst(food);//从蛇头增长
int scoreGet = (10000 - 200 * countMove) / timeInterval;
//计分标准为最低10分
score += (scoreGet > 10) ? scoreGet : 10;
//countMove清0,重新计算,因为countMove越大,得到的分数越低
//countMove的涵义是吃到食物前移动的次数
countMove = 0;
food = createFood(); //创建新的食物
matrix[food.x][food.y] = true;
return true;
}else{//吃到蛇体本身,失败
return false;
}
}else{//如果坐标上没有东西,移动蛇体
nodeArray.addFirst(new Node(x, y));
matrix[x][y] = true;
n = (Node) nodeArray.removeLast();
matrix[n.x][n.y] = false;
countMove++;
return true;
}
}
return false; //触到边线,失败
}
//作为线程运行的主体,测试时的入口
public void run(){
isRunning = true;
while(isRunning){
try{
Thread.sleep(timeInterval);
}catch(Exception e){
break;
}
if(!isPaused){
if(moveOn()){//没有触碰到蛇体或者墙壁
//标记此 Observable 对象为已改变的对象;现在 hasChanged 方法将返回 true。
//这时,Observer会自动调用update方法
setChanged();
//则通知其所有观察者,并调用 clearChanged 方法来指示此对象不再改变。
notifyObservers();
}else{//挂掉了
JOptionPane.showMessageDialog(null, "","You failed。Game Over!",
JOptionPane.INFORMATION_MESSAGE);
break;
}
}
}
isRunning = false;
}
private Node createFood(){
int x = 0;
int y = 0;
//随机获取一个有效区域内的蛇体和食物不重叠的位置
do{
Random r = new Random();
// 返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)
// 和指定值(不包括)之间均匀分布的 int 值。
x = r.nextInt(maxX);
y = r.nextInt(maxY);
}while(matrix[x][y]);
return new Node(x, y);
}
public void speedUp(){
timeInterval *= speedChangeRate;
}
public void speedDown(){
timeInterval /= speedChangeRate;
}
public void changePauseState(){
isPaused = !isPaused;
}
public String toString(){
String result = "";
for(int i = 0 ; i < nodeArray.size(); ++i ){
Node n = (Node) nodeArray.get(i);
result += "[" + n.x + "," + n.y + "]";
}
return result;
}
}
class Node{
int x;
int y;
Node(int x, int y){
this.x = x;
this.y = y;
}
}
2.SnakeControl.java
import java.awt.event.*;
import java.awt.event.KeyEvent.*;
public class SnakeControl implements KeyListener{
SnakeModel model;
public SnakeControl(SnakeModel model){
this.model = model;
}
public void keyPressed(KeyEvent e){
int keyCode = e.getKeyCode();
if(model.isRunning){//运行状态下,处理按键
switch(keyCode){
case KeyEvent.VK_UP:
model.changeDirection(SnakeModel.UP);
break;
case KeyEvent.VK_DOWN:
model.changeDirection(SnakeModel.DOWN);
break;
case KeyEvent.VK_LEFT:
model.changeDirection(SnakeModel.LEFT);
break;
case KeyEvent.VK_RIGHT:
model.changeDirection(SnakeModel.RIGHT);
break;
case KeyEvent.VK_ADD:
case KeyEvent.VK_PAGE_UP:
model.speedUp();
break;
case KeyEvent.VK_SUBTRACT:
case KeyEvent.VK_PAGE_DOWN:
model.speedDown();
break;
case KeyEvent.VK_SPACE:
case KeyEvent.VK_P:
model.changePauseState();
break;
case KeyEvent.VK_R:
case KeyEvent.VK_ENTER:
model.reset();
break;
default:
}
}
}
public void keyTyped(KeyEvent e){
}
public void keyReleased(KeyEvent e){
}
}
3.SnakeView.java
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class SnakeView implements Observer{
SnakeControl control = null;
SnakeModel model = null;
JFrame mainFrame;
Canvas paintCanvas;
JLabel labelScore;
public static final int canvasWidth = 300;
public static final int canvasHeight = 300;
public static final int nodeWidth = 10;
public static final int nodeHeight = 10;
public SnakeView(SnakeModel model, SnakeControl control){
this.model = model;
this.control = control;
mainFrame = new JFrame("Snake");
Container cp = mainFrame.getContentPane();
//创建顶部的分数显示
labelScore = new JLabel("Score:");
cp.add(labelScore, BorderLayout.NORTH);
//创建中间的游戏显示区域、
paintCanvas = new Canvas();
paintCanvas.setSize(canvasWidth + 1, canvasHeight+1);
paintCanvas.addKeyListener(control);
cp.add(paintCanvas, BorderLayout.CENTER);
//创建地下的帮助栏
JPanel panelButton = new JPanel();
panelButton.setLayout(new BorderLayout());
JLabel labelHelp;
labelHelp = new JLabel("PageUp, PageDown for speed;", JLabel.CENTER);
panelButton.add(labelHelp, BorderLayout.NORTH);
labelHelp = new JLabel("ENTER or R or S for start;", JLabel.CENTER);
panelButton.add(labelHelp, BorderLayout.CENTER);
labelHelp = new JLabel("SPACE or P for pause", JLabel.CENTER);
panelButton.add(labelHelp, BorderLayout.SOUTH);
cp.add(panelButton, BorderLayout.SOUTH);
mainFrame.addKeyListener(control);
mainFrame.pack();
mainFrame.setResizable(false);
mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
mainFrame.setVisible(true);
}
void repaint(){
Graphics g = paintCanvas.getGraphics();
//设置背景
g.setColor(Color.WHITE);
g.fillRect(0, 0, canvasWidth, canvasHeight);
//在画布上画蛇
g.setColor(Color.BLACK);
LinkedList na = model.nodeArray;
Iterator it = na.iterator();
while(it.hasNext()){
Node n = (Node)it.next();
drawNode(g, n);
}
//画食物
g.setColor(Color.RED);
Node n = model.food;
drawNode(g, n);
//更新分数
updateScore();
}
private void drawNode(Graphics g, Node n){
//矩形周围留空,提高视觉效果
g.fillRect(n.x*nodeWidth, n.y*nodeHeight, nodeWidth-1, nodeHeight-1);
}
public void updateScore(){
String s = "Score: " + model.score;
labelScore.setText(s);
}
public void update(Observable o, Object arg){
repaint();
}
}
4.Snake.java
public class Snake {
public static void main(String[] args) {
SnakeModel model = new SnakeModel(30, 30);
SnakeControl control = new SnakeControl(model);
SnakeView view = new SnakeView(model, control);
//添加一个观察者,让view成为model的观察者
model.addObserver(view);
//Thread的start方法会自动调用该线程的run()方法
(new Thread(model)).start();
}
}
java控制台贪食蛇_java中的贪食蛇例程相关推荐
- java开根号函数_Java中真的只有值传递么?
原创: ITwalking 转载于公众号[ 编程大道] (本文非引战或diss,只是说出自己的理解,欢迎摆正心态观看或探讨) 回顾值传递和引用传递 关于Java是值传递还是引用传递,网上有不一样的说法 ...
- java构造器详解_Java中关于构造器的使用详解
这篇文章主要介绍了Java构造器使用方法及注意事项的相关资料,这里举例说明如何使用构造器及需要注意的地方,需要的朋友可以参考下 Java构造器使用方法及注意事项 超类的构造器在子类的构造器运行之前运行 ...
- java是什么意思_java中是什么意思?
慕田峪7331174 Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言.Java技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动 ...
- java可以多重继承吗_Java中的多重继承与组合vs继承
java可以多重继承吗 有时我写了几篇有关Java继承,接口和组成的文章. 在这篇文章中,我们将研究多重继承,然后了解组成优于继承的好处. Java中的多重继承 多重继承是创建具有多个超类的单个类的能 ...
- java中有没有栈_Java中堆和栈有什么区别
stack 和 heep 都是内存的一部分stack 空间小,速度比较快, 用来放对象的引用heep 大,一般所有创建的对象都放在这里.栈(stack):是一个先进后出的数据结构,通常用于保存方法(函 ...
- java 基本类型 引用_java中 引用类型 和 基本类型 有何区别?
栈与堆都是Java用来在Ram中存放数据的地方.与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆. Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newa ...
- java读取文件 路径_Java中的获取文件的物理绝对路径,和读取文件
获取文件的绝对路径,读取该文件 一.文件目录打印图 下面的文件目录图,是项目中文件的位置信息:下面的例子是按照这个图来演示的. . |-- java | |-- ibard | | |-- demo1 ...
- java多线程 线程安全_Java中的线程安全
java多线程 线程安全 Thread Safety in Java is a very important topic. Java provides multi-threaded environme ...
- java 异常处理发生异常_Java中的异常处理
java 异常处理发生异常 Exception Handling in Java is a very interesting topic. Exception is an error event th ...
- java string 对象地址_Java中String对象的存储位置(学习笔记)
packagetest.string.equal;public classMain {/*** 创建了三个对象,"helloworld对象创建在常量池中",每次new String ...
最新文章
- c语言面向对象编程中的类_C ++中的面向对象编程
- 使用SaltStack安装JDK1.6
- [AngularJS学习笔记] 基础学习01
- 【PC工具】更新文字转语音、文字文本朗读工具,语音朗读软件,TTS语音合成...
- Matplotlib实例教程(十六)3D直方图
- POJ - 3358 Period of an Infinite Binary Expansion(欧拉定理)
- 大数据相加_推动媒体融合与大数据相加发展
- 如何设置mysql字符集支持utf-8 和gbk_如何设置Mysql数据库默认的字符集编码为GBK...
- 让所有连接都弹出新窗口
- redux入门指南(一)
- ML 12 13 mixture of gaussions and EM
- python+selenium+unittest测试框架3-项目构建和发送邮件
- springmvc配置拦截器及测试详解
- 服务器 ××× 上的MSDTC不可用解决办法
- face_alignment库获取人脸图片landmark示例
- 如何连接新浪sae共享数据库
- 清橙网A1110. 街道
- 【看表情包学Linux】进程创建 | 进程终止 | 分叉函数 fork | 写时拷贝 | 内核数据结构缓冲池 | slab 分派器
- ServiceMesh到底好不好
- 前端学习之版心和布局流程
热门文章
- win10怎么删除hiberfil.sys文件教程
- php 教育类,php教育培训网站是哪个
- 计算机研究生哪个子专业最容易考公务员
- 赋值,浅拷贝,深拷贝区别和实现方法
- centos 安装Times New Roman
- POI excel 单元格换行
- E. Thematic Contests(离散化+排序+二分)Codeforces Round #521 (Div. 3)
- E. Thematic Contests【dp】
- ccf201412-3集合竞价
- 熊猫之死,是腾讯对360的又一次胜利