/
sprite_3d.dart
155 lines (129 loc) · 4.93 KB
/
sprite_3d.dart
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
part of '../display.dart';
/// The [Sprite3D] class enables 3D transformations of 2D display objects.
///
/// Use the [rotationX], [rotationY] and [rotationZ] properties to rotate the
/// display object in 3D space. Use the [offsetX], [offsetY] and [offsetZ]
/// properties to move the display object in 3D space.
///
/// Example:
///
/// var flip = Sprite3D()
/// flip.addChild(bitmap);
/// flip.rotationY = PI / 4
/// flip.addTo(stage);
///
class Sprite3D extends DisplayObjectContainer3D implements Sprite {
@override
Graphics? _graphics;
/// Specifies the Graphics object that belongs to this sprite where vector
/// drawing commands can occur.
@override
Graphics get graphics => _graphics ??= Graphics();
@override
set graphics(Graphics value) {
_graphics = value;
}
//----------------------------------------------------------------------------
/// Specifies the display object over which the sprite is being dragged, or on
/// which the sprite was dropped.
@override
DisplayObject? dropTarget;
/// Lets the user drag this sprite with the mouse or the current touch point.
///
/// If this method is called within the context of a touch event, the drag
/// will be performed accordingly all future touch events with the same
/// [TouchEvent.touchPointID]. Otherwise the drag will be performed based
/// on mouse events.
///
/// The sprite remains draggable until explicitly stopped through a call
/// to the [stopDrag] method.
///
/// With [lockCenter] you can specify whether the draggable sprite is locked
/// to the center of the pointer position (true), or locked to the point where
/// the user first clicked the sprite (false).
///
/// [bounds] is the value relative to the coordinates of the Sprite's
/// parent that specify a constraint rectangle for the Sprite.
@override
void startDrag([bool lockCenter = false, Rectangle<num>? bounds]) {
final stage = this.stage;
final inputEvent = InputEvent.current;
final globalPoint = Point<num>(0.0, 0.0);
var anchorPoint = Point<num>(0.0, 0.0);
var touchPointID = 0;
if (inputEvent == null && stage != null) {
globalPoint.copyFrom(stage.mousePosition);
} else if (inputEvent is MouseEvent) {
globalPoint.setTo(inputEvent.stageX, inputEvent.stageY);
} else if (inputEvent is TouchEvent) {
globalPoint.setTo(inputEvent.stageX, inputEvent.stageY);
touchPointID = inputEvent.touchPointID;
} else {
return;
}
if (lockCenter) {
anchorPoint = this.bounds.center;
} else {
globalToLocal(globalPoint, anchorPoint);
}
stage!._startDrag(this, globalPoint, anchorPoint, bounds, touchPointID);
}
/// Ends the [startDrag] method.
///
/// A sprite that was made draggable with the [startDrag] method remains
/// draggable until a [stopDrag] method is added or the sprite was dragged
/// with a different touch point.
@override
void stopDrag() {
final stage = this.stage;
stage?._stopDrag(this);
}
//----------------------------------------------------------------------------
@override
Rectangle<num> get bounds {
final bounds = super.bounds;
return _graphics == null ? bounds : bounds.boundingBox(_graphics!.bounds);
}
//----------------------------------------------------------------------------
/// Designates another sprite to serve as the hit area for a sprite.
///
/// If the hitArea is null (the default), the sprite itself is used as the hit
/// area. The value of the hitArea property can be a reference to a Sprite
/// object.
///
/// You can change the hitArea property at any time; the modified sprite
/// immediately uses the hit area behavior. The sprite designated as the
/// hit area does not need to be visible; its graphical shape, although not
/// visible, is still detected as the hit area.
///
/// Note: You must set to false the [mouseEnabled] property of the sprite
/// designated as the hit area. Otherwise, your sprite button might not work
/// because the sprite designated as the hit area receives the user input
/// events instead of your sprite button.
@override
Sprite? hitArea;
@override
DisplayObject? hitTestInput(num localX, num localY) {
final hitArea = this.hitArea;
final graphics = _graphics;
DisplayObject? target;
if (hitArea != null) {
final point = Point<num>(localX, localY);
localToGlobal(point, point);
hitArea.globalToLocal(point, point);
target = hitArea.hitTestInput(point.x, point.y);
return target != null ? this : null;
}
target = super.hitTestInput(localX, localY);
if (target == null && graphics != null) {
target = graphics.hitTest(localX, localY) ? this : null;
}
return target;
}
//----------------------------------------------------------------------------
@override
void render(RenderState renderState) {
_graphics?.render(renderState);
super.render(renderState);
}
}