Java简易版贪吃蛇的原理与制作
贪吃蛇实际上是一个较为简单的线程游戏,其制作思路主要为以下几个步骤:1.主框架类(GameFrame):作为游戏的顶层容器和游戏程序的入口点。在代码中我将它写入了GamePanel里。2.游戏面板类(GamePanel):作为游戏画面的显示组件,同时用来运行游戏循环,并对用户的输入事件进行处理。3.贪吃蛇类(Snake):作为贪吃蛇的封装类,用来设置贪吃蛇的属性,并对其运动逻辑进行更新
贪吃蛇实际上是一个较为简单的线程游戏,其制作思路主要为以下几个步骤:
1.主框架类(GameFrame):作为游戏的顶层容器和游戏程序的入口点。在代码中我将它写入了GamePanel里。
2.游戏面板类(GamePanel):作为游戏画面的显示组件,同时用来运行游戏循环,并对用户的输入事件进行处理。
3.贪吃蛇类(Snake):作为贪吃蛇的封装类,用来设置贪吃蛇的属性,并对其运动逻辑进行更新,同时对其图形进行绘制。
4.食物类(Food):作为食物的封装类,用来设置食物的属性,并对其运动逻辑进行更新,同时对其图形进行绘制。
游戏中常见的碰撞检测方法有两种:边界检测法和中心检测法,前者判断两个物体的坐标范围是否存在交集,后者计算两个物体中心键的距离是否小于一个指定值。
我在代码中使用了中心检测法,其描述可为如下形式:((x1+w1/2)-(x2+w2/2))*((x1+w1/2)-(x2+w2/2))+((y1+h1/2)-(y2+h2/2))*((y1+h1/2)-(y2+h2/2))<L*L
边界检测法更适合于类似俄罗斯方块的制作,其碰撞条件如下:x1-x2<w2&&x2-x1<w1&&y1-y2<h2&&y2-y1<h1
剩下的讲解我的代码中有详细的注释,大家可以自行学习理解。
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GamePanel extends JPanel implements Runnable, KeyListener {// 继承键盘事件监听接口
private int x, y;
private int dx, dy;
private int direction;// 保存方向值
public static final int SOUTH = 0, NORTH = 1, EAST = 2, WEST = 3;// 向南、北、东、西运动
private Snake sk;// 建立贪吃蛇对象
private Food bk;// 建立食物对象
Image im;
Graphics g;
ImageIcon ima=new ImageIcon("C:\\Users\\Alienware\\Desktop\\123.jpg");
public GamePanel() {
JFrame f = new JFrame("贪吃蛇");
f.setLocation(600, 100);
f.setSize(1000, 800);
f.add(this);
f.setDefaultCloseOperation(3);
x = 50;
y = 50;
dx = 10;
dy = 10;
addKeyListener(this);// 注册键盘事件监听器
// this.setVisible(true);
// System.out.println(this.getGraphics());
f.setVisible(true);
// 实例化贪吃蛇的对象,并传递一个GamePanel对象的引用
sk = new Snake(this);
// 实例化食物对象并传递一个GamePanel对象和Snake对象的引用
bk = new Food(this, sk);
this.requestFocus();
}
public void gameUpdate() {
sk.update();// 更新贪吃蛇坐标位置
bk.update(this);// 更新食物坐标位置
switch (direction) {
case SOUTH:
y = y + dy;
break;
case NORTH:
y = y - dy;
break;
case EAST:
x = x + dx;
break;
case WEST:
x = x - dx;
break;
}
}
// Image im=new BufferedImage(100,100,BufferedImage.TYPE_4BYTE_ABGR);
public void gameRender(Image im) {
// System.out.println(im);
Graphics dbg = im.getGraphics();
dbg.drawImage(ima.getImage(),0,0,this.getWidth(),this.getHeight(),null);
sk.draw(dbg);// 在后备缓冲区绘制贪吃蛇图形
bk.draw(dbg);// 在后备缓冲区绘制食物图形
}
public void gamePaint(Image im) {
g = this.getGraphics();
// System.out.println(im);
// System.out.println(g);
g.drawImage(im, 0, 0, null);// 将后备缓冲区的内容在屏幕上显示出来
//g.dispose();
}
boolean isPaused = false;
public void run() {
while (true) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
im = new BufferedImage(this.getWidth(), this.getHeight(),
BufferedImage.TYPE_4BYTE_ABGR);
if (isPaused == false) {
gameUpdate();
}
gameRender(im);
gamePaint(im);
//g.drawImage(im, 0, 0, null);
// System.out.println("x="+x+" y="+y);
}
}
public void keyPressed(KeyEvent e) {
int keycode = e.getKeyCode();// 获取按键信息
System.out.println("keycode=" + keycode);
if (keycode == KeyEvent.VK_SPACE)// 若按下的是“空格”键。则切换
isPaused = !isPaused;
switch (keycode) {// 根据不同的按键为direction赋值
case KeyEvent.VK_DOWN:// 如果按键盘“下”方向键
direction = SOUTH;
System.out.println(direction);
break;
case KeyEvent.VK_UP:// 如果按键盘“上”方向键
direction = NORTH;
System.out.println(direction);
break;
case KeyEvent.VK_RIGHT:// 如果按键盘“右”方向键
direction = EAST;
System.out.println(direction);
break;
case KeyEvent.VK_LEFT:// 如果按键盘“左”方向键
direction = WEST;
System.out.println(direction);
break;
}
}
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
public int getDirection() {
return direction;
}
public static void main(String[] args) {
GamePanel g = new GamePanel();
Thread thread1 = new Thread(g);
thread1.start();
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
public class Snake {
GamePanel gameP;
private Point[] body;//点类型数组,保存蛇身个小球坐标
public static final int MAXLENTH=50;//蛇身最大长度
private int head;//指示蛇头位置
private int tail;//指示蛇尾位置
public int length;//蛇身长度
private int speed;//运行速度
public int x,y;//蛇头小球的横纵坐标
public int r;//蛇身小球的半径
public Snake(GamePanel gp){
gameP=gp;//通过构造方法的参数来获取对GamePanel对象的引用
body=new Point[MAXLENTH];
head=-1;
tail=-1;
length=1;
speed=10;
x=50;
y=50;
r=10;
}
public void draw(Graphics g){//绘制贪吃蛇的图形
System.out.println("head="+head+" "+"tail="+tail);
g.setColor(Color.BLUE);//设置蛇身为蓝色
if(length>1){
int i=tail;
while(i!=head){//循环绘制蛇身各个小球
g.fillOval(body[i].x, body[i].y, r, r);
i=(i+1)%body.length;
}
}
g.setColor(Color.RED);//设置蛇头为红色
g.fillOval(body[head].x, body[head].y, r, r);
if(length==1){
length++;
}
}
public void update(){//更新游戏逻辑(贪吃蛇的坐标)
int direction=gameP.getDirection();
switch(direction){
case GamePanel.SOUTH:
y+=speed;
break;
case GamePanel.NORTH:
y-=speed;
break;
case GamePanel.EAST:
x+=speed;
break;
case GamePanel.WEST:
x-=speed;
break;
}
head=(head+1)%body.length;//更新蛇头指针位置
tail=(head+body.length-length+1)%body.length;//更新蛇尾指针坐标
body[head]=new Point(x,y);//保存蛇头小球坐标值
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Random;
public class Food {
private GamePanel gameP;
private Snake snk;
public Point location;//食物的坐标
public Point size;//食物方块的尺寸
private Random rand;//随机类对象
public Food(GamePanel gp,Snake sk){
gameP=gp;//通过构造方法的参数来获取对GamePanel对象的引用
snk=sk;//通过构造方法的参数来获取对Snake对象的引用
rand=new Random();
//食物随机的出现在屏幕上某个位置
location=new Point(Math.abs(rand.nextInt(gp.getWidth())%gameP.getWidth()),Math.abs(rand.nextInt(gp.getHeight())%gameP.getHeight()));
size=new Point(sk.r,sk.r);//食物尺寸与贪吃蛇小球大小相同
}
public void draw(Graphics g){//绘制食物图形
g.setColor(Color.PINK);//设置食物颜色
g.fillRect(location.x, location.y, size.x, size.y);//绘制食物
}
public void update(GamePanel gp){//更新游戏逻辑(食物坐标)
//碰撞检测(中心检测法),判断贪吃蛇是否吃到了食物
if((snk.x-location.x)*(snk.x-location.x)+(snk.y-location.y)*(snk.y-location.y)<(snk.r*snk.r)){
//若贪吃蛇的蛇头与食物发生碰撞,则随机生成新的食物位置
location=new Point(Math.abs(rand.nextInt(gp.getWidth())%gameP.getWidth()),Math.abs(rand.nextInt(gp.getHeight())%gameP.getHeight()));
if(snk.length<Snake.MAXLENTH){
snk.length++;//若蛇身长度未达到最大值,则蛇身伸长一个单位
}
}
}
}
更多推荐
所有评论(0)