In my previous post on making rpg combat fun, I talked about some high-level principles behind what's fun and what's not. This time, I delve into specifics.
Rogue-Like RPGs
Rogue-like games make combat fun by not telling you the mechanics. A lot of the 'fun' in a roguelike is learning the rules; what various creatures do, how useful your various abilities are, when you should run, when you should fold, etc etc. For people that like learning mechanics that way, roguelikes are a lot of fun. For people that skew more towards achievers on the Bartle scale, roguelikes can be frustrating. I think the success of WoW shows that there's tons of achievers out there. As an explorer, I like discovering mechanics -- but I also find Rogue-like games frustrating, I think in part because the fun bit of the mechanic is hidden. The game isn't really about discovering mechanics; it's about getting to the bottom of the dungeon and 'winning', which is an achievement. Ultimately, I think achievement is the strongest motivator. So let's leave rogue-likes behind.
Achievement RPGs
In achievement-oriented RPGs, players can have dozens or hundreds of hours of new abilities, creatures, and environments to explore. The fundamental mechanic of these games is always combat. Combat has to be fun, and they make it so by changing it up. Sometimes just cosmetically (with new environments and different-looking creatures), other times with new mechanics. New mechanics include new player abilities, new creature abilities, environmental restrictions (such as a pool of lava or spinning blades that one must avoid and might push an enemy into), and complications like adding a second creature to fight -- forcing the player to not just kill one target, but figure out how to juggle two targets. Mixing two types of targets together creates a huge explosion in the puzzle space. And when the player gains another dozen abilities, they might tackle that exact same mix of targets in an entirely new way.
It's easy to see why RPGs give players new abilities, and then pit them against enemies with ever-changing abilities, too. The game is combat, everything else is window dressing. Make combat interesting, and the player will suffer your bad dialog, predictable plots, and boring tradeskills. And if your abilities are balanced, bam, instant puzzle.
Power Trips
Another aspect of achievement games is the power trip. That's why games have levels. Not because the badge is 'good gameplay', or some sort of esoteric bullshit. But because, when you're level 20, you can go back to that level 1 orc and pound the shit out of him. The tough meany that killed you three times when you were level 19 becomes less of a challenge after you level up to 20. He's not really difficult at all any more, because you now know how the fight goes, plus you've got a little bit of extra hp, ac, and damage output. It feels like a challenge, because you're focused on the fight.
(That, btw, is the point I made in the previous post. If you're busy executing your combat plan, you don't have time to think about bad dialog or predictable plots. Keep the player focused on the combat puzzle, even if his chance of success is 99%, and he thinks it's challenging and fun.)
The Grind
RPGs can become boring if you're forced to 'grind.' But a grind is no different than any other part of the game; you're still in combat 90% of the time. But a grind is combat that isn't new. It's you against the exact same enemies you've fought before, with the exact same abilities. Neither you nor them have different powers. You've solved the puzzle, and now you're asked to solve it over and over again.
I usually got around that boring bit of grinding by focusing on a meta-issue. Not winning the combat itself, but winning faster. By figuring out a circuit through a dozen mobs that lets me kill them as fast as possible. By finding clusters of the mob that I need to kill so that I am not waiting for them to respawn, and I'm not wasting too much time travelling from one group to another. I was able to choose and pursue these goals myself; most players, I think, don't. If you can make that meta goal explicit, it might be one way of alleviating the grind.
The obvious solution, of course, is new abilities or cosmetics. Yet that's kind of the point here; sometimes, for some reason, players will want to go back and kill the same creature over and over again. Normally the game shepherds players into new areas. Some games (Lineage comes to mind here) fail at giving new abilities to either the player or his quarry. But most designers know that's a design that turns off a lot of players; they know that they need to give the player either a new ability, a new opponent, or at least new scenery in which to solve the same puzzle.
What happens when you can't? There is no solution, of course. It's more of a statement about the goals that the game has set up. In order to make money in World of Warcraft, I'd go kill elementals for hours. Usually I could only stand about an hour at a time, but I spent dozens of hours killing those creatures over and over again. Eventually, Blizzard figured out that players were grinding for cash. They solved this problem not by somehow making the grind more fun (my argument is that's impossible), but by adding ways to get cash that were both more efficient and more fun.
There's one other issue I'd like to talk about, an interaction between quests and combat that can make combat unfun.
Press the Button
Say you've got a quest to go collect 10 wolf pelts. Sure, ok, go kill wolves until you've got 10 pelts. You play the combat minigame, usually against a new creature, and have fun. Turn in your pelts, which is where the big XP is, and move on.
But what about the quests where the goal isn't to kill or collect drops, but do something completely different? Say you need to hit a button in the middle of a field, but there's a bunch of wolves there. Now the wolves are in your way. You can solve the puzzle of how to kill them, but it's not really your goal. A good designer can make 'press the button' into an interesting story, but ultimately the player wants the quest reward, not the quest text. The 'button' could be a gravestone they need to read, or an altar where they need to perform a ritual, or a dropped scroll that they need to pick up. Players think of these tasks as different and interesting, but fundamentally they're just pressing a button. Run over here, hover your mouse, and click. The game spits out some flavor text, but really it's just a button.
And many players skip quest text altogether, using add-ons to tell them what combat puzzle they need to go solve next.
Is it better to ask players to go kill 10 wolves? Or ask him to do something such that the player chooses to engage in combat because those wolves are effin annoying and keep interrupting him while he's trying to press the button? In the button case, the player might see combat as an annoyance. I remember many times in WoW where we had to go press some button, and I worked with group-mates to train the mobs out of there, or stealth through the encounter, or whatever, to avoid combat. Combat should have been the game, but I was inventing a new game to avoid it.
And I think that's the answer. Tell the player to kill "the five guards" then press the button, or give them mechanics to avoid combat altogether, so that they get the thrill of 'cleverly' avoiding combat. You want your players to have happy emotions, to think that they've achieved something tricky or clever. Give them the tools so that, however they're solving the quest, what they're engaging in is not clearing out an annoyance but positively engaging in a new puzzle.
see also: Bartle's book on designing virtual worlds
Saturday, April 24, 2010
Monday, April 19, 2010
Menu State Management in Games
I've written about high-level game state management before, but I didn't provide any direct code. I got a couple questions about this recently, so I decided to put a post together.
Menu management is a very clear example of the State pattern. Each different page in the menu is a different concrete subclass derived from a common State base class and managed by a Context. There's a few tricks that make this a bit easier.
For example, menus are often nested. This suggests using a Stack pattern for the context. I generally have a GameContext class that has Push, Pop, and Switch methods. They can either take a State subclass instance as a parameter, or some sort of identifier. I think this choice is 50-50; I don't have a clear preference for either one.
There's two ways of doing identifiers. Again, I don't have a clear preference here either. I tend to switch back & forth between these two solutions. (1) Add an ID in the class itself, e.g.
The Context itself also tends to be an instance of the Singleton pattern, with some public, global access. Pop, Push, and Switch might be static methods, for example; I find that means less code and complexity on the client side. (Never trust anyone using your class to be able to code their way out of a paper bag! Simpler interfaces are better.)
I usually start with a simple, copy-n-pasted examples of the different Menu classes. For example, they'll have their own Scenes for 3D objects and 2D UI bits. This is usually easier, faster, and more reliable than trying to develop the Most Awesomest Generic Menu Class Ever. The UI manager will take button clicks, and then call Context.Switch() or Pop() as needed, or Push() if the user hits the 'previous menu' button.
Game startup, then, will do stuff like initialize the 3D environment, game asset libraries, sound, etc, then start up the game state context and tell it which State to start with, which is often a CompanyLogoState. Usually I have game startup then call Context.Run, which does a simple loop of CurrentState.HandlePendingEvents, CurrentState.Draw, and CurrentState.Tick. There's some complexity there with handling events, being able to handle Push and Pop, updating the state at the right time, etc.
CompanyLogoState.Tick() will usually draw a 2D company logo, gradually brightening from black to white, holding, then back to black. When it gets to black, Tick() will call Context.Switch( GameTitleState.kStateId ), which pops the CompanyLogo off the stack and puts GameTitle in its place. That state does the same thing -- bring up the lights, so the title screen, then switch to the Main Menu state. Both the CompanyLogo and GameTitle states will move on to the next state if a key is pressed; that's done in their HandlePendingEvents() method. Eventually, one of the various Menu states (MainMenu, PlayGameMenu, LoadSavedGameMenu / StartNewGameMenu, etc etc) will need to actually start the game. That's cake: just have it call Context.Push( GameState.kMenuId ). And if the game needs to switch to a full-screen menu at some point, it can pause itself and push a new state onto the stack: Context.Push( SaveGameMenu.kMenuId ). Of course it will be important to plan out all of your various menus and states, and make sure you don't have any recursive loops.
Using this pattern, all of the various high-level states in the game are handled through the Context, which also does event handling and rendering. I've even once modified the process to work in a nested window as well - such as when you bring up the 'game menu' while a game is in progress, which doesn't back out into a full-screen menu but instead shows the game in the background, paused & faded.
As with any code, start simple. Copy n paste as needed. When you need more complexity, well-written code is easy to extend.
Menu management is a very clear example of the State pattern. Each different page in the menu is a different concrete subclass derived from a common State base class and managed by a Context. There's a few tricks that make this a bit easier.
For example, menus are often nested. This suggests using a Stack pattern for the context. I generally have a GameContext class that has Push, Pop, and Switch methods. They can either take a State subclass instance as a parameter, or some sort of identifier. I think this choice is 50-50; I don't have a clear preference for either one.
There's two ways of doing identifiers. Again, I don't have a clear preference here either. I tend to switch back & forth between these two solutions. (1) Add an ID in the class itself, e.g.
public static const MainMenu::kMenuId = 'main';
This tends to be the less error-prone, although it does mean that you've got to add an extra #include (in C++), and whatever language you use it means another dependency. (2) Use a string constant. C++ compilers tend to tolerate four-character codes, ie Context.Switch( 'main' );
The downside is that if you change the identifiers or add a new menu or have a typo, you run the risk of the system blowing up at runtime. However you might choose to do the identifiers, you also need a way to register them with the Context, and that adds another layer of complexity. So your choice is: that complexity, or require any class that requests a menu state change to refer to the new menu class -- which can get messy itself. Meh? All coding is tradeoffs. Pick one. Whatever your feelings on Good and Proper Coding Practices, neither one has been proven to cause cancer in lab rats.The Context itself also tends to be an instance of the Singleton pattern, with some public, global access. Pop, Push, and Switch might be static methods, for example; I find that means less code and complexity on the client side. (Never trust anyone using your class to be able to code their way out of a paper bag! Simpler interfaces are better.)
I usually start with a simple, copy-n-pasted examples of the different Menu classes. For example, they'll have their own Scenes for 3D objects and 2D UI bits. This is usually easier, faster, and more reliable than trying to develop the Most Awesomest Generic Menu Class Ever. The UI manager will take button clicks, and then call Context.Switch() or Pop() as needed, or Push() if the user hits the 'previous menu' button.
Game startup, then, will do stuff like initialize the 3D environment, game asset libraries, sound, etc, then start up the game state context and tell it which State to start with, which is often a CompanyLogoState. Usually I have game startup then call Context.Run, which does a simple loop of CurrentState.HandlePendingEvents, CurrentState.Draw, and CurrentState.Tick. There's some complexity there with handling events, being able to handle Push and Pop, updating the state at the right time, etc.
CompanyLogoState.Tick() will usually draw a 2D company logo, gradually brightening from black to white, holding, then back to black. When it gets to black, Tick() will call Context.Switch( GameTitleState.kStateId ), which pops the CompanyLogo off the stack and puts GameTitle in its place. That state does the same thing -- bring up the lights, so the title screen, then switch to the Main Menu state. Both the CompanyLogo and GameTitle states will move on to the next state if a key is pressed; that's done in their HandlePendingEvents() method. Eventually, one of the various Menu states (MainMenu, PlayGameMenu, LoadSavedGameMenu / StartNewGameMenu, etc etc) will need to actually start the game. That's cake: just have it call Context.Push( GameState.kMenuId ). And if the game needs to switch to a full-screen menu at some point, it can pause itself and push a new state onto the stack: Context.Push( SaveGameMenu.kMenuId ). Of course it will be important to plan out all of your various menus and states, and make sure you don't have any recursive loops.
Using this pattern, all of the various high-level states in the game are handled through the Context, which also does event handling and rendering. I've even once modified the process to work in a nested window as well - such as when you bring up the 'game menu' while a game is in progress, which doesn't back out into a full-screen menu but instead shows the game in the background, paused & faded.
As with any code, start simple. Copy n paste as needed. When you need more complexity, well-written code is easy to extend.
Subscribe to:
Posts (Atom)