继续写完贪吃蛇,还有其他部分在前几篇文章中
今天写🐍
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;
}
}
}
}