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
(新手上路,源代码已经上传)
转载请附上连接

posted @ 2019-11-18 10:10  G521  阅读(128)  评论(0编辑  收藏  举报