是我第22喜欢的贪吃蛇时间 1759239 金益恒
稍微翻了一下以前学java时做的练习,看到了贪吃蛇的代码。不是很长,也有改进空间,刚好可以拿来用,此篇博文诞生,下面就是心路历程和修改思路:
First:这是贪吃蛇的界面,我们先设置窗口的大小和行列数,给到标题“贪吃蛇”和出现位置,面子工程第一步,当然这些参数可以随意一点,这里强迫症发作就把数值保持一致。
另:为方便读者阅读已修改绝大多数的变量名(比如说SnakeFrame原来就叫SheGeZi。。。现规范格式,进行统一)
备注总结彩蛋之类的在篇尾,嗯
public class SnakeFrame exten
ds Frame{
public static final int BLOCK_WIDTH = 15 ;
public static final int BLOCK_HEIGHT = 15 ;
public static final int ROW = 40;
public static final int COL = 40;
public static void main(String[] args) {
new SnakeFrame().launch();
}
public void launch(){
this.setTitle("贪恰蛇");
this.setSize(ROW*BLOCK_HEIGHT, COL*BLOCK_WIDTH);
this.setLocation(300, 300);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
this.setResizable(false);
this.setVisible(true);
}
}
下面我们来画网格线以方便玩家进行定位
起初为了醒目是红线网格,现在看来红线其实并不好,还起到了反效果,故这里修改成了灰色网格,同上进行了变量名修改,往后再不赘述(不全改都跑不通我干嘛要作死好麻烦。。。)
@Override
public void paint(Graphics g) {
Color c = g.getColor();
g.setColor(Color.GRAY);
for(int i = 0;i<ROW;i++){
g.drawLine(0, i*BLOCK_HEIGHT, COL*BLOCK_WIDTH,i*BLOCK_HEIGHT );
}
for(int i=0;i<COL;i++){
g.drawLine(i*BLOCK_WIDTH, 0 , i*BLOCK_WIDTH ,ROW*BLOCK_HEIGHT);
}
g.setColor(c);
}
Part3:用构造方法和Draw方法把蛇画出来,Node类表示蛇的节点,这部分除了修改变量名之外做好统一规范之外,没做修改
关于Direction,这是个enum
public class Node {
private static final int BLOCK_WIDTH = SnakeFrame.BLOCK_WIDTH;
private static final int BLOCK_HEIGHT = SnakeFrame.BLOCK_HEIGHT;
private int row;
private int col;
private Direction dir ;
private Node pre;
private Node next;
public Node(int row, int col, Direction dir) {
this.row = row;
this.col = col;
this.dir = dir;
}
public void draw(Graphics g){
Color c = g.getColor();
g.setColor(Color.BLACK);
g.fillRect(col*BLOCK_WIDTH, row*BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
g.setColor(c);
}
}
public class Node {
private static final int BLOCK_WIDTH = SnakeFrame.BLOCK_WIDTH;
private static final int BLOCK_HEIGHT = SnakeFrame.BLOCK_HEIGHT;
private int row;
private int col;
private Direction dir ;
private Node pre;
private Node next;
public Node(int row, int col, Direction dir) {
this.row = row;
this.col = col;
this.dir = dir;
}
public void draw(Graphics g){
Color c = g.getColor();
g.setColor(Color.BLACK);
g.fillRect(col*BLOCK_WIDTH, row*BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
g.setColor(c);
}
}
public enum Direction {
L,U,R,D
}
再就是怎么让蛇动起来并恰东西:
首先想到的是这样:其移动是通过在头部添加一个单元格,在尾部删除一个单元格,那么:
就在Snake类中添加一个keyPressed方法
当然,这主要是根据键盘的上下左右键来确定蛇头结点的方向,然后用move方法再根据头结点的方向来在头部加一个格子。
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
switch(key){
case KeyEvent.VK_LEFT :
if(head.dir!=Direction.R){
head.dir = Direction.L;
}
break;
case KeyEvent.VK_UP :
if(head.dir!=Direction.D){
head.dir = Direction.U;
}
break;
case KeyEvent.VK_RIGHT :
if(head.dir!=Direction.L){
head.dir = Direction.R;
}
break;
case KeyEvent.VK_DOWN :
if(head.dir!=Direction.U){
head.dir = Direction.D;
}
break;
}
}
public void move() {
addNodeInHead();
deleteNodeInTail();
}
private void deleteNodeInTail() {
Node node = tail.pre;
tail = null;
node.next = null;
tail = node;
}
private void addNodeInHead() {
Node node = null;
switch(head.dir){
case L:
node = new Node(head.row,head.col-1,head.dir);
break;
case U:
node = new Node(head.row-1,head.col,head.dir);
break;
case R:
node = new Node(head.row,head.col+1,head.dir);
break;
case D:
node = new Node(head.row+1,head.col,head.dir);
break;
}
node.next = head;
head.pre = node;
head = node;
}
public void draw(Graphics g){
if(head==null){
return ;
}
move();
for(Node node = head;node!=null;node = node.next){
node.draw(g);
}
}
关于蛇吃的蛋:
getRect方法:用于碰撞检测
reAppear方法:用于重新产生蛋的方法
public class Egg {
private int row;
private int col;
private static final int BLOCK_WIDTH = SnakeFrame.BLOCK_WIDTH;
private static final int BLOCK_HEIGHT = SnakeFrame.BLOCK_HEIGHT;
private static final Random r = new Random();
private Color color = Color.RED;
public Egg(int row, int col) {
this.row = row;
this.col = col;
}
public Egg() {
this((r.nextInt(SnakeFrame.ROW-2))+2,(r.nextInt(SnakeFrame.COL-2))+2);
}
public void reAppear(){
this.row = (r.nextInt(SnakeFrame.ROW-2))+2;
this.col = (r.nextInt(SnakeFrame.COL-2))+2;
}
public void draw(Graphics g){
Color c= g.getColor();
g.setColor(color);
g.fillOval(col*BLOCK_WIDTH, row*BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
g.setColor(c);
if(color==Color.RED){
color = Color.BLUE;
}
else{
color = Color.RED;
}
}
public Rectangle getRect(){
return new Rectangle(col*BLOCK_WIDTH, row*BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
}
}
判断蛇是否吃到了蛋:
吃到了,则加长
public Rectangle getRect(){
return new Rectangle(head.col*BLOCK_WIDTH, head.row*BLOCK_HEIGHT, BLOCK_WIDTH, BLOCK_HEIGHT);
}
public boolean eatEgg(Egg egg){
if(this.getRect().intersects(egg.getRect())){
addNodeInHead();
egg.reAppear();
return true;
}
else{
return false;
}
}
接下来是增量开发时间:
贪吃蛇还能加什么呢,坦白来说没什么好加的了
于是我们就给他加了个边框。。。
加了个双缓冲。。。。
又加了个控制画面。。。。
Finally!下面是贴代码time:
private class MyPaintThread implements Runnable{
@Override
public void run() {
while(true){
repaint();
try {
Thread.sleep(50);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
private Image offScreenImage = null;
@Override
public void update(Graphics g) {
if(offScreenImage==null){
offScreenImage = this.createImage(ROW*BLOCK_HEIGHT, COL*BLOCK_WIDTH);
}
Graphics offg = offScreenImage.getGraphics();
paint(offg);
g.drawImage(offScreenImage, 0, 0, null);
}
private void checkDead() {
if(head.row<2||head.row>SnakeFrame.ROW||head.col<0||head.col>SnakeFrame.COL){
this.sf.gameOver();
}
for(Node node =head.next;node!=null;node = node.next){
if(head.row==node.row&&head.col == node.col){
this.sf.gameOver();
}
}
}
private boolean b_gameOver = false;
public void gameOver(){
b_gameOver = true;
}
@Override
public void update(Graphics g) {
if(b_gameOver){
g.drawString("游戏结束!!!", ROW/2*BLOCK_HEIGHT, COL/2*BLOCK_WIDTH);
}
}
这篇博文的重难点在:
那么
GAME OVER~~~~撒花撒花撒花~~~~~~游戏结束~~~~~~~~
就这么长了毕竟介于“不那么简单也不难”的代码貌似也就这个了呢。。。
简要对代码做了写解释(因为莫得备注)
那为什么没备注呢(因为当时根本没想到要写备注)
至少了解到了备注的重要性,嗯
以上。
原文:https://www.cnblogs.com/danhuabaoyikouyinzi/p/10476353.html