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

Side by Side Diff: samples/pop_pop_win/lib/src/canvas/game_element.dart

Issue 242443008: samples/pop_pop_win: now based on StageXL (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: tiny nit Created 6 years, 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 part of pop_pop_win.canvas;
2
3 class GameElement extends ParentThing {
4 static const _edgeOffset = 32;
5 static const _backgroundSize = const Size(2048, 1536);
6 static const _backgroundEdgeOffset = 256;
7 static const _backgroundHoleSize = 16 * SquareElement._size + 2 * _edgeOffset;
8 static const _boardOffset = const Vector(352, 96);
9 static const _popExplodeAnimationOffset = const Vector(-88, -88);
10 static const _popAnimationHitFrame = 12;
11
12 static const _dartAnimationOffset =
13 const Vector(-512 + 0.5 * SquareElement._size,
14 -388 + 0.5 * SquareElement._size);
15
16 final CanvasThing _canvas = new CanvasThing(0, 0);
17 final GameBackgroundElement _background = new GameBackgroundElement();
18 final BoardElement _boardElement = new BoardElement();
19 final ScoreElement _scoreElement;
20 final NewGameElement _newGameElement = new NewGameElement();
21 final GameTitleElement _titleElement = new GameTitleElement();
22 final TextureAnimationThing _popAnimationLayer, _dartAnimationLayer;
23 final TextureData _textureData;
24 final EventHandle _targetChanged = new EventHandle();
25
26 int _targetX, _targetY;
27 double _scale;
28 Vector _scaledBoardOffset;
29 Box _scaledInnerBox;
30 SquareElement _mouseDownElement, _lastHoldUnfreeze;
31 Timer _mouseDownTimer;
32
33 Game _game;
34
35 GameElement(TextureData textureData)
36 : _textureData = textureData,
37 _popAnimationLayer = new TextureAnimationThing(0, 0, textureData),
38 _dartAnimationLayer = new TextureAnimationThing(0, 0, textureData),
39 _scoreElement = new ScoreElement(),
40 super(100, 100) {
41 _canvas.registerParent(this);
42 _canvas.add(_background);
43 _canvas.add(_boardElement);
44 _canvas.add(_newGameElement);
45 _canvas.add(_scoreElement);
46 _canvas.add(_popAnimationLayer);
47 _canvas.add(_titleElement);
48 _canvas.add(_dartAnimationLayer);
49
50 _newGameElement.clicked.listen((args) => GameAudio.click());
51
52 MouseManager.setClickable(_titleElement, true);
53 MouseManager.getClickStream(_titleElement).listen((args) =>
54 _titleClickedEventHandle.add(EventArgs.empty));
55 }
56
57 Stream<EventArgs> get newGameClick => _newGameElement.clicked;
58
59 Game get game => _game;
60
61 void set game(Game value) {
62 _game = value;
63 if (value == null) {
64 size = const Size(100, 100);
65 } else {
66 _updateSize(value.field.width, value.field.height);
67 }
68 }
69
70 bool get canRevealTarget =>
71 _targetX != null && _game.canReveal(_targetX, _targetY);
72
73 bool get canFlagTarget =>
74 _targetX != null && _game.canToggleFlag(_targetX, _targetY);
75
76 void setGameManager(GameManager manager) {
77 _scoreElement.setGameManager(manager);
78 }
79
80 void revealTarget() {
81 if (_targetX != null) {
82 game.reveal(_targetX, _targetY);
83 _target(null, null);
84 }
85 }
86
87 void toggleTargetFlag() {
88 if (_targetX != null) {
89 final success = _toggleFlag(_targetX, _targetY);
90 if (success) {
91 _target(null, null);
92 }
93 }
94 }
95
96 Stream get targetChanged => _targetChanged.stream;
97
98 int get visualChildCount => 1;
99
100 Thing getVisualChild(int index) {
101 assert(index == 0);
102 return _canvas;
103 }
104
105 void update() {
106 super.update();
107 final offset = _scaledBoardOffset +
108 const Coordinate(_edgeOffset, _edgeOffset);
109
110 _canvas.setTopLeft(_boardElement, offset);
111 _canvas.setTopLeft(_popAnimationLayer, offset);
112 _canvas.setTopLeft(_dartAnimationLayer, offset);
113
114 // score offset
115 // end of the board - score width
116 final x = _scale * (40 + _backgroundSize.width - _boardOffset.x - _scoreElem ent.width);
117
118 _canvas.setTopLeft(_scoreElement, new Coordinate(x, 0));
119 _canvas.getChildTransform(_scoreElement).scale(_scale, _scale);
120
121 final newGameTopLeft = new Coordinate(
122 (_boardOffset.x + _newGameElement.width * 0.2) * _scale, 0);
123 _canvas.setTopLeft(_newGameElement, newGameTopLeft);
124 _canvas.getChildTransform(_newGameElement).scale(_scale, _scale);
125
126 final titleMultiplier = 1.7;
127 final titleTopLeft = new Coordinate(_scale * 0.5 * (_backgroundSize.width -
128 _titleElement.width * titleMultiplier), 0);
129 _canvas.setTopLeft(_titleElement, titleTopLeft);
130 _canvas.getChildTransform(_titleElement)
131 .scale(titleMultiplier * _scale, titleMultiplier * _scale);
132 }
133
134 void drawOverride(CanvasRenderingContext2D ctx) {
135 // draw children via super
136 super.drawOverride(ctx);
137
138 // draw target element
139 _drawTarget(ctx);
140 }
141
142 void _drawTarget(CanvasRenderingContext2D ctx) {
143 assert((_targetX == null) == (_targetY == null));
144 if (_targetX != null) {
145 final halfSize = SquareElement._size * 0.5;
146 var targetLoc = new Vector(_targetX, _targetY);
147 targetLoc = targetLoc.scale(SquareElement._size);
148
149 ctx.fillStyle = 'rgba(255, 0, 0, 0.5)';
150 CanvasUtil.centeredCircle(ctx,
151 targetLoc.x + halfSize, targetLoc.y + halfSize, halfSize);
152 ctx.fill();
153 }
154 }
155
156 void _startPopAnimation(Coordinate start, [Iterable<Coordinate> reveals = null ]) {
157 if(reveals == null) {
158 assert(game.state == GameState.lost);
159 reveals = new NumberEnumerable.fromRange(0, game.field.length)
160 .map((i) {
161 final t = game.field.getCoordinate(i);
162 final c = new Coordinate(t.item1, t.item2);
163 return new Tuple(c, game.getSquareState(c.x, c.y));
164 })
165 .where((t2) => t2.item2 == SquareState.bomb || t2.item2 == SquareState .hidden)
166 .map((t2) => t2.item1)
167 .toList();
168 }
169
170 final values = reveals.map((c) {
171 final initialOffset = new Vector(SquareElement._size * c.x,
172 SquareElement._size * c.y);
173 final squareOffset = _popExplodeAnimationOffset + initialOffset;
174
175 var delay = _popAnimationHitFrame + ((c - start).magnitude * 4).toInt();
176 delay += rnd.nextInt(10);
177
178 return [c, initialOffset, squareOffset, delay];
179 }).toList();
180
181 values.sort((a, b) {
182 final int da = a[3];
183 final int db = b[3];
184 return da.compareTo(db);
185 });
186
187 for (final v in values) {
188 final Coordinate c = v[0];
189 final Vector initialOffset = v[1];
190 final Vector squareOffset = v[2];
191 final int delay = v[3];
192
193 final ss = game.getSquareState(c.x, c.y);
194
195 String texturePrefix;
196 int frameCount;
197
198 switch (ss) {
199 case SquareState.revealed:
200 case SquareState.hidden:
201 texturePrefix = 'balloon_pop';
202 frameCount = 28;
203 break;
204 case SquareState.bomb:
205 texturePrefix = 'balloon_explode';
206 frameCount = 24;
207 break;
208 default:
209 throw 'not supported';
210 }
211
212 final request = new TextureAnimationRequest(texturePrefix, frameCount, squ areOffset,
213 delay: delay, initialFrame: 'balloon.png', initialFrameOffset: initial Offset);
214
215 switch (ss) {
216 case SquareState.revealed:
217 case SquareState.hidden:
218 request.started.listen((args) => GameAudio.pop());
219 break;
220 case SquareState.bomb:
221 request.started.listen((args) => GameAudio.bomb());
222 break;
223 }
224
225 _popAnimationLayer.add(request);
226 }
227 }
228
229 void _startDartAnimation(List<Coordinate> points) {
230 assert(points.length >= 1);
231 GameAudio.throwDart();
232 for(final point in points) {
233 final squareOffset = _dartAnimationOffset +
234 new Vector(SquareElement._size * point.x, SquareElement._size * point. y);
235
236 _dartAnimationLayer.add(new TextureAnimationRequest('dart_fly_shadow', 54, squareOffset));
237 _dartAnimationLayer.add(new TextureAnimationRequest('dart_fly', 54, square Offset));
238 }
239 }
240
241 void wireSquareMouseEvent(Thing square) {
242 MouseManager.getClickStream(square).listen(_squareClicked);
243 MouseManager.getMouseDownStream(square).listen(_squareMouseDown);
244 MouseManager.getMouseUpStream(square).listen(_squareMouseUp);
245 MouseManager.getMouseMoveStream(square).listen(_squareMouseMove);
246 }
247
248 void _squareClicked(ThingMouseEventArgs args) {
249 if (!_game.gameEnded && _lastHoldUnfreeze == null) {
250 final SquareElement se = args.thing;
251 _click(se.x, se.y, args.shiftKey);
252 }
253 }
254
255 void _squareMouseDown(ThingMouseEventArgs args) {
256 _lastHoldUnfreeze = null;
257 if (_mouseDownTimer != null) {
258 _mouseDownTimer.cancel();
259 }
260 final SquareElement se = args.thing;
261 _mouseDownElement = se;
262 _mouseDownTimer = new Timer(const Duration(seconds: 1), _mouseDownTimeoutHan dle);
263 }
264
265 void _squareMouseMove(ThingMouseEventArgs args) {
266 final SquareElement se = args.thing;
267 if (_mouseDownElement != se) {
268 _clearTimeout();
269 }
270 }
271
272 void _squareMouseUp(ThingMouseEventArgs args) {
273 final SquareElement se = args.thing;
274 _clearTimeout();
275 }
276
277 void _mouseDownTimeoutHandle() {
278 assert(_mouseDownTimer != null);
279 assert(_mouseDownElement != null);
280 _click(_mouseDownElement.x, _mouseDownElement.y, true);
281 _lastHoldUnfreeze = _mouseDownElement;
282 _clearTimeout();
283 }
284
285 void _clearTimeout() {
286 if (_mouseDownTimer != null) {
287 _mouseDownTimer.cancel();
288 _mouseDownTimer = null;
289 }
290 _mouseDownElement = null;
291 }
292
293 void _target(int x, int y) {
294 _targetX = x;
295 _targetY = y;
296 _targetChanged.add(null);
297 invalidateDraw();
298 }
299
300 bool _toggleFlag(int x, int y) {
301 assert(!game.gameEnded);
302 final ss = game.getSquareState(x, y);
303 if (ss == SquareState.hidden) {
304 game.setFlag(x, y, true);
305 GameAudio.flag();
306 return true;
307 } else if (ss == SquareState.flagged) {
308 game.setFlag(x, y, false);
309 GameAudio.unflag();
310 return true;
311 }
312 return false;
313 }
314
315 void _click(int x, int y, bool alt) {
316 assert(!game.gameEnded);
317 final ss = game.getSquareState(x, y);
318
319 List<Coordinate> reveals = null;
320
321 if (alt) {
322 if (ss == SquareState.hidden || ss == SquareState.flagged) {
323 _toggleFlag(x, y);
324 } else if (ss == SquareState.revealed) {
325 if (game.canReveal(x, y)) {
326 // get adjacent ballons
327 final adjHidden = game.field.getAdjacentIndices(x, y)
328 .map((i) {
329 final t = game.field.getCoordinate(i);
330 return new Coordinate(t.item1, t.item2);
331 })
332 .where((t) => game.getSquareState(t.x, t.y) == SquareState.hidden)
333 .toList();
334
335 assert(adjHidden.length > 0);
336
337 _startDartAnimation(adjHidden);
338 reveals = game.reveal(x, y);
339 }
340 }
341 } else {
342 if (ss == SquareState.hidden) {
343 _startDartAnimation([new Coordinate(x, y)]);
344 reveals = game.reveal(x, y);
345 }
346 }
347
348 if (reveals != null && reveals.length > 0) {
349 assert(game.state != GameState.lost);
350 if (!alt) {
351 // if it was a normal click, the first item should be the clicked item
352 var first = reveals[0];
353 assert(first.x == x);
354 assert(first.y == y);
355 }
356 _startPopAnimation(new Coordinate(x, y), reveals);
357 } else if (game.state == GameState.lost) {
358 _startPopAnimation(new Coordinate(x, y));
359 }
360 }
361
362 void _updateSize(int w, int h) {
363 final sizeX = _getScale(w, _backgroundSize.width, _backgroundHoleSize);
364 final sizeY = _getScale(h, _backgroundSize.height, _backgroundHoleSize);
365
366 _canvas.size = size = new Size(sizeX, sizeY);
367
368 // NOTE: width wins here. Need to do work to make left and right sides
369 // scale nicely when not a square
370 _scale = sizeX / _backgroundSize.width;
371 _scaledBoardOffset = _boardOffset.scale(_scale);
372
373 _scaledInnerBox = new Box(_backgroundEdgeOffset * _scale, 0,
374 sizeX - 2 * _backgroundEdgeOffset * _scale, sizeY);
375 }
376
377 static num _getScale(int count, num fullSize, num holeSize) {
378 final k = count * SquareElement._size + 2 * _edgeOffset;
379
380 return k * fullSize / holeSize;
381 }
382 }
OLDNEW
« no previous file with comments | « samples/pop_pop_win/lib/src/canvas/game_background_element.dart ('k') | samples/pop_pop_win/lib/src/canvas/game_root.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698