On Sun, Sep 15, 2013 at 12:25 PM, Paul Pittlerson <[email protected]>wrote:
> I'm trying to follow the MVC architecture promoted by cocos, but am having
> trouble understanding how to 'control the controls' of some situations.
>
Don't feel obligated to do MVC, or to do it strictly.
>
> For example:
> The user is in a game and presses F10 to bring up the in-game menu;
> This should disable all the controls except F10 which is the shortcut to
> close the menu (along with the MenuItem for doing so).
>
The core of this is:
- the on_key_press handler active in-game detects F10 and when detected
adds the in_game_menu_layer to the scene.
- the on_key_press handler for the menu layer does it logic but returns
True for keys that no other handlers should process, False or None for the
ones that you want to allow other handlers to proccess.
For the in-game menu, probably you want to return True for all the
keys, meaning only the keys that you handle in the in-game menu will be
active
>
> Now, that ^ is what I'm stuck at right now, but in the future the same
> situation will apply to things like: Agents with different spells on
> different keyboard shortcuts, a worker unit with a menu of buildings which
> is only available when the worker is selected, and so on. Basically, I need
> some convention for quickly changing between control mappings.
>
>
Add and remove the apropiate layer: SpellsLayer , BuildingsCommandsLayer
You can have two active controllers at the same time, if the first to be
invoked returns a False / None for some keys.
> I can imagine doing this with some elaborate system of if-then-else
> statements in the Control part of the MVC system, but that is of course
> very undesirable.
>
> So I hope for some guidance on how to best build this in cocos.
>
Avoiding big trees of if does not mandates MVC, you can design with
different degrees of MVC.
Lets call 'control' a subsystems that displays to the user, receive user
input and translate into actions in the game.
A control will have a 'target'
The role of control is to translate user input (kbd, mouse, joystick) to
logical actions to be performed by / to the target
So, the first design task is to define at a high level the target ( unit ?
building ? minimap ? ...) and the logical actions ('attack', 'spell', ...).
Then there should be a mechanism to make the logical action happen.
This can be fleshed out with more o less MVC, and in infinite variations.
Lets progress on one:
Light MVC:
The control is a Layer subclass that mixes view and controller, let call it
ControlLayer .
The event handlers of ControlLayer will handle the user input, do any
keybinding translation, detect if the event should translate to a 'logical
action', be ignored or needs a change in the control's view.
By example, hoovering the mouse over a menu item may need to highlight that
item; is not a 'logical action', should be handled directly bu the
ControlLayer.
On the other side, clicking over the menu item should send the appropriate
action to target and nothing more.
The target is a class instance, and it has a member .user_commands that
will be used to communicate to the target which actions the user wants to
perform. The exact class is not important.
target.user_commands will hold a queue of ('logical_action', param)
When the event handlers in control layer extracts a logical action from the
stream of user input, it adds to the queue in target.user_commands.
by example, event key up 'B' -> translates to ('bet', amount) , where
amount comes from the control state.
Now, at each frame in the gameplay, objects that are targets of a control
should process those user_commands.
Add the requirement that target should have a method
.process_user_commands() with the obvious responsibility.
This method can be called from the .update() method of target, if it have
one, or a set of controlled objects can be maintained by the level object,
in each frame call the process_user_commands for each object in the set
To dispatch the user commands without 'trees of if' we can do, in the
target's class,
def process_user_commands(self):
while self.user_commands:
cmd, arg = self.user_commands.pop()
fn = getattr(self, cmd)
fn(arg)
here, ('bet', 1000) will call self.bet(1000), and there will be the game
logic of the action bet.
This sketched the data flow user -> model
Theres another data flow to address: from the model to the control
If the control does not depend on the state of target, like a menu with
attack - hide options, there no flow at all from target to control
if it depends on some state of target but that state does not change from
the moment the control pop-ups until the interaction with the user is
complete, like in choosing from an inventory, the function that instantiate
o retargets the control can set the needed state and thats all.
If some state in target should reflect in the control and changes while the
control is active, the best is to schedule in ControlLayer a function that
collects the variable state needed ( direct accessing members like
target.energy, calling informative methods like
target.can_cast_spell('earthquake') , etc)
What is forbidden in the control layer is:
- changing any member of target , except for target.user_commands
- adding constraits not present in the target. By example, if after
casting the spell 'earthquake' the game should not allow to recast for some
quantity of time, then it would be bad if the control directly disabled the
spell for some amount of time. It should only pass 'earthquake' and let the
scheduled query-to-target tell if the spell should be disabled or not, or
what amount of time the disabled state animation should run.
For full MVC style you will need to translate SpellLayer to a triad model /
view / controller , where
- view a layer without event handlers which holds all the visible Menu
parts
- controller a layer with no visible parts,
- model a class instance, function or some other callable in model
Look at the cocos provided samples/Tetrico for an example, or at the very
incomplete game at http://code.google.com/p/pigeonsgame/
--
You received this message because you are subscribed to the Google Groups
"cocos2d discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/cocos-discuss.
For more options, visit https://groups.google.com/groups/opt_out.