1.概述
首先要了解游戏的画面--一个画面为一帧,那怎么让画面动起来还是要靠定时器进行刷新。
这个小游戏主要需要掌握的技术要点:
首先:面板的绘制,必须是需要一个面板来展示游戏嘛;其次:键盘输入的控制(玩游戏肯定是在键盘上操作嘛),最后:定时器的操作(看多少秒刷新一帧,让游戏动起来的关键)
那下面的代码实现就主要围绕着三个方面来进行啦
2.代码实现
2.1 绘制面板及画面
Step1:先绘制静态窗口,再窗口上面绘制一个游戏面板,主要的操作就在游戏面板中进行,这个类就是游戏的启动类
public class StartGame { public static void main(String[] args) { //1.绘制一个静态窗口 JFrame frame=new JFrame("贪吃蛇游戏"); frame.setBounds(10,10,900,720); frame.setResizable(false); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //2.绘制一个面板 游戏面板 frame.add(new GamePanel()); frame.setVisible(true); }
Step2:绘制游戏面板
我们先看一下效果图:可以看到将这个面板分成了三个区域,其中1就是一个图标,2部分记录了当前蛇的长度和分数,第三个部分就是主要玩游戏的地方(包括蛇的绘制、一个食物,一句话语(按下空格开始游戏))
需要明确的是:一个画面中的某一点其实可以抽象成一个坐标来表示,所以无论是食物还是蛇我们都可以通过坐标来进行表示
先定义一些变量:(这是所有的变量定义,有些变量后面才会用到,后面再进行解释)
int length; //蛇的长度 int[] snakeX=new int[500]; //蛇x坐标 int[] snakeY=new int[500]; //y坐标 String fx; //方向 boolean isStart=false; //游戏是否开始 //定时器 Timer timer; int delay; //时间 //1.定义一个食物 int foodX; int foodY; Random random=new Random(); //死亡判断 boolean isFail=false; //积分系统 int score;
再初始化:
length=3; snakeX[0]=100;snakeY[0]=100; snakeX[1]=75;snakeY[1]=100; snakeX[2]=50;snakeY[2]=100; fx="R"; foodX=25+25*random.nextInt(34); foodY=75+25*random.nextInt(24); score=0;
再将物体画在面板上:主要是重写paintComponent()方法:
//画头部 Data.header.paintIcon(this,g,25,11); g.fillRect(25,75,850,600); //根据方向画头部的方向 if(fx.equals("R")){ Data.right.paintIcon(this,g,snakeX[0],snakeY[0]); }else if(fx.equals("L")) { Data.left.paintIcon(this, g, snakeX[0], snakeY[0]); }else if(fx.equals("U")) { Data.up.paintIcon(this, g, snakeX[0], snakeY[0]); }else if(fx.equals("D")) { Data.down.paintIcon(this, g, snakeX[0], snakeY[0]); } //画身体 for(int i=1;i<length;i++){ Data.body.paintIcon(this,g,snakeX[i],snakeY[i]); } //画积分 g.setColor(Color.white); g.setFont(new Font("微软雅黑",Font.BOLD,20)); g.drawString("长度:"+length,750,35); g.drawString("分数:"+score,750,60); //画食物 Data.food.paintIcon(this,g,foodX,foodY); //游戏提示 if(isStart==false){ //画一个文字 g.setColor(Color.white); g.setFont(new Font("微软雅黑",Font.BOLD,40)); g.drawString("按下空格开始游戏",300,300); } //失败提示 if(isFail==true){ //画一个文字 g.setColor(Color.red); g.setFont(new Font("微软雅黑",Font.BOLD,40)); g.drawString("游戏失败 按下空格重新开始",200,300); }
这里蛇的头部和身体都是由一张图片组成,主要需要定义一个Data类记录这些图片:
/*** * 图片数据 */ public class Data { //头部 public static URL headerURL = Data.class.getResource("/statics/header.png"); public static ImageIcon header = new ImageIcon(headerURL); //贪吃蛇 头部上下左右 public static URL upURL = Data.class.getResource("/statics/up.png"); public static URL downURL = Data.class.getResource("/statics/down.png"); public static URL leftURL = Data.class.getResource("/statics/left.png"); public static URL rightURL = Data.class.getResource("/statics/right.png"); public static ImageIcon up = new ImageIcon(upURL);//上 public static ImageIcon down = new ImageIcon(downURL);//下 public static ImageIcon left = new ImageIcon(leftURL);//左 public static ImageIcon right = new ImageIcon(rightURL);//右 //身体 public static URL bodyURL = Data.class.getResource("/statics/body.png"); public static ImageIcon body = new ImageIcon(bodyURL); //食物 public static URL foodURL = Data.class.getResource("/statics/food.png"); public static ImageIcon food = new ImageIcon(foodURL); }
2.2 键盘点击事件
这里主要是需要继承KeyListener重写方法,在keyPressed()方法中进行操作。这里的输入主要是蛇的移动上下左右、还有空格。
空格键的处理:如果游戏失败,那就按空格键重新开始,如果游戏还未失败那就是按空格键暂停或者开始:
//键盘按下,未释放 //获取按下的键盘是哪个键 int keyCode = keyEvent.getKeyCode(); if(keyCode==KeyEvent.VK_SPACE){ //如果失败了就重新开始 if(isFail){ isFail=false; //重新初始化 init(); }else{ //如果没有失败就是暂停或者开始 isStart=!isStart; } repaint();//刷新页面 }
蛇的移动:这里主要是根据键盘的输入来定义蛇的移动方向,并且不能转头
if(keyCode==KeyEvent.VK_RIGHT){ if(fx.equals("L")){ fx="L"; }else{ fx="R"; } }else if(keyCode==KeyEvent.VK_LEFT){ if(fx.equals("R")){ fx="R"; }else{ fx="L"; } }else if(keyCode==KeyEvent.VK_UP){ if(fx.equals("D")){ fx="D"; }else{ fx="U"; } }else if(keyCode==KeyEvent.VK_DOWN){ if(fx.equals("U")){ fx="U"; }else{ fx="D"; } }
2.3 定时器刷新
主要是需要继承ActionListener重写actionPerformed()方法
初始化定时器:这里指的是多少毫秒刷新一次,也可以根据这个时间调节快慢
delay=100; timer=new Timer(100,this);
这里的逻辑主要是蛇的移动的坐标:
if(isStart && isFail==false) { /*** * 3 2 1 * 先是第3个到第2个,身体向前移动 */ for (int i = length-1; i >0; i--) { snakeX[i] = snakeX[i - 1]; snakeY[i] = snakeY[i - 1]; } //通过控制方向让头部移动 if(fx.equals("R")){ snakeX[0] = snakeX[0] + 25; /*** * 这里的边界判断是指 * 当头部到边界时 * 重新设定头部位置 * 但是已经不需要 * 当到边界时游戏结束即可 */ //边界判断 // if(snakeX[0]>850){ // snakeX[0]=25; // } }else if(fx.equals("L")){ snakeX[0] = snakeX[0] - 25; //边界判断 // if(snakeX[0]<25){ // snakeX[0]=25; // } }else if(fx.equals("U")){ snakeY[0] = snakeY[0] - 25; //边界判断 // if(snakeY[0]<75){ // snakeY[0]=650; // } }else if(fx.equals("D")){ snakeY[0] = snakeY[0] + 25; //边界判断 // if(snakeY[0]>650){ // snakeY[0]=75; // } }
蛇吃食物:当蛇头的坐标与食物的坐标重合时就证明吃到了食物,分数+1,蛇的长度也进行相应的加1,并且重新生成食物就可以
if(snakeX[0]==foodX && snakeY[0]==foodY){ //长度+1,分数+1 length++; score++; //重新生成食物 foodX=25+25*random.nextInt(34); foodY=75+25*random.nextInt(24); }
在进行游戏结束的判断、刷新页面:
/*** * 判断是否结束 */ private void isFailMethod() { for(int i=1;i<length;i++){ //撞到身体 if(snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]){ isFail=true; } } //碰撞检测--小蛇头和墙壁 if ((snakeX[0]<25 || snakeX[0]>850)||(snakeY[0]<75 || snakeY[0]>650 ) ){ isFail = true; } }
一定不要忘记最后让定时器启动!!!!
timer.start();
3.总结
主要的代码逻辑这里就可以分别进行说明啦。整个运行的代码我上传在我的资源上啦