贪吃蛇——Snake

继续写完贪吃蛇,还有其他部分在前几篇文章中
今天写🐍
snake_head.pngsnake_body.png

package cn.tedu.Game;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyEvent;
import java.awt.image.BufferedImage;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.awt.Color;

//import com.sun.prism.paint.Color;

/**
 * @author 作者:
 * @email 邮箱:
 * @version 创建时间: 2020年1月8日上午8:29:22
 * @description 描述:蛇
 */
public class Snake extends SuperClass {
	private static final BufferedImage images;
	private static final BufferedImage img;
	static {
		images = loadImage("snake_head.png");
		img = loadImage("snake_body.png");
	}

	private int speed;// 移动速度
	private int length;// 长度
	private int num;
	// 蛇的身体放到集合里
	public static List<Point> bodyPoints = new LinkedList<>();
	public int score = 0;// 计算分数
	private static BufferedImage newImgSnakeHead;// 旋转后的蛇头图片
	boolean up, down, left, right = true;// 初始状态向右
	
	// 构造方法
	public Snake(int x, int y) {
		super(40, 40, x, y, true);
		this.speed = 4;
		this.length = 1;
		this.num = 7;
		newImgSnakeHead = images;// 蛇头
	}

	// 蛇的长度
	public int getLength() {
		return length;
	}

	// 设置蛇的长度
	public void setLength(int length) {
		this.length = length;
	}

	// 实现键盘的功能
	public void keyPressed(KeyEvent e) {
		switch (e.getKeyCode()) {
		case KeyEvent.VK_UP:// 上键
			if (!down) {// 不能向初始方向的反方向移动
				up = true;
				down = false;
				left = false;
				right = false;
				newImgSnakeHead = (BufferedImage) RotatePicture.rotateImage(images, -90);// 旋转图片
			}
			break;
		case KeyEvent.VK_DOWN:// 下键
			if (!up) {
				up = false;
				down = true;
				left = false;
				right = false;
				newImgSnakeHead = (BufferedImage) RotatePicture.rotateImage(images, 90);
			}
			break;
		case KeyEvent.VK_LEFT:// 左键
			if (!right) {
				up = false;
				down = false;
				left = true;
				right = false;
				newImgSnakeHead = (BufferedImage) RotatePicture.rotateImage(images, -180);
			}
			break;
		case KeyEvent.VK_RIGHT:// 右键
			if (!left) {
				up = false;
				down = false;
				left = false;
				right = true;
				newImgSnakeHead = images;
			}
			break;
		}
	}

	// 重写父类的移动方法
	@Override
	public void move() {
		if (up)
			y -= speed;
		else if (down)
			y += speed;
		else if (left)
			x -= speed;
		else if (right)
			x += speed;
	}

	// 画对象
	@Override
	public void paintObject(Graphics g) {
		outOfBounds();// 调用出界函数
		eatBody();// 调用处理是否会吃到自己的函数
		bodyPoints.add(new Point(x, y));// 保存轨迹
		if (bodyPoints.size() == (this.length + 1) * num) {// 当保存的轨迹点的个数为蛇的长度+1的num倍时
			bodyPoints.remove(0);// 移除第一个
		}
		g.drawImage(newImgSnakeHead, x, y,width,height, null);// 画蛇头
		drawBody(g);// 画蛇身
		move();// 调用移动方法
	}

	// 是否会吃到自己
	public void eatBody() {
		for (Point point : bodyPoints) {
			for (Point point2 : bodyPoints) {
				if (point.equals(point2) && point != point2) {
					this.score = 0;
					//this.live = false;// 食物死亡
				}
			}
		}
	}

	// 画蛇的身体
	public void drawBody(Graphics g) {
		int length = bodyPoints.size() - 1 - num;// 前num个存储的是蛇头的当前轨迹坐标
		for (int i = length; i >= num; i -= num) {// 从尾部添加
			Point p = bodyPoints.get(i);
			Random rand = new Random();
			int r =rand.nextInt(256);
			int green =rand.nextInt(256);
			int b =rand.nextInt(256);
			Color color2 = new Color(r, green, b); // ffee77黄色
			g.setColor(color2);
			g.fillOval(p.x, p.y,30,30);//画身体
			//g.drawImage(img, p.x, p.y,30,30, null);
		}
	}

	// 出界处理
	private void outOfBounds() {
		boolean xOut = (x <= 0 || x >= (MainGame.GAME_WIDTH - width));
		boolean yOut = (y <= 40 || y >= (MainGame.GAME_HEIGHT - height));
		if (xOut || yOut) {
			live = false;
		}
	}

	@Override
	public BufferedImage getImage() {
		return images;
	}

}

package cn.tedu.Game;

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;

import javax.imageio.ImageIO;

/**
 * @author 作者:
 * @email 邮箱:
 * @version 创建时间: 2020年1月8日上午8:32:08
 * @description 描述:贪吃蛇的旋转类
 */
public class RotatePicture {
	// 按指定角度旋转图片
	public static Image rotateImage(final BufferedImage bufferedimage, final int degree) {
		int w = bufferedimage.getWidth();// 得到图片宽度。
		int h = bufferedimage.getHeight();// 得到图片高度。
		int type = bufferedimage.getColorModel().getTransparency();// 得到图片透明度。
		BufferedImage img;// 空的图片。
		Graphics2D graphics2d;// 空的画笔。
		(graphics2d = (img = new BufferedImage(w, h, type)).createGraphics())
				.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);// 旋转,degree是整型,度数,比如垂直90度。
		graphics2d.drawImage(bufferedimage, 0, 0, null);// 从bufferedimagecopy图片至img,0,0是img的坐标。
		graphics2d.dispose();
		return img;// 返回复制好的图片,原图片依然没有变,没有旋转,下次还可以使用。
	}

}

package cn.tedu.Game;

import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;


import sun.audio.AudioPlayer;
import sun.audio.AudioStream;

/**
 * @author 作者:Lipt
 * @email 邮箱:
 * @version 创建时间: 2020年1月8日上午8:13:31
 * @description 描述:主函数
 *		1、加载窗体
 * 		2、画界面:画背景、画对象、画状态
 * 		3、添加对象
 * 		4、定时加载对象
 * 		5、定时器定时加载
 * 		6、键盘功能
 */
public class MainGame extends Frame implements KeyListener {

	public static final int GAME_WIDTH = 1400;// 窗体宽度
	public static final int GAME_HEIGHT = 825;// 窗体高度

	public static final int START = 0;// 开始状态
	public static final int RUN = 1;// 运行
	public static final int PAUSE = 2;
	public static final int GAME_OVER = 3;// 结束
	public static final int HELP = 4;// 结束
	public static final int WIN = 5;// 胜利
	public static final int LOGO = 6;//图标

	public static int state = LOGO;// 默认初始状态

	public static BufferedImage start;
	public static BufferedImage pause;
	public static BufferedImage gameover;
	public static BufferedImage help;
	public static BufferedImage win;
	public static BufferedImage logo;
	
	static {
		logo = SuperClass.loadImage("logo.png");
		start = SuperClass.loadImage("start.PNG");
		gameover = SuperClass.loadImage("fail.png");
		pause = SuperClass.loadImage("pause.png");
		help = SuperClass.loadImage("help.png");
		win = SuperClass.loadImage("win.png");
	}

	// public static final String IMG_PRE = "img/";// 图片路径前缀

	Snake mySnake = new Snake(100, 100);// 蛇
	Apple food = new Apple();// 食物
	Missile[] missile = {};// 炸弹
	Star[] star = {};// 心
	BlueStone[] blue = {};// 蓝宝石
	DeepRed[] deep = {};// 大红宝石
	YellowStone[] yellow = {};// 黄宝石

