《Java小游戏实现》:贪吃蛇
在完成坦克大战之后,就想到了贪吃蛇这个小游戏,因为这两个游戏太像了,因此,就决定把这个游戏来尝试的写下。接下来的几篇博文就是来记录这个小游戏实现的全过程。
突然,想起,一年前(时间是2015年7月3日),我刚学习Java的时候看过别人写的这个游戏源代码,还专门写了篇博文,连接如下:http://www.voidcn.com/article/p-mfgogccw-zu.html
确实好巧,今天我自己就从零开始来完成这个小游戏,完成的方式也是一步一步的添加功能这样的方式来实现。
第一步完成的功能:写一个界面
大家见到的贪吃蛇小游戏,界面肯定是少不了的。因此,第一步就是写一个小界面。
实现代码如下:
public class SnakeFrame extends Frame{
public static void main(String[] args) {
SnakeFrame s = new SnakeFrame();
s.launchFrame();
}
private void launchFrame() {
this.setLocation(300, 400);
this.setSize(400, 400);
this.setBackground(Color.WHITE);
this.setTitle("Snake");
//添加关闭的处理事件
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//禁止改变窗的大小
this.setResizable(false);
this.setVisible(true);
}
}
第二步完成的功能:在界面上画成一格一格的
我们见过的贪吃蛇游戏,是有一个格子一个格子构成,然后蛇在这个里面运动。
重写paint方法,单元格就是横着画几条线竖着画几条线即可。
代码如下:
@Override
public void paint(Graphics g) {
Color c = g.getColor();
g.setColor(Color.GRAY);
/* * 画线 * */
int col = GAME_WIDTH/squareSize;
int row = GAME_HEIGHT/squareSize;
for(int i=0;i
g.drawLine(i*squareSize, 0, i*squareSize, GAME_HEIGHT);
}
for(int i=0;i
g.drawLine(0, i*squareSize, GAME_WIDTH, i*squareSize);
}
g.setColor(c);
}
效果如下:
第三步完成的功能:建立另外的线程来控制重画
由于,蛇的运动就是改变蛇所在的位置,然后进行重画,就是我们所看到的运动。因此,在这里,我们单独用一个线程来控制重画。
1、新建一个MyPaintThread类,实现了Runnable接口
private class MyPaintThread implements Runnable{
@Override
public void run() {
//每隔50ms重画一次
while(true){
repaint();//会自动调用paint方法
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2、在SnakeFrame的launchFrame方法中添加代码:new Thread(new MyPaintThread()).start();即可。
第四步完成的功能:在界面上画一个蛇出来
贪吃蛇游戏中的蛇就是用一个“点”来表示。
这里,我们将蛇新建一个类,用面向对象的思想,发现,这个类应该有如下的属性和方法:
1、位置
2、大小,即长度、宽度
3、方向
4、构造方法
5、draw方法
Snake类的代码如下:
public class Snake {
//位置
private int x;
private int y;
//大小
private static final int WIDTH = 10 ;
private static final int HEIGHT = 10 ;
private SnakeFrame snakeFrame ;
//方向
private Direction dir =Direction.D;
private SnakeFrame snakeFrame ;
public Snake(int x, int y, SnakeFrame snakeFrame) {
this.x = x;
this.y = y;
this.snakeFrame = snakeFrame;
}
public Snake(int x, int y,Direction dir, SnakeFrame snakeFrame) {
this(x,y,snakeFrame);
this.dir = dir ;
}
public void draw(Graphics g){
Color c = g.getColor();
g.setColor(Color.BLACK);
g.fillRect(x, y, WIDTH, HEIGHT);
g.setColor(c);
}
}
Direction是一个enum,具体如下:
public enum Direction {
L,U,R,D
}
在SnakeFrame类中new一个Snake对象,然后调用Snake对象的draw方法即可。
效果如下:
第五步完成的功能:通过键盘控制蛇的上下左右移动
首先想到的是这样:在Snake类中添加一个keyPressed方法,然后在SnakeFrame的键盘事件中调用Snake对象的keyPressed方法。
具体如下:
Snake类中添加一个keyPressed方法
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_LEFT :
this.x = x - WIDTH;
break;
case KeyEvent.VK_UP :
this.y = y - HEIGHT;
break;
case KeyEvent.VK_RIGHT :
this.x = x + WIDTH;
break;
case KeyEvent.VK_DOWN :
this.y = y + WIDTH;
break;
}
//处理蛇的边界
if(x<=0){
x = 0;
}
else if(x>SnakeFrame.GAME_WIDTH - WIDTH){
x = SnakeFrame.GAME_WIDTH - WIDTH;
}
if(y<=0){
y = 0;
}
else if(y>SnakeFrame.GAME_HEIGHT - HEIGHT){
y = SnakeFrame.GAME_HEIGHT - HEIGHT ;
}
}
在SnakeFrame中完整代码如下:
public class SnakeFrame extends Frame{
//游戏界面的大小
public static final int GAME_WIDTH =400;
public static final int GAME_HEIGHT =400;
//游戏中方格的大小
private static final int squareSize = 10;
Snake s = new Snake(40,40,Direction.D,this);
public static void main(String[] args) {
SnakeFrame s = new SnakeFrame();
s.launchFrame();
}
private void launchFrame() {
this.setLocation(300, 400);
this.setSize(GAME_WIDTH, GAME_HEIGHT);
this.setBackground(Color.WHITE);
this.setTitle("Snake");
//添加关闭的处理事件
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
//禁止改变窗的大小
this.setResizable(false);
this.setVisible(true);
new Thread(new MyPaintThread()).start();
this.addKeyListener(new MyKeyListener());
}
@Override
public void paint(Graphics g) {
Color c = g.getColor();
g.setColor(Color.GRAY);
/* * 画线 * */
int col = GAME_WIDTH/squareSize;
int row = GAME_HEIGHT/squareSize;
for(int i=0;i
g.drawLine(i*squareSize, 0, i*squareSize, GAME_HEIGHT);
}
for(int i=0;i
g.drawLine(0, i*squareSize, GAME_WIDTH, i*squareSize);
}
g.setColor(c);
s.draw(g);
}
/* * 重画线程类 * */
private class MyPaintThread implements Runnable{
@Override
public void run() {
//每隔50ms重画一次
while(true){
repaint();//会自动调用paint方法
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/* * 键盘监听类 * */
private class MyKeyListener extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
s.keyPressed(e);
}
}
}
以上就完成了通过键盘来控制着蛇的上下左右移动。
第六步完成的功能:改善Snake类,如果没有按键,则按照原来的方向移动
由于上面的Snake类中的keyPressed方法实现的是:每按键一次,蛇就移动一次,完全没有把方向加入进去,即我们没有完成这样的功能,如果我们没有按键,则按照原来的方向移动。
为了解决这个问题,则需要对Snake类来进行改善。
public class Snake {
//位置
private int x;
private int y;
//大小
private static final int WIDTH = 10 ;
private static final int HEIGHT = 10 ;
//方向
private Direction dir =Direction.D;
private SnakeFrame snakeFrame ;
public Snake(int x, int y, SnakeFrame snakeFrame) {
this.x = x;
this.y = y;
this.snakeFrame = snakeFrame;
}
public Snake(int x, int y,Direction dir, SnakeFrame snakeFrame) {
this(x,y,snakeFrame);
this.dir = dir ;
}
public void draw(Graphics g){
Color c = g.getColor();
g.setColor(Color.BLACK);
g.fillRect(x, y, WIDTH, HEIGHT);
g.setColor(c);
move();
}
/* * 函数功能:根据按键来确定蛇的移动方向 * */
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_LEFT :
this.dir = Direction.L;
break;
case KeyEvent.VK_UP :
this.dir = Direction.U;
break;
case KeyEvent.VK_RIGHT :
this.dir = Direction.R;
break;
case KeyEvent.VK_DOWN :
this.dir = Direction.D;
break;
default:
this.dir = Direction.STOP;
}
}
/* * 根据方向的具体移动 * */
public void move(){
if(dir == Direction.L){
x = x - WIDTH;
}
else if(dir == Direction.U){
y = y - HEIGHT;
}
else if(dir == Direction.R){
x = x + WIDTH;
}
else if(dir == Direction.D){
y = y + HEIGHT;
}
//处理蛇的边界
if(x<=0){
x = 0;
}
else if(x>SnakeFrame.GAME_WIDTH - WIDTH){
x = SnakeFrame.GAME_WIDTH - WIDTH;
}
if(y<=0){
y = 0;
}
else if(y>SnakeFrame.GAME_HEIGHT - HEIGHT){
y = SnakeFrame.GAME_HEIGHT - HEIGHT ;
}
}
}
SnakeFrame的代码与上面贴出来一致。
这样,就实现了,当我们没有按方向键时,则按照原来的方向移动。
未完,待续!!!!
接下来要实现的功能有: 1、随机产生其他的蛇; 2、蛇吃其他的蛇变大