Case study 6: Modularity & Components

From Open Surge Engine Wiki
Revision as of 21:41, 23 September 2011 by Alexandre (Talk | contribs) (Example)

Jump to: navigation, search

Modularity

Motivation

Whenever your game gets big, having lots of global variables can make your code difficult to read. The need to remember many of them and what they do may be a big problem.

Fortunately, we can decouple the code. If one day you need to change how specific elements of the game work, you don't need to go through all your scripts and modify a lot of code, because you have used the power of decoupling.

Example

Let's say our game stores a lot of data related to the player: how long has he or she been playing, how many bonus items have been collected, and so on. You could store those stuff in global variables and get over with it, but then you'd have tightly coupled code. A better way to solve this problem is to have an object to store the data internally, and then talk to that object to retrieve or modify the values.

In the example below, we have a .player_data object which will store all the player data. testObject will talk to .player_data, but notice that globals aren't used for anything other than exchanging variables. This results in decoupled code, and gives .player_data full control over its data. .player_data may be used independently of testObject. The goal is to have as few dependencies as possible.

// stores data related to the player
object .player_data
{
    requires 0.2.0
    always_active

    state main {
        hide
        let $bonus=0
        change_state wait
    }

    state wait {
    }

    // adds $_fun_param1 to the bonus score
    state @add_bonus {
        let $bonus+=$_fun_param1
        return_to_previous_state
    }

    // sets the bonus score to $_fun_value
    state @get_bonus {
        let $_fun_value=$bonus
        return_to_previous_state
    }
}

// will communicate to .player_data
object testObject
{
    requires 0.2.0
    always_active

    state main {
        create_child .player_data // ideally, .player_data should be spawned by the startup object
        change_state retrieve_data
    }

    state retrieve_data {
        change_closest_object_state .player_data @get_bonus
        let $bonus=$_fun_value
        change_state idle
    }

    state update_data {
        let $_fun_param1=10
        change_closest_object_state .player_data @add_bonus
        change_state retrieve_data
    }

    state idle {
        textout default 0 0 "Bonus: $bonus"
        on_button_pressed fire1 update_data
    }
}

Components

TODO