小游戏(贪食蛇)
线程
面向对象
文件操作
内部类
数据库
目标:
可娱乐
记录娱乐的结果
步骤:
1--了解swing相关知识和小游戏设计
通过main方法启动初始化界面
逐步添加界面元素
蛇的构成(多个关节组成)和运动方式(确认好方向,去尾加头)
食物的构成怎么出现(随机,位置与界面宽度和高度保持整除关系(余数为龙))
蛇如何吃豆子(头部元素与豆子元素坐标重合)
确定使用哪一种容器(LinkedList)
2--配置界面
宽度、高度
3--画出蛇
准备数据(一个关节就是一个对象 一条蛇是一个容器)
初始多个关节数据(关联着)
作业:
1--能独立开发出当前效果
2--继续思考并实践后续开发
4--蛇运动(按照方向运动) 可以自定义线程、Timer
方向控制(键盘方向键控制方向 、 snake按照要求的方向继续运动)
360、撞墙、咬自己、调速、暂停
5--蛇吃豆子
6--记录每次游戏的成绩
Main 类
package 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 javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
/**
* 1--初始化界面 2--初始化面板 3--面板与界面合并
*/
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 = 10;//多少个蛇的关节
private int se_size = 20;//蛇身体尺寸
private int se_x = 100;
private int se_y = 100;
private int b_size = 20; //豆子的尺寸
private String tip = "";
private String status = "";
private String dirction = Constant.UP;
private int score = 0;
private double speed = 200;
private LinkedList
private LinkedList
boolean b = true;
// 总初始化方法
private void init() {
initSnake();
initPanel();
initFrame();
initBean();
inttThread();
}
private void initBean() {
//初始化豆子
int x = (int)(Math.random()*fw);
int y = (int)(Math.random()*fh);
//随机出现豆子的坐标
int b_x = x- x% se_size;
int b_y = y- y% se_size;
//初始化元素
//判断食物是否在身上
for (int i = 0; i < snake.size(); i++) {
if(snake.get(i).getSe_x() == b_x && snake.get(i).getSe_y() ==b_y) {
b =false;
}
}
if(b) {
douzi.add(new Bean(b_size, b_x, b_y));
}else {
initBean();
}
}
private void inttThread() {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if ("".equalsIgnoreCase(status)) {
//吃豆子
if(snake.getFirst().getSe_x() == douzi.getFirst().getB_x() &&
snake.getFirst().getSe_y() == douzi.getFirst().getB_y()) {
douzi.clear();
snake.add(new SE(se_size,
snake.getLast().getSe_x(),
snake.getLast().getSe_y()));
score ++;
initBean();
}
// 判断是否咬到自己,(既是坐标与身体上的任意一个元素的坐标重合)
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()) {
gameOver();
}
}
// 操作snake容器中的元素
// 移除最后一个(蛇尾)
snake.removeLast();
// 添加一个到头部
if (dirction.equalsIgnoreCase(Constant.UP)) {
// 如果新的头部y坐标越界了 提示GAMEOVER
if (snake.getFirst().getSe_y() - se_size < 0) {
gameOver();
}else {
//在头部添加
snake.addFirst(
new SE(se_size, snake.getFirst().getSe_x(), snake.getFirst().getSe_y() - se_size));
}
}
if (dirction.equalsIgnoreCase(Constant.RIGHT)) {
if (snake.getFirst().getSe_x() + se_size > fw) {
gameOver();
}else {
snake.addFirst(
new SE(se_size,
snake.getFirst().getSe_x() + se_size,
snake.getFirst().getSe_y()));
}
}
if (dirction.equalsIgnoreCase(Constant.LEFT)) {
if (snake.getFirst().getSe_x() - se_size < 0) {
gameOver();
}else {
snake.addFirst(
new SE(se_size,
snake.getFirst().getSe_x() - se_size,
snake.getFirst().getSe_y()));
}
}
if (dirction.equalsIgnoreCase(Constant.DOWN)) {
if (snake.getFirst().getSe_y() + se_size > fh) {
gameOver();
}else {
snake.addFirst(
new SE(se_size,
snake.getFirst().getSe_x(),
snake.getFirst().getSe_y() + se_size));
}
}
jp.repaint();
try {
Thread.sleep((long) speed);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
}).start();
}
//游戏结束条件
public void gameOver() {
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) {
// tip ="";
status = "";
snake.clear();
initSnake();
score =0;
}
if (op_result == 2) {
System.exit(0);
}
}
/**
*
* 此方法描述的是:蛇吃豆子 (不能出现在蛇身上.不能出界)
* Bean
* 初始化豆子
* 画出豆子
* 吃豆子
* 身体长一个
* @author:[email protected]
* @version: 2018年9月18日
下午3:38:21
*/
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 = 4376420223914299841L;
@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.RED);
} else {
g.setColor(Color.GREEN);
}
g.fill3DRect(snake.get(i).getSe_x(),
snake.get(i).getSe_y(),
snake.get(i).getSe_size(),
snake.get(i).getSe_size(), true);
}
//画豆子
g.setColor(Color.PINK);
g.fill3DRect(douzi.getFirst().getB_x(),
douzi.getFirst().getB_y(),
douzi.getFirst().getB_size(),
douzi.getFirst().getB_size(),
true);
Integer i = new Integer(score);
String s = i.toString();
g.setColor(Color.YELLOW);
g.setFont(new Font("宋体",Font.BOLD,40));
g.drawString("总分:", 30, 40);
g.drawString(s, 150, 40);
}
};
jp.setOpaque(false);
}
private void initFrame() {
this.setTitle("测试!");
this.setSize(fw, fh);
this.getContentPane().setBackground(Color.DARK_GRAY);
this.setUndecorated(true);
this.setLocationRelativeTo(null); //设置窗体居中
this.add(jp);//添加到画布里去
this.setAlwaysOnTop(true); //窗体一直处于屏幕的最前端
this.setVisible(true);
// 当前对象具有多重身份(这是由继承结构决定的)
// 第一个this -- 窗口对象
// 第二个this -- 键盘监听器
this.addKeyListener(this);
}
public Main() {
init();
}
public static void main(String[] args) {
// new Main().init();
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.dirction.equalsIgnoreCase(Constant.LEFT) && e.getKeyCode() == KeyEvent.VK_RIGHT) {
this.dirction = Constant.RIGHT;
}
if (!this.dirction.equalsIgnoreCase(Constant.RIGHT) && e.getKeyCode() == KeyEvent.VK_LEFT) {
this.dirction = Constant.LEFT;
}
if (!this.dirction.equalsIgnoreCase(Constant.UP) && e.getKeyCode() == KeyEvent.VK_DOWN) {
this.dirction = Constant.DOWN;
}
if (!this.dirction.equalsIgnoreCase(Constant.DOWN) && e.getKeyCode() == KeyEvent.VK_UP) {
this.dirction = Constant.UP;
}
if (e.getKeyCode() == KeyEvent.VK_SPACE) {
// 先检查Status的值是什么,如果是 "" ,就修改成psuse 如果是pause 就改成 ""
switch (status) {
case Constant.PAUSE:
this.status = "";
break;
case "":
this.status = Constant.PAUSE;
break;
default:
break;
}
}
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
}
SE 蛇类源代码
package java20180917.snake;
import java.io.Serializable;
/*
* 蛇身体关节元素 实体类
* */
public class SE implements Serializable{
/**
* serialVersionUID:TODO(用一句话描述这个变量表示什么)
*
* @since Ver 1.1
*/
private static final long serialVersionUID = 4042880054351783092L;
private int se_size;
private int se_x;
private int se_y;
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;
}
@Override
public String toString() {
return "SE [se_size=" + se_size + ", se_x=" + se_x + ", se_y=" + 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
}
}
Bean 豆子类的源代码
package java20180917.snake;
import java.io.Serializable;
/*
* 蛇身体关节元素 实体类
* */
public class SE implements Serializable{
/**
* serialVersionUID:TODO(用一句话描述这个变量表示什么)
*
* @since Ver 1.1
*/
private static final long serialVersionUID = 4042880054351783092L;
private int se_size;
private int se_x;
private int se_y;
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;
}
@Override
public String toString() {
return "SE [se_size=" + se_size + ", se_x=" + se_x + ", se_y=" + 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
}
}
一些固定不变的常量源代码
package java20180917.snake;
/**
*
* 此类描述的是:
* @author:[email protected]
* @version: 2018年9月18日
下午1:03:12
*/
public interface Constant {
/**
* 方向常量
*/
public static final String UP = "up";
public static final String DOWN = "down";
public static final String RIGHT = "right";
public static final String LEFT ="left";
public static final String TIP = "GAME OVER !";
public static final String Stop="stop";
public static final String PAUSE ="pause";//暂停
}