Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(77)

Side by Side Diff: sky/examples/game/lib/node.dart

Issue 1218593002: Move sky/examples to sky/sdk/lib/example, and code changes to support that change. Fixes T277. (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 part of sprites;
2
3 double convertDegrees2Radians(double degrees) => degrees * Math.PI/180.8;
4
5 double convertRadians2Degrees(double radians) => radians * 180.0/Math.PI;
6
7 /// A base class for all objects that can be added to the sprite node tree and r endered to screen using [SpriteBox] and
8 /// [SpriteWidget].
9 ///
10 /// The [Node] class itself doesn't render any content, but provides the basic f unctions of any type of node, such as
11 /// handling transformations and user input. To render the node tree, a root nod e must be added to a [SpriteBox] or a
12 /// [SpriteWidget]. Commonly used sub-classes of [Node] are [Sprite], [NodeWithS ize], and many more upcoming subclasses.
13 ///
14 /// Nodes form a hierarchical tree. Each node can have a number of children, and the transformation (positioning,
15 /// rotation, and scaling) of a node also affects its children.
16 class Node {
17
18 // Member variables
19
20 SpriteBox _spriteBox;
21 Node _parent;
22
23 Point _position = Point.origin;
24 double _rotation = 0.0;
25
26 Matrix4 _transformMatrix = new Matrix4.identity();
27 Matrix4 _transformMatrixNodeToBox;
28 Matrix4 _transformMatrixBoxToNode;
29
30 double _scaleX = 1.0;
31 double _scaleY = 1.0;
32
33 /// The visibility of this node and its children.
34 bool visible = true;
35
36 double _zPosition = 0.0;
37 int _addedOrder;
38 int _childrenLastAddedOrder = 0;
39 bool _childrenNeedSorting = false;
40
41 /// Decides if the node and its children is currently paused.
42 ///
43 /// A paused node will not receive any input events, update calls, or run any animations.
44 ///
45 /// myNodeTree.paused = true;
46 bool paused = false;
47
48 bool _userInteractionEnabled = false;
49
50 /// If set to true the node will receive multiple pointers, otherwise it will only receive events the first pointer.
51 ///
52 /// This property is only meaningful if [userInteractionEnabled] is set to tru e. Default value is false.
53 ///
54 /// class MyCustomNode extends Node {
55 /// handleMultiplePointers = true;
56 /// }
57 bool handleMultiplePointers = false;
58 int _handlingPointer;
59
60 List<Node>_children = [];
61
62 // Constructors
63
64 /// Creates a new [Node] without any transformation.
65 ///
66 /// var myNode = new Node();
67 Node() {
68 }
69
70 // Property setters and getters
71
72 /// The [SpriteBox] this node is added to, or null if it's not currently added to a [SpriteBox].
73 ///
74 /// For most applications it's not necessary to access the [SpriteBox] directl y.
75 ///
76 /// // Get the transformMode of the sprite box
77 /// var transformMode = myNode.spriteBox.transformMode;
78 SpriteBox get spriteBox => _spriteBox;
79
80 /// The parent of this node, or null if it doesn't have a parent.
81 ///
82 /// // Hide the parent
83 /// myNode.parent.visible = false;
84 Node get parent => _parent;
85
86 /// The rotation of this node in degrees.
87 ///
88 /// myNode.rotation = 45.0;
89 double get rotation => _rotation;
90
91 void set rotation(double rotation) {
92 assert(rotation != null);
93 _rotation = rotation;
94 _invalidateTransformMatrix();
95 }
96
97 /// The position of this node relative to its parent.
98 ///
99 /// myNode.position = new Point(42.0, 42.0);
100 Point get position => _position;
101
102 void set position(Point position) {
103 assert(position != null);
104 _position = position;
105 _invalidateTransformMatrix();
106 }
107
108 /// The draw order of this node compared to its parent and its siblings.
109 ///
110 /// By default nodes are drawn in the order that they have been added to a par ent. To override this behavior the
111 /// [zPosition] property can be used. A higher value of this property will for ce the node to be drawn in front of
112 /// siblings that have a lower value. If a negative value is used the node wil l be drawn behind its parent.
113 ///
114 /// nodeInFront.zPosition = 1.0;
115 /// nodeBehind.zPosition = -1.0;
116 double get zPosition => _zPosition;
117
118 void set zPosition(double zPosition) {
119 assert(zPosition != null);
120 _zPosition = zPosition;
121 if (_parent != null) {
122 _parent._childrenNeedSorting = true;
123 }
124 }
125
126 /// The scale of this node relative its parent.
127 ///
128 /// The [scale] property is only valid if [scaleX] and [scaleY] are equal valu es.
129 ///
130 /// myNode.scale = 5.0;
131 double get scale {
132 assert(_scaleX == _scaleY);
133 return _scaleX;
134 }
135
136 void set scale(double scale) {
137 assert(scale != null);
138 _scaleX = _scaleY = scale;
139 _invalidateTransformMatrix();
140 }
141
142 /// The horizontal scale of this node relative its parent.
143 ///
144 /// myNode.scaleX = 5.0;
145 double get scaleX => _scaleX;
146
147 void set scaleX(double scaleX) {
148 assert(scaleX != null);
149 _scaleX = scaleX;
150 _invalidateTransformMatrix();
151 }
152
153 /// The vertical scale of this node relative its parent.
154 ///
155 /// myNode.scaleY = 5.0;
156 double get scaleY => _scaleY;
157
158 void set scaleY(double scaleY) {
159 assert(scaleY != null);
160 _scaleY = scaleY;
161 _invalidateTransformMatrix();
162 }
163
164 /// A list of the children of this node.
165 ///
166 /// This list should only be modified by using the [addChild] and [removeChild ] methods.
167 ///
168 /// // Iterate over a nodes children
169 /// for (Node child in myNode.children) {
170 /// // Do something with the child
171 /// }
172 List<Node> get children {
173 _sortChildren();
174 return _children;
175 }
176
177 // Adding and removing children
178
179 /// Adds a child to this node.
180 ///
181 /// The same node cannot be added to multiple nodes.
182 ///
183 /// addChild(new Sprite(myImage));
184 void addChild(Node child) {
185 assert(child != null);
186 assert(child._parent == null);
187
188 _childrenNeedSorting = true;
189 _children.add(child);
190 child._parent = this;
191 child._spriteBox = this._spriteBox;
192 _childrenLastAddedOrder += 1;
193 child._addedOrder = _childrenLastAddedOrder;
194 if (_spriteBox != null) _spriteBox._eventTargets = null;
195 }
196
197 /// Removes a child from this node.
198 ///
199 /// removeChild(myChildNode);
200 void removeChild(Node child) {
201 assert(child != null);
202 if (_children.remove(child)) {
203 child._parent = null;
204 child._spriteBox = null;
205 if (_spriteBox != null) _spriteBox._eventTargets = null;
206 }
207 }
208
209 /// Removes this node from its parent node.
210 ///
211 /// removeFromParent();
212 void removeFromParent() {
213 assert(_parent != null);
214 _parent.removeChild(this);
215 }
216
217 /// Removes all children of this node.
218 ///
219 /// removeAllChildren();
220 void removeAllChildren() {
221 for (Node child in _children) {
222 child._parent = null;
223 child._spriteBox = null;
224 }
225 _children = [];
226 _childrenNeedSorting = false;
227 if (_spriteBox != null) _spriteBox._eventTargets = null;
228 }
229
230 void _sortChildren() {
231 // Sort children primarily by zPosition, secondarily by added order
232 if (_childrenNeedSorting) {
233 _children.sort((Node a, Node b) {
234 if (a._zPosition == b._zPosition) {
235 return a._addedOrder - b._addedOrder;
236 }
237 else if (a._zPosition > b._zPosition) {
238 return 1;
239 }
240 else {
241 return -1;
242 }
243 });
244 _childrenNeedSorting = false;
245 }
246 }
247
248 // Calculating the transformation matrix
249
250 /// The transformMatrix describes the transformation from the node's parent.
251 ///
252 /// You cannot set the transformMatrix directly, instead use the position, rot ation and scale properties.
253 ///
254 /// Matrix4 matrix = myNode.transformMatrix;
255 Matrix4 get transformMatrix {
256 if (_transformMatrix != null) {
257 return _transformMatrix;
258 }
259
260 double cx, sx, cy, sy;
261
262 if (_rotation == 0.0) {
263 cx = 1.0;
264 sx = 0.0;
265 cy = 1.0;
266 sy = 0.0;
267 }
268 else {
269 double radiansX = convertDegrees2Radians(_rotation);
270 double radiansY = convertDegrees2Radians(_rotation);
271
272 cx = Math.cos(radiansX);
273 sx = Math.sin(radiansX);
274 cy = Math.cos(radiansY);
275 sy = Math.sin(radiansY);
276 }
277
278 // Create transformation matrix for scale, position and rotation
279 _transformMatrix = new Matrix4(cy * _scaleX, sy * _scaleX, 0.0, 0.0,
280 -sx * _scaleY, cx * _scaleY, 0.0, 0.0,
281 0.0, 0.0, 1.0, 0.0,
282 _position.x, _position.y, 0.0, 1.0);
283
284 return _transformMatrix;
285 }
286
287 void _invalidateTransformMatrix() {
288 _transformMatrix = null;
289 _invalidateToBoxTransformMatrix();
290 }
291
292 void _invalidateToBoxTransformMatrix () {
293 _transformMatrixNodeToBox = null;
294 _transformMatrixBoxToNode = null;
295
296 for (Node child in children) {
297 child._invalidateToBoxTransformMatrix();
298 }
299 }
300
301 // Transforms to other nodes
302
303 Matrix4 _nodeToBoxMatrix() {
304 assert(_spriteBox != null);
305 if (_transformMatrixNodeToBox != null) {
306 return _transformMatrixNodeToBox;
307 }
308
309 if (_parent == null) {
310 // Base case, we are at the top
311 assert(this == _spriteBox.rootNode);
312 _transformMatrixNodeToBox = new Matrix4.copy(_spriteBox.transformMatrix).m ultiply(transformMatrix);
313 }
314 else {
315 _transformMatrixNodeToBox = new Matrix4.copy(_parent._nodeToBoxMatrix()).m ultiply(transformMatrix);
316 }
317 return _transformMatrixNodeToBox;
318 }
319
320 Matrix4 _boxToNodeMatrix() {
321 assert(_spriteBox != null);
322
323 if (_transformMatrixBoxToNode != null) {
324 return _transformMatrixBoxToNode;
325 }
326
327 _transformMatrixBoxToNode = new Matrix4.copy(_nodeToBoxMatrix());
328 _transformMatrixBoxToNode.invert();
329
330 return _transformMatrixBoxToNode;
331 }
332
333 /// Converts a point from the coordinate system of the [SpriteBox] to the loca l coordinate system of the node.
334 ///
335 /// This method is particularly useful when handling pointer events and need t he pointers position in a local
336 /// coordinate space.
337 ///
338 /// Point localPoint = myNode.convertPointToNodeSpace(pointInBoxCoordinate s);
339 Point convertPointToNodeSpace(Point boxPoint) {
340 assert(boxPoint != null);
341 assert(_spriteBox != null);
342
343 Vector4 v =_boxToNodeMatrix().transform(new Vector4(boxPoint.x, boxPoint.y, 0.0, 1.0));
344 return new Point(v[0], v[1]);
345 }
346
347 /// Converts a point from the local coordinate system of the node to the coord inate system of the [SpriteBox].
348 ///
349 /// Point pointInBoxCoordinates = myNode.convertPointToBoxSpace(localPoint );
350 Point convertPointToBoxSpace(Point nodePoint) {
351 assert(nodePoint != null);
352 assert(_spriteBox != null);
353
354 Vector4 v =_nodeToBoxMatrix().transform(new Vector4(nodePoint.x, nodePoint.y , 0.0, 1.0));
355 return new Point(v[0], v[1]);
356 }
357
358 /// Converts a [point] from another [node]s coordinate system into the local c oordinate system of this node.
359 ///
360 /// Point pointInNodeASpace = nodeA.convertPointFromNode(pointInNodeBSpace , nodeB);
361 Point convertPointFromNode(Point point, Node node) {
362 assert(node != null);
363 assert(point != null);
364 assert(_spriteBox != null);
365 assert(_spriteBox == node._spriteBox);
366
367 Point boxPoint = node.convertPointToBoxSpace(point);
368 Point localPoint = convertPointToNodeSpace(boxPoint);
369
370 return localPoint;
371 }
372
373 // Hit test
374
375 /// Returns true if the [point] is inside the node, the [point] is in the loca l coordinate system of the node.
376 ///
377 /// myNode.isPointInside(localPoint);
378 ///
379 /// [NodeWithSize] provides a basic bounding box check for this method, if you require a more detailed check this
380 /// method can be overridden.
381 ///
382 /// bool isPointInside (Point nodePoint) {
383 /// double minX = -size.width * pivot.x;
384 /// double minY = -size.height * pivot.y;
385 /// double maxX = minX + size.width;
386 /// double maxY = minY + size.height;
387 /// return (nodePoint.x >= minX && nodePoint.x < maxX &&
388 /// nodePoint.y >= minY && nodePoint.y < maxY);
389 /// }
390 bool isPointInside(Point point) {
391 assert(point != null);
392
393 return false;
394 }
395
396 // Rendering
397
398 void _visit(RenderCanvas canvas) {
399 assert(canvas != null);
400 if (!visible) return;
401
402 _prePaint(canvas);
403 _visitChildren(canvas);
404 _postPaint(canvas);
405 }
406
407 void _prePaint(RenderCanvas canvas) {
408 canvas.save();
409
410 // Get the transformation matrix and apply transform
411 canvas.concat(transformMatrix.storage);
412 }
413
414 /// Paints this node to the canvas.
415 ///
416 /// Subclasses, such as [Sprite], override this method to do the actual painti ng of the node. To do custom
417 /// drawing override this method and make calls to the [canvas] object. All dr awing is done in the node's local
418 /// coordinate system, relative to the node's position. If you want to make th e drawing relative to the node's
419 /// bounding box's origin, override [NodeWithSize] and call the applyTransform ForPivot method before making calls for
420 /// drawing.
421 ///
422 /// void paint(RenderCanvas canvas) {
423 /// canvas.save();
424 /// applyTransformForPivot(canvas);
425 ///
426 /// // Do painting here
427 ///
428 /// canvas.restore();
429 /// }
430 void paint(RenderCanvas canvas) {
431 }
432
433 void _visitChildren(RenderCanvas canvas) {
434 // Sort children if needed
435 _sortChildren();
436
437 int i = 0;
438
439 // Visit children behind this node
440 while (i < _children.length) {
441 Node child = _children[i];
442 if (child.zPosition >= 0.0) break;
443 child._visit(canvas);
444 i++;
445 }
446
447 // Paint this node
448 paint(canvas);
449
450 // Visit children in front of this node
451 while (i < _children.length) {
452 Node child = _children[i];
453 child._visit(canvas);
454 i++;
455 }
456 }
457
458 void _postPaint(RenderCanvas canvas) {
459 canvas.restore();
460 }
461
462 // Receiving update calls
463
464 /// Called before a frame is drawn.
465 ///
466 /// Override this method to do any updates to the node or node tree before it' s drawn to screen.
467 ///
468 /// // Make the node rotate at a fixed speed
469 /// void update(double dt) {
470 /// rotation = rotation * 10.0 * dt;
471 /// }
472 void update(double dt) {
473 }
474
475 /// Called whenever the [SpriteBox] is modified or resized, or if the device i s rotated.
476 ///
477 /// Override this method to do any updates that may be necessary to correctly display the node or node tree with the
478 /// new layout of the [SpriteBox].
479 ///
480 /// void spriteBoxPerformedLayout() {
481 /// // Move some stuff around here
482 /// }
483 void spriteBoxPerformedLayout() {
484 }
485
486 // Handling user interaction
487
488 /// The node will receive user interactions, such as pointer (touch or mouse) events.
489 ///
490 /// class MyCustomNode extends NodeWithSize {
491 /// userInteractionEnabled = true;
492 /// }
493 bool get userInteractionEnabled => _userInteractionEnabled;
494
495 void set userInteractionEnabled(bool userInteractionEnabled) {
496 _userInteractionEnabled = userInteractionEnabled;
497 if (_spriteBox != null) _spriteBox._eventTargets = null;
498 }
499
500 /// Handles an event, such as a pointer (touch or mouse) event.
501 ///
502 /// Override this method to handle events. The node will only receive events i f the [userInteractionEnabled] property
503 /// is set to true and the [isPointInside] method returns true for the positio n of the pointer down event (default
504 /// behavior provided by [NodeWithSize]). Unless [handleMultiplePointers] is s et to true, the node will only receive
505 /// events for the first pointer that is down.
506 ///
507 /// Return true if the node has consumed the event, if an event is consumed it will not be passed on to nodes behind
508 /// the current node.
509 ///
510 /// // MyTouchySprite gets transparent when we touch it
511 /// class MyTouchySprite extends Sprite {
512 ///
513 /// MyTouchySprite(Image img) : super (img) {
514 /// userInteractionEnabled = true;
515 /// }
516 ///
517 /// bool handleEvent(SpriteBoxEvent event) {
518 /// if (event.type == 'pointerdown) {
519 /// opacity = 0.5;
520 /// }
521 /// else if (event.type == 'pointerup') {
522 /// opacity = 1.0;
523 /// }
524 /// return true;
525 /// }
526 /// }
527 bool handleEvent(SpriteBoxEvent event) {
528 return false;
529 }
530 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698