开发者

How to simplify this code or a better design?

I am developing a game, the game have different mode. Easy, Normal, and Difficult. So, I'm thinking about how to store the game mode. My first idea is using number to represent the difficulty.

Easy = 0 Normal = 1 Difficult = 2

So, my code will have something like this:

switch(gameMode){

case 0:
//easy
break;

case 1:
//normal
break;

case 3:
//difficult
break;

}

But I think it have some problems, if I add a new mode, for example, "Extreme", I need to add case 4... ... it seems not a gd design.

So, I am thinking making a gameMode object, and different gameMode is sub class of the super class gameMode. The gameMode object is something like this:

    class GameMode{
    int maxEnemyNumber;
    int maxWeaponNumber;
      public static GameMode init(){
         GameMode gm = GameMode();
         gm.maxEnemyNumber = 0;
开发者_如何学JAVA         gm.maxWeaponNumber = 0;
         return gm;
      }    

    }

class EasyMode extends GameMode{

      public static GameMode init(){
         GameMode gm = super.init();
         gm.maxEnemyNumber = 10;
         gm.maxWeaponNumber = 100;
         return gm;
      }    
}


class NormalMode extends GameMode{

      public static GameMode init(){
         GameMode gm = super.init();
         gm.maxEnemyNumber = 20;
         gm.maxWeaponNumber = 80;
         return gm;
      }    
}

But I think it seems too "bulky" to create an object to store gameMode, my "gameMode" only store different variables for game settings.... Is that any simple way to store data only instead of making an Object? thz u.


I think you are trying to represent a table of configuration data. Either put this in a configuration file if you're using a language that supports that, or use literal data in your code.

For instance, you might write this in C:

typedef enum difficulties {
  DIFFICULTY_EASY,
  DIFFICULTY_MEDIUM,
  DIFFICULTY_HARD
} difficulties;

struct {
  int max_enemies;
  int max_weapons;
} difficulty_settings[] = {
  {10, 4},
  {20, 5},
  {30, 6}
};

And when you want to read a particular setting, for example max_enemies for the easy level, then you can writedifficulty_settings[DIFFICULTY_EASY].max_enemies

It's easy to add more configuration (either more parameters, or more difficulty levels) by extending the table.


The overriding goal you should have here is to centralize the logic for retrieving the values related to different levels. By providing one place where these values are stored, you minimize the number of places within the code you need to change if you add another level, add other values, etc.

A class interface is a good choice for this solution. However, if you have a limited number of configuration options represented by the class, there is no reason you need to use inheritance. You can start out with a single class that encapsulates the logic. If the rest of your code retrieves its settings via the class interface you can later introduce a more complex design, such as subclasses for each mode, if it becomes necessary with limited modifications to the rest of your game.

For example, a first implementation may be something like

enum mode {
    MODE_EASY = 0,
    MODE_NORMAL = 1,
    MODE_DIFFICULT = 2,
};

class gameSettings {
    public gameSettings(mode GameMode) {
        m_mode = GameMode;
    }

    public int getMaxWeaponNumber() {
        int maxWeaponNumber;
        switch(m_mode) {
            case EASY_MODE:
                maxWeaponNumber = 100;
                break;

            // Other mode settings.               
         }

         return maxWeaponNumber;
    }

    // Other game settings....

    private mode m_mode;

}

This combines the straightforwardness of a switch() statement with the benefits of a class interface. You can also swap out your switch() statement with a lookup table, as suggested by another poster, or some other mechanism as appropriate for your application.


I don't know java (which is what your examples look like), so I present my ideas in some simple C#.

Here is an idea. Use your game mode as a flag instead. If you start with:

[Flags]
enum GameModes
{
    Unknown = 0,
    ModeA = 1,
    ModeB = 2,
    ModeC = 4,
}

Now you have levels 1-7 available.

GameModes Difficulty = GameModes.ModeA | GameModes.ModeB;    // difficulty = 3
GameModes Difficulty = GameModes.ModeB;    // difficulty = 2

In addition, either method you showed will require you to add more options should levels (modes) change, get added, etc. Have your mode templates read in from XML (or other source of your choice), save the mode data into a serializable class. I don't think you should need base class extended by anything.


Use the switch approach in the constructor of your GameMode class.


Besides some syntax issues, I think you're on the right track. I don't think you have to worry about memory, considering there is probably only one mode at once. This is a form of the strategy pattern. You could extend it so the modes do more. For instance, instead of basically just holding constants, perhaps there could be a generateEnemies method that actually creates a set or list of enemies. This moves more of the strategy into the mode object. Sane defaults in the superclass can help avoid redundant code.


Its difficult to say what kind of refactoring could be done here, as there is too less information about other classes. But you could check the State pattern which encapsulates different behaviours in different state objects. Your approach of extending a base GameMode class is very similar to the state pattern. I think it's better than a switch-case-block... and patterns are reliable ways of doing things, if well applied.


Why do you think the switch is harder to mantain? If you add another mode you will have to add code, no matter what solution you employ.

The only case I can think of where you don't have to add code if you add another mode is if you generate the parameters of the game from the value of gameMode.

For instance: maxenemy = 5 * gameMode;

I think that unless you have very complicated initialisation to perform a switch is more than sufficient. I know, I know, objects and classes are nice and all that jazz, but if you just have to define a few vars and the thing works, investing time in developing a complex game mode class may not be a rewarding solution after all (I mean, how many game modes are you planning to add?).


Make use of the strategy pattern.

In Java terms:

public interface Strategy {
    void execute();
}

public class SomeStrategy implements Strategy {
    public void execute() {
        System.out.println("Some logic.");
    }
}

which you use as follows:

Map<String, Strategy> strategies = new HashMap<String, Strategy>();
strategies.put("strategyName1", new SomeStrategy1());
strategies.put("strategyName2", new SomeStrategy2());
strategies.put("strategyName3", new SomeStrategy3());

// ...

strategies.get(s).execute();
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