![]() |
|
||||||||||
|
|||||
|
Регистрация: Jan 2014
Сообщений: 8
|
Как лучше организовать систему заклинаний, чтобы при нажатии на цифру вызывалось (или не вызывалось - в зависимости от cooldown'a) то заклинание, которое привязано к этой клавише?
На данный момент есть главный класс Main, и по одному классу (spell_1, spell_2...) на заклинание. В Main идет проверка: - если нажата цифра 1 и кулдаун 1го заклинания = 0, то создается экземпляр класса spell_1, ... - если нажата цифра 2 и кулдаун 2го заклинания = 0, то создается экземпляр класса spell_2, ... и т.д Соответственно, кулдауны всех заклинаний обрабатываются тоже в главном классе. Всё работает, но по мере роста количества заклинаний, переменных в Main становится все больше и больше, что не есть хорошо. Вот, ищу способ всё это унифицировать. Подскажите саму логику создания подобных систем... |
|
|||||
|
.
|
Можно сделать один SpellController, ссылку на него пока хранить в Main. Подписать его на события клавиатуры. Но не забывать о том, что в разные состояния игры события должны обрабатываться по-разному. Иногда вы бываете, например, в меню настроек. Там точно не должны включатся спеллы.
Именно в нем сделать обработку клавиш и добавлять вью ваших спеллов в какой-нибудь контейнер, ссылку на который необходимо передать во время инициализации SpellController. Добавлено через 6 минут P.S. Я рекомендую ознакомиться чем класс отличается от объекта. Достаточно хорошо эта тема освещена в книге Колина Мука. |
|
|||||
|
[+1 09.05.15]
Регистрация: Jan 2015
Сообщений: 113
|
Я бы сделал так..
Есть две фабрики для скинов мага и для самой магии - package { import flash.display.DisplayObject; import flash.utils.Dictionary; public class MageSkinFactory { protected static const MAGE_SKINS:Dictionary = new Dictionary(); public static function setMageSkinMap(skin:DisplayObject, id:uint):void { MageSkinFactory.MAGE_SKINS[id] = skin; } public static function getMageSkin(id:uint):DisplayObject { return MageSkinFactory.MAGE_SKINS[id]; } } } package { import flash.display.DisplayObject; import flash.utils.Dictionary; public class SpellFactory { protected static const SPELLS:Dictionary = new Dictionary(); public static function setSpellMap(spell:Class, id:uint):void { SpellFactory.SPELLS[id] = spell; } public static function getSpell(id:uint):DisplayObject { return new (SpellFactory.SPELLS[id] as Class)() as DisplayObject; } } } package { public class MageSkinType { public static const DEFAULT_MAGE_SKIN:uint = 1; public static const FIRE_SPELL_MAGE_SKIN:uint = 2; public static const WATER_SPELL_MAGE_SKIN:uint = 3; } } package { public class SpellType { public static const FIRE_SPELL_TYPE:uint = 49; public static const WATER_SPELL_TYPE:uint = 50; } } package { import aze.motion.eaze; import flash.display.DisplayObject; import flash.display.Sprite; import flash.events.Event; public class Mage extends Sprite { protected var _currentSkin:DisplayObject; protected var _currentState:uint; protected var _isRun:Boolean = false; public function setState(state:uint):void { if (this._isRun || state == this._currentState) return; super.removeChildren(); this._currentState = state; this._currentSkin = MageSkinFactory.getMageSkin(this._currentState); super.addChild(this._currentSkin); this._isRun = true; this.animation(); } protected function animation():void { eaze(this._currentSkin as Sprite).to(1, {rotation:360}).onComplete(this.animation_completeCallback); } protected function animation_completeCallback():void { this._isRun = false; super.removeChildren(); this._currentState = MageSkinType.DEFAULT_MAGE_SKIN; this._currentSkin = MageSkinFactory.getMageSkin(this._currentState); super.addChild(this._currentSkin); super.dispatchEvent(new Event(Event.CHANGE)); } public function get isRun():Boolean { return _isRun; } } } package { import flash.display.Sprite; public class Spell extends Sprite { public function execute():void{} } } package { import aze.motion.eaze; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; public class FireSpell extends Spell { private var _textField:TextField; public function FireSpell() { super(); this.init(); } private function init():void { this._textField = new TextField(); this._textField.autoSize = TextFieldAutoSize.CENTER; var textFormat:TextFormat = new TextFormat(); textFormat.size = 50; textFormat.color = 0xE24B4B; textFormat.bold = true; this._textField.defaultTextFormat = textFormat; this._textField.text = 'FIRE!!!'; super.addChild(this._textField); } override public function execute():void { eaze(this._textField).to(1, { alpha:0 } ); } } } package { import aze.motion.eaze; import flash.text.TextField; import flash.text.TextFieldAutoSize; import flash.text.TextFormat; public class WaterSpell extends Spell { private var _textField:TextField; public function WaterSpell() { super(); this.init(); } private function init():void { this._textField = new TextField(); this._textField.autoSize = TextFieldAutoSize.CENTER; var textFormat:TextFormat = new TextFormat(); textFormat.size = 50; textFormat.color = 0x4FD5DF; textFormat.bold = true; this._textField.defaultTextFormat = textFormat; this._textField.text = 'WATER!!!'; super.addChild(this._textField); } override public function execute():void { eaze(this._textField).to(1, { alpha:0 } ); } } } Ну а дальше немного сложней... Я с час думал, как же сделать пример без всяких парадигм и мне пришло только то, что нужно создать класс, который будет обрабатывать нажатия кнопок. Нажатия кнопок мы будем связывать с классами-заданиями, в которых и будем вызывать методы мага и заклинаний. Это немного неправильно, но если Вы говорите о переполнения класса Main, то для Вас это будет самое то. Вот класс, который обрабатывает нажатия - package { import flash.events.EventDispatcher; import flash.events.IEventDispatcher; public class Controller { private var _keys:Object = { }; private var _tasks:Object = { }; public function Controller() { } public function setDependence(keyCode:uint, task:Task):void { trace(keyCode, task) this._tasks[String(keyCode)] = task; } public function update():void { var isKeyDownValid:Boolean; for (var item:String in this._keys) { isKeyDownValid = this._tasks[item]; trace(item, this._tasks[item]) if (isKeyDownValid) { (this._tasks[item] as Task).execute(); return; } } } public function clearKeys():void { for (var item:String in this._keys) { delete this._keys[item]; } } public function get keys():Object { return _keys; } } } package { import flash.display.DisplayObjectContainer; import flash.geom.Point; public class FireSpellTask extends SpellTask { private var _mage:Mage; private var _view:DisplayObjectContainer; public function FireSpellTask(view:DisplayObjectContainer, mage:Mage) { this._view = view; this._mage = mage; } override public function execute():void { if (this._mage.isRun) return; this._mage.setState(MageSkinType.FIRE_SPELL_MAGE_SKIN); var spell:Spell = SpellFactory.getSpell(SpellType.FIRE_SPELL_TYPE) as Spell; var randomPoint:Point = super.getPointImpakt(); spell.x = randomPoint.x; spell.y = randomPoint.y; this._view.addChild(spell); spell.execute(); } } } package { import flash.display.DisplayObjectContainer; import flash.geom.Point; public class WaterSpellTask extends SpellTask { private var _mage:Mage; private var _view:DisplayObjectContainer; public function WaterSpellTask(view:DisplayObjectContainer, mage:Mage) { this._view = view; this._mage = mage; } override public function execute():void { if (this._mage.isRun) return; this._mage.setState(MageSkinType.WATER_SPELL_MAGE_SKIN); var spell:Spell = SpellFactory.getSpell(SpellType.WATER_SPELL_TYPE) as Spell; var randomPoint:Point = super.getPointImpakt(); spell.x = randomPoint.x; spell.y = randomPoint.y; this._view.addChild(spell); spell.execute(); } } } А связываем это все в классе-конфигурации приложения - package { import flash.display.DisplayObject; import flash.display.DisplayObjectContainer; import flash.display.Shape; import flash.display.Sprite; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.text.TextField; import flash.ui.Keyboard; import flash.ui.KeyboardType; public class Config { private var _viewPort:DisplayObjectContainer; private var _whiteMage:Mage; private var _world:World; private var _controller:Controller; public function Config(viewPort:DisplayObjectContainer) { this.init(viewPort); } private function init(viewPort:DisplayObjectContainer):void { this._viewPort = viewPort; this._controller = new Controller(); this.installMageSkinFactory(); this.installSpellFactory(); this._whiteMage = this.createMage(); this._whiteMage.setState(MageSkinType.DEFAULT_MAGE_SKIN); this.installSpellTaskMap(); this._viewPort.addChild(this._whiteMage); this.installViewPort(); } private function installSpellTaskMap():void { this.setSpellTaskMap(Keyboard.NUMBER_1, new FireSpellTask(this._viewPort, this._whiteMage)); this.setSpellTaskMap(Keyboard.NUMBER_2, new WaterSpellTask(this._viewPort, this._whiteMage)); } private function setSpellTaskMap(keyCode:uint, task:Task):void { this._controller.setDependence(keyCode, task); } private function installViewPort():void { this._viewPort.stage.addEventListener(KeyboardEvent.KEY_DOWN, viewPort_keyDownHandler); this._viewPort.stage.addEventListener(MouseEvent.MOUSE_MOVE, stage_mouseMoveHandler); } private function stage_mouseMoveHandler(event:MouseEvent):void { this._whiteMage.x = event.stageX; this._whiteMage.y = event.stageY; } private function viewPort_keyDownHandler(event:KeyboardEvent):void { this._controller.keys[event.keyCode] = true; this._controller.update(); this._controller.clearKeys(); } private function createMage():Mage { return new WhiteMage(); } private function installSpellFactory():void { SpellFactory.setSpellMap(this.createFireSpell(), SpellType.FIRE_SPELL_TYPE); SpellFactory.setSpellMap(this.createWaterSpell(), SpellType.WATER_SPELL_TYPE); } private function installMageSkinFactory():void { MageSkinFactory.setMageSkinMap(this.createDefaultMageSkin(), MageSkinType.DEFAULT_MAGE_SKIN); MageSkinFactory.setMageSkinMap(this.createFireSpellMageSkin(), MageSkinType.FIRE_SPELL_MAGE_SKIN); MageSkinFactory.setMageSkinMap(this.createWaterSpellMageSkin(), MageSkinType.WATER_SPELL_MAGE_SKIN); } private function createDefaultMageSkin():DisplayObject { var circle:DisplayObjectContainer = this.createCircle(30, 0x9D9191); var rect:DisplayObject = this.createRect(30, 30, 0x9FB37B); rect.x -= rect.width / 2; rect.y -= rect.height / 2; circle.addChild(rect); return circle; } protected function createCircle(radius:Number, color:uint):DisplayObjectContainer { var circle:Sprite = new Sprite(); circle.graphics.beginFill(color); circle.graphics.drawCircle(0, 0, radius); circle.graphics.endFill(); return circle; } protected function createRect(width:Number, height:Number, color:uint):DisplayObject { var rect:Shape = new Shape(); rect.graphics.beginFill(color); rect.graphics.drawRect(0, 0, width, height); rect.graphics.endFill(); return rect; } private function createFireSpellMageSkin():DisplayObject { var circle:DisplayObjectContainer = this.createCircle(30, 0xEC4242); var rect:DisplayObject = this.createRect(30, 30, 0xFDAB31); rect.x -= rect.width / 2; rect.y -= rect.height / 2; circle.addChild(rect); return circle; } private function createWaterSpellMageSkin():DisplayObject { var circle:DisplayObjectContainer = this.createCircle(30, 0x46E8C8); var rect:DisplayObject = this.createRect(30, 30, 0x4E49E4); rect.x -= rect.width / 2; rect.y -= rect.height / 2; circle.addChild(rect); return circle; } private function createFireSpell():Class { return FireSpell; } private function createWaterSpell():Class { return WaterSpell; } } } Ну и напоследок главный класс - Я понимаю, что понять это тяжело и кода много, но а чего Вы хотели? |
|
|||||
|
[+1 09.05.15]
Регистрация: Jan 2015
Сообщений: 113
|
|
|
|||||
|
.
|
Нормально. Только это не люблю:
За модификатор доступа после оверрайда. Можно чуть человечнее... За if в одну строчку. Не поставить никак бряк на return. Можно так или |
|
|||||
|
Цитата:
Но лучше так, да. в FD это шаблон по умолчанию. Дело привычки |
|
|||||
|
.
|
Я не понял. Я имел ввиду точку останова на строке, содержащей return при выполнении условия, а не только на самом условии.
|
|
|||||
|
[+1 09.05.15]
Регистрация: Jan 2015
Сообщений: 113
|
Вот по поводу if в одну строчку я с Вами полностью согласен. Когда-то у меня прям мания была писать в одну строчку или не писать скобки. Но потом я понял, что нужно уважать людей, которые будут работать с твоим кодом и пришлось отказаться от привычки. Но иногда, как это видно, в черновом варианте все ещё проскальзывает.
А вот по поводу override я несогласен с Вами. Как правило все методы, свойства и аксессоры помеченные, как public, кучкуются рядом и когда изучаешь код визуально, то лично мне кажется лучше смотреть - чем - Добавлено через 44 секунды В первом случаи визуально, как-то быстрее определяешь что метод переопределен. Добавлено через 1 минуту И в автокомплите так быстрее, ведь стоит только набрать override, а не public override. |
![]() |
![]() |
Часовой пояс GMT +4, время: 20:33. |
|
|
« Предыдущая тема | Следующая тема » |
|
|