贪吃蛇—–小游戏
-
Snake类
分析Snake类,必须要考虑以下几个问题:
1,贪吃蛇的身体如何绘制?
2,位置和方向怎样更新?
相信你有自己的答案,这里给出经验方法
1,使用数组存放蛇身(蛇身由实心圆圈连成),数组的长度即为蛇身的最大长度。即将蛇变为数组处理
2,利用上述数组,保证数组的循环,前一个圆圈的坐标作为下一个圆圈的坐标的更新值。意味着只有蛇头圆圈的坐标需要更新,其余圆圈的坐标直接采用数组上一个圆圈的保存值。
package tcs;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;//导入随机类
public class Food {
public Point location; // 食物的坐标
public Point size; // 食物的方块尺寸
private GamePanel gameP;
private Snake snk;
private Random rand;
public Food(GamePanel gp, Snake sk) {// 初始化各变量
gameP = gp;
snk = sk;
rand = new Random();
location = new Point(Math.abs(rand.nextInt() % gameP.width), Math.abs(rand.nextInt() % gameP.heigth));
size = new Point(sk.diameter, sk.diameter);// 尺寸与贪吃蛇圆圈相同
}
public void update() {// 判断是否重合,重合则认为Food被蛇吃到
if ((Math.abs((snk.x + snk.diameter / 2) - (location.x + size.x / 2)) < snk.diameter)
&& (Math.abs((snk.y + snk.diameter / 2) - (location.y + size.y / 2)) < snk.diameter)) {
location = new Point(Math.abs(rand.nextInt() % gameP.width), Math.abs(rand.nextInt() % gameP.heigth));
if (snk.length < Snake.MAXLENTH) {
snk.length++;
}
}
}
public void draw(Graphics g) {
g.setColor(Color.black);// 食物是黑色
g.fillRect(location.x, location.y, size.x, size.y);// 食物用方块绘制
}
}
- Food类
分析Food类,同样需要考虑两个问题:
1,怎样判断食物被蛇吃了?
2,事物的坐标如何更新?
对于第一个问题,我们只需检测蛇头是否与食物发生了碰撞,如果两个对象碰到了一起,则认为食物被吃了,执行事物的坐标更新;第二个问题,导入Random随机类,在Panel上产生随机点作为Food的新位置
package tcs;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;//导入随机类
public class Food {
public Point location; // 食物的坐标
public Point size; // 食物的方块尺寸
private GamePanel gameP;
private Snake snk;
private Random rand;
public Food(GamePanel gp, Snake sk) {// 初始化各变量
gameP = gp;
snk = sk;
rand = new Random();
location = new Point(Math.abs(rand.nextInt() % gameP.width), Math.abs(rand.nextInt() % gameP.heigth));
size = new Point(sk.diameter, sk.diameter);// 尺寸与贪吃蛇圆圈相同
}
public void update() {// 判断是否重合,重合则认为Food被蛇吃到
if ((Math.abs((snk.x + snk.diameter / 2) - (location.x + size.x / 2)) < snk.diameter)
&& (Math.abs((snk.y + snk.diameter / 2) - (location.y + size.y / 2)) < snk.diameter)) {
location = new Point(Math.abs(rand.nextInt() % gameP.width), Math.abs(rand.nextInt() % gameP.heigth));
if (snk.length < Snake.MAXLENTH) {
snk.length++;
}
}
}
public void draw(Graphics g) {
g.setColor(Color.black);// 食物是黑色
g.fillRect(location.x, location.y, size.x, size.y);// 食物用方块绘制
}
}
- GamePanel类
框架的建立十分重要,需要考虑很多问题,如:实现动画效果的帧变化;如何让帧速率稳定有效(创建线程);为何要离屏绘制及如何离屏绘制蛇身和食物等。
为了方便大家实验,这里先给出代码
package tcs;
import java.awt.*;
import java.awt.event.*;
public class GamePanel extends Panel implements Runnable, KeyListener {
public int width; // 面板宽度
public int heigth; // 面板高度
public int incre = 1; // 面板
private Image im;
private Graphics dbg;
private Thread gamethread; // 线程控制游戏运行
private static final int FPS = 30; // 帧变化速度,表现为蛇移动速度
private boolean running = false;
private boolean isPaused = false;
private int direction;
public static final int SOUTH = 0; // 后期显示
public static final int NORTH = 1;
public static final int EAST = 2;
public static final int WEST = 3;
private Snake sk;
private Food bk;
public GamePanel() {// 面板初始化
width = 300;
heigth = 300;
setPreferredSize(new Dimension(width, heigth));
sk = new Snake(this);// 引用
bk = new Food(this, sk);// 引用
// 以下三句为按键检测
setFocusable(true);
requestFocus();
addKeyListener(this);
}
public int getDirection() {
return direction;
}
public void gameStart() {
if (!running) {
gamethread = new Thread(this);
gamethread.start(); // 启动此线程(实际上只有这一个线程)
}
}
public void gameStop() {
running = false;
}
public void gamePaint() {
Graphics g;
try {
g = this.getGraphics();
if (g != null && im != null) {
g.drawImage(im, 0, 0, null);
}
g.dispose();
} catch (Exception e) {
}
}
// 离屏绘制
public void gameRender() {
if (im == null) {
// 建立im对象,进行离屏绘制
im = createImage(width, heigth);
if (im == null) {
System.out.println("im is null");
} else {
dbg = im.getGraphics();
}
}
dbg.setColor(Color.white);
dbg.fillRect(0, 0, width, heigth);
sk.draw(dbg);
bk.draw(dbg);
}
public void gameUpdate() {
if (!isPaused) {
sk.update();
bk.update();
}
}
// 重载run()方法,将游戏循环放置其中
public void run() {
long t1, t2, dt, sleepTime;
long period = 1000 / FPS; //
t1 = System.nanoTime(); //
while (true) {
gameUpdate();
gameRender();
gamePaint();
t2 = System.nanoTime();
dt = (t2 - t1) / 1000000L;
sleepTime = period - dt;
if (sleepTime <= 0)
sleepTime = 2;
try {
Thread.sleep(sleepTime);
} catch (InterruptedException ex) {
}
t1 = System.nanoTime();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();
if (keycode == KeyEvent.VK_P) {
isPaused = !isPaused;
System.out.println("key is P");
}
if (!isPaused) {
switch (keycode) {
case KeyEvent.VK_DOWN:
direction = SOUTH;
System.out.println("key is down" + direction);
break;
case KeyEvent.VK_UP:
direction = NORTH;
System.out.println("key is up" + direction);
break;
case KeyEvent.VK_RIGHT:
direction = EAST;
System.out.println("key is right" + direction);
break;
case KeyEvent.VK_LEFT:
direction = WEST;
System.out.println("key is left" + direction);
break;
}
}
}
public void keyReleased(KeyEvent e) {
}
}
-Frame类
package tcs;
import java.awt.*;
import java.awt.event.*;
public class GameFrame {
public GameFrame() {
Frame app = new Frame("GameFrame");
app.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
app.setLocation(100, 100);
GamePanel drawB = new GamePanel();
app.add(drawB, BorderLayout.CENTER);
app.pack();
app.setResizable(false);
app.setVisible(true);
drawB.gameStart();
}
/**
* @param args
* the command line arguments
*/
public static void main(String[] args) {
new GameFrame();
// TODO code application logic here
}
}
实践创建java项目
运行GameFrame.java
注:文章转载,转载地址:
http://blog.csdn.net/qq_33232071/article/details/50583572