目录
创建窗体
创建游戏棋盘
创建蛇的节点
创建蛇身
让蛇移动
添加键盘监听
添加边界处理
把食物绘制到棋盘上
吃食物
创建窗体
创建一个MainFrame类继承JFrame,表示主窗体。
public class MainFrame extends JFrame {//创建窗体对象时,初始化船体参数public MainFrame(){initFrame();}
}
MainFrame类中写一个initFrame方法,初始化窗体参数
//1.初始化窗体参数
private void initFrame() {//设置窗体标题setTitle("黑马贪吃蛇");//设置窗体大小setSize(610, 640);//设置窗体位置setLocation(400, 400);//设置窗体大小不能改变setResizable(false);//设置窗体关闭按钮的作用,是正常退出setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
在MainFrame中添加一个main方法,创建窗体并运行,就可以看到窗体了
//主方法
public static void main(String[] args) {//创建窗体,并显示在屏幕上new MainFrame().setVisible(true);
}
创建游戏棋盘
在JFrame类中写一个initGamePanel方法,初始化游戏棋盘
//初始化游戏面板
private void initGamePanel() {JPanel jPanel = new JPanel() {//paint是用来绘制面板中的内容@Overridepublic void paint(Graphics g) {//设置画笔颜色g.setColor(Color.black); //设置画笔颜色是黑色//绘制40条横线(起点横坐标,起点纵坐标,终点横坐标,终点纵坐标)for(int i=1;i<=40;i++){g.drawLine(0,15*i,600,15*i);}//绘制40条竖线for (int i=1;i<=40;i++){g.drawLine(15*i,0,15*i,600);}}};add(jPanel);
}
创建蛇的节点
创建一个Node类表示节点,一条蛇有若干个节点组成,每一个节点其实就是一个小方格,我们用行和列来定义节点在棋盘中的位置。
public class Node {private int x; //横坐标private int y; //纵坐标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;}
}
创建蛇身
创建Snake类表示蛇,一条蛇有多个节点使用LinkedList集合存储Node节点,蛇出生的时候 有3个节点。
public class Snake {//bodyprivate LinkedList<Node> body;//创建蛇对象时,初始化蛇身public Snake() {initSnake();}//初始化蛇身 3个节点public void initSnake(){//创建蛇的躯体body=new LinkedList<>();//给蛇添加3个节点,在棋盘的中心位置横向排列body.add(new Node(20,20));body.add(new Node(21,20));body.add(new Node(22,20));}//获取蛇蛇身public LinkedList<Node> getBody(){return body;}
}
把蛇绘制到棋盘上
在MainFrame中添加一个创建Snake的成员变量,表示窗体中有一条蛇
public class MainFrame extends JFrame {//定义成员变量private Snake snake=new Snake();....
}
在绘制棋盘的paint方法中,添加下面的代码绘制把蛇绘制到棋盘上
//绘制横线
...
//绘制竖线
...//绘制蛇,根据每一个节点的坐标在棋盘上绘制矩形
for (Node node : snake.getBody()) {//每一个节点的宽度和高度是15g.fillRect(node.getX()*15,node.getY()*15,15,15);
}
再次运行,就可以看到有一条蛇静静的躺在棋盘中间了
让蛇移动
定义一个枚举类型,表示运动的4个方向
public enum Direction {UP,DOWN,LEFT,RIGHT
}
在Snake类中定义一个移动方向的变量成员变量,和move方法。
public class Snake{//蛇头运动的方向private Direction direction;//移动的方法: 每次移动在蛇头运动方向添加一个节点,再删除最后一个节点public void move(){//获取蛇头的节点Node head = body.getFirst();//新的蛇头节点Node newHead=null;//检查移动的方向switch (direction){//如果向左移动case LEFT://创建一个新的蛇头节点newHead=new Node(head.getX()-1,head.getY());//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);//删除蛇尾body.removeLast();break;case RIGHT://创建一个新的蛇头节点newHead=new Node(head.getX()-1,head.getY());//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);//删除蛇尾body.removeLast();break;case UP://创建一个新的蛇头节点newHead=new Node(head.getX(),head.getY()-1);//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);//删除蛇尾body.removeLast();break;case DOWN://创建一个新的蛇头节点newHead=new Node(head.getX(),head.getY()+1);//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);//删除蛇尾body.removeLast();break;}}
}
在MainFrame类中,创建一个定时器每100毫秒,重绘游戏棋盘
public class MainFrame extends JFrame {...//游戏棋盘面板JPanel jPanel=null;//定义定时器private Timer timer;public MainFrame() throws HeadlessException {//初始化窗体参数initFrame();//初始化窗体中的游戏面板initGamePanel();//初始化定时器initTimer();}//2.初始化游戏棋盘private void initGamePanel() {jPanel = new JPanel() {//paint是用来绘制面板中的内容@Overridepublic void paint(Graphics g) {//每次重绘时清空面板中的内容g.clearRect(0,0,getWidth(),getHeight());....}};add(jPanel);}//3.初始化定时器private void initTimer() {TimerTask task=new TimerTask() {@Overridepublic void run() {//调用蛇移动的方法snake.move();//每次移动重绘游戏棋盘,会自动调用jPanel的paint方法jPanel.repaint();}};timer=new Timer();timer.scheduleAtFixedRate(task,0,100);}
}
添加键盘监听
在MainFrame类中,添加一个setKeyListener的方法,监听上下左右四个键
public class MainFrame extends JFrame {...public MainFrame() throws HeadlessException {...//添加键盘监听setkeyListener();}//添加键盘监听private void setkeyListener() {//对上下左右键进行监听addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {switch (e.getKeyCode()){//按下上键case KeyEvent.VK_UP://蛇头方向改为上snake.setDirection(Direction.UP);break;//按下下键case KeyEvent.VK_DOWN://蛇头方向改为下snake.setDirection(Direction.DOWN);break;//按下左键case KeyEvent.VK_LEFT://蛇头方向改为左snake.setDirection(Direction.LEFT);break;//按下右键case KeyEvent.VK_RIGHT://蛇头方向改为右snake.setDirection(Direction.RIGHT);break;}}});}
}
到此蛇就可以跟随键盘移动了
添加边界处理
当蛇移动到边界处就游戏结束,把标记改为false
public class Snake{...//定义一个标记true表示蛇是活的,可以运动private boolean isLive=true;//检查蛇是否碰壁private void checkOver() {//获取蛇头Node head = body.getFirst();int x=head.getX();int y=head.getY();if(x<0||y<0||x>=40||y>=40){isLive=false;}}
}
在定时器中调用checkOver()方法
//3.初始化定时器
private void initTimer() {TimerTask task=new TimerTask() {@Overridepublic void run() {//移动snake.move();//检查是否碰壁snake.checkOver();}};timer=new Timer();timer.scheduleAtFixedRate(task,0,100);
}
把食物绘制到棋盘上
创建一个Food类表示食物,其实食物也是一个节点,所以让Food继承Node
public class Food extends Node {//创建食物的时候,随机产生一个位置public Food() {reset();}//随产生位置public void reset(){//随机生成食物的坐标Random r=new Random();setX(r.nextInt(40));setY(r.nextInt(40));}
}
在MainFrame中定义一个成员Food表示食物,并把食物绘制到棋盘上
public class MainFrame extends JFrame {//定义食物private Node food=new Node();public MainFrame() throws HeadlessException {//初始化窗体参数initFrame();//初始化窗体中的游戏面板initGamePanel();//初始化定时器initTimer();//添加键盘监听setkeyListener();}//2.初始化游戏棋盘private void initGamePanel() {jPanel = new JPanel() {//paint是用来绘制面板中的内容@Overridepublic void paint(Graphics g) {//清空棋盘g.clearRect(0,0,600,600);//绘制横线、绘制竖线、绘制蛇//绘制食物g.fillRect(food.getX()*15,food.getY()*15,15,15);}};add(jPanel);}
}
吃食物
在Snake类中添加一个eatFood方法
//吃食物
public void eatFood() {//获取蛇头Node head = body.getFirst();//如果蛇头和食物的位置重合,就在蛇头添加一个元素if(head.getX()==MainFrame.food.getX()&&head.getY()==MainFrame.food.getY()){//沿着蛇头运动方向创建一个节点//新的蛇头节点Node newHead=null;//检查移动的方向switch (direction){//如果向左移动case LEFT://创建一个新的蛇头节点newHead=new Node(head.getX()-1,head.getY());//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);break;case RIGHT://创建一个新的蛇头节点newHead=new Node(head.getX()+1,head.getY());//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);break;case UP://创建一个新的蛇头节点newHead=new Node(head.getX(),head.getY()-1);//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);break;case DOWN://创建一个新的蛇头节点newHead=new Node(head.getX(),head.getY()+1);//把心得蛇头节点添加到body的第一个元素body.addFirst(newHead);break;}//每次吃完食物,让食物重置MainFrame.food.reset();}
}
在定时器中调用吃食物的方法
//2.初始化游戏棋盘
private void initGamePanel() {jPanel = new JPanel() {//paint是用来绘制面板中的内容@Overridepublic void paint(Graphics g) {//清空棋盘g.clearRect(0,0,600,600);//绘制横线、绘制竖线、绘制蛇//绘制食物g.fillRect(food.getX()*15,food.getY()*15,15,15);}};add(jPanel);
}