Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

In general, what I am asking is, given any game where a game element can look/behave/affect-other-elements one way under one set of conditions, and look/behave/affect-other-elements a different way under another, and there are many such conditions, what is the best approach to developing this flexibility into the core? (with one aim being to keep the game "fresh" by introducing variation on the game-play during the life of a game...)

Specifically, In a Match 3 game, a valid move involves swapping a pair of adjacent tiles so that three-identical-tiles in a row are formed. The identical tiles are removed from the grid and replaced by those above them. New spaces (on top) on the grid are now filled with new tiles. This is the standard behavior. Richer Match-3 games, such as Bejweled, offer modified behavior based on the same mechanic when a player matches 4 tiles-in-row resulting in retention of the one tile that was swapped, and triggering alternative animations, sounds, scoring, etc. And yet still, 5-in-a-row, and cross-patterns, "power-up" tiles behave in very different ways and affect neighboring tiles in alternative ways as well.

ANY pointers for good practices here would be highly appreciated.

share|improve this question
    
You seem to be asking a lot here, I'd recommend editing the question to only contain what you think the key information is. For example most of the first paragraph can be condensed into two or three sentences. Finally, one pointer would be scripting. –  Byte56 Mar 28 '12 at 14:38
    
thanks for the feedback –  Wissam Mar 29 '12 at 6:03

2 Answers 2

This is likely to depend on the tools you are using (as well as your preferences in code design). A more procedural approach might organize calls to functions that describe the different power-up effects in a switch or set of nested if-else statements. A more object oriented approach might involve a base tile class with an empty virtual method called something like powerUp(). Then child classes for specific kinds of tiles can override this method to describe their specific ability. Finally, the option I tend to favor is a bit more functional in nature. Your tile class could contain a lambda, delegate, function pointer that describe how the tile behaves when cleared.

Hope these suggestions help stimulate some ideas for you. It really comes down to a matter of personal preference beyond any tool/engine architectural conventions or limitations.

share|improve this answer
    
Thank you - that is helpful. Can you recommend any open-source games where either methodology is evident, where it might be helpful to have a peek under the hood? (even if it's not a match-3 game -- any game where a standard element has its behavior -- and other attributes -- modified, as a result of a "power-up") –  Wissam Apr 1 '12 at 7:59
    
I can't think of a specific open-source game to recommend. If you post implementations of your game working both with and without the power-up(s) in question, that will make it easier for others to advise you on how to most easily switch between those functionalities. –  Gary Dahl Apr 11 '12 at 13:50
    
I second this object oriented approach for this problem. More specifically, use the Strategy pattern for the inherited objects. Although using events may be more straightforward in some languages. –  ChrisC Jul 30 '12 at 17:06

You could make a two-dimensional grid made of Array of IElement type. I imagine String or int would be enough for an element's name/id (e.g. "Diamond" or "Chest"), but your request for the game being easily upgradeable implies elements may have some state or even a functionality.

The IElement would be an interface with following methods:

1. canSwap ( swapWith:IElement ):Boolean
2. isHeavy ():Boolean
3. onActivate ():Array
3. onExplode ( power:int ):Array

Ad 1. Can a chest change places with a stone, or for some reason not? For example in some game type you could mark some elements as heavy (e.g. a heavy chest) and make a rule that two heavy items can't be swapped.

Ad 3. This method will be fired when a user selects the element as first. The method update's element's state (if needed) and returns an Array of actions to be done outside of the element, e.g. [RemoveFromGridAction, ExplodeAction] for a BombElement

Ad 4. As above, but here the method will be used when the element is a neighbour of an exploding bomb. A WoodenBoxElement would return [RemoveFromGridAction] Array, a BombElement would return [RemoveFromGridAction, ExplodeAction], and a MetalCubeElement would return [] (an empty Array).

All of this enforce on you, to make either various versions of Classes implementing IElement interface, or put there an additional method for every new game mechanic you add.


If you want to make a Bejeweled-like game with dozens or more of rule variations, then that would become a huge project and I suggest a MVC pattern:

Model - the grid of dictionaries (or dynamic objects, or associative arrays). These dictionaries are simply value objects that store any data you want, e.g. {'type':'diamond', 'x':0, 'y':5, 'heavy':true, 'explode_radius': 1, 'bonus':true, 'value': 115, 'lifetime_in_turns': '5' }

View - components responsible for drawing the Elements, animating the process of swapping them, new elements falling down etc.

Controller - Various commands responsible for almost everything:

  • ChangeContextCommand - this command receives an event with a ruleset, unregisters current commands and registers commands responsible for a new ruleset chosen by a user.
  • ActivateCommand - this command receives an event with X and Y coordinates, gets data from Model for these coordinates, and decides what to do next. Actionscript 3 + Robotlegs example

    public class ActivateElementCommand extends Command {
    private const MAX_HUMIDITY_TO_EXPLODE:int = 3;
    
    [Inject]
    public var e:ElementActionEvent;
    
    [Inject]
    public var grid:GridProxy;
    
    override public function execute ():void
    {
        var x:int = e.x;
        var y:int = e.y;
        var element:Object = grid.getElement ( x, y );
        if ( element.explode_radius ) {
            // it's gonna blow!
            var neighbours:Vector.<Object> = grid.getElementsSurrounding ( x, y );
            var humidity:int = 0;
            for ( var i:int = 0; i < neighbours.length; i++ ) {
                if ( neighbours[i].type == TypeConstants.WATER ) humidity += 1;
            }
            if ( humidy > MAX_HUMIDITY_TO_EXPLODE ) return; // can't fire up the match!
    
            grid.removeElement ( x, y );
            neighbours = grid.getElementsSurrounding ( x, y, element.explode_radius );
            for ( var i:int = 0; i < neighbours.length; i++ ) {
                el:Object = neighbours[i];
                dispatch ( new ExplodeEvent(el.x, el.y, x, y, element.explode_radius) );
            }
        }
    }
    }
    
  • ExplodeCommand - receives an event with X and Y coordinates of element being currently processed, as well as X and Y coordinates of element that blew up and it's explosion_range to be able to calculate the fire_power on the element (if needed). The fire_power could decrease humidity for example.

as You can see, you can easily create different ActionCommands for different rulesets. and then register the appropriate commands when game mode is changed. You could also not register an ActionCommand at all, if you don't want elements to do anything when clicked, in some particular ruleset.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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