Java -- 贪吃蛇日志2

昨晚实现了蛇身的增长,思路如下:

      蛇身的增长:写一个类,这个类中有一个SnakeHead类型的数组(SnakeHead类型的数组是为了方便传
递坐标),在方法snakeRun()中实现蛇身的增长:在蛇头的坐标变化前,获取各节身体的坐标。下标为0的元素
获取蛇头在坐标位变化前的坐标,下标为1的元素获取下标为0的元素坐标变化前的坐标......(以此类推)。然后
在paint()方法中,在画完蛇头后,开始画蛇身(当然SnakeJPanel1中需要添加一个蛇身类的成员变量)。蛇每吃
掉一个食物,蛇身类的对象中的数组便增加一个元素。

       蛇身类代码如下:

package doodleSnake;

import java.util.ArrayList;

public class SnakeBody {
	ArrayList<SnakeHead>  body;  //蛇的身体的数组
	
	public SnakeBody() {
		this.body  = new ArrayList<SnakeHead>();
	}
	
	public int getIndexX(int index) { //获取下标为index的元素的x坐标
		SnakeHead h = body.get(index);
		return h.getX();
	}
	
	public int getIndexY(int index) {//获取下标为index的元素的y坐标
		SnakeHead h = body.get(index);
		return h.getY();
	}
	
	public void setIndexCoordination(int index, int x, int y) { //设置下标为index的元素的坐标
		this.body.get(index).setX(x);
		this.body.get(index).setY(y);
	}
	
	public void setCoordinate() {//设置除第一节外其他身体部分的坐标
		if(this.body.size() >= 2) {
			for(int i=this.body.size()-1; i>=1; i--) {
				this.setIndexCoordination(i, this.getIndexX(i-1), this.getIndexY(i-1));
				//System.out.println(i+":  ("+ this.getIndexX(i-1)+","+this.getIndexY(i-1)+")");
			}
		}
	}
	
	public void addBody() { //蛇身的增长
		this.body.add(new SnakeHead());
		if(this.body.size() >= 2) {
		this.setIndexCoordination(this.body.size()-1, this.getIndexX(this.body.size()-2), this.getIndexY(this.body.size()-2));
		}
	}
	
}

 

新的JPanel1代码如下:

package doodleSnake;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

public class SnakePanel1 extends JPanel implements KeyListener{
	JPanel jps[];   //定义面板数组,充当背景。
	SnakeHead head; //定义蛇头
	Food food; //定义食物
	SnakeBody snaekBody; //定义蛇的身体
	
	public SnakePanel1() { //构造方法
		
		this.head = new SnakeHead();
		this.food = new Food();
		this.snaekBody = new SnakeBody();
		this.setSize(619,619);   //设置大面板尺寸
		this.setLayout(new GridLayout(20,20,1,1));  //设置大面板布局方式:分成20*20的区域,间距为1个像素
		jps = new JPanel[400]; //创建一个容量为400的JPanels数组,存放小面板
		for(int i=0; i<jps.length; i++) {
			jps[i] = new JPanel();
			jps[i].setBackground(Color.green); //设置小面板的颜色为绿色
			this.add(jps[i]); //在大面板中添加小面板
		}
		this.setFocusable(true);     //获取焦点
 		addKeyListener(this);     //监听自己
	}
	
	public void setColor(Color c) {
		for(int i=0; i<jps.length; i++) {
			jps[i].setBackground(c); //设置小面板的颜色为绿色
		}
	}
	
	public void paint(Graphics g) {
		super.paint(g);
		g.setColor(Color.cyan);
		g.fillRect(this.food.getX(), this.food.getY(), 30, 30);//画食物
		
		g.setColor(Color.PINK);
		for(int i=0; i<this.snaekBody.body.size(); i++) { //画蛇身
			g.fillRect(this.snaekBody.getIndexX(i), this.snaekBody.getIndexY(i), 30, 30);
			System.out.println("i: "+i+"size: "+this.snaekBody.body.size());
		}
		
		g.setColor(Color.RED);
		g.fillRect(this.head.getX(), this.head.getY(), 30, 30);// 画蛇头,PS:先画食物,再画蛇头,这样蛇头才会覆盖食物
	}
	
	public boolean foodBeEaten() {
		if(this.head.getX() == this.food.getX()  &&  this.head.getY() == this.food.getY()) {
			return true;
		}
		return false;
	}
	
	public void snakeRun() {
		while(true) {
			try {
				Thread.sleep(head.getSpeed());      //设置蛇的移动速度
			} catch (InterruptedException e) {
				// TODO 自动生成的 catch 块
				e.printStackTrace();
			}
			
			
				if(this.snaekBody.body.size() != 0) {
				this.snaekBody.setCoordinate(); //设置其他身体的坐标,PS:必须先设置非第一节的蛇身的坐标,否则第二节蛇身的坐标永远会与第一节相同,即画出来的蛇身会少一节
				this.snaekBody.setIndexCoordination(0, this.head.getX(), this.head.getY()); //设置第一节身体的坐标
				
				
				}
			
			if(head.getDirection() == 1) {
				head.setY(head.getY()-31);
			}
			else if(head.getDirection() == 2) {
				head.setX(head.getX()+31);
			}
			else if(head.getDirection() == 3) {
				head.setY(head.getY()+31);
			}
			else if(head.getDirection() == 4) {
				head.setX(head.getX()-31);
			}
			
			if(this.foodBeEaten()) {
				food = new Food();
				this.snaekBody.addBody(); //蛇身增长
				System.out.println("蛇身的长度:"+this.snaekBody.body.size());
				if(this.snaekBody.body.size() == 1) { //赋予地址,避免在(0,0)闪烁
					this.snaekBody.setIndexCoordination(0, this.head.getX(), this.head.getY());
				}
			}
			
			repaint();
		}
		
	}

	@Override
	public void keyPressed(KeyEvent e) {

		// TODO 自动生成的方法存根
		int n = e.getKeyCode();
		if(n == KeyEvent.VK_UP  && head.getDirection() != 3) {  //当按下向上的键且蛇的移动方向不是向下时....
			head.setDirection(1);
		}
		else if(n == KeyEvent.VK_DOWN  &&  head.getDirection() != 1) {
			head.setDirection(3);
		}
		else if(n == KeyEvent.VK_LEFT  &&  head.getDirection() != 2) {
			head.setDirection(4);
		}
		else if(n == KeyEvent.VK_RIGHT  &&  head.getDirection() != 4) {
			head.setDirection(2);
		}
		//repaint();
	}

	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO 自动生成的方法存根
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO 自动生成的方法存根
		
	}
	
}

实现蛇身增长的过程中遇到的问题:

  1. 蛇每吃到一个食物,总是会在(0,0)位置画一节蛇身(一闪而过),其原因是: 刚开始SnakeBody类的addBody方法中,没有对新增蛇身的坐标进行初始化,所以系统自动将新增蛇身的坐标设为(0,0)。
  2. 蛇有了第一节身体后,再次吃到食物却没有长出第二节身体,但是当蛇第三次吃到食物后,蛇身增长正常化。其原因为: 在JPanel1类中SnakeRun()方法中,在改变蛇的坐标时,错误的做法是先改变蛇头的坐标,再改变蛇身的坐标。这样会导致蛇的第一节身体的坐标永远与蛇头的坐标相通,故而再paint方法中蛇头会将第一节蛇身覆盖,即蛇永远少画了一节身体。所以在改变蛇的坐标时,应当先改变蛇身体的坐标,再改变蛇头的坐标。

接下来要实现的功能:

1、按键&信息 面板的“开始”、“暂停”、“结束”、“得分”、“时间”。”设置“功能最后实现。

2、游戏结束的判断:蛇撞墙。

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值