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.util.LinkedList;
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 = 600;
private int fh = 600;
private int count = 4;
private int b_size=20;
private int se_size = 20;
private int se_x = 100;
private int se_y = 200;
private LinkedList
private String direction = Constant.UP;
private String tip = "";
private String status = "";
private long speed = 300;
// 豆子初始化
private LinkedList
private int Score;
// 总初始化方法
private void init() {
initSnake();
initPanel();
initFrame();
initBean();
initThread();
}
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;
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 = "";
// 让方块重新向上跑
direction = Constant.UP;
// 重新调用方块,初始化蛇
initSnake();
speed=300;
Score=0;
}
if (op_result == 2) {
System.exit(0);
}
}
private void initThread() {
// 添加线程,让方块跟着键盘的指定方面运动
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if ("".equalsIgnoreCase(status)) {
if (snake.getFirst().getSe_x() == b.getFirst().getB_x()
&& snake.getFirst().getSe_y() == b.getFirst().getB_y()) {
//吃掉一个豆子,就把原来的豆子清掉,重新在创建一个豆子
b.clear();
//新建一个豆子
//在蛇方块的尾部增加一个方块
snake.add(new SE(se_size, snake.getLast().getSe_x(), snake.getLast().getSe_y()));
initBean();
Score++;
// 加速
if(Score==5) {
speed-=100;
}
else if(Score==15) {
speed-=150;
}
else if(Score==25) {
speed-=200;
}
}
// 判断是否咬到自己(即头部坐标与身体上的任何一个元素的坐标重合)
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));
}
}
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 < b.size(); i++) {
g.setColor(Color.YELLOW);
g.fillRect(b.get(i).getB_x(), b.get(i).getB_y(), b.get(i).getB_size(), b.get(i).getB_size());
}
for (int i = 0; i < snake.size(); i++) {
if (i == 0) {
g.setColor(Color.GRAY);
} else {
g.setColor(Color.BLUE);
}
g.fill3DRect(snake.get(i).getSe_x(), snake.get(i).getSe_y(), snake.get(i).getSe_size(),
snake.get(i).getSe_size(), true);
}
Integer a = new Integer(Score);
g.setColor(Color.ORANGE);
g.setFont(new Font("", Font.BOLD, 30));
g.drawString("成绩:"+a.toString(), 460, 50);
}
};
// 设置透明度
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) {
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 = "";
break;
case "":
this.status = Constant.PAUSE;
break;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
接口:
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;
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;
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 + "]";
}
}