童年的回忆之大鱼吃小鱼

简介

恰逢六一便去学并写了段有关童年回忆的小游戏:大鱼吃小鱼

大鱼吃完小鱼后可以使得自身变大,变大之后便可以吃掉原本比自己大的小鱼

最经典的是Popcap Games发布的吞食鱼版本

游戏设计

 基于这个游戏的理解

我们对游戏做出一下假设

状态

假设游戏有五个状态

游戏状态
状态0状态1状态2状态3状态4
初始页面游戏页面失败页面通关页面暂停页面

状态0通过点击任意位置进入状态1

状态1被大鱼吃掉后进入状态2

状态1达到指定分数后进入状态3

状态1点击空格键后进入状态4

状态4点击空格键后进入状态1

角色

此处主要分为两大类

一类是敌人,一类是玩家

 敌方鱼

敌方鱼有三种一种是我们初始可以吃的一种是我们要吃到一定的鱼的数目后才可以升级

越高级的鱼越多分数

怪物图片等级分数
小海马11
大嘴鱼220
灯笼鱼

340

BOSS

Boss是大鲨鱼类似吞食鱼的大鲨鱼在出来之前会有感叹号提示,玩家必须提前躲避

Boss
怪物图片等级分数
大鲨鱼max(不可杀死)0

 Player

玩家初始会在中间生成,但生命此处定义初始只有一次,在分数足够后被撞击可以用分数抵消

玩家图片初始等级分数
大眼鱼10

 游戏实现

首先是初始界面

界面实现

也就是state0

核心就是如何把字输送到图像上

    public static void drawWord(Graphics g, String str, Color color, int size, int x, int y) {
        g.setColor(color);
        g.setFont(new Font("宋体", Font.BOLD, size));
        g.drawString(str, x, y);
    }

有了这个我们顺便也就可以把游戏的所有状态到达的情况显示出来了

public class Bg {
    void paintSelf(Graphics g, int fishLevel) {
        g.drawImage(GameUtils.bgimg, 0, 0, null);
        switch (GameWin.state) {
            case 0:
                GameUtils.drawWord(g, "开始", Color.red, 80, 600, 400);
                break;
            case 1:
                GameUtils.drawWord(g, "积分" + GameUtils.count, Color.ORANGE, 50, 200, 120);
                GameUtils.drawWord(g, "难度" + GameUtils.level, Color.ORANGE, 50, 600, 120);
                GameUtils.drawWord(g, "等级" + fishLevel, Color.ORANGE, 50, 1000, 120);
                break;
            case 2:
                GameUtils.drawWord(g, "积分" + GameUtils.count, Color.ORANGE, 50, 200, 120);
                GameUtils.drawWord(g, "难度" + GameUtils.level, Color.ORANGE, 50, 600, 120);
                GameUtils.drawWord(g, "等级" + fishLevel, Color.ORANGE, 50, 1000, 120);
                GameUtils.drawWord(g, "失败", Color.red, 80, 580, 450);
                break;
            case 3:
                GameUtils.drawWord(g, "积分" + GameUtils.count, Color.ORANGE, 50, 200, 120);
                GameUtils.drawWord(g, "难度" + GameUtils.level, Color.ORANGE, 50, 600, 120);
                GameUtils.drawWord(g, "等级" + fishLevel, Color.ORANGE, 50, 1000, 120);
                GameUtils.drawWord(g, "胜利了!", Color.ORANGE, 80, 580, 450);
            case 4:
                break;
            default:
        }
    }
}

工具类实现

图像导入

 //背景图
    public static Image bgimg = Toolkit.getDefaultToolkit().createImage("src/images/sea.jpg");
 //敌方鱼类
    public static Image enamyl_1img = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/fish1_r.gif");
    public static Image enamyr_1img = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/fish1_l.gif");
    public static Image enamyl_2img = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/fish2_r.png");
    public static Image enamyr_2img = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/fish2_l.png");
    public static Image enamyl_3img = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/fish3_r.gif");
    public static Image enamyr_3img = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/fish3_l.gif");
    public static Image bossimg = Toolkit.getDefaultToolkit().createImage("src/images/enemyFish/boss.gif");

    //我方鱼类
    public static Image MyFishimg_L = Toolkit.getDefaultToolkit().createImage("src/images/myFish/myfish_left.gif");
    public static Image MyFishimg_R = Toolkit.getDefaultToolkit().createImage("src/images/myFish/myfish_right.gif");

除此之外,我们将玩家所获得的分数方向移动、关卡信息敌方鱼的集合也存储在这里面


    //方向
    static boolean UP = false;
    static boolean DOWN = false;
    static boolean LEFT = false;
    static boolean RIGHT = false;

    //分数
    static int count = 0;

    //关卡等级
    static int level = 0;

    //敌方鱼类集合
    public static List<Enamy> EnamyList = new ArrayList<>();

核心逻辑的实现

窗口类主要实现的是敌方的生成与我方的生成

敌方

通过对时间的间隔的控制来达到控制鱼群的生成速度

通过Math.random()生成的随机数的大小判断鱼的方向

random=Math.random();
//敌方鱼生成switch (GameUtils.level) {
case 4:

    if(time%60==0){
        if(random>0){
            boss=new Boss();
            isboss=true;
        }
    }
case 3:
case 2:
    if (time % 30 == 0) {
        if (random < 0.5) {
            enamy = new Enamy_3_L();
        } else {
            enamy = new Enamy_3_R();
        }
        GameUtils.EnamyList.add(enamy);
    }
case 1:
    if (time % 40 == 0) {
        if (random > 0.5) {
            enamy = new Enamy_2_L();
        } else {
            enamy = new Enamy_2_R();
        }
        GameUtils.EnamyList.add(enamy);
    }
case 0:
    //
    if(time%60==0){
        if(random>0){
            boss=new Boss();
            isboss=true;
        }
    }
    //
    if (time % 240 == 0) {
        if (random > 0.5) {
            enamy = new Enamy_2_L();
        } else {
            enamy = new Enamy_2_R();
        }
        GameUtils.EnamyList.add(enamy);
    }
    if (time % 10 == 0) {
        if (random < 0.5) {
            enamy = new Enamy_1_L();
        } else {
            enamy = new Enamy_1_R();
        }
        GameUtils.EnamyList.add(enamy);
    }
default:
}

我方鱼的生成直接实例化角色类Fish即可

碰撞检测

判断角色之间的矩形框是否有重合

for(Enamy enamy:GameUtils.EnamyList)
{
//碰撞检测
enamy.x = enamy.x + enamy.speed * enamy.dir;
if (isboss) {
    if (boss.getRec().intersects(enamy.getRec())) {
        enamy.x = -200;
        enamy.y = -200;
    }
    if (boss.getRec().intersects(fish.getRec())) {
        if (GameUtils.count <= 0) {
            fish.x = 700;
            fish.y = 500;
            state = 2;
        } else {
            GameUtils.count -= 100;
        }

    }
}
if (fish.getRec().intersects(enamy.getRec())) {
    if (fish.level >= enamy.type) {
        enamy.x = -200;
        enamy.y = -200;
        GameUtils.count = GameUtils.count + enamy.count;
    } else {
        if (GameUtils.count <= 0) {
            fish.x = 700;
            fish.y = 500;
            state = 2;
        } else {
            GameUtils.count -= 100;
        }
    }
}
}

玩家的移动机制

W/⬆️:向上移动

S/⬇️:向下移动

A/⬅️:向左移动

D/➡️:向右移动

在键盘处添加监听

if(state==0&&e.getKeyCode()==10){
    state=1;
    repaint();
}
if((e.getKeyCode()==87||e.getKeyCode()==38)){
    GameUtils.UP=true;
}
if((e.getKeyCode()==83||e.getKeyCode()==40)){
    GameUtils.DOWN=true;
}
if(e.getKeyCode()==65||e.getKeyCode()==37){
    GameUtils.LEFT=true;
}
if(e.getKeyCode()==68||e.getKeyCode()==39){
    GameUtils.RIGHT=true;
}

暂停机制

在键盘监听处添加

if(e.getKeyCode()==32){
switch (state){
    case 1:
           state=4;
           GameUtils.drawWord(getGraphics(),"游戏暂停",Color.RED,120,620,360);
           break;
    case 4:
           state=1;
           break;
    default:
      }
}

重新开始机制

void reGame(){
        GameUtils.EnamyList.clear();
        time=0;
        isboss=false;
        fish.x=700;
        fish.y=500;
        fish.level=1;
        boss=null;

    }

在键盘监听处添加

if(e.getKeyCode()==82){
    reGame();
    state=1;
}

等级机制

此处定义为玩家初始为1级玩家可以食用等级笑语等于自己的鱼

玩家到达一定等级后游戏难度升级

if(GameUtils.count<5){
    GameUtils.level=0;
    fish.level=1;
}
else if(GameUtils.count<=15){
    GameUtils.level=1;
}
else if(GameUtils.count<=50){
    GameUtils.level=2;
    fish.level=2;
}
else if(GameUtils.count<=150){
    GameUtils.level=3;
    fish.level=3;
}
else if(GameUtils.count<=300){
    GameUtils.level=4;
    fish.level=3;
}
else if(GameUtils.count>300) {
    state=3;
}

缺陷

1.在游戏运行时间越长由于贴图的鱼过多导致资源浪费,

①可以考虑将鱼存储在一个对象池中,每一次游到边界或被吃到就回归到池子中

②或者考虑发生上述时间直接把该鱼从List中删除

2.可以做一些等级进度条,随着鱼吃的数目进度条随之变化

游戏源代码链接

link

参考

Java实现大鱼吃小鱼游戏(开源)-朝阳同学

【尚学堂】Java开发游戏_大鱼吃小鱼项目实战教程

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值