找了好多案例,发现都是贴图的,要么就是代码无法运行的,好不容易找到一个,结果代码粘贴的辣眼睛。
接下来就是整个贪吃蛇,包结构
贪吃蛇这个原理:
- 蛇身打印,利用矩形填充打印方块,几个方块存储在数组中,按顺序打印出来。数组存储的数据时按键方向判断之后对相应方向、比如上或者下加上高度或者宽度。
- 蛇移动,就是不停刷新界面,重新绘制方块。方块的绘制上面连接里面有,刷新方块上面连接也有。
- 键盘控制方向,键盘是new一个键盘监视器,把他给SnakeClient,然后new SnakeClient时候就可以调用。每个按键都有自己的代码,用getKeyCode返回按键值,然后用一个case给方向Direction赋值。其中方向,用了一个枚举类型来存储四个方向,不用枚举应该也可以,使用字符串常量,或者一个变量给四个值来判断方向,我还没有尝试,大家有兴趣可以自己试试。
- 吃食物,用一个矩形区域检测,这个是java自带的,直接调用Rectangle中的这个检测函数。把food的矩形和蛇头的矩形区域比较。比较之后再次重新调用food的set函数设置food下次出现位置。
- this涉及的比较多,函数重写有一点,就是paint,还有repaint调用。学会这个对对象和类有挺大帮助。
代码缺点:
- 还没实现蛇身碰撞检测,这会加大代码量,本代码力求最简单
- 还没实现边界检测,蛇会跑到界面外
- 还没实现计分板功能,虽然这个需求比较简单,但是我们的目标是尽量少的代码,让初学者能看懂
第一个是显示界面,运用线程启动,用刷新来重新绘制图形
package cn.led.snake;
import java.awt.*;
import java.awt.event.*;
public class SnakeClient extends Frame{
Snake mySnake = new Snake(this);
Food food = new Food(this);
public void lanch(){
this.setBounds(200,100, 700,700); //设置窗体大小和位置
this.setTitle("我是贪吃蛇");
this.setVisible(true); //使用该属性才能显示窗体
this.setBackground(Color.black);
//实现程序运行关闭的功能
this.addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(-1);
}
});
this.addKeyListener(new KeyMointer());//调用键盘,不启用这个无法开启键盘控制
new Thread(new PaintThread()).start();//开启线程
}
//画图函数,这个是重写paint,貌似是Frame类的内置函数
public void paint(Graphics g){
mySnake.paint(g);
food.paint(g);
}
class PaintThread implements Runnable{
public void run() {
//while(true)保持蛇能一直运行
while(true){
repaint();
try {
//物体运行太快,肉眼无法追踪,这是减慢速度,使得肉眼能跟上刷新速度
Thread.sleep(250);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//键盘控制
class KeyMointer extends KeyAdapter{
public void keyPressed(KeyEvent e){
mySnake.keyPress(e);
}
}
public static void main(String[] args){
SnakeClient snakeClient = new SnakeClient();
snakeClient.lanch();
}
}
第二个是蛇的绘制
package cn.led.snake;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
public class Snake {
final static int WIDTH = 20;//蛇身的宽
final static int HEIGHT = 20;//蛇身的高
final static int maxLong = 900;//蛇最多节数
enum Direction{Left,Up,Right,Down};//方向枚举
int number = 5;//蛇身初始化节数
int[] x = new int[maxLong];//蛇身x轴位置
int[] y = new int[maxLong]; //蛇身y轴位置
Direction snakeDirection ;
SnakeClient sc;
public Snake(SnakeClient sn) {
this.number = 5;
//初始化蛇身,不初始化可能会随机出现在界面外
for(int i=0;i<=number;i++){
x[i] = 100;
y[i] = 100;
}
//初始方向
this.snakeDirection = Direction.Right;
this.sc = sn;
}
public void move() {
if(this.snakeDirection==Direction.Down) {
for (int i = 0; i < number; i++) {
x[i] = x[i+1];
y[i] = y[i+1];
}
y[number] = y[number]+HEIGHT;
}
else if(this.snakeDirection==Direction.Right) {
for (int i = 0; i < number; i++) {
x[i] = x[i+1];
y[i] = y[i+1];
}
x[number] = x[number]+WIDTH;
}
else if(this.snakeDirection==Direction.Up) {
for (int i = 0; i < number; i++) {
x[i] = x[i+1];
y[i] = y[i+1];
}
y[number] = y[number]-HEIGHT;
}
if(this.snakeDirection==Direction.Left){
for (int i = 0; i < number; i++) {
x[i] = x[i+1];
y[i] = y[i+1];
}
x[number] -= WIDTH;
}
}
//方向键对蛇的控制
public void keyPress(KeyEvent e){
int press = e.getKeyCode();
switch(press){
case KeyEvent.VK_LEFT:
this.snakeDirection = Direction.Left;
break;
case KeyEvent.VK_UP:
this.snakeDirection = Direction.Up;
break;
case KeyEvent.VK_RIGHT:
this.snakeDirection = Direction.Right;
break;
case KeyEvent.VK_DOWN:
this.snakeDirection = Direction.Down;
break;
}
}
public void paint(Graphics g){
Color c = g.getColor();
g.setColor(Color.blue); //设置颜色为蓝色
for (int i = 0; i <=number; i++) { //最后一个画出的是蛇头
if (i==number) {
g.setColor(Color.yellow);
g.fillRect(x[number], y[number], 20, 20); //蛇头设置成黄色
}
g.fillRect(x[i], y[i], 20, 20); //填充矩形
}
g.setColor(c);
move();
eatFood(this.sc.food);
}
//蛇吃食物
public void eatFood(Food food){
//判断是否产生碰撞,返回true则刷新食物
if(this.getRec().intersects(food.getRec())){
number++; //吃到食物蛇长度+1
x[number] = sc.food.getX();
y[number] = sc.food.getY();
this.sc.food.setX(((int)(Math.random()*29))*Snake.WIDTH);
this.sc.food.setY((int)(Math.random()*29+1)*Snake.HEIGHT);
}
}
public Rectangle getRec(){
return new Rectangle(x[number],y[number],WIDTH,HEIGHT);
}
}
第三个是食物绘制代码
package cn.led.snake;
import java.awt.*;
public class Food {
public static int WIDTH = 20;
public static int HEIGHT = 20;
private boolean isLive = true;//判断食物是否还在
int x ,y;//初始化食物出现地点
SnakeClient ms;
public Food(SnakeClient ms){
x = ((int)(Math.random()*50))*SnakeClient.WIDTH;
y = (int)(Math.random()*50)*SnakeClient.HEIGHT;
isLive = true;
this.ms = ms;
}
public boolean isLive() {
return isLive;
}
public void setLive(boolean isLive) {
this.isLive = isLive;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
//画食物
public void paint(Graphics g){
if(isLive==true){
Color c = g.getColor();
g.setColor(Color.red);
g.fillRect(x, y, WIDTH, HEIGHT);
}
}
public Rectangle getRec(){
return new Rectangle(x,y,WIDTH,HEIGHT);
}
}
运行效果图---------动图-----------