一个简单的小游戏,写的比随意,看起来很乱,思路有以下几点:
1.键盘事件控制四个方向移动
2.定义Point类的集合points存放蛇身的位置信息,这里用Point类存放了每节身体的x,y坐标,最后在面板中统一画出
3.面板中重写paintComponent方法画图
4.利用线程,调用repaint放法不重画面板
关于蛇的移动,这里移动一步的方法是,向集合中添加当前移动方向上的下一个点作为蛇头的新坐标,并在集合中移除蛇尾坐标
程序如下:
package com.Sanke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import java.util.Random; import javax.swing.JFrame; import javax.swing.JPanel; class SnakeClient extends JFrame{ //定义蛇身节点位置集合 List<Point> points = new ArrayList<Point>(); //本想定义四个移动方向,但貌似没怎么用过 private static final int UP=1; private static final int DOWN=2; private static final int LEFT=3; private static final int RIGHT=4; //当前方向 private int dir = UP; //四个布尔变量,用于判断蛇的移动方向 private boolean left=false; private boolean right=false; private boolean up=false; private boolean down=false; //蛇的生命状态 private boolean Live = true; //画图面板 private myPanel pan; //奖励 private Bonus bonus; public SnakeClient() { // TODO Auto-generated constructor stub init(); this.setSize(806,629); this.setResizable(false); this.setLocationRelativeTo(null); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); new myThread().start(); } void init(){ //初始蛇身为三个节点 points.add(new Point(0,40)); points.add(new Point(0,20)); points.add(new Point(0,0)); bonus=new Bonus(); pan = new myPanel(); this.add(pan); this.addKeyListener(new KeyMinotor()); } //蛇的移动,在方向不变的情况下向单一方向移动 void Move(){ int x = points.get(points.size()-1).x; int y = points.get(points.size()-1).y; switch(dir) { case UP: y-=20;break; case DOWN: y+=20;break; case LEFT: x-=20;break; case RIGHT: x+=20;break; } if(x<0) x = pan.getWidth()-20; if(x>=pan.getWidth()) x = 0; if(y>=pan.getHeight()) y = 0; if(y<0) y = pan.getHeight()-20; points.add(new Point(x, y)); points.remove(0); //System.out.println(x+" "+y); } //检测蛇头是否碰撞到身体 boolean hitBody(){ //取蛇头位置信息 int x = points.get(points.size()-1).x; int y = points.get(points.size()-1).y; //从蛇身开始遍历 for(int i=0;i<points.size()-1;i++) { Point p = points.get(i); if(x==p.x&&y==p.y) //头和身体坐标一样,说明发生碰撞 { return true; } } return false; } //事件监听类 class KeyMinotor extends KeyAdapter{ @Override public void keyPressed(KeyEvent e) { // TODO Auto-generated method stub super.keyPressed(e); int keycode=e.getKeyCode(); switch(keycode){ case KeyEvent.VK_UP: if(dir!=DOWN) up=true;break; //下次移动方向不能与当前方向相反 case KeyEvent.VK_DOWN: if(dir!=UP) down=true;break; case KeyEvent.VK_LEFT: if(dir!=RIGHT) left=true;break; case KeyEvent.VK_RIGHT: if(dir!=LEFT) right=true;break; } //通过四个布尔型变量的值确定最后方向 if(up&&!down&&!left&&!right) dir=UP; if(!up&&down&&!left&&!right) dir=DOWN; if(!up&&!down&&left&&!right) dir=LEFT; if(!up&&!down&&!left&&right) dir=RIGHT; //System.out.println(dir); } @Override public void keyReleased(KeyEvent e) { // TODO Auto-generated method stub super.keyReleased(e); int keycode=e.getKeyCode(); switch(keycode){ case KeyEvent.VK_UP: up=false;break; case KeyEvent.VK_DOWN: down=false;break; case KeyEvent.VK_LEFT: left=false;break; case KeyEvent.VK_RIGHT: right=false;break; } } } //自定义面板 class myPanel extends JPanel{ @Override protected void paintComponent(Graphics g) { // TODO Auto-generated method stub super.paintComponent(g); Graphics2D g2 = (Graphics2D) g; if(Live){ //画蛇 for(Point point:points) { int x=(int)point.getX(); int y=(int)point.getY(); g2.fillOval(x, y, 20, 20); } g2.drawString("当前长度:"+points.size(), 5, 13); //移动一步 Move(); //构造蛇头的rectangle对象 //System.out.println(points.get(points.size()-1).x+" "+points.get(points.size()-1).y); Rectangle rec = new Rectangle(points.get(points.size()-1).x,points.get(points.size()-1).y,20,20); if(bonus.getRec().intersects(rec))//检测蛇头是否吃到奖励 // if(points.get(points.size()-1).x==bonus.getX()&&points.get(points.size()-1).y==bonus.getY()) { int x = bonus.getX(); int y = bonus.getY(); switch(dir) { case UP: y-=20;break; case DOWN: y+=20;break; case LEFT: x-=20;break; case RIGHT: x+=20;break; } //吃到奖励蛇身加1 points.add(new Point(x,y)); //奖励消失 bonus.setLive(false); } //判断碰撞 if(hitBody()){ //发生碰撞,蛇的生命状态设为false Live = false; } //画奖励 bonus.draw(g2); // System.out.println(pan.getWidth()+" "+pan.getHeight()); }else { g2.setFont(new Font("楷体", Font.BOLD, 30)); g2.setColor(Color.RED); g2.drawString("GAME OVER!", 300, 300); } } } //自定义线程 class myThread extends Thread{ @Override public void run() { // TODO Auto-generated method stub //super.run(); while(true){ //调用repaint方法可重画面板 repaint(); try { //线程休眠 this.sleep(200); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } class Bonus{ private int x=300; private int y=300; private boolean Live = true; private Random ran = new Random(); public Bonus() { // TODO Auto-generated constructor stub } public void draw(Graphics2D g){ if(!this.isLive())//如果奖励的状态值为false { //给奖励点重新赋坐标值 x=ran.nextInt(pan.getWidth()); y=ran.nextInt(pan.getHeight()); //坐标对20取整 x=x/20*20; y=y/20*20; if(x==pan.getWidth()) x-=20; if(x<0) x+=20; if(y==pan.getHeight()) y-=20; if(y==0) y+=20; System.out.println(x+" "+y); this.setLive(true); } g.setPaint(Color.RED); g.fillOval(x, y, 20, 20); } //返回蛇身的rectangle对象 public Rectangle getRec(){ return new Rectangle(x,y,20,20); } public boolean isLive() { return Live; } public void setLive(boolean live) { Live = live; } public int getX() { return x; } public int getY() { return y; } } //主方法 public static void main(String[] args) { new SnakeClient(); } }//运行效果: