2
\$\begingroup\$

I'm thinking of ways to implement the Observer pattern in a game I'm developing at the moment. I can have a Game World (local map) with Game Objects (player, NPCs, monsters etc...) inside of it. Other Game classes (like quest progression tracker for flagging triggers, location tracker for path finding, or maybe a new map need to be loaded into memory and rendered to show the new area the player just walked into) need to be notified when the player walks into a building, or fires a projectile. Also the input listener needs to be aware of when the user presses a key or clicks the mouse, and somehow transport that information to the rest of the game so that it can allow the appropriate actions to take place.

So I'm stuck at the implementation stage. I know I can use the Observer pattern, and possibly the State pattern as well. I know I'll need a Game World (Subject), Game Objects (Listeners), and Game Events (triggers the Game World to render the changes). However that could be the wrong way to go about it, any suggestions?

BTW, its a 2D JRPG tiling styled game, in the fashion of Zelda, Breadth of Fire, Pokémon, or the older Final Fantasies

Alright I've gone and done an implementation, but ran into a few minor issues, although it seems to be working properly.

public interface WorldListener {
    public void OnWorldEvent(WorldEvent e);
}

Above is the Observer that listens to the subject.

public class WorldEvent {
    final int WorldObjectMovedEvent = 1;
}

Above is the Event that triggers a notification.

public class World {

    static WorldListener listener;

    static void addWorldListener(WorldListener wl) {
        listener = wl;
    }

    static void WorldChanged() {
        listener.OnWorldEvent(new WorldEvent());
    }
}

Above is the subject that only stores one subscriber at the moment, I'll make it into a list once i write a class for another observer, right now, I only have one Observer. There is no need for a list at the moment.

public void OnWorldEvent(WorldEvent e) {
    System.out.println("Something has happened in the world");
}

static private void addWorldListener(WorldListener wl) {
    World.addWorldListener(wl);
}

The code above goes into the object that is currently acting as an observer, when an event is fired, it triggers the world's WorldChanged() method, which in turn fires the OnWorldEvent of any listener.

The problem I have ran into is that I can't move the WorldEvent, WorldListener, or World classes into a separate package under the moniker World.my.game because of the static reference. So I'm not sure I'm implementing it correctly. Also if there are any suggestions on making this better, or if I'm flat out doing it wrong let me know, as I haven't delved into design patterns yet and this is my first attempt.

\$\endgroup\$
  • \$\begingroup\$ This has some hints about how to implement the observer. \$\endgroup\$ – The Light Spark Jul 7 '14 at 15:23
  • 1
    \$\begingroup\$ You might be interested in entity component system as a general design (there's a couple of tags here: entity-system and entity-component). \$\endgroup\$ – didierc Jul 7 '14 at 18:26
  • \$\begingroup\$ There's also a popular approach in functional programming called functional reactive programming (FRP), but the underlying principle is usable in other settings: en.wikipedia.org/wiki/Reactive_programming \$\endgroup\$ – didierc Jul 7 '14 at 18:32
  • \$\begingroup\$ Patterns are solutions to recurring design problems. It sounds like you're looking for a problem to apply a solution, which I think is backwards. \$\endgroup\$ – Fuhrmanator Jul 8 '14 at 21:12
  • \$\begingroup\$ Just do it, somehow code it, then if you don't like it, refactor it, still don't like it ? refactor it again, repeat until you love it. In the end you might end up with some very readable easy to use pattern you like and in few years you might find out this pattern actually has a name. You become master by practicing. \$\endgroup\$ – aeroson Feb 22 '17 at 12:47
2
\$\begingroup\$

The problems i have run into is i can't move the WorldEvent,WorldListener, or World classes into a separate package under the moniker World.my.game because of the static reference.

Don't make the listener inside the World object static. A static class member means the object is shared across all instances of the type (all instances of World in this case). That's not want you want here: you want each World to have it's own listener, so client code can listen to the individual world or worlds it cares about.

i haven't delved into design patterns yet and this is my first attempt

This is a problem that most people have when first hearing about or approaching "design patterns." Design patterns exist to create a common vocabulary for talking about problems and solutions. They should not be viewed as solutions in and of themselves. That means when you encounter a problem, you shouldn't necessarily go hunting for a "design pattern" to try and fit over the problem, and you shouldn't worry about implementing the solution to a problem "correctly" in terms of the canonical definition of the pattern.

Focus instead on solving the actual problem. In this case, the problem you have encountered is that you need some way for other code to react to world events when they happen. And it's true that this the basic premise of the observer pattern -- but that doesn't mean there is a single "correct" way to implement the observer (and there shouldn't be!), nor does it mean you should think about the solution in terms of the pattern. It is a subtle distinction, but it will help you avoid "square peg, round hole" problems in the future if you focus more on the needs of the solution rather than the definition of the pattern.

\$\endgroup\$
  • \$\begingroup\$ So if the World Listener shouldn't be static, then how will i refer to it from a non static method? I don't want to create multiple instances of World, seeing as there is only one game world, and i don't plan on adding a feature of multiple game worlds. And i'm not sure i follow you about the design patterns aren't solutions. I get that there is more than one way to implement them "correctly", but i'm more so concerned about implementing them incorrectly, or in a badly designed way. Also i turned to design patterns because the last project i coded was a mess and i needed to clean it up. \$\endgroup\$ – cortell davis Jul 7 '14 at 18:18
  • \$\begingroup\$ You should pass the World (and/or the WorldListener as appropriate) to methods that need them. It makes your dependencies explicit, which is good because it helps you identify where you need to reduce dependencies (because too many complex dependency chains produces code that is "a mess"). Plus it eliminates the issues involved with static classes that hold state that you are running afoul of. \$\endgroup\$ – Josh Jul 7 '14 at 18:29
  • 1
    \$\begingroup\$ If you only expect to have one world, only create one world object. Don't make the World class static or a singleton; that is a bad design direction (it unnecessarily pessimizes your architecture). Even if you don't expect to have more than one world instance now, you don't want to artificially limit your ability to do so in the future -- even if it never plays into your game design, there are various interesting technical optimizations one can make by supporting multiple world objects (such as preloading state to reduce load times on reloads or transitions). \$\endgroup\$ – Josh Jul 7 '14 at 18:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.