Tutorials, extensions, and source files for ActionScript, Flash, and other Adobe products.

 

senocular.com ActionScript Library

Seeker.as

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
package com.senocular.gyro {
	
	import flash.events.Event;
	import flash.events.IEventDispatcher;
	import flash.utils.Dictionary;
	
	/**
	 * Creates a persistent process used for one or more objects to consistently
	 * act upon or "follow" a target object based on the behavior defined
	 * by an ISeek instance
	 */
	public class Seeker
		extends DynamicDispatcher
		implements IStartable {
		
		protected var _seek:ISeek;
		protected var _target:*;
		protected var _property:String;
		protected var interpolaterList:Array = [];
		protected var hasCustomSeekList:Dictionary = new Dictionary();
		
		protected static var defaultSeek:Seek = new Seek();
	
		public function get target():* {
			return _target;
		}
		public function set target(o:*):void {
			_target = o;
			updateInterpolaters();
		}
		
		public function get property():String {
			return _property;
		}
		public function set property(s:String):void {
			_property = s;
			updateInterpolaters();
		}
		
		public function get seek():ISeek {
			return (_seek != defaultSeek) ? _seek : null;
		}
		public function set seek(s:ISeek):void {
			_seek = (s) ? s : defaultSeek;
		}
		
		public function Seeker(target:*, property:String = "", seek:ISeek = null, eventDispatcher:IEventDispatcher = null, eventType:String = Event.ENTER_FRAME, eventPriority:int = 0){
			super(eventDispatcher, eventType, eventPriority);
			this.target = target;
			this.property = property;
			this.seek = (seek) ? seek : defaultSeek;
			
			addEventListener(GyroEvent.START, startHandler, false, 0, true);
			addEventListener(GyroEvent.STOP, stopHandler, false, 0, true);
			
			start();
		}
		
		public function start():void {
			dispatchEvent(new GyroEvent(GyroEvent.START, this));
		}
		public function stop():void {
			dispatchEvent(new GyroEvent(GyroEvent.STOP, this));
		}
		
		public function setTarget(target:*, property:String = ""){
			this.target = target;
			this.property = property;
		}
		
		public function addProperty(owner:*, property:String = "", seek:ISeek = null):IInterpolate {
			return addInterpolate(new InterpolateProperty(0, 1, owner, property));
		}
		
		public function addInterpolate(interpolater:IInterpolate, seek:ISeek = null):IInterpolate {
			removeInterpolate(interpolater);
			interpolaterList.push(interpolater);
			if (seek) hasCustomSeekList[interpolater] = seek;
			return interpolater;
		}
		
		/**
		 * Removes an interpolated object currently seeking
		 * this target instance.
		 */
		public function removeInterpolate(interpolater:IInterpolate):IInterpolate {
			var index:int = interpolaterList.indexOf(interpolater);
			if (index != -1){
				interpolaterList.splice(index, 1);
			}
			if (interpolater in hasCustomSeekList) {
				delete hasCustomSeekList[interpolater];
			}
			return interpolater;
		}
		
		protected function startHandler(event:GyroEvent):void {
			eventEnabled = true;
		}
		
		protected function stopHandler(event:GyroEvent):void {
			eventEnabled = false;
		}
		
		protected function updateInterpolaters():void {
			for each (var interpolater:IInterpolate in interpolaterList) {
				
				// interpolates typically have an end property
				// Seeks will use this to match the the target
				// TODO: need an interface type to check?
				if ("end" in interpolater){
					Object(interpolater).end = (target && property) ? target[property] : target;
				}
			}
		}
		
		protected override function eventHandler(event:Event):void {
			for each (var interpolater:IInterpolate in interpolaterList) {
				
				// interpolates typically have an end property
				// Seeks will use this to match the the target
				// TODO: need an interface type to check? But end will not have the same type
				// 		using * for Interfacing only is not recommended
				// TODO: should we really be modifying the interpolator?  Suspect not...
				if ("end" in interpolater){
					// this is updated for every event in case the
					// target value has changed
					Object(interpolater).end = (target && property) ? target[property] : target;
				}
				if (interpolater in hasCustomSeekList){
					ISeek(hasCustomSeekList[interpolater]).call(interpolater);
				}else{
					_seek.call(interpolater);
				}
				
				// TODO: determine if at destination
				if (false){
					dispatchEvent(new GyroEvent(GyroEvent.AT_DESTINATION, this));
				}
			}
		}
	}
}