Java迷宫版 吃豆人(有音乐)
Java吃豆人+迷宫
本来想着自己用Java编写的吃豆人的,但是如果自己画地图的话,那么多点不好弄,于是就想着让它自己随机生成地图,最后看起来还是可以的,而且我又在网上找了找音频,把声音配上去了,
还是很有成就感的~~,,,喜欢的小伙伴可以康康~
思路:
地图:
就是用地图的尺寸除定义的方块的大小得到地图的点的个数,创建一个图然后便利图中的点,每个点随机和它右方,下方的点建立连接,最后画地图的时候,便利所有点,把连接的都画出来用graphy,drawLine()方法,传进去两个点的X,Y;
无环
(地图生成后需要判断是否是无环图,因为如果产生的地图有环的画有可能产生死区,例如玩家人物四面都有墙,这就很尬尴了,所以创建地图后判断是否有环,有环的话,地图清零重新生成。)
判断墙壁
例如向右走的话:获得玩家人物的XY,判断右边两个点是否连接,连接说明有墙,不能走,
那两个点就是(玩家.X+方块.size,玩家.Y),(玩家.X+方块.size,玩家.Y+方块.size),
import usage.GameObject;
import usage.Map;
import usage.data;
import usage.node;
public class Characters extends GameObject {
private Map map;
public Characters(int x, int y,Map map) {
super(x, y);
this.map=map;
}
public boolean moveRight(){
if (this.getX()+2*data.X<data.GameSizeX&&!map.getG().isConnect(new node(this.getX()+data.X,this.getY()),new node(this.getX()+data.X,this.getY()+data.X)))
{
setX(getX()+data.X);
return true;
}
return false;
} // 判断人物能否移动,例如如果人物右边两条线连起来了就不能移动
public boolean moveLeft(){
if (this.getX()-data.X>0&&!map.getG().isConnect(new node(this.getX(),this.getY()),new node(this.getX(),this.getY()+data.X)))
{
setX(getX()-data.X);
return true;
}
return false;
} //同上
public boolean moveUp()
{
if (this.getY()-data.X>0&&!map.getG().isConnect(new node(this.getX(),this.getY()),new node(this.getX()+data.X,this.getY())))
{
this.setY(getY()-data.X);
return true;
}
return false;
}
public boolean moveDown(){
if (this.getY()+2*data.X<data.GameSizeY&&!map.getG().isConnect(new node(this.getX(),this.getY()+data.X),new node(this.getX()+data.X,this.getY()+data.X)))
{
setY(getY()+data.X);
return true;
}
return false;
}
}
小怪物
小怪物直接网上找的图片,
每个小怪物新开一个线程
并且自动更改方向,防止一直在一个地方
小怪物和玩家人物都是继承了一个类,用来判断墙壁。。。
package characters;
import usage.Img;
import usage.Map;
import usage.data;
import java.awt.*;
/*
吃豆人中的那些小怪物们,
*/
public class monsters extends Characters {
Image image;
private static dir dir;
private boolean Game_Over;
private myCharacter character;
public monsters(int x, int y, Map map,myCharacter character) {
super(x, y, map);
this.image=initImg();
new thread().start();
this.dir= dir.down;
Game_Over=false;
this.character=character;
}
private enum dir{ // 方向
left,right,up,down
}
/*
随机选择一种图片
*/
private Image initImg(){
String path="";
switch ((int)(Math.random()*5)){
case 0:path="usage/imgs/monster_1.png";break;
case 1: path="usage/imgs/monster_2.png";break;
case 2:path="usage/imgs/monster_3.png";break;
case 3:path="usage/imgs/monster_4.png";break;
case 4:path="usage/imgs/monster_5.png";break;
}
return Img.getImg(path);
}
public boolean isGame_Over() {
return Game_Over;
}
/*
检查是否与游戏玩家相撞,
*/
private void check(){
if (character.getX()==this.getX()&&character.getY()==this.getY()){
Game_Over=true; //撞到就游戏结束
}
}
public void draw(Graphics graphics){
this.check();
if (isGame_Over())return; // 这个怪物被撞到就游戏结束
graphics.drawImage(image,this.getX(),this.getY(), data.X,data.X,null);
}
private void move(){ //根据当前方向移动
switch (dir){
case up: if (!moveUp())
dir= Math.random()>0.5?monsters.dir.down: Math.random()>0.5?monsters.dir.left: monsters.dir.right;
break;
case down:if (!moveDown())
dir= Math.random()>0.5?monsters.dir.up:Math.random()>0.5?monsters.dir.left: monsters.dir.right;
break;
case left:if (!moveLeft())
dir= Math.random()>0.5?monsters.dir.right:Math.random()>0.5?monsters.dir.down: monsters.dir.up;
break;
case right:if (!moveRight())
dir= Math.random()>0.5?monsters.dir.left: Math.random()>0.5?monsters.dir.down: monsters.dir.up;
break;
}
if (Math.random()>0.7){//随机改变方向,防止发生在一个地方内出不来
switch ((int) (Math.random()*4)){
case 0:dir= monsters.dir.right;break;
case 1:dir= monsters.dir.left;break;
case 2:dir= monsters.dir.up;break;
case 3:dir= monsters.dir.down;break;
}
}
}
class thread extends Thread{ // 小怪物移动线程
@Override
public void run() {
while (true){
move();
try {
Thread.sleep(300);
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
}
}
}
玩家
通过键盘监听器,另外说明一点,键盘监听器似乎只有窗口类才能用,所以这里留有键盘监听的接口,通过游戏主类调用另外还包括吃豆人张嘴闭嘴
用扇形和圆形来画,眼睛就用圆;注意我这里的所有人物什么的坐标都是一个方块的左上角的X,Y坐标。
package characters;
import usage.Map;
import usage.data;
import usage.music.music_run;
import java.awt.*;
public class myCharacter extends Characters {
public myCharacter(int x, int y, Map map) {
super(x, y, map);
}
private void drawMove(Graphics graphics){ //这个画的是张嘴的
graphics.fillArc(this.getX(),
this.getY(), data.X, data.X,(int)(5*Math.PI),(int)((100-(1.0/12))*Math.PI)); //扇形
}
private void drawStay(Graphics graphics){ //这个画的是闭嘴的 和上面那个配合就是一张一张的
graphics.fillOval(this.getX(),
this.getY(), data.X, //圆
data.X);
}
public void draw(Graphics graphics,boolean isMove){
graphics.setColor(Color.darkGray); //设置颜色
if (isMove){ //控制张嘴,闭嘴, 有点乱,但是将就着能用,,,
if (Math.random()>0.2) {
this.drawMove(graphics);
}
else this.drawStay(graphics);
}else {
this.drawMove(graphics);
}
this.drawEye(graphics); //画吃豆人的眼睛,上面画的是吃豆人的黄色身体
}
private void drawEye(Graphics g){
g.setColor(Color.red);
g.fillOval((int)(this.getX()+ data.X/1.5),
this.getY()+ data.X/6,
data.X/8, data.X/8);
}
public void move(String move){ //移动,调用父类的方法
new music_run().start();
switch (move){
case "right":moveRight();break;
case "left":moveLeft();break;
case "up":moveUp();break;
case "down":moveDown();break;
}
}
}
图片:
这个是比较正常的地图了那个吃豆人截图的时候正好闭上嘴了。。。 下面那个是减小了地图的方块大小于是就有了迷宫。。。(这个截图是以前截的图,有闭环-死区,不过加上一个判断地图是否还有闭环后就完美解决了)
这个检查了闭环就没问题了
图论
用到了一点点图论
package usage;
import Graphy.NodeGraphy;
import java.awt.*;
import java.util.Iterator;
import java.util.Random;
/*
定义游戏地图类
*/
public class Map {
NodeGraphy graphy;
Random random=new Random(System.currentTimeMillis());//产生随意数
private int X=(int)(data.GameSizeX/data.mySize); //计算地图的x方向的点数
private int Y=(int)(data.GameSizeY/data.mySize); // y轴方向的点数
public Map(){
this.initMap();
}
//初始化地图
private void initMap(){
graphy=new NodeGraphy((X)*(Y));
for (int i = 1; i <X-1;i+=1) {
for (int j = 1; j <Y ; j+=1) {
node node=new node((int)(i*data.mySize),(int)(j*data.mySize));
graphy.addNode(node);// 向地图中加入点
}
}
this.addEdge(); // 设置线
}
private void addEdge(){
for (int i = 0; i <graphy.getE() ; i++) {
node node=graphy.getNode(i);
// 下面随机产生的线(地图) 每个点只用产生右边和下边的,然后从左上到右下有全地图都会随机产生边了
if (Math.random()>0.7){
node.setDown();
graphy.ctNode(node, node.getDown());
}
if(Math.random()>0.7){
node.setRight();
graphy.ctNode(node, node.getRight());
}
}
}
//画地图
public void draw(Graphics g){
g.setColor(Color.BLUE);
for (int i = 0; i <graphy.getE(); i++) {
node n=graphy.getNode(i);
for (Iterator<node> it = n.getNec(); it.hasNext(); ) {
node node = it.next();
if (graphy.isConnect(n,node)){
Graphics2D g2=(Graphics2D)g; //
g2.setStroke(new BasicStroke(2));//设置线的粗细 只能用Graph2D
g2.drawLine(node.getX(),node.getY(),n.getX(),n.getY());
}
}
}
}
//得到地图的抽象图 图论算法
public NodeGraphy getG() {
return this.graphy;
}
}
基础图
package Graphy;
import java.util.HashSet;
import java.util.Iterator;
/*
图论 数据结构
*/
public class graphy {
private HashSet<Integer> adj[];
private int E;
public graphy(int V){
adj=new HashSet[V];
for (int i = 0; i <V ; i++) {
adj[i]=new HashSet<>();
}
}
public int getE() {
return E;
}
public void addEdge(int v, int w)
{
adj[v].add(w);
adj[w].add(v);
E++;
}
public Iterator<Integer> getIterator(int v){
return adj[v].iterator();
}
public boolean isConnect(int v,int w){
return adj[v].contains(w);
}
}
基于基础图的符号图
package Graphy;
import usage.node;
import java.util.HashMap;
import java.util.Iterator;
/*
符号图 这些图都是算法书里面的原型,基本没怎么变
*/
public class NodeGraphy {
private HashMap<node,Integer> mst;
private node[] nodes;
private graphy graphy;
private int E;
public NodeGraphy(int V){
graphy =new graphy(V); //基础图
mst=new HashMap<>(400);
nodes=new node[V];
E=0;
}
public void addNode(node node){ //把结点都存进容器
mst.put(node,E);
nodes[E]=node;
E++;
}
public void ctNode(node x,node y){ // 将两个节点连接起来
if (mst.get(x)==null||mst.get(y)==null)return ;
graphy.addEdge(mst.get(x),mst.get(y)); //通过基础图把两个节点在基础图中的映射连接
}
public boolean isConnect(node x,node y){ //判断两个节点是否相连接,主要是把获得节点在基础图的映射,查找基础图是否相连接
if (mst.get(x)==null||mst.get(y)==null)return false;
return graphy.isConnect(mst.get(x),mst.get(y));
}
public node getNode(int index){
return nodes[index];
} //查找结点通过序号
public Iterator<node> getNodes(){ //获得所有节点的迭代器
return mst.keySet().iterator();
}
public int getE() {
return E;
} //获得节点的数量
}
音乐
这个是随便找的,需要用到Jar包,我用的是maven
<dependency>
<groupId>javazoom</groupId>
<artifactId>jlayer</artifactId>
<version>1.0.1</version>
</dependency>
这是依赖
private void check(){ //检查玩家人物是否吃到小豆豆
for (star s: stars ) {
if (s.x==character.getX()&&s.y==character.getY()&&s.isLive){
s.isLive=false;
new music_eat().start(); //播放吃到到豆豆的音乐
E--;
goal+=2;
if (E<=0)GameOver=true;
}
}
package usage.music;
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class music_eat extends Thread{
long start=System.currentTimeMillis();
@Override
public void run() {
try {
File file= new File("src\\music\\eat.mp3");
Player player=new Player(new BufferedInputStream(new FileInputStream(file)));
player.play();
player.close();
this.stop();
} catch (JavaLayerException e) {
} catch (FileNotFoundException e) {
}
}
}
源代码
更新了一点bug:
链接:https://pan.baidu.com/s/1WimmqJzQxZk9sJOEqE_t7A
提取码:i5nb
(新手上路,源代码已经上传)
转载请附上连接