14
\$\begingroup\$

I'm working on a game where some in-game events need to happen once in a while. A nice example would be a tutorial. You start the game, and at several points in the game an event occurs:

  • You encounter your first enemy, the game pauses and you receive an explanation on how to kill it.
  • You killed the first enemy, you receive a "good job" message.
  • You gain a new item, a menu with the items stats popup.
  • etc etc.

The game I'm working on is a puzzle game where the rules in the game are pretty much all the same, so it seems inefficient to hardcode all these events in separate levels.

Should I somehow define these events in an external source, like XML? Then write an interpreter that reads out the XML and sets the events requirements for the level? I'm not sure how I could define an event that should occur when you killed two enemies for example.

Just to be clear, I'm not looking for the best programming language or scripting language to do this, but more at the best method to handle this.

Thanks!


Edit: A second example since my question was pretty hard to understand:

The problem I'm having is to put some extra actions in the game in a procedure that is always pretty much the same. Like an RPG battle, everyone has a turn, picks a skill etc - it's always the same. But what if there was a case where I would like to display a cutscene somewhere in between. Modyfing the entire game structure to pass in an altered battle class with the cutscene included seems very inefficient. I'm wondering how is this usually done.

\$\endgroup\$
6
  • 8
    \$\begingroup\$ Dont try to overgeneralize things, tutorials for instance are very specific and come with a lot of different triggers/events. Nothing wrong with hardcoding/scripting. \$\endgroup\$ Jul 1, 2011 at 19:06
  • 1
    \$\begingroup\$ @Maik If you put that into an answer Id +1 it.. Simple and solved is better than pretty any day. \$\endgroup\$
    – James
    Jul 1, 2011 at 21:35
  • \$\begingroup\$ Your second example makes it a lot clearer that an abstract messaging system would be a big win. For a tutorial you can just hard-code things since they only happen once right at the beginning, but for ongoing events that can happen at any time during the entire length of the game, well that's different. \$\endgroup\$
    – jhocking
    Jul 3, 2011 at 21:20
  • \$\begingroup\$ Its still a bit vague, please list at least 3 triggers for 3 different cutscenes. its very hard to answer in general. Basically you must find a common pattern to understand how to implement it best. \$\endgroup\$ Jul 3, 2011 at 21:22
  • \$\begingroup\$ What do You want? You want to pause the actions and do the extra, then unpause the actions? \$\endgroup\$
    – user712092
    Jul 4, 2011 at 10:34

3 Answers 3

7
\$\begingroup\$

This depends a lot on how the events are actually communicated between objects in your game. For example, if you are using a central messaging system then you could have a tutorial module that listens for certain messages and creates tutorial popups whenever it hears certain messages. Then you could set what message to listen for, along with what popup to show, in an XML file or something that is parsed by the tutorial module. By having a separate tutorial object that monitors the game state and displays tutorial popups when it notices stuff in the game, you can change the tutorial object at will without needing to change anything else about your game. (Is this the Observer pattern? I'm not familiar with all the design patterns.)

Overall though it depends on the complexity of your tutorial if it is worth worrying about this. Hard-coding the events in your code and/or levels doesn't seem like a big deal to me for just a handful of tutorial popups. I am curious what exactly you have in mind that makes you think it'll be inefficient, since all you should be doing every trigger is just dispatching a message to the tutorial module, something like TutorialModule.show("1st_kill");

\$\endgroup\$
2
  • \$\begingroup\$ I think since its a puzzle game his logic is in one location for multiple levels and such, making the checks for should we do a tutorial for this be something that lasts all over. Honestly if it is a puzzle game I do not think this is going to take a huge hit for it even if it is not the prettiest code, and at the end of the day code that works in a game that ships is always -always- 100% better than pretty code that never sees the light of day ;) \$\endgroup\$
    – James
    Jul 1, 2011 at 21:34
  • \$\begingroup\$ Never thought of something like the observer pattern, sounds like a nice solution. I´ll give it a try, thanks :) \$\endgroup\$
    – omgnoseat
    Jul 3, 2011 at 20:27
7
\$\begingroup\$

Here's the design constraints as I understand them:

  1. The core gameplay code doesn't care about level requirements and shouldn't be coupled to the code that deals with them.

  2. At the same time, it's the core gameplay code that knows when the specific events meeting those requirements occurs (getting an item, killing an enemy, etc.)

  3. Different levels have different sets of requirements and those need to be described somewhere.

Given those, I'd likely do something like this: First, make a class that represents a game level. It will encapsulate the set of specific requirements a level has. It has methods that can be called when game events occur.

Give the core gameplay code a reference to the current level object. When gameplay events occur, it will tell the level by calling methods on it: enemyKilled, itemPickedUp, etc.

Internally, Level needs a few things:

  • State to track which events have already occurred. This way it can distinguish the first enemy killed from others, and knows the first time you've picked up a given item.
  • A list of LevelRequirement objects that describe the specific set of goals you need for that level.

When you enter a level, you'll create a Level with the right LevelRequirements, set up the gameplay code, and give it that level.

Each time a game event occurs, gameplay passes it to Level. That in turn calculcates aggregate data (total number of enemies killed, enemies of that type killed, etc.) It then walks through its requirement objects, giving each one the aggregegate data. A requirement tests to see if it's met, and if so spawns whatever resulting behavior is appropriate (showing tutorial text, etc.)

LevelRequirement basically needs two things:

  1. A description of a test to tell if the requirement has been met. This can just be a function if your language makes that easy, otherwise you can model it in data. (I.e. have a RequirementType enum with stuff like FIRST_KILL and then a big switch on that knows how to check each kind.)
  2. An action to perform when the requirement is met.

There's still the question of where those sets of requirements are described. You could do something like XML or another text file format. That's useful if:

  1. Non-programmers will be authoring levels.
  2. You want to be able to change requirements without recompiling and/or restarting.

If neither of those is the case, I'd probably just construct them directly in code. Simpler is always better.

\$\endgroup\$
1
  • \$\begingroup\$ The first 3 points are a very close description of the method I'm using now, impressive! Yeah the thing I'm struggling with most is where to describe the requirement, and how to translate it to the game (since it's most probably going to be something external). Thanks for the in-depth explanation :) \$\endgroup\$
    – omgnoseat
    Jul 3, 2011 at 20:37
7
\$\begingroup\$

I thought You need to know how to make these events and the rest of post is about it, If You want just to store these events then use some relational database or decribe them by text and use scripting language (he will do parsing and evaluating for You). :)

What You want is to recognize events happened (1) and then do some actions which are demanded by these events (print message, check for keypress...) (2). You also want to make these events happen only once (3).

Basically You want to check for conditions and then schedule some behaviour.

How to recognize events (1)

  • You want to recognize events like these "first enemy encountered", "new item gained"
  • if generic part happens, "enemy encountered", "item gained" You check for specific part "first ...", "new item gained"

What are events made of

In more general view, each such event is made of:

  • preconditions, You check them
  • actions which will be done when preconditions are met (say ""You slained first enemy!", say ""make combos by pressing A and B buttons", say "press 'enter' to continue", require-key "enter")

How to store these events

In some data structure:

  • have list of preconditions (strings or code if You are writing it in some high-level language)
  • have list of actions (they might be strings, Quake engine uses strings for events)

You can also store it in relational database, althought it looks like it is not necessary, if You want to make this game in big You might need to make one.

You then have to parse these strings/things. Or You can use some scripting language like Python or LUA or language like LISP, they all can parse and execute it for You. :)

How to use these events in game loop (2)

You will need these two data structures:

  • queue of events (events which are scheduled to be run are put here)
  • queue of actions (scheduled actions, events imply which actions are done)

Algorithm:

  • If You recognize some of event's preconditions are met You put him into event queue
  • (3) Then You should make sure this event happened only once if You want :) (for example with boolean array has_this_event_happened["first enemy encountered"])
  • (if action queue is empty, then) If there is event in event queue You put his actions into action queue and remove him from event queue
  • If there is action in action queue You start doing what is demanded by it
  • If such action is done You remove it from action queue

How to make these actions itself (2)

You make list of objects, which have function "update". They are sometimes called entities (in Quake engine) or actors (in Unreal engine).

  1. You start these objects when they are demanded to start in action queue.
  2. these object can be used for other things such as some other timers. In Quake these entities are used for whole game logic, I recommend You to read some material about it.

Action "say something"

  1. You print something on screen
  2. You want this message to appear for few seconds
  3. in "update":
    • make variable remove_me_after and decrease it by time which passed
    • when variable is 0 You remove this action from action queue
    • You also remove this object (or schedule it to be removed...)

Action "require key"

  1. It depeneds on how You want to make it, but I think You You make a message
  2. in "update"":
    • You just check for wanted keypress event
    • You probably need some array/queue to hold keypress events
    • then You can remove it from action queue and remove the object

What methods to learn

\$\endgroup\$
2
  • \$\begingroup\$ -1 right, or he just calls a function, seriously, OP just wants a message box when a certain condition is met \$\endgroup\$ Jul 3, 2011 at 15:32
  • \$\begingroup\$ Thats a very nice write up, but not exactly what I was looking for. I did have a hard time explaining what I want. I added a second explanation: The problem I'm having is to put some extra actions in the game in a procedure that is always pretty much the same. Like an RPG battle, everyone has a turn, picks a skill etc - it's always the same. But what if there was a case where I would to display a cut-scene somewhere in between. Modyfing the entire game structure to pass in an altered battle class with the cutsene included seems very inefficient. I'm wondering how this is usually done? \$\endgroup\$
    – omgnoseat
    Jul 3, 2011 at 20:43

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .