其中掺杂中多线程的的使用以及对屏幕闪烁的解决.
这个项目是对所有基础的一个小总结,值得用心去学习,总结
构建我们的基本类以及画面.
我们需要的类有三个,YARD,SNAKE,EGG.
通过面向对象的构建过程,我们首先要对我们的画面大小进行规定.
这时候,我们需要的有ROWS(行多少个小格)
COLS(列多少个小格),以及BLOCK_SIZE(每个小格的尺寸)...
int COLS = 100;int ROWS =100 ;int BLOCK_SIZE = 5;//(全部为public)
其次是我们的awt框架,使用的是Frame形式,我们有了以上数据之后,调用java.awt.Frame.
this.Location(200,200);//这个Frame窗口的初次出现位置
this.setSize(长,宽);//通过以上定义,对这个画面尺寸进行规定
this.setVisible(boolean)//是否取用Frame为默认调用
通过上面的定义我们可以画出一个空白大小的画面.
我们需要考虑的是,把这些画面分割个一个个小格子,这样更好的直观.需要调用的是java.awt.Graphics(一个抽象的接口)
这个时候,一个重要的用法出现了,paint对我们的画面进行修改
public void paint(Graphics g) {
Color c = g.getColor(); //用一个java.awt.Color类中的方法,定义一个c.把当前颜色保存在c中
g.setColor(Color.*);//对我的画笔颜色进行改变.
g.fillRect(0, 0, COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE);//画出我们的矩形的尺寸(需要用到Frame中的)
g.setColor(Color.*);//画完上述矩形的颜色之后,我们对画笔颜色再次改变进行画线
for(int i=1; i
g.drawLine(0, BLOCK_SIZE * i, COLS * BLOCK_SIZE, BLOCK_SIZE * i);//对横向画线
for(int i=1; i
g.drawLine(BLOCK_SIZE * i, 0, BLOCK_SIZE * i, BLOCK_SIZE * ROWS);
通过上述方法,我们对我们的院子进行了勾画.
通过以上方法对我们的snake以及egg,进行Run命令,对我们的画面进行模拟,是否需要调整,
以上为awt的画法.当我们的界面画出来之后,我们需要对关闭发方式进行定义
引用WindowAdapter添加监听addWindowListener()引用里面的windowClosing进行重写
this.addWindowListener(new WindowAdapter()){//匿名类方法定义
public void windowClosing(WindowEvent e){System.exit(0);}
这个代码为界面关闭Window事件,也需要引用
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
此时,我们的界面窗口可以看到我们的一个蛇头,一个窗口,以及一个鸡蛋.
private static Random r = new Random();//鸡蛋的随机出现定义.
public Egg() {this(r.nextInt(Yard.ROWS-2) + 2, r.nextInt(Yard.COLS));}
我们实现三者的实物出现之后,我们需要知道的是更多的属性去定义.
对于Snake来说,他需要有蛇头,以及蛇头以外的蛇尾,我们需要对蛇头,以及蛇尾分别进行定义
定义方法与我们之前的"小孩拉手"相似,为一个循环拉手问题.
我们需要的有head(),tail().addTohead,addTotail,next,prev来解决蛇移动的问题.
我们可以通过将尾巴替代蛇头,在移动方向添加新的蛇头来定义我们的移动.这样可以有deletetail方法.以及Node的定义蛇身的每一个点,
通过循环画笔,对其进行绘画,这样可以实现移动过程中吃到鸡蛋的添加过程.
我们还需要通过KeyPress()的指令,通过对键盘事件的监听,实现我们对方向的定义.
通过方向的定义,我们在将蛇头变化的位置以及对应添加的位置对新出现的点进行位置定义.
private void move() {
addToHead();
deleteFromTail();
checkDead();
}
以上我们实现的是,我们通过键盘实现对蛇的移动
我们还需要对PantThread的多线程方法的定义,我们使这个蛇进行持续的循环方向运动,
我们还要思考的是,如何实现蛇头跟鸡蛋发生碰撞时,如何实现这个过程.Rectangle函数,需要我们去了解.
public void eat(Egg e) {
if(this.getRect().intersects(e.getRect())) {
e.reAppear();
this.addToHead();
y.setScore(y.getScore() + 5);
}
}
private Rectangle getRect() {
return new Rectangle();
}
这个时候,我们完成了碰撞增长,移动,持续移动的测试之后,我们还需要有的是游戏进程的判定,
分为得分的判定,跟碰撞同步,以及撞墙和自己碰到自己身体时候的失败判定,以及游戏进程中的重新开始(暂停未涉及)的
'多线程判定.游戏在进行中的进行的重新开始,为多线程.
private class PaintThread implements Runnable {
private boolean running = true;
private boolean pause = false;
public void run() {
while(running) {
if(pause) continue;
else repaint();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public void pause() {
this.pause = true;
}
public void reStart() {
this.pause = false;
s = new Snake(Yard.this);
gameOver = false;
}
public void gameOver() {
running = false;
}
}
这样我们一个最简单的贪吃蛇就可以做完了,我们可以在其中继续添加功能,实现暂停等操作.
PS:屏幕闪烁问题的解决
public void update(Graphics g) {
if(offScreenImage == null) {
offScreenImage = this.createImage(COLS * BLOCK_SIZE, ROWS * BLOCK_SIZE);
}
Graphics gOff = offScreenImage.getGraphics();
paint(gOff);
g.drawImage(offScreenImage, 0, 0, null);
}
update指令的了解.以及对offScreenImage的了解. Image的了解.