	// 加载窗体
	public void loadFrame() {
		this.setTitle("贪吃蛇");// 设置窗体标题
		this.setSize(MainGame.GAME_WIDTH, MainGame.GAME_HEIGHT);// 设置窗体大小
		this.setLocationRelativeTo(null);// 居中
		// 设置可关闭
		this.addWindowListener(new WindowAdapter() {
			@Override
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		// 注册监听事件
		addKeyListener(this);
		// 设置可见
		this.setVisible(true);
		// this.add(this);
		action();
		// 运行重绘线程
		new MyThread().start();
		// 添加键盘监听器,处理键盘按下事件
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				mySnake.keyPressed(e);// 委托给mysnake
			}
		});

	}

	// 检测是否结束
	public void checkGameOver() {
		if (!mySnake.live) {
			state = GAME_OVER;
		}
		if(mySnake.score >= 50){
			state = WIN;
		}
	}

	BufferedImage img;

	// 画界面
	@Override
	public void paint(Graphics g) {
		// 画背景
		try {
			img = ImageIO.read(getClass().getResource("background.PNG"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		g.drawImage(img, 0, 0, null);
		// 画星星
		for (int i = 0; i < star.length; i++) {
			star[i].paintObject(g);
			if (star[i].live) {// 如果食物活着,就画食物
				star[i].paintObject(g);
				star[i].eaten(mySnake);// 判断是否被吃
			} else {// 否则,产生新食物
				Random rand = new Random();
				star[i] = new Star(rand.nextInt(1121), rand.nextInt(600));
			}
		}
		// 画蓝宝石
		for (int i = 0; i < blue.length; i++) {
			blue[i].paintObject(g);
			if (blue[i].live) {// 如果食物活着,就画食物
				blue[i].paintObject(g);
				blue[i].eaten(mySnake);// 判断是否被吃
			} else {// 否则,产生新食物
				Random rand = new Random();
				blue[i] = new BlueStone(rand.nextInt(1121), rand.nextInt(600));
			}
		}
		// 画大红宝石
		for (int i = 0; i < deep.length; i++) {
			deep[i].paintObject(g);
			if (deep[i].live) {// 如果食物活着,就画食物
				deep[i].paintObject(g);
				deep[i].eaten(mySnake);// 判断是否被吃
			} else {// 否则,产生新食物
				Random rand = new Random();
				deep[i] = new DeepRed(rand.nextInt(1121), rand.nextInt(600));
			}
		}
		// 画黄宝石
		for (int i = 0; i < yellow.length; i++) {
			yellow[i].paintObject(g);
			if (yellow[i].live) {// 如果食物活着,就画食物
				yellow[i].paintObject(g);
				yellow[i].eaten(mySnake);// 判断是否被吃
			} else {// 否则,产生新食物
				Random rand = new Random();
				yellow[i] = new YellowStone(rand.nextInt(1121), rand.nextInt(600));
			}
		}
		// 画炸弹
		for (int i = 0; i < missile.length; i++) {
			missile[i].paintObject(g);
			if (missile[i].live) {// 如果炸弹活着,就画炸弹
				missile[i].paintObject(g);
				missile[i].crash(mySnake);// 判断是否被吃
			}
		}
		//画蛇以及唯一的苹果
		if (state == RUN) {
			if (mySnake.live) {// 如果蛇活着,就画蛇
				mySnake.paintObject(g);
				if (food.live) {// 如果食物活着,就画食物
					food.paintObject(g);
					food.eaten(mySnake);// 判断是否被吃
				} else {// 否则,产生新食物
					food = new Apple();
				}
				
			} else {// 蛇死亡,弹出游戏结束字样
				g.drawImage(null, 1000, 700, null);
			}
			drawScore(g);// 画分数
		}
//		if (state == GAME_OVER) {
//			//drawScore(g);// 画分数
//		}
		/** 画状态 */
		switch (state) {
		case START:
			g.drawImage(start, 0, 0, 1400, 825, null);
			break;
		case PAUSE:
			g.drawImage(pause, 300, 212, 800, 400, null);
			break;
		case GAME_OVER:
			g.drawImage(gameover, 200, 100, null);
			g.setFont(new Font("隶书", Font.BOLD, 80));
			g.setColor(Color.yellow);
			g.drawString("很遗憾你的分数不足100分", 200, 400);
			g.drawString("您的得分是"+mySnake.score+"分!", 400, 500);
			break;
		case HELP:
			g.drawImage(help, 0, 0, 1400, 825, null);
			break;
		case WIN:
			g.drawImage(win, 100, 100, 1400, 825, null);
			g.setFont(new Font("隶书", Font.BOLD, 80));
			g.setColor(Color.red);
			g.drawString("您的得分是"+mySnake.score+"!", 380, 600);
			break;
		case LOGO:
			g.drawImage(logo,0 , 0, 1400, 825, null);
			break;
		case RUN:
			
			//g.drawImage(logo,0 , 0, 1400, 825, null);
			break;
		}
	}

	// 画分数
	public void drawScore(Graphics g) {
		g.setFont(new Font("隶书", Font.BOLD, 40));
		g.setColor(Color.RED);
//		Font scorefont1 = new Font("华文琥珀", 0, 40);
//		g.setFont(scorefont1);
		g.drawString("得分: " + mySnake.score, 1100, 100);// 显示得分
	}

	// 添加星星
	public Star[] nextStar() {
		Star[] star = new Star[1];
		for (int i = 0; i < star.length; i++) {
			star[i] = new Star((int) (Math.random() * 1000) + 20, (int) (Math.random() * 600) + 40);// 随机生成星星的横纵坐标
		}
		return star;
	}

	// 添加蓝宝石
	public BlueStone[] nextBlueStone() {
		BlueStone[] bl = new BlueStone[1];
		for (int i = 0; i < bl.length; i++) {
			bl[i] = new BlueStone((int) (Math.random() * 1000) + 20, (int) (Math.random() * 600) + 40);// 随机生成星星的横纵坐标
		}
		return bl;
	}

	// 添加大红宝石
	public DeepRed[] nextDeepRed() {
		DeepRed[] de = new DeepRed[1];
		for (int i = 0; i < de.length; i++) {
			de[i] = new DeepRed((int) (Math.random() * 1000) + 20, (int) (Math.random() * 600) + 40);// 随机生成星星的横纵坐标
		}
		return de;
	}

	// 添加黄宝石
	public YellowStone[] nextYellowStone() {
		YellowStone[] ye = new YellowStone[1];
		for (int i = 0; i < ye.length; i++) {
			ye[i] = new YellowStone((int) (Math.random() * 1000) + 20, (int) (Math.random() * 600) + 40);// 随机生成星星的横纵坐标
		}
		return ye;
	}

	// 添加炸弹
	public Missile[] nextMissile() {
		Missile[] missile = new Missile[1];
		for (int i = 0; i < missile.length; i++) {
			missile[i] = new Missile((int) (Math.random() * 1000), (int) (Math.random() * 600 + 40));// 随机生成星星的横纵坐标
		}
		return missile;
	}

	int enterIndex = 0;
	int enterIndex1 = 0;
	int enterIndex2 = 0;
	int enterIndex3 = 0;
	int enterIndex4 = 0;

	// 定时加载对象
	public void enterAction() {
		// 爱心
		if (enterIndex++ % 600 == 0) {
			Star[] st = nextStar();
			star = Arrays.copyOf(star, star.length + st.length);
			System.arraycopy(st, 0, star, star.length - st.length, st.length);
		}
		// 黄宝石
		if (enterIndex4++ % 800 == 0) {
			YellowStone[] y = nextYellowStone();
			yellow = Arrays.copyOf(yellow, yellow.length + y.length);
			System.arraycopy(y, 0, yellow, yellow.length - y.length, y.length);
		}
		// 大红宝石
		if (enterIndex3++ % 1000 == 0) {
			DeepRed[] d = nextDeepRed();
			deep = Arrays.copyOf(deep, deep.length + d.length);
			System.arraycopy(d, 0, deep, deep.length - d.length, d.length);
		}
		// 蓝宝石
		if (enterIndex2++ % 1200 == 0) {
			BlueStone[] b = nextBlueStone();
			blue = Arrays.copyOf(blue, blue.length + b.length);
			System.arraycopy(b, 0, blue, blue.length - b.length, b.length);
		}
		// 炸弹
		if (enterIndex1++ % 800 == 0) {
			Missile[] mi = nextMissile();
			missile = Arrays.copyOf(missile, missile.length + mi.length);
			System.arraycopy(mi, 0, missile, missile.length - mi.length, mi.length);
		}
	}

	// 定时器定时加载
	public void action() {
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				if (state == RUN) {
					// 定时加载对象
					enterAction();
					checkGameOver();
				}
				repaint();
			}
		}, 10, 1);
	}

	// 防止图片闪烁,使用双重缓存
	Image backImg = null;

	@Override
	public void update(Graphics g) {
		if (backImg == null) {
			backImg = createImage(MainGame.GAME_WIDTH, MainGame.GAME_HEIGHT);
		}
		Graphics backg = backImg.getGraphics();
		Color c = backg.getColor();
		backg.setColor(Color.BLACK);
		backg.fillRect(0, 0, MainGame.GAME_WIDTH, MainGame.GAME_HEIGHT);
		backg.setColor(c);
		paint(backg);
		g.drawImage(backImg, 0, 0, null);
	}

	// 创建一个不断重绘的线程内部类
	class MyThread extends Thread {
		@Override
		public void run() {
			while (true) {
				repaint();
				try {
					sleep(30);// 每30毫秒重绘一次
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}

	// 主函数
	public static void main(String[] args) {

		new MainGame().loadFrame();// 加载窗体
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyPressed(KeyEvent e) {
		// TODO Auto-generated method stub

	}

	@Override
	public void keyReleased(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_SPACE) {
			// System.out.println("空格");
			if (state == LOGO) {
				state = START;	
			}else if (state == START) {
				state = RUN;
				if (state == RUN) {
					FileInputStream fis = null;
					try {
						fis = new FileInputStream("music/bgm.wav");
						AudioStream as = new AudioStream(fis);
						AudioPlayer.player.start(as);
					} catch (IOException e1) {
						// TODO Auto-generated catch block
						e1.printStackTrace();
					}
				} 
			} else if (state == RUN) {
				state = PAUSE;
			} else if (state == PAUSE) {
				state = RUN;
			}
		}
		if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
			// System.out.println("ESC");
			if (state == RUN) {
				state = GAME_OVER;
				
			} else if (state == PAUSE) {
				state = GAME_OVER;
			}
		}
		if (e.getKeyCode() == KeyEvent.VK_H) {
			if (state == START) {
				state = HELP;
			} else if (state == HELP) {
				state = START;
			}
		}

	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值