OLD | NEW |
| (Empty) |
1 part of game; | |
2 | |
3 const double _steeringThreshold = 0.0; | |
4 const double _steeringMax = 150.0; | |
5 | |
6 // Random generator | |
7 Math.Random _rand = new Math.Random(); | |
8 | |
9 const double _gameSizeWidth = 1024.0; | |
10 const double _gameSizeHeight = 1024.0; | |
11 | |
12 const double _shipRadius = 30.0; | |
13 const double _lrgAsteroidRadius = 40.0; | |
14 const double _medAsteroidRadius = 20.0; | |
15 const double _smlAsteroidRadius = 10.0; | |
16 const double _maxAsteroidSpeed = 1.0; | |
17 | |
18 const int _lifeTimeLaser = 50; | |
19 | |
20 const int _numStarsInStarField = 150; | |
21 | |
22 class GameDemoWorld extends NodeWithSize { | |
23 | |
24 // Images | |
25 Image _imgNebula; | |
26 | |
27 SpriteSheet _spriteSheet; | |
28 | |
29 // Inputs | |
30 double _joystickX = 0.0; | |
31 double _joystickY = 0.0; | |
32 bool _fire; | |
33 | |
34 Node _gameLayer; | |
35 | |
36 Ship _ship; | |
37 List<Asteroid> _asteroids = []; | |
38 List<Laser> _lasers = []; | |
39 StarField _starField; | |
40 Nebula _nebula; | |
41 | |
42 GameDemoWorld(ImageMap images, this._spriteSheet) : super(new Size(_gameSizeWi
dth, _gameSizeHeight)) { | |
43 | |
44 // Fetch images | |
45 _imgNebula = images["res/nebula.png"]; | |
46 | |
47 _gameLayer = new Node(); | |
48 this.addChild(_gameLayer); | |
49 | |
50 // Add some asteroids to the game world | |
51 for (int i = 0; i < 5; i++) { | |
52 addAsteroid(AsteroidSize.large); | |
53 } | |
54 for (int i = 0; i < 5; i++) { | |
55 addAsteroid(AsteroidSize.medium); | |
56 } | |
57 | |
58 // Add ship | |
59 addShip(); | |
60 | |
61 // Add starfield | |
62 _starField = new StarField(_spriteSheet["star.png"], _numStarsInStarField); | |
63 _starField.zPosition = -2.0; | |
64 addChild(_starField); | |
65 | |
66 // Add nebula | |
67 addNebula(); | |
68 | |
69 userInteractionEnabled = true; | |
70 handleMultiplePointers = true; | |
71 } | |
72 | |
73 // Methods for adding game objects | |
74 | |
75 void addAsteroid(AsteroidSize size, [Point pos]) { | |
76 Asteroid asteroid = new Asteroid(_spriteSheet["asteroid_big_1.png"], size); | |
77 asteroid.zPosition = 1.0; | |
78 if (pos != null) asteroid.position = pos; | |
79 _gameLayer.addChild(asteroid); | |
80 _asteroids.add(asteroid); | |
81 } | |
82 | |
83 void addShip() { | |
84 Ship ship = new Ship(_spriteSheet["ship.png"]); | |
85 ship.zPosition = 10.0; | |
86 _gameLayer.addChild(ship); | |
87 _ship = ship; | |
88 } | |
89 | |
90 void addLaser() { | |
91 Laser laser = new Laser(_spriteSheet["laser.png"], _ship); | |
92 laser.zPosition = 8.0; | |
93 _lasers.add(laser); | |
94 _gameLayer.addChild(laser); | |
95 } | |
96 | |
97 void addNebula() { | |
98 _nebula = new Nebula.withImage(_imgNebula); | |
99 _gameLayer.addChild(_nebula); | |
100 } | |
101 | |
102 void update(double dt) { | |
103 // Move asteroids | |
104 for (Asteroid asteroid in _asteroids) { | |
105 asteroid.position = pointAdd(asteroid.position, asteroid._movementVector); | |
106 } | |
107 | |
108 // Move lasers and remove expired lasers | |
109 for (int i = _lasers.length - 1; i >= 0; i--) { | |
110 Laser laser = _lasers[i]; | |
111 laser.move(); | |
112 if (laser._frameCount > _lifeTimeLaser) { | |
113 laser.removeFromParent(); | |
114 _lasers.removeAt(i); | |
115 } | |
116 } | |
117 | |
118 // Apply thrust to ship | |
119 if (_joystickX != 0.0 || _joystickY != 0.0) { | |
120 _ship.thrust(_joystickX, _joystickY); | |
121 } | |
122 | |
123 // Move ship | |
124 _ship.move(); | |
125 | |
126 // Check collisions between asteroids and lasers | |
127 for (int i = _lasers.length -1; i >= 0; i--) { | |
128 // Iterate over all the lasers | |
129 Laser laser = _lasers[i]; | |
130 | |
131 for (int j = _asteroids.length - 1; j >= 0; j--) { | |
132 // Iterate over all the asteroids | |
133 Asteroid asteroid = _asteroids[j]; | |
134 | |
135 // Check for collision | |
136 if (pointQuickDist(laser.position, asteroid.position) < laser.radius + a
steroid.radius) { | |
137 // Remove laser | |
138 laser.removeFromParent(); | |
139 _lasers.removeAt(i); | |
140 | |
141 // Add asteroids | |
142 if (asteroid._asteroidSize == AsteroidSize.large) { | |
143 for (int a = 0; a < 3; a++) addAsteroid(AsteroidSize.medium, asteroi
d.position); | |
144 } | |
145 else if (asteroid._asteroidSize == AsteroidSize.medium) { | |
146 for (int a = 0; a < 5; a++) addAsteroid(AsteroidSize.small, asteroid
.position); | |
147 } | |
148 | |
149 // Remove asteroid | |
150 asteroid.removeFromParent(); | |
151 _asteroids.removeAt(j); | |
152 break; | |
153 } | |
154 } | |
155 } | |
156 | |
157 // Move objects to center camera and warp objects around the edges | |
158 centerCamera(); | |
159 warpObjects(); | |
160 } | |
161 | |
162 void centerCamera() { | |
163 const cameraDampening = 0.1; | |
164 Point delta = new Point(_gameSizeWidth/2 - _ship.position.x, _gameSizeHeight
/2 - _ship.position.y); | |
165 delta = pointMult(delta, cameraDampening); | |
166 | |
167 for (Node child in _gameLayer.children) { | |
168 child.position = pointAdd(child.position, delta); | |
169 } | |
170 | |
171 // Update starfield | |
172 _starField.move(delta.x, delta.y); | |
173 } | |
174 | |
175 void warpObjects() { | |
176 for (Node child in _gameLayer.children) { | |
177 if (child.position.x < 0) child.position = pointAdd(child.position, new Po
int(_gameSizeWidth, 0.0)); | |
178 if (child.position.x >= _gameSizeWidth) child.position = pointAdd(child.po
sition, new Point(-_gameSizeWidth, 0.0)); | |
179 if (child.position.y < 0) child.position = pointAdd(child.position, new Po
int(0.0, _gameSizeHeight)); | |
180 if (child.position.y >= _gameSizeHeight) child.position = pointAdd(child.p
osition, new Point(0.0, -_gameSizeHeight)); | |
181 } | |
182 } | |
183 | |
184 // Handling controls | |
185 | |
186 void controlSteering(double x, double y) { | |
187 _joystickX = x; | |
188 _joystickY = y; | |
189 } | |
190 | |
191 void controlFire() { | |
192 addLaser(); | |
193 } | |
194 | |
195 // Handle pointer events | |
196 | |
197 int _firstPointer = -1; | |
198 int _secondPointer = -1; | |
199 Point _firstPointerDownPos; | |
200 | |
201 bool handleEvent(SpriteBoxEvent event) { | |
202 Point pointerPos = convertPointToNodeSpace(event.boxPosition); | |
203 int pointer = event.pointer; | |
204 | |
205 switch (event.type) { | |
206 case 'pointerdown': | |
207 if (_firstPointer == -1) { | |
208 // Assign the first pointer | |
209 _firstPointer = pointer; | |
210 _firstPointerDownPos = pointerPos; | |
211 } | |
212 else if (_secondPointer == -1) { | |
213 // Assign second pointer | |
214 _secondPointer = pointer; | |
215 controlFire(); | |
216 } | |
217 else { | |
218 // There is a pointer used for steering, let's fire instead | |
219 controlFire(); | |
220 } | |
221 break; | |
222 case 'pointermove': | |
223 if (pointer == _firstPointer) { | |
224 // Handle turning control | |
225 double joystickX = 0.0; | |
226 double deltaX = pointerPos.x - _firstPointerDownPos.x; | |
227 if (deltaX > _steeringThreshold || deltaX < -_steeringThreshold) { | |
228 joystickX = (deltaX - _steeringThreshold)/(_steeringMax - _steeringT
hreshold); | |
229 if (joystickX > 1.0) joystickX = 1.0; | |
230 if (joystickX < -1.0) joystickX = -1.0; | |
231 } | |
232 | |
233 double joystickY = 0.0; | |
234 double deltaY = pointerPos.y - _firstPointerDownPos.y; | |
235 if (deltaY > _steeringThreshold || deltaY < -_steeringThreshold) { | |
236 joystickY = (deltaY - _steeringThreshold)/(_steeringMax - _steeringT
hreshold); | |
237 if (joystickY > 1.0) joystickY = 1.0; | |
238 if (joystickY < -1.0) joystickY = -1.0; | |
239 } | |
240 | |
241 controlSteering(joystickX, joystickY); | |
242 } | |
243 break; | |
244 case 'pointerup': | |
245 case 'pointercancel': | |
246 if (pointer == _firstPointer) { | |
247 // Un-assign the first pointer | |
248 _firstPointer = -1; | |
249 _firstPointerDownPos = null; | |
250 controlSteering(0.0, 0.0); | |
251 } | |
252 else if (pointer == _secondPointer) { | |
253 _secondPointer = -1; | |
254 } | |
255 break; | |
256 default: | |
257 break; | |
258 } | |
259 return true; | |
260 } | |
261 } | |
262 | |
263 // Game objects | |
264 | |
265 enum AsteroidSize { | |
266 small, | |
267 medium, | |
268 large, | |
269 } | |
270 | |
271 class Asteroid extends Sprite { | |
272 Point _movementVector; | |
273 AsteroidSize _asteroidSize; | |
274 double _radius; | |
275 | |
276 double get radius { | |
277 if (_radius != null) return _radius; | |
278 if (_asteroidSize == AsteroidSize.small) _radius = _smlAsteroidRadius; | |
279 else if (_asteroidSize == AsteroidSize.medium) _radius = _medAsteroidRadius; | |
280 else if (_asteroidSize == AsteroidSize.large) _radius = _lrgAsteroidRadius; | |
281 return _radius; | |
282 } | |
283 | |
284 Asteroid(Texture img, AsteroidSize this._asteroidSize) : super(img) { | |
285 size = new Size(radius * 2.0, radius * 2.0); | |
286 position = new Point(_gameSizeWidth * _rand.nextDouble(), _gameSizeHeight *
_rand.nextDouble()); | |
287 rotation = 360.0 * _rand.nextDouble(); | |
288 | |
289 _movementVector = new Point(_rand.nextDouble() * _maxAsteroidSpeed * 2 - _ma
xAsteroidSpeed, | |
290 _rand.nextDouble() * _maxAsteroidSpeed * 2 - _ma
xAsteroidSpeed); | |
291 | |
292 userInteractionEnabled = true; | |
293 } | |
294 | |
295 bool handleEvent(SpriteBoxEvent event) { | |
296 if (event.type == "pointerdown") { | |
297 colorOverlay = new Color(0x99ff0000); | |
298 } | |
299 else if (event.type == "pointerup") { | |
300 colorOverlay = null; | |
301 } | |
302 return false; | |
303 } | |
304 } | |
305 | |
306 class Ship extends Sprite { | |
307 Vector2 _movementVector; | |
308 double _rotationTarget; | |
309 | |
310 Ship(Texture img) : super(img) { | |
311 _movementVector = new Vector2.zero(); | |
312 rotation = _rotationTarget = 270.0; | |
313 | |
314 // Create sprite | |
315 size = new Size(_shipRadius * 2.0, _shipRadius * 2.0); | |
316 position = new Point(_gameSizeWidth/2.0, _gameSizeHeight/2.0); | |
317 } | |
318 | |
319 void thrust(double x, double y) { | |
320 _rotationTarget = convertRadians2Degrees(Math.atan2(y, x)); | |
321 Vector2 directionVector = new Vector2(x, y).normalize(); | |
322 _movementVector.addScaled(directionVector, 1.0); | |
323 } | |
324 | |
325 void move() { | |
326 position = new Point(position.x + _movementVector[0], position.y + _movement
Vector[1]); | |
327 _movementVector.scale(0.9); | |
328 | |
329 rotation = dampenRotation(rotation, _rotationTarget, 0.1); | |
330 } | |
331 } | |
332 | |
333 class Laser extends Sprite { | |
334 int _frameCount = 0; | |
335 Point _movementVector; | |
336 double radius = 10.0; | |
337 | |
338 Laser(Texture img, Ship ship) : super(img) { | |
339 size = new Size(20.0, 20.0); | |
340 position = ship.position; | |
341 rotation = ship.rotation + 90.0; | |
342 transferMode = TransferMode.plus; | |
343 double rotRadians = convertDegrees2Radians(rotation); | |
344 _movementVector = pointMult(new Point(Math.sin(rotRadians), -Math.cos(rotRad
ians)), 10.0); | |
345 _movementVector = new Point(_movementVector.x + ship._movementVector[0], _mo
vementVector.y + ship._movementVector[1]); | |
346 } | |
347 | |
348 void move() { | |
349 position = pointAdd(position, _movementVector); | |
350 _frameCount++; | |
351 } | |
352 } | |
353 | |
354 // Background starfield | |
355 | |
356 class StarField extends Node { | |
357 Texture _img; | |
358 int _numStars; | |
359 List<Point> _starPositions; | |
360 List<double> _starScales; | |
361 List<double> _opacity; | |
362 | |
363 StarField(this._img, this._numStars) { | |
364 _starPositions = []; | |
365 _starScales = []; | |
366 _opacity = []; | |
367 | |
368 for (int i = 0; i < _numStars; i++) { | |
369 _starPositions.add(new Point(_rand.nextDouble() * _gameSizeWidth, _rand.ne
xtDouble() * _gameSizeHeight)); | |
370 _starScales.add(_rand.nextDouble()); | |
371 _opacity.add(_rand.nextDouble() * 0.5 + 0.5); | |
372 } | |
373 } | |
374 | |
375 void paint(RenderCanvas canvas) { | |
376 // Setup paint object for opacity and transfer mode | |
377 Paint paint = new Paint(); | |
378 paint.setTransferMode(TransferMode.plus); | |
379 | |
380 double baseScaleX = 32.0 / _img.size.width; | |
381 double baseScaleY = 32.0 / _img.size.height; | |
382 | |
383 // Draw each star | |
384 for (int i = 0; i < _numStars; i++) { | |
385 Point pos = _starPositions[i]; | |
386 double scale = _starScales[i]; | |
387 paint.color = new Color.fromARGB((255.0*_opacity[i]).toInt(), 255, 255, 25
5); | |
388 | |
389 canvas.save(); | |
390 | |
391 canvas.translate(pos.x, pos.y); | |
392 canvas.scale(baseScaleX * scale, baseScaleY * scale); | |
393 | |
394 canvas.drawImageRect(_img.image, _img.frame, _img.spriteSourceSize, paint)
; | |
395 | |
396 canvas.restore(); | |
397 } | |
398 } | |
399 | |
400 void move(double dx, double dy) { | |
401 for (int i = 0; i < _numStars; i++) { | |
402 double xPos = _starPositions[i].x; | |
403 double yPos = _starPositions[i].y; | |
404 double scale = _starScales[i]; | |
405 | |
406 xPos += dx * scale; | |
407 yPos += dy * scale; | |
408 | |
409 if (xPos >= _gameSizeWidth) xPos -= _gameSizeWidth; | |
410 if (xPos < 0) xPos += _gameSizeWidth; | |
411 if (yPos >= _gameSizeHeight) yPos -= _gameSizeHeight; | |
412 if (yPos < 0) yPos += _gameSizeHeight; | |
413 | |
414 _starPositions[i] = new Point(xPos, yPos); | |
415 } | |
416 } | |
417 } | |
418 | |
419 class Nebula extends Node { | |
420 | |
421 Nebula.withImage(Image img) { | |
422 for (int i = 0; i < 2; i++) { | |
423 for (int j = 0; j < 2; j++) { | |
424 Sprite sprt = new Sprite.fromImage(img); | |
425 sprt.pivot = Point.origin; | |
426 sprt.position = new Point(i * _gameSizeWidth - _gameSizeWidth, j * _game
SizeHeight - _gameSizeHeight); | |
427 addChild(sprt); | |
428 } | |
429 } | |
430 } | |
431 } | |
432 | |
433 // Convenience methods | |
434 | |
435 Point pointAdd(Point a, Point b) { | |
436 return new Point(a.x+ b.x, a.y + b.y); | |
437 } | |
438 | |
439 Point pointMult(Point a, double multiplier) { | |
440 return new Point(a.x * multiplier, a.y * multiplier); | |
441 } | |
442 | |
443 double dampenRotation(double src, double dst, double dampening) { | |
444 double delta = dst - src; | |
445 while (delta > 180.0) delta -= 360; | |
446 while (delta < -180) delta += 360; | |
447 delta *= dampening; | |
448 | |
449 return src + delta; | |
450 } | |
451 | |
452 double pointQuickDist(Point a, Point b) { | |
453 double dx = a.x - b.x; | |
454 double dy = a.y - b.y; | |
455 if (dx < 0.0) dx = -dx; | |
456 if (dy < 0.0) dy = -dy; | |
457 if (dx > dy) { | |
458 return dx + dy/2.0; | |
459 } | |
460 else { | |
461 return dy + dx/2.0; | |
462 } | |
463 } | |
OLD | NEW |