package tm.change.snake;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Observable;
import java.util.Random;
import javax.swing.JOptionPane;
import tm.change.Node;
/**
*
* @author 张新华 870775401@qq.com
* @version 创建时间 : 2016-8-24 下午02:20:47
*
*/
public class SnakeModel extends Observable implements Runnable {
private Boolean[][] matrix;// 标志位置上有没有蛇或者食物 也就是整个地图
private LinkedList<Object> snakeList = new LinkedList<Object>();// 定义蛇体,用list方便蛇的增长
private Node food;// 食物
private Integer maxX;
private Integer maxY;
private Integer direction = 2;// 定义蛇的运动初始方向
private Boolean running = false;// 定义蛇的运行状态
private Integer timeInterval = FinalData.TIMEINTERVAL;// 时间间隔,毫秒
private Double speedChangeRate = FinalData.SPEEDCHANGERATE;// 每次得速度变化率
private Boolean paused = false;// 暂停标志
private Integer score = 0; // 得分
private Integer countMove = 0;// 吃到食物前移动的次数
// UP and DOWN should be even
// RIGHT and LEFT should be odd
public static final int UP = 2;
public static final int DOWN = 4;
public static final int LEFT = 1;
public static final int RIGHT = 3;
/**
* 初始化 参数
*
* @param maxX
* @param maxY
*/
public SnakeModel(Integer maxX, Integer maxY) {
this.maxX = maxX;
this.maxY = maxY;
reset();// 在构造函数中运行作用就是初始化数据
}
/**
* 恢复设置
*/
public void reset() {
direction = SnakeModel.UP; // 蛇运行的方向
timeInterval = FinalData.TIMEINTERVAL; // 时间间隔,毫秒
paused = 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,否则为横向位置的一半
Integer initArrayLength = maxX / 2;
snakeList.clear();
for (int i = 0; i < initArrayLength; i++) {
Integer x = maxX / 2 + i;
Integer y = maxY / 2;
snakeList.add(new Node(x, y));// 将蛇点加入蛇身里
matrix[x][y] = true;// 标记为蛇
}
// 创建食物
food = createFood();
matrix[food.getX()][food.getY()] = true;// 标记出来 高亮显示
}
/**
* 创建食物
*/
public Node createFood() {
int x = 0;
int y = 0;
// 随机获取一个有效区域内的与蛇体和食物不重叠的位置
do {
Random r = new Random();
x = r.nextInt(maxX);
y = r.nextInt(maxY);
} while (matrix[x][y]);
return new Node(x, y);
}
/**
* 改变蛇的运动方向,但不能与原来的运动方向同向或相反
*/
public void changeDirection(Integer newDirection) {
if (direction % 2 != newDirection % 2) {
direction = newDirection;
}
}
/**
* 移动蛇
*/
public Boolean moveOn() {
Node tNode = (Node) snakeList.getFirst();
Integer x = tNode.getX();
Integer y = tNode.getY();
// 根据方向增减坐标值
switch (direction) {
case UP:
y--;
break;
case DOWN:
y++;
break;
case LEFT:
x--;
break;
case RIGHT:
x++;
break;
}
// 如果新坐标落在有效范围内,则进行处理
if ((0 <= x && x < maxX) && (0 <= y && y < maxY)) {
if (matrix[x][y]) { // 如果新坐标的点上有东西(蛇体或者食物)
if (x == food.getX() && y == food.getY()) { // 吃到食物,成功
snakeList.addFirst(food); // 从蛇头赠长
// 分数规则,与移动改变方向的次数和速度两个元素有关
int scoreGet = (10000 - 200 * countMove) / timeInterval;
score += scoreGet > 0 ? scoreGet : 10;
countMove = 0;
food = createFood(); // 创建新的食物
matrix[food.getX()][food.getY()] = true; // 设置食物所在位置
return true;
} else
// 吃到蛇体自身,失败
return false;
} else { // 如果新坐标的点上没有东西(蛇体),移动蛇体
snakeList.addFirst(new Node(x, y));
matrix[x][y] = true;
tNode = (Node) snakeList.removeLast();
matrix[tNode.getX()][tNode.getY()] = false;
countMove++;
return true;
}
}
return false; // 触到边线,失败
}
public void speedUp() {
timeInterval = Integer.valueOf((int) (timeInterval*speedChangeRate));
}
public void speedDown() {
timeInterval = Integer.valueOf((int) (timeInterval/speedChangeRate));
}
public void changePauseState() {
paused = !paused;
}
public String toString() {
String result = "";
for (int i = 0; i < snakeList.size(); ++i) {
Node tNode = (Node) snakeList.get(i);
result += "[" + tNode.getX() + "," + tNode.getY() + "]";
}
return result;
}
@Override
public void run() {
// TODO Auto-generated method stub
running = true;
while (running) {
try {
Thread.sleep(timeInterval);
} catch (Exception e) {
break;
}
if (!paused) {
if (moveOn()) {
setChanged(); // Model通知View数据已经更新
notifyObservers();
} else {
JOptionPane.showMessageDialog(null,
"you failed",
"Game Over",
JOptionPane.INFORMATION_MESSAGE);
break;
}
}
}
running = false;
}
public Boolean[][] getMatrix() {
return matrix;
}
public void setMatrix(Boolean[][] matrix) {
this.matrix = matrix;
}
public LinkedList<Object> getSnakeList() {
return snakeList;
}
public void setSnakeList(LinkedList<Object> snakeList) {
this.snakeList = snakeList;
}
public Node getFood() {
return food;
}
public void setFood(Node food) {
this.food = food;
}
public Integer getMaxX() {
return maxX;
}
public void setMaxX(Integer maxX) {
this.maxX = maxX;
}
public Integer getMaxY() {
return maxY;
}
public void setMaxY(Integer maxY) {
this.maxY = maxY;
}
public Integer getDirection() {
return direction;
}
public void setDirection(Integer direction) {
this.direction = direction;
}
public Boolean getRunning() {
return running;
}
public void setRunning(Boolean running) {
this.running = running;
}
public Integer getTimeInterval() {
return timeInterval;
}
public void setTimeInterval(Integer timeInterval) {
this.timeInterval = timeInterval;
}
public Double getSpeedChangeRate() {
return speedChangeRate;
}
public void setSpeedChangeRate(Double speedChangeRate) {
this.speedChangeRate = speedChangeRate;
}
public Boolean getPaused() {
return paused;
}
public void setPaused(Boolean paused) {
this.paused = paused;
}
public Integer getScore() {
return score;
}
public void setScore(Integer score) {
this.score = score;
}
public Integer getCountMove() {
return countMove;
}
public void setCountMove(Integer countMove) {
this.countMove = countMove;
}
public static int getUp() {
return UP;
}
public static int getDown() {
return DOWN;
}
public static int getLeft() {
return LEFT;
}
public static int getRight() {
return RIGHT;
}
}