package com.java20180917.snake;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Date;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.Properties;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* 1.初始化界面 2.初始化面板 3.面板与界面合并
*
* @author Xiaolei
*
*/
public class Main extends JFrame implements KeyListener {
private static final long serialVersionUID = -1803858577233572276L;
//定义容器
private JPanel jp = null;
//定义窗口
private int fw;
private int fh;
//定义蛇的大小和位置和长度
private int count;
private int b_size;
private int se_size;
private int se_x;
private int se_y;
private LinkedList
private String direction = Constant.UP;
private String tip = "";
private String status = "";
//速度
private long speed;
private Random rand = new Random();
private LinkedList
private Color[] colors = { Color.white, Color.orange, Color.BLUE, Color.CYAN, Color.gray, Color.yellow };
//成绩和关卡定义
private int Score;
private int cheak = 1;
//定义记录暂停和重启的时间
private long startTime;
private long endTime;
//暂停游戏间隔时间定义
private long pausetime;
private long resettime;
private long sumtime;
// 总初始化方法
private void init() {
initCoket();
initSnake();
initBean();
initPanel();
initFrame();
initThread();
}
private void initCoket() {
Properties pps = new Properties();
try {
pps.load(new FileInputStream("E:\\workspace-sts\\java20180917\\src\\config.properties"));
Enumeration enum1 = pps.propertyNames();// 得到配置文件的名字
while (enum1.hasMoreElements()) {
// 把指定的键的值赋给当前类定义的变量
fw = Integer.parseInt(pps.getProperty("fw"));
fh = Integer.parseInt(pps.getProperty("fh"));
count = Integer.parseInt(pps.getProperty("count"));
b_size = Integer.parseInt(pps.getProperty("b_size"));
se_size = Integer.parseInt(pps.getProperty("se_size"));
se_x = Integer.parseInt(pps.getProperty("se_x"));
se_y = Integer.parseInt(pps.getProperty("se_y"));
speed = Long.parseLong(pps.getProperty("speed"));
// 第二种方式
String strKey = (String) enum1.nextElement();
String strValue = pps.getProperty(strKey);
if (strKey.equals("fw")) {
fw = Integer.parseInt(strValue);
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void initBean() {
// 返回一个伪随机数,它是取自此随机数生成器序列的、在 0(包括)和指定值(不包括)之间均匀分布的 int 值。
int b_x = 20 * Math.round((new Random().nextInt(30)));
int b_y = 20 * Math.round((new Random().nextInt(30)));
// 如果蛇的列表中不包含豆子的位置 如果此列表包含指定元素,则返回 true。
if (!(snake.contains(new SE(b_size, b_x, b_y)))) {
b.add(new Bean(b_x, b_y, b_size));
}
}
// 如果方面符合条件,就触发该方法,弹出窗口
private void popup() {
tip = Constant.TIP;
status = Constant.STOP;
// 让方块重新向上跑
direction = Constant.UP;
//重画
jp.repaint();
int op_result = JOptionPane.showConfirmDialog(jp, "GAME OVER!", "",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.ERROR_MESSAGE);
if (op_result == 0) {
// 重新开始游戏
// 让蛇的运动条件重新开始
status = "";
// 把蛇的链表集合清空掉
snake.clear();
// 把Game Over字体清空。
tip = "";
// 重新调用方块,初始化蛇
initSnake();
//成绩和速度重新赋值
speed = 250;
Score = 0;
}
if (op_result == 2) {
System.exit(0);
}
}
private void initThread() {
// 添加线程,让方块跟着键盘的指定方面运动
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
System.out.print("");
if ("".equalsIgnoreCase(status)) {
//判断吃豆子
if (snake.getFirst().getSe_x() == b.getFirst().getB_x()
&& snake.getFirst().getSe_y() == b.getFirst().getB_y()) {
b.clear();
//重新初始化豆子的数据
initBean();
//长长
snake.addLast(new SE(se_size, snake.getLast().getSe_x(), snake.getLast().getSe_y()));
Score++;
// 加速
if(Score%2==0 && cheak<=5) {
speed-=30;
jp.repaint();
int op_result = JOptionPane.showConfirmDialog(jp, "你已通过第"+cheak+"关,是否继续游戏?", "",
JOptionPane.OK_CANCEL_OPTION,
JOptionPane.ERROR_MESSAGE);
cheak++;
if (op_result == 2) {
System.exit(0);
}
}
}
// 判断是否咬到自己(即头部坐标与身体上的任何一个元素的坐标重合)
for (int i = 1; i < snake.size(); i++) {
if (snake.getFirst().getSe_x() == snake.get(i).getSe_x()
&& snake.getFirst().getSe_y() == snake.get(i).getSe_y()) {
popup();
}
}
// 操作snake容器中的元素
// 移除最后一个
snake.removeLast();
// 添加一个到头部
// 让方块往上走
if (direction.equalsIgnoreCase(Constant.UP)) {
// 如果新的头部y的坐标出界,提示game over
if (snake.getFirst().getSe_y() - se_size < 0) {
popup();
}
//在蛇方块的头部加一个蛇方块
snake.addFirst(
new SE(se_size, snake.getFirst().getSe_x(), snake.getFirst().getSe_y() - se_size));
}
// 让方块往下走
if (direction.equalsIgnoreCase(Constant.Down)) {
//蛇方块的坐标从左上角开始计算
//如果蛇的头部的位置+自身的大小大于窗口总宽度就结束游戏
if (snake.getFirst().getSe_y() + se_size > fh) {
popup();
}
snake.addFirst(
new SE(se_size, snake.getFirst().getSe_x(), snake.getFirst().getSe_y() + se_size));
}
// 让方块往左走
if (direction.equalsIgnoreCase(Constant.LEFT)) {
// 如果方面的头碰到墙壁就结束游戏,弹窗
if (snake.getFirst().getSe_x() - se_size < 0) {
popup();
}
snake.addFirst(
new SE(se_size, snake.getFirst().getSe_x() - se_size, snake.getFirst().getSe_y()));
}
// 让方块往右走
if (direction.equalsIgnoreCase(Constant.RIGHT)) {
if (snake.getFirst().getSe_x() + se_size > fw) {
popup();
}
snake.addFirst(
new SE(se_size, snake.getFirst().getSe_x() + se_size, snake.getFirst().getSe_y()));
}
// 方块动起来后,重画填充
// 组件将被重新绘制。
jp.repaint();
try {
Thread.sleep(speed);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}).start();
}
private void initSnake() {
// 创建多个有关联着的SE
// 添加到snake容器中
for (int i = 0; i < count; i++) {
snake.add(new SE(se_size, se_x, se_y + se_size * i));
}
// long kaishi = System.na
// System.nanoTime()
startTime = System.nanoTime();
}
private void initPanel() {
jp = new JPanel() {
private static final long serialVersionUID = 1L;
// 在面板中填充方块的初始位置和颜色
@Override
public void paint(Graphics g) {
super.paint(g);
if (!"".equals(tip)) {
g.setColor(Color.red);
g.setFont(new Font("", Font.BOLD, 40));
g.drawString(tip, 160, 160);
}
for (int i = 0; i < snake.size(); i++) {
if (i == 0) {
g.setColor(Color.BLUE);
} else {
g.setColor(Color.WHITE);
}
g.fill3DRect(snake.get(i).getSe_x(), snake.get(i).getSe_y(), snake.get(i).getSe_size(),
snake.get(i).getSe_size(), true);
}
// 初始化豆子
for(int i = 0; i < b.size(); i++) {
if(b!=null) {
g.setColor(colors[rand.nextInt(colors.length)]);
g.fill3DRect(b.get(i).getB_x(), b.get(i).getB_y(), b.get(i).getB_size(), b.get(i).getB_size(), true);
}
}
g.setColor(Color.ORANGE);
g.setFont(new Font("", Font.BOLD, 15));
g.drawString("成绩:"+Score, 20, 50);
g.drawString("当前关卡:"+cheak, 20, 80);
g.drawString("当前运动速度:"+speed+"/ms", 20, 110);
//结束时间
endTime = System.nanoTime();
//记录游戏时间 游戏中暂停后,时间不会停止记录,所以要减去暂停到重新启动的时间
g.drawString("通关时间:"+(endTime-startTime-sumtime)/1000000000+"秒", 20, 140);
if(Score>25) {
g.setColor(Color.red);
g.setFont(new Font("", Font.BOLD, 25));
g.drawString("你已经通关啦", 235, 80);
}
}
};
// 设置透明度
jp.setOpaque(false);
}
private void initFrame() {
// 设置窗口标题
this.setTitle("测试");
// 设置窗口大小
this.setSize(fw, fh);
// 设置窗口背景颜色
this.getContentPane().setBackground(Color.black);
// 禁用或启用此框架的装饰。
this.setUndecorated(true);
// 把面板放到窗口上
this.add(jp);
// 设置窗口可见
this.setVisible(true);
// 当前对象具有多重身份 (这是由继承结构决定的)
// 第一个this --- 窗口对象
// 第二个this --- 键盘监听器
this.addKeyListener(this);
// 把窗口设置在指定的位置
this.setLocationRelativeTo(null);
}
public Main() {
init();
}
public static void main(String[] args) throws FileNotFoundException, IOException {
new Main();
//
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyPressed(KeyEvent e) {
// 按下按一个按键 停止虚拟机运行
// System.out.println(e.getKeyCode());
// 按下esc键 关停虚拟机
if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
System.exit(0);
}
// 获取键盘值的上下左右,赋于我的当前对象
if (!this.direction.equalsIgnoreCase(Constant.LEFT) && e.getKeyCode() == KeyEvent.VK_RIGHT) {
this.direction = Constant.RIGHT;
}
if (!this.direction.equalsIgnoreCase(Constant.RIGHT) && e.getKeyCode() == KeyEvent.VK_LEFT) {
this.direction = Constant.LEFT;
}
if (!this.direction.equalsIgnoreCase(Constant.UP) && e.getKeyCode() == KeyEvent.VK_DOWN) {
this.direction = Constant.Down;
}
if (!this.direction.equalsIgnoreCase(Constant.Down) && e.getKeyCode() == KeyEvent.VK_UP) {
this.direction = Constant.UP;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
// 先检查status的值 如果是 "" 就修改成 pause 如果是 pause 就改成 ""
switch (status) {
case Constant.PAUSE://重启
this.status = "";
pausetime = System.nanoTime();
sumtime +=(pausetime-resettime);
break;
case ""://暂停
this.status = Constant.PAUSE;
resettime = System.nanoTime();
break;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
蛇类:
package com.java20180917.snake;
import java.io.Serializable;
/**
* 蛇身体关节元素 实体类
* @author Xiaolei
*
*/
public class SE implements Serializable{
/**
*
*/
private static final long serialVersionUID = 4103030147063529932L;
private int se_size;
private int se_x;
private int se_y;
public SE(int se_size, int se_x, int se_y) {
super();
this.se_size = se_size;
this.se_x = se_x;
this.se_y = se_y;
}
public SE() {
super();
// TODO Auto-generated constructor stub
}
public int getSe_size() {
return se_size;
}
public void setSe_size(int se_size) {
this.se_size = se_size;
}
public int getSe_x() {
return se_x;
}
public void setSe_x(int se_x) {
this.se_x = se_x;
}
public int getSe_y() {
return se_y;
}
public void setSe_y(int se_y) {
this.se_y = se_y;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
@Override
public String toString() {
return "SE [se_size=" + se_size + ", se_x=" + se_x + ", se_y=" + se_y + "]";
}
}
接口:package com.java20180917.snake;
/**
* 常量接口
* @author Xiaolei
*
*/
public interface Constant {
/**
*方向常量
*/
public static final String UP = "up";
public static final String Down = "down";
public static final String LEFT = "left";
public static final String RIGHT = "right";
public static final String TIP = "GAME OVER !";
public static final String STOP = "stop";//停止
public static final String PAUSE = "pause";//暂停
}
豆子类:
package com.java20180917.snake;
public class Bean {
private int b_x;
private int b_y;
private int b_size;
public Bean() {
super();
// TODO Auto-generated constructor stub
}
public Bean(int b_x, int b_y, int b_size) {
super();
this.b_x = b_x;
this.b_y = b_y;
this.b_size = b_size;
}
public int getB_x() {
return b_x;
}
public void setB_x(int b_x) {
this.b_x = b_x;
}
public int getB_y() {
return b_y;
}
public void setB_y(int b_y) {
this.b_y = b_y;
}
public int getB_size() {
return b_size;
}
public void setB_size(int b_size) {
this.b_size = b_size;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + b_size;
result = prime * result + b_x;
result = prime * result + b_y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Bean other = (Bean) obj;
if (b_size != other.b_size)
return false;
if (b_x != other.b_x)
return false;
if (b_y != other.b_y)
return false;
return true;
}
@Override
public String toString() {
return "Bean [b_x=" + b_x + ", b_y=" + b_y + ", b_size=" + b_size + "]";
}
}
配置文件值:也可以放在Mian类当中
#初始速度
speed=300
#初始长度
count = 4
fw = 600
fh = 600
b_size=20
se_size = 20
se_x = 100
se_y = 200
speed = 250