Добрый день.
Чтобы удалить элемент нам не нужно знать что за элемент мы удаляем, а лишь ссылки на следующий и предыдущий элементы.
Также нужны классы двухстороннего списка.
На этот раз будем рассматривать двухсторонние списки и подписки на событие.
Все это используется здесь:
( Нажмите на флешку для получения фокуса )
( Нажмите на флешку для получения фокуса )
Первое, про что я расскажу - это двухсторонние списки.
Что это такое?
Двухсторонний список - это список, у элементов которого есть ссылки на следующий и предыдущий элементы.
Что? Как это работает?
У каждого элемента есть две ссылки: на предыдущий и следующий элементы.
Допустим, в списке есть один элемент.
- SomeElement1
- next : null
- previous : null
Внезапно, в список добавился еще один элемент.
- SomeElement1
- next : SomeElement2
- previous : null
- SomeElement2
- next : null
- prevoius : SomeElement1
И еще один.
- SomeElement1
- next : SomeElement2
- previous : null
- SomeElement2
- next : SomeElement3
- prevoius : SomeElement1
- SomeElement3
- next : null
- prevoius : SomeElement2
Чтобы удалить элемент нам не нужно знать что за элемент мы удаляем, а лишь ссылки на следующий и предыдущий элементы.
Удалим, к примеру, второй элемент.
Берем ссылку на следующий элемент ( третий ) и ставим у него prevoius в значение previous удаляемого элемента. Аналогично поступаем с предыдущим элементом - у предыдущего ставим next в значение next удаляемого элемента.
И получается:
- SomeElement1
- next : SomeElement3
- previous : null
- SomeElement3
- next : null
- prevoius : SomeElement1
Понятно. Как я могу это использовать?
Двухсторонние списки применимы для хранения чего-либо, когда неважно в каком порядке идут элементы, главное, что все они находятся в одном месте.
Как сделать этот список?
Я уже реализовал его для собственных нужд.
Там есть, как минимум, один недостаток - из списка можно удалить элемент другого списка. И все сломается. Не делайте так. Никогда.
Я делал его для себя, поэтому меня это не беспокоит. :)
Теперь про подписки на событие. При вызове события, уведомления рассылаются всем подписчикам.
Эээ.. В чем прикол? Ведь так и устроена система событий в ActionScript, разве нет?
Да. Вероятно, так она и устроена. Прикол в том, что нам нужно подписаться на событие всего один раз.
И что это нам дает?
Так как рассылка уведомлений происходит из одного места, это, по-сути, дает нам возможность управлять слушателями события всех подписчиков.
Возьмем пример сверху.
Если бы у каждого кружка был свой слушатель события ENTER_FRAME, и нам вдруг понадобилось его убрать, то пришлось бы перелопатить все кружки и отключать слушатель у каждого.
А так, у нас есть один слушатель ENTER_FRAME, из которого вызываются методы update для каждого подписчика ( кружка ). При необходимости, мы можем удалить один слушатель, и все кружки перестанут обновляться.
Для хранения подписчиков удобно использовать двухсторонний список.
Оки, хочу сделать пример с падающей хренотенью из мышки!
Хорошо. Здесь используются фильтры, если не читали про них - читаем и паттерн Singleton, тоже читаем. Кстати, в статье про фильтры я сказал, "на этот раз напишем все полностью из кода". Это не так. После публикации я обнаружил, что там нужно создать Movieclip с именем Circle. Мне впадлу было переделывать, так что оставил как есть.
Теперь реально сделаем все из кода ( фон не считается ). :Р
Main.as:
package { import flash.display.MovieClip; import flash.events.Event; import flash.events.KeyboardEvent; import flash.ui.Keyboard; public class Main extends MovieClip { public static var instance : Main; public const STAGE_HEIGHT : Number = 400.0; private const MIN_SPARK_SPEED_X : Number = -10.0, MAX_SPARK_SPEED_X : Number = 10.0, MIN_SPARK_SPEED_Y : Number = -10.0, MAX_SPARK_SPEED_Y : Number = 0.0, GRAVITY : Number = 1.0, SPARK_RADIUS : Number = 5.0; private var subscribes : List, paused : Boolean; public function Main () : void { // Use Singleton pattern // http://konanmentor.blogspot.com/2012/08/design-pattern-singleton.html // Do you remenber? if ( !Main.instance ) { Main.instance = this; this.init(); } } private function init () : void { this.subscribes = new List(); // Set paused true to run this.resume method paused = true; // Start listen ENTER_FRAME event to trigger this.update method this.resume(); this.stage.addEventListener( KeyboardEvent.KEY_DOWN, keyDownHandler ); } private function keyDownHandler ( e : KeyboardEvent ) : void { if ( e.keyCode == Keyboard.SPACE ) { if ( this.paused ) { this.resume(); } else { this.pause(); } } } public function subscribe( callback : Function ) : ListItem { return subscribes.push( callback ); } public function unsubscribe( subscription : ListItem ) : void { subscribes.pull( subscription ); } private function update ( e : Event ) : void { // Loop through all subscribers for ( var listItem : ListItem = this.subscribes.getFirst(); listItem; listItem = listItem.getNext() ) { var data : Function = listItem.GetData() as Function; data.call(); } // Create new spark this.createSpark(); } public function pause () : void { if ( !this.paused ) { this.paused = true; this.removeEventListener( Event.ENTER_FRAME, this.update ); } } public function resume () : void { if ( this.paused ) { this.paused = false; this.addEventListener( Event.ENTER_FRAME, this.update ); } } private function createSpark () : void { var options : Object = { x : stage.mouseX, y : stage.mouseY, speedX : Math.random() * ( MAX_SPARK_SPEED_X - MIN_SPARK_SPEED_X ) + MIN_SPARK_SPEED_X, speedY : Math.random() * ( MAX_SPARK_SPEED_Y - MIN_SPARK_SPEED_Y ) + MIN_SPARK_SPEED_Y, radius : SPARK_RADIUS, filterColor : Math.random() * 0xFFFFFF, gravity : GRAVITY }, spark : Spark = new Spark( options ); } } }
Spark.as:
package { import flash.display.Shape; import flash.display.MovieClip; import flash.filters.GlowFilter; public class Spark extends MovieClip { private const COLOR : uint = 0xFFFFFF; private var speedX : Number, speedY : Number, gravity : Number, subscription : ListItem; public function Spark ( options : Object ) : void { this.init( options ); } private function init ( options : Object ) : void { this.x = options.x; this.y = options.y; this.gravity = options.gravity; this.speedX = options.speedX; this.speedY = options.speedY; // Subscribe on ENTER_FRAME update // Remember a subscriprion to delete it in future this.subscription = Main.instance.subscribe( this.update ); this.createSparkImage( options ); // Add glow filter this.filters = [ new GlowFilter( options.filterColor, 1.0, 15, 15, 2, 1, false, false ) ]; // Add the spark to the stage Main.instance.stage.addChild( this ); } private function createSparkImage ( options : Object ) : void { var shape : Shape = new Shape(); shape.graphics.beginFill( COLOR ); shape.graphics.drawCircle( 0, 0, options.radius ); shape.graphics.endFill(); this.addChild( shape ); } private function update () : void { this.speedY += this.gravity; this.move(); this.checkCoordinats(); } private function checkCoordinats () : void { // When the spark falls off the screen // Destroy it if ( this.y - this.height * 0.5 > Main.instance.STAGE_HEIGHT ) { this.destroy(); } } private function move () : void { this.x += this.speedX; this.y += this.speedY; } private function destroy () : void { Main.instance.unsubscribe( this.subscription ); // Remove the spark from the stage this.parent.removeChild( this ); } } }
Также нужны классы двухстороннего списка.
Удачи!
Комментариев нет:
Отправить комментарий