【问题标题】:What is the misuse of static final objects in my rpg game?在我的 rpg 游戏中滥用静态最终对象是什么?
【发布时间】:2015-05-19 05:00:03
【问题描述】:

所以我一直在开发一款非常简单的基于文本的游戏。它由用户输入和一些选项驱动。我已经让游戏运行并一直在调试,但我遇到了一个错误,我似乎无法找到问题的根源。

只要你的“警觉”数据足够高,只要你移动,敌人就会在我的游戏中生成。因为我有不同的敌人具有不同的统计数据,所以我只使用了具有自己特定统计数据的静态最终对象,如下所示。

public static final Monsters CRAWLER = new Monsters("Crawler", 15, 5, 100, 3);
public static final Monsters HOWLER = new Monsters ( "Howler", 20, 10, 50, 4);
public static final Monsters PROWLER = new Monsters ( "Prowler", 30, 15, 150, 5);
public static final Monsters MANTIS = new Monsters ( "Mantis", 40, 20, 200, 8);
public static final Monsters GOLEM = new Monsters ("Golem", 60, 25, 300, 10);
public static final Monsters DOGS = new Monsters ( "Group of Dogs", 10 ,5, 40, 2 );

此代码位于一个名为 Monsters 的类中,该类扩展了一个抽象类 Character,因为它们共享实例变量 Name、health、alert、atk 和 xp。

然后我将这些敌人放入一个 Monsters 对象 Arraylist 和另一个用于战斗中怪物的 arraylist。

ArrayList<Monsters> allenemy = new ArrayList<Monsters>();
ArrayList<Monsters> currentenemy = new ArrayList<Monsters>();

Allenemy 数组具有上述怪物及其属性,当前敌人是玩家战斗的那个。战斗同时发生,玩家和怪物都会受到 getAtk、setHealth 和 getHealth 的伤害。如果玩家的生命值变为 0,则会显示游戏结束消息。另一方面,如果敌人的生命值变为 0,则会显示不同的消息,并将敌人从当前敌人身上移除。但是,遇到同一个敌人(同名)时,敌人会立即死亡。唯一可能的方法是敌人的生命值是 0,所以我认为它一定与公共静态最终 Monster 对象有关。谁能帮我?下面是一些更具体的代码。

敌人生成方法: public static String espawn(玩家一){

    int enemychance = (int)(Math.random()*101);
    Monsters current= null;
    if ( enemychance >= 0 && enemychance <= 25 ) current = one.allenemy.get(5); //end if enemychance is from 0 to 25
    if ( enemychance > 25 && enemychance <= 50 ) current = one.allenemy.get(0); //end if enemychance is from 26 to 50
    if ( enemychance > 50 && enemychance <= 70 ) current = one.allenemy.get(1); //end if enemychance is from 51 to 70
    if ( enemychance > 70 && enemychance <= 85 ) current = one.allenemy.get(2); //end if enemychance is from 71 to 85
    if ( enemychance > 85 && enemychance <= 95 ) current = one.allenemy.get(3); //end if enemychance is from 86 to 95
    if ( enemychance > 95 && enemychance <= 100) current = one.allenemy.get(4); //end if enemychance is from 96 to 100
    one.currentenemy.add(current);
    String espawn = "\nA " + current.getName() + " has appeared.";
    return espawn;
} //end static espawn method

战斗循环:

if ( one.getAlert() >= 15){ //threshold for spawning monsters
            if ( enemy <= 30 ){ //chance for encountering enemies
                System.out.print ( Interaction.espawn(one) + "\n");
                while (one.currentenemy.get(0).getHealth() > 0 && one.getHealth() > 0){
                    flee =  (int)((Math.random()*4)+1); //1-5 for fleeing
                    attack1 = (int)((Math.random()*9)+1); //1-10 for your attack chance
                    attack2 = (int)((Math.random()*9)+1); //1-10 for enemy attack chance
                    attack3 = (int)((Math.random()*9)+1); //1-10 for enemy attackchance while fleeing
                    System.out.print ("\n" + Interaction.combatmenu ( one) + "\n");
                    int check2 = reader.nextInt();
                    if ( check2 == 1 ){
                        if ( attack1 <= 6 ) {
                            hp();
                            System.out.print (Interaction.atk1(one));
                            one.setHealth(one.getHealth()-one.currentenemy.get(0).getAtk());
                        } //end if enemy atk hits
                        else { 
                            System.out.print (Interaction.atk3());
                        } //end if enemy atk misses
                        if ( attack2 <= 8 ){
                            System.out.print (Interaction.atk2(one));
                            one.currentenemy.get(0).setHealth(one.currentenemy.get(0).getHealth()-one.getAtk()); //calls arraylist index 0's setHealth method as arraylist index 0's getHealth method-player's getAtk method
                        } //end if your attack hits
                        else{
                            System.out.print (Interaction.atk4());
                        } //end if your attack misses
                    } //end if user wants to attack
                    if ( check2 == 2 ) {
                        if ( flee == 1 ){
                            System.out.print (Interaction.flee1());
                            one.currentenemy.remove(0);
                            break here;
                        } //end if flee works
                        else{
                            System.out.print (Interaction.flee2());
                            one.setHealth(one.getHealth()-one.currentenemy.get(0).getAtk());
                            if ( attack3 <= 6 ) {
                                hp();
                                System.out.print (Interaction.atk1(one));
                                one.setHealth(one.getHealth()-one.currentenemy.get(0).getAtk());
                            } //end if enemy attack hits
                            else {
                                System.out.print (Interaction.atk3());
                            } //end if enemy atk misses
                        } //end if flee fails
                    } //end if user wants to flee
                } //end while player and enemy are not dead
                if (one.currentenemy.get(0).getHealth() <= 0 ){
                    System.out.print ( Interaction.deade(one));
                    if ( loot <= 4 ){
                        System.out.print ( Interaction.loot1(one) + "\n" + Interaction.atk(one));
                    } //end if no weapon has been found for 80%
                    else {
                        System.out.print ( Interaction.loot2());
                        one.setAtk(one.weapon.get(0).getAtk());
                    } //end if weapon has been found for 20%
                    one.setXP(one.getXP() + one.currentenemy.get(0).getXP());
                    one.maxXP();
                    Interaction.lvlup(one);
                    one.currentenemy.remove(0);
                 if ( one.getHealth()<= 0){
                    hp();   
                 } //end if player is dead  
                } //end if enemy is dead
            } // if enemy spawn chance for 20%
        } //end if alert is greater than 15

最后,示例输出:

第一次遭遇:敌方犬群攻击你,造成5点伤害。 你攻击了敌方犬群,造成 20 点伤害。

生命值:85 攻击:20 敌人生命值:20 敌人攻击力:5

按 1 进行攻击。 按2逃离。 1 敌人的攻击打偏了!你攻击了敌方犬群,造成 20 点伤害。 狗群死了。

你在死去的狗群身上找到了一个棒球棒并装备了它。 你的攻击增加了50

第二次相遇:一群狗出现了。 狗群死了。 你没有在身上找到任何东西。你已经升级了。您的统计数据已被重置并增加。

所以,这群 Dogs 会立即死去,杀死它会获得 XP。这证实了敌人的生命值必须达到 0,因为只有在那个循环中玩家才能获得 XP。有任何想法吗?我知道这是一个相当混乱的代码,可能在你眼里很恶心,但我是一个学习型的学生,所以请原谅我。请,谢谢!

【问题讨论】:

    标签: java


    【解决方案1】:

    我不完全理解你的代码,但我最近在尝试快速创建多面体类时遇到了类似的问题。

    您真正应该关注的是两件事:工厂模式和复杂的枚举。也就是说,带有初始化器的枚举和create() 方法,它们返回一个描述怪物的对象的新实例。你是对的,肯定有一些东西是从以前遗留下来的,我们希望这样的材料可以简单地被垃圾收集。

    例如:

    interface Monsters {
        …
    }
    
    interface MonstersFactory {
        public Monsters create();
    }
    
    enum StockMonstersFactory implements MonstersFactory {
        CRAWLER("Crawler", 15, 5, 100, 3),
        HOWLER( "Howler", 20, 10, 50, 4),
        PROWLER( "Prowler", 30, 15, 150, 5),
        MANTIS( "Mantis", 40, 20, 200, 8),
        GOLEM("Golem", 60, 25, 300, 10),
        DOGS( "Group of Dogs", 10 ,5, 40, 2 );
    
        private StockMonstersFactory(String name, /*…other initialization options…*/) {
            //…
            //standard initializer, set enum constants to what you need them 
    

    成为 //… }

        public Monsters create() {
            Monsters monsters = new Monsters(/*Initialization constants stored in enumeration fields*/);
            return monsters;
        }
    }
    

    我希望你明白吗?当你需要一个新的怪物时,而不是简单地使用current = one.allenemy.get(#);——这几乎肯定是问题所在——你会使用current = StockMonstersFactory.[chosen monster].create();,它会给你一个完全新鲜的对象,不记得以前发生的任何事情。

    当然,还有其他方法可以获取您正在寻找的东西,但这就是我想到的。如果您向我们提供有关如何实例化这些怪物的更具体的代码,这也可能会有所帮助; one.allenemy.get(…) 可以具体扩展。

    无论如何,这种事情是创建枚举的很大一部分。

    【讨论】:

    • 我没有学过也没有遇到过枚举器。因此,在应用您的解决方案之前,我将花更多时间自己学习这一点。我第一次看到它的理解方式是它是一种类?我也不明白为什么有两个接口Monsters和MonstersFactory。另外,我会保留我的静态最终对象吗?如果是,StockMonstersFactory 内部到底发生了什么?枚举器中是否有私有的 StockMonstersFactory (构造函数?)?我为这么多问题道歉,但我对此完全陌生。感谢您的帮助。
    • 在对枚举器进行了更多研究之后,我对您上面的代码有了更多的了解,但是当我尝试编写 create 方法时,我不确定到底要在参数中添加什么。我尝试过使用字符串名称、int health 等,但 blueJ 给了我一个错误:')' expected
    • 工厂模式是一种提供特定对象的设计模式。由于您需要创建的类数量有限且已设置,因此我建议在枚举中实现工厂功能。 (对我来说,这是柏拉图式的固体;对你来说,这是你的怪物。)看看这个:tutorialspoint.com/design_pattern/factory_pattern.htm 和这个:docs.oracle.com/javase/tutorial/java/javaOO/enum.html,它应该可以帮助你。
    【解决方案2】:

    你怀疑静态变量是对的。您只有一个 DOGS 实例。当您第一次与它战斗时,您将其生命值降至零。下次你与一群狗战斗时,你会将相同的物体放入敌人列表中。

    【讨论】:

    • 我认为既然狗的实例被添加到 currentenemy 数组列表中,使用 set 和 get 方法只会修改 currentenemy 数组列表中的 Monster 对象。然后,一旦生成了一个新怪物,该怪物的特定属性就会从尚未修改的 allenemy arraylist 中添加到 currentenemyarraylist。
    【解决方案3】:

    当怪物从当前怪物数组列表中移除时,尝试重置怪物的生命值。我相信因为这些是静态决赛,所以您没有正确实例化新怪物。这就是健康仍然为 0 的原因。

    【讨论】:

      猜你喜欢
      • 2023-03-10
      • 1970-01-01
      • 1970-01-01
      • 2015-07-30
      • 1970-01-01
      • 2018-08-14
      相关资源
      最近更新 更多