-
Notifications
You must be signed in to change notification settings - Fork 5
/
Being.as
433 lines (356 loc) · 10.1 KB
/
Being.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
package sentinel.gameplay.world
{
import flash.utils.getDefinitionByName;
import sentinel.framework.Data;
import sentinel.framework.errors.FrameworkError;
import sentinel.framework.graphics.IGraphics;
import sentinel.framework.IServiceable;
import sentinel.framework.Service;
import sentinel.framework.ServiceManager;
import sentinel.framework.Thing;
import sentinel.gameplay.IPositionProvider;
import sentinel.gameplay.physics.Body;
import sentinel.gameplay.physics.Engine;
import sentinel.gameplay.physics.Vector2D;
import sentinel.gameplay.ui.BaseUI;
/**
* A Being is an object that lives in a World. It can define graphics and a physics body. It
* should be used as the base class for all of your gameplay objects within a World like trees,
* enemies, loot, projectiles, the main hero, etc. Because a Being is used to describe any
* element that could appear within a World, it can be also used to represent less obvious items
* like health bars and text that is attached to certain positions within the World.
* @author Marty Wallace.
*/
public class Being extends Thing implements IPositionProvider, IServiceable
{
/**
* Attempts to create a new Being from save data obtained via <code>Being.save()</code>.
* @param type The type of object to try and create, as a fully qualified class name.
* @param data The save data.
*/
public static function create(type:String, save:Data = null):Being
{
var className:Class = null;
try
{
// Attempt to obtain the class definition from the 'type' string value.
className = getDefinitionByName(type) as Class;
}
catch (error:ReferenceError)
{
throw FrameworkError.compile('Type {{ type }} could not be loaded. You may need to manually reference this type in your project.', {
type: type
});
return null;
}
var being:Being = new className() as Being;
if (being !== null && save !== null)
{
// Apply save data.
being.load(save);
}
return being;
}
private var _graphics:IGraphics;
private var _body:Body;
private var _position:Vector2D;
private var _rotation:Number = 0;
private var _services:ServiceManager;
/**
* Constructor.
*/
public function Being()
{
super();
_position = new Vector2D();
var services:Vector.<BeingService> = defineServices();
if(services !== null && services.length > 0)
{
_services = new ServiceManager(this, Vector.<Service>(services));
_services.construct();
}
}
/**
* Deconstruct this Being. Also deconstructs its graphics and physics body. If this Being
* belongs to a World, it will remove itself from it.
*/
public override function deconstruct():void
{
if (_graphics !== null) _graphics.deconstruct();
if (_body !== null) _body.deconstruct();
if (_services !== null) _services.deconstruct();
super.deconstruct();
}
protected override function update():void
{
alignGraphics();
if (_services !== null) _services.update();
super.update();
}
/**
* Position and rotate the graphics owned by this Being to mimic its physics body.
* This method does nothing unless this Being owns both graphics and a physics body.
*/
public function alignGraphics():void
{
if (_graphics !== null)
{
if (_body !== null)
{
_graphics.x = _body.position.x;
_graphics.y = _body.position.y;
_graphics.rotation = _body.rotation;
}
else
{
_graphics.x = _position.x;
_graphics.y = _position.y;
_graphics.rotation = _rotation;
}
}
}
/**
* Position and rotate the physics body owned by this Being to mimic its graphics.
* This method does nothing unless this Being owns both a physics body and graphics.
*/
public function alignBody():void
{
if (_body !== null)
{
if (_graphics !== null)
{
_body.moveTo(_graphics.x, _graphics.y);
_body.rotation = _graphics.rotation;
}
else
{
_body.moveTo(_position.x, _position.y);
_body.rotation = _rotation;
}
}
}
/**
* Utility to method for setting the x and y values at the same time.
* @param x The new x coordinate.
* @param y The new y coordinate.
*/
public function moveTo(x:Number, y:Number):void
{
_position.x = x;
_position.y = y;
if (_body !== null)
{
_body.moveTo(x, y);
}
if (_graphics !== null)
{
_graphics.x = x;
_graphics.y = y;
}
}
/**
* Saves a simple representation of this Being, useful for working with
* <code>Being.create()</code>.
*/
public override function save():Data
{
return super.save().merge({
x: Number(x.toFixed(2)),
y: Number(y.toFixed(2)),
rotation: rotation
});
}
/**
* Applies properties stored in a simple object to this Being.
* @param data The data to apply.
*/
public override function load(data:Data):void
{
x = data.get('x');
y = data.get('y');
rotation = data.get('rotation', 0);
}
/**
* Removes this Being from its parent World.
* @param destroy Whether or not to also <code>deconstruct()</code> this Being.
*/
public override function removeFromParent(destroy:Boolean = false):void
{
if (world !== null)
{
world.remove(this, destroy);
super.removeFromParent(destroy);
}
}
protected final override function addedT(world:Thing):void
{
if (world is BaseWorld)
{
_graphics = defineGraphics();
if (_graphics !== null)
{
// Add the graphics to the World's graphics container.
_graphics.addTo((world as BaseWorld).__content);
if (!_graphics.atZero)
{
// If the position of the graphics has been modified, use those values for
// the final position.
moveTo(_graphics.x, _graphics.y);
rotation = _graphics.rotation;
}
else
{
alignGraphics();
}
}
if ((world as BaseWorld).engine !== null)
{
// Attempt to define a body for this Being.
_body = defineBody((world as BaseWorld).engine);
if (_body !== null)
{
if (!_body.atZero)
{
// If the position of the body has been modified, use those values for the
// final position. This overrides the position of the graphics.
moveTo(_body.position.x, _body.position.y);
rotation = _body.rotation;
}
else
{
alignBody();
}
}
}
added(world as BaseWorld);
}
else
{
throw FrameworkError.compile('Instances of Being can only be added to a World.');
}
}
protected function added(to:BaseWorld):void
{
//
}
protected final override function removedT(world:Thing):void
{
if (world is BaseWorld)
{
if (_graphics !== null) _graphics.deconstruct();
if (_body !== null) _body.deconstruct();
removed(world as BaseWorld);
}
else
{
throw FrameworkError.compile('Instances of Being can only be removed from a World.');
}
}
protected function removed(from:BaseWorld):void
{
//
}
/**
* Defines graphics to be used by this Being. Graphics are defined when this Being is added
* to a World.
*/
protected function defineGraphics():IGraphics
{
return null;
}
/**
* Defines a physics body to be used by this Being. The body is defined when this Being is
* added to a World.
* @param engine A reference to the physics engine.
*/
protected function defineBody(engine:Engine):Body
{
return null;
}
/**
* Defines the list of services that will be used by this Being.
*/
protected function defineServices():Vector.<BeingService>
{
return null;
}
/**
* Returns a Service attached to this Being.
* @param name The name of the Service to get.
*/
public function getService(name:String):Service
{
return _services.getService(name);
}
/**
* The parent World containing this Being.
*/
public function get world():BaseWorld { return parent as BaseWorld; }
/**
* The Map loaded by the parent World containing this Being.
*/
public function get map():BaseMap{ return world.map; }
/**
* The graphics representing this Being.
*/
public function get graphics():IGraphics { return _graphics; }
/**
* The physics body used by this Being.
*/
public function get body():Body { return _body; }
/**
* Returns the position of this Being. Modifying the <code>x</code> or <code>y</code> values
* of the result will not affect this Being, use <code>moveTo()</code> or modify the
* <code>x</code> and <code>y</code> values of this Being directly instead.
*/
public function get position():Vector2D
{
if (_graphics !== null)
{
_position.x = _graphics.x;
_position.y = _graphics.y;
}
if (_body !== null)
{
_position.x = _body.position.x;
_position.y = _body.position.y;
}
return _position;
}
public function set position(value:Vector2D):void
{
moveTo(value.x, value.y);
}
/**
* Get or set the x position of this Being.
* This is an alias for <code>position.x</code> and <code>moveTo(value, y)</code>.
*/
public function get x():Number { return position.x; }
public function set x(value:Number):void { moveTo(value, position.y); }
/**
* Get or set the y position of this Being.
* This is an alias for <code>position.y</code> and <code>moveTo(x, value)</code>.
*/
public function get y():Number { return position.y; }
public function set y(value:Number):void { moveTo(position.x, value); }
/**
* Get or set the rotation of this Being.
*/
public function get rotation():Number
{
if (_graphics !== null) _rotation = _graphics.rotation;
if (_body !== null) _rotation = _body.rotation;
return _rotation;
}
public function set rotation(value:Number):void
{
_rotation = value;
if (_body !== null) _body.rotation = value;
if (_graphics !== null) _graphics.rotation = value;
}
/**
* Returns the active UI, if this Being is a descendant of <code>GameplayState</code>.
*/
protected function get ui():BaseUI { return world !== null ? world.ui : null; }
}
}