Skip to content

Instantly share code, notes, and snippets.

@vrobel
Created July 24, 2012 19:18
Show Gist options
  • Save vrobel/3172033 to your computer and use it in GitHub Desktop.
Save vrobel/3172033 to your computer and use it in GitHub Desktop.
SystemEnabledRule
package com.blackmoondev.ashes.boot.vo
{
import net.richardlord.ash.core.Game;
import net.richardlord.ash.core.SystemEnabledRule;
import org.hamcrest.Matcher;
import org.hamcrest.collection.inArray;
import org.hamcrest.core.not;
import org.hamcrest.object.equalTo;
public class StateSystemRules
{
private var systemRules:Vector.<SystemEnabledRule>;
public function StateSystemRules() {
systemRules = new <SystemEnabledRule>[];
}
public function setCurrentState(game:Game, state:String):void {
for each (var rule:SystemEnabledRule in systemRules) {
rule.update(game, state);
}
}
public function enableSystemsIfState(stateOrStates:*, ...systemClasses):void {
var rule:Matcher = getRuleForStateOrStates(stateOrStates);
var systemEnabledRule:SystemEnabledRule = new SystemEnabledRule(rule, systemClasses);
systemRules.push(systemEnabledRule);
}
public function disableSystemsIfState(stateOrStates:*, ...systemClasses):void {
var rule:Matcher = not(getRuleForStateOrStates(stateOrStates));
var systemEnabledRule:SystemEnabledRule = new SystemEnabledRule(rule, systemClasses);
systemRules.push(systemEnabledRule);
}
private function getRuleForStateOrStates(stateOrStates:*):Matcher {
if (stateOrStates is String) {
return equalTo(stateOrStates);
} else if (stateOrStates is Array) {
return inArray(stateOrStates)
} else {
throw new ArgumentError('Not supported stateOrStates type ' + stateOrStates + ' should be String or Array');
}
}
}
}
package com.blackmoondev.ashes.boot.vo
{
import net.richardlord.ash.core.Game;
import org.flexunit.assertThat;
import org.hamcrest.object.notNullValue;
import org.hamcrest.object.nullValue;
public class StateSystemRulesTest
{
private var game:Game;
private var stateRules:StateSystemRules;
private static const STATE_A:String = 'STATE_A';
private static const STATE_B:String = 'STATE_B';
[Before]
public function setup():void {
game = new Game();
game.addSystem(new SystemA(), 0);
game.addSystem(new SystemB(), 1);
stateRules = new StateSystemRules();
}
[Test]
public function system_removed_when_state_match_for_disable():void {
stateRules.disableSystemsIfState(STATE_A, SystemA);
setState(STATE_A);
assertThat(game.getSystem(SystemA), nullValue());
}
[Test]
public function system_not_removed_when_state_not_match_for_disable():void {
stateRules.disableSystemsIfState(STATE_A, SystemA);
setState(STATE_B);
assertThat(game.getSystem(SystemA), notNullValue());
}
[Test]
public function system_removed_when_state_not_match_for_enable():void {
stateRules.enableSystemsIfState(STATE_A, SystemA);
setState(STATE_B);
assertThat(game.getSystem(SystemA), nullValue());
}
[Test]
public function system_not_removed_when_state_match_for_enable():void {
stateRules.enableSystemsIfState(STATE_A, SystemA);
setState(STATE_A);
assertThat(game.getSystem(SystemA), notNullValue());
}
[Test]
public function system_readded_when_state_goes_to_disabled_and_then_not_disabled():void {
stateRules.disableSystemsIfState(STATE_A, SystemA);
setState(STATE_A);
setState(STATE_B);
assertThat(game.getSystem(SystemA), notNullValue());
}
[Test]
public function system_readded_when_state_goes_to_not_enabled_and_then_enabled():void {
stateRules.enableSystemsIfState(STATE_A, SystemA);
setState(STATE_B);
setState(STATE_A);
assertThat(game.getSystem(SystemA), notNullValue());
}
private function setState(state:String):void {
stateRules.setCurrentState(game, state);
}
}
}
import net.richardlord.ash.core.System;
internal class SystemA extends System {}
internal class SystemB extends System {}
//I use this package just to use internal priority value
package net.richardlord.ash.core
{
import flash.utils.Dictionary;
import org.hamcrest.Matcher;
public class SystemEnabledRule
{
private var _rule:Matcher;
private var _systemClasses:Array;
private var systemCache:Dictionary = new Dictionary(true);
private var inited:Boolean = false;
private var added:Boolean = true; //Systems must be added first.
public function SystemEnabledRule(rule:Matcher, systemClasses:Array) {
_rule = rule;
_systemClasses = systemClasses;
}
public function update(game:Game, checkValue:Object):void {
var shouldAdd:Boolean = _rule.matches(checkValue);
var stateChange:Boolean = shouldAdd != added;
//we cant do addSystems first because systems are not cached yet
var notInitedAndShouldRemove:Boolean = !inited && !shouldAdd;
var needInvalidation:Boolean = (stateChange) || (notInitedAndShouldRemove);
if (needInvalidation) {
inited = true;
shouldAdd ? addSystems(game) : removeSystems(game)
}
}
private function addSystems(game:Game):void {
for (var i:int = 0; i < _systemClasses.length; i++) {
addSystem(_systemClasses[i], game);
}
added = true;
}
private function addSystem(SystemClass:Class, game:Game):void {
var system:System = systemCache[SystemClass];
if(!system)
throw new Error("System " + SystemClass + " is not yet created. Add it to the game first");
delete systemCache[SystemClass];
game.addSystem(system, system.priority);
}
private function removeSystems(game:Game):void {
for (var i:int = 0; i < _systemClasses.length; i++) {
removeSystem(_systemClasses[i], game);
}
added = false;
}
private function removeSystem(SystemClass:Class, game:Game):void {
var system:System = game.getSystem(SystemClass);
if(!system)
throw new Error("System " + SystemClass + " is not yet created. Add it to the game first");
game.removeSystem(system);
systemCache[SystemClass] = system;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment