source: osm/applications/editors/josm/plugins/wms-turbo-challenge2/src/wmsturbochallenge/GameWindow.java

Last change on this file was 35939, checked in by taylor.smock, 3 years ago

fix #21773: Update deprecated functions in wms-turbo-challenge2

This is replacing ImmutableGpxTrack (deprecated in r15496) with
GpxTrack (added in r15496)

File size: 24.1 KB
RevLine 
[19990]1/*
2 * GPLv2 or 3, Copyright (c) 2010 Andrzej Zaborowski
3 */
4package wmsturbochallenge;
5
[26174]6import static org.openstreetmap.josm.tools.I18n.tr;
7
[24999]8import java.awt.Color;
9import java.awt.Graphics;
10import java.awt.Image;
[19990]11import java.awt.Point;
[24999]12import java.awt.Toolkit;
[19990]13import java.awt.event.ActionEvent;
14import java.awt.event.ActionListener;
[24999]15import java.awt.event.KeyAdapter;
[19990]16import java.awt.event.KeyEvent;
17import java.awt.image.BufferedImage;
[24999]18import java.util.ArrayList;
19import java.util.Arrays;
20import java.util.Collection;
21import java.util.HashMap;
22import java.util.List;
[19990]23
[24999]24import javax.swing.ImageIcon;
[19990]25import javax.swing.JFrame;
26import javax.swing.JPanel;
27import javax.swing.Timer;
28
[24999]29import org.openstreetmap.josm.data.ProjectionBounds;
30import org.openstreetmap.josm.data.coor.EastNorth;
31import org.openstreetmap.josm.data.gpx.GpxData;
[35939]32import org.openstreetmap.josm.data.gpx.GpxTrack;
[24999]33import org.openstreetmap.josm.data.gpx.WayPoint;
[34570]34import org.openstreetmap.josm.data.projection.ProjectionRegistry;
[33837]35import org.openstreetmap.josm.gui.MainApplication;
[24999]36import org.openstreetmap.josm.gui.layer.GpxLayer;
37import org.openstreetmap.josm.gui.layer.Layer;
38
[33342]39/**
40 * This implements the game logic.
41 */
[19990]42public class GameWindow extends JFrame implements ActionListener {
[23190]43 public GameWindow(Layer ground) {
[26174]44 setTitle(tr("The Ultimate WMS Super-speed Turbo Challenge II"));
[23190]45 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
46 setUndecorated(true);
47 setSize(s.getScreenSize().width, s.getScreenSize().height);
48 setLocationRelativeTo(null);
49 setResizable(false);
[19990]50
[23190]51 while (s.getScreenSize().width < width * scale ||
[33342]52 s.getScreenSize().height < height * scale) {
53 scale--;
54 }
[23190]55 add(panel);
[19990]56
[23190]57 setVisible(true);
[19990]58
[23190]59 /* TODO: "Intro" screen perhaps with "Hall of Fame" */
[19990]60
[23190]61 screen_image = new BufferedImage(width, height,
62 BufferedImage.TYPE_INT_RGB);
63 screen = screen_image.getGraphics();
[19990]64
[23190]65 this.ground = ground;
[33837]66 ground_view = new FakeMapView(MainApplication.getMap().mapView, 0.0000001);
[19990]67
[23190]68 /* Retrieve start position */
69 EastNorth start = ground_view.parent.getCenter();
70 lat = start.north();
71 lon = start.east();
[19990]72
[23190]73 addKeyListener(new TAdapter());
[19990]74
[23190]75 timer = new Timer(80, this);
76 timer.start();
[19990]77
[23190]78 car_gps = new gps();
79 car_gps.start();
[19990]80
[32322]81 car_engine = new EngineSound();
[23190]82 car_engine.start();
[19990]83
[33342]84 for (int i = 0; i < maxsprites; i++) {
[23190]85 sprites[i] = new sprite_pos();
[33342]86 }
[19990]87
[23190]88 generate_sky();
89 }
[19990]90
[32322]91 protected EngineSound car_engine;
[19990]92
[23190]93 protected gps car_gps;
94 protected class gps extends Timer implements ActionListener {
95 public gps() {
96 super(1000, null);
97 addActionListener(this);
[19990]98
[30737]99 trackSegs = new ArrayList<>();
[23190]100 }
[19990]101
[23190]102 protected Collection<WayPoint> segment;
103 protected Collection<Collection<WayPoint>> trackSegs;
[19990]104
[32914]105 @Override
[23190]106 public void actionPerformed(ActionEvent e) {
107 /* We should count the satellites here, see if we
108 * have a fix and add any distortions. */
[19990]109
[34570]110 segment.add(new WayPoint(ProjectionRegistry.getProjection().eastNorth2latlon(
[23190]111 new EastNorth(lon, lat))));
112 }
[19990]113
[24999]114 @Override
[23190]115 public void start() {
116 super.start();
[19990]117
[23190]118 /* Start recording */
[30737]119 segment = new ArrayList<>();
[23190]120 trackSegs.add(segment);
121 actionPerformed(null);
122 }
[19990]123
[23190]124 public void save_trace() {
125 int len = 0;
[33342]126 for (Collection<WayPoint> seg : trackSegs) {
[23190]127 len += seg.size();
[33342]128 }
[19990]129
[23190]130 /* Don't save traces shorter than 5s */
131 if (len <= 5)
132 return;
[19990]133
[23190]134 GpxData data = new GpxData();
[35939]135 data.tracks.add(new GpxTrack(trackSegs, new HashMap<>()));
[19990]136
[32518]137 ground_view.parent.getLayerManager().addLayer(
[23190]138 new GpxLayer(data, "Car GPS trace"));
139 }
140 }
[19990]141
[23190]142 /* These are EastNorth, not actual LatLon */
143 protected double lat, lon;
144 /* Camera's altitude above surface (same units as lat/lon above) */
145 protected double ele = 0.000003;
146 /* Cut off at ~75px from bottom of the screen */
147 protected double horizon = 0.63;
148 /* Car's distance from the camera lens */
149 protected double cardist = ele * 3;
[19990]150
[23190]151 /* Pixels per pixel, the bigger the more oldschool :-) */
152 protected int scale = 5;
[19990]153
[23190]154 protected BufferedImage screen_image;
155 protected Graphics screen;
156 protected int width = 320;
157 protected int height = 200;
158 protected int centre = width / 2;
[19990]159
[23190]160 double maxdist = ele / (horizon - 0.6);
161 double realwidth = maxdist * width / height;
162 double pixelperlat = 1.0 * width / realwidth;
163 double sratio = 0.85;
164 protected int sw = (int) (2 * Math.PI * maxdist * pixelperlat * sratio);
[19990]165
[23190]166 /* TODO: figure out how to load these dynamically after splash
167 * screen is shown */
168 protected static final ImageIcon car[] = new ImageIcon[] {
169 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
170 WMSRacer.class.getResource(
[32914]171 "/images/car0-l.png"))),
[23190]172 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
173 WMSRacer.class.getResource(
[32914]174 "/images/car0.png"))),
[23190]175 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
176 WMSRacer.class.getResource(
[32914]177 "/images/car0-r.png"))),
[23190]178 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
179 WMSRacer.class.getResource(
[32914]180 "/images/car1-l.png"))),
[23190]181 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
182 WMSRacer.class.getResource(
[32914]183 "/images/car1.png"))),
[23190]184 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
185 WMSRacer.class.getResource(
[32914]186 "/images/car1-r.png"))),
[23190]187 };
188 protected static final ImageIcon bg[] = new ImageIcon[] {
189 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
190 WMSRacer.class.getResource(
[32914]191 "/images/bg0.png"))),
[23190]192 };
193 protected static final ImageIcon skyline[] = new ImageIcon[] {
194 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
195 WMSRacer.class.getResource(
[32914]196 "/images/horizon.png"))),
[23190]197 };
198 protected static final ImageIcon cactus[] = new ImageIcon[] {
199 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
200 WMSRacer.class.getResource(
[32914]201 "/images/cactus0.png"))),
[23190]202 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
203 WMSRacer.class.getResource(
[32914]204 "/images/cactus1.png"))),
[23190]205 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
206 WMSRacer.class.getResource(
[32914]207 "/images/cactus2.png"))),
[23190]208 };
209 protected static final ImageIcon cloud[] = new ImageIcon[] {
210 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
211 WMSRacer.class.getResource(
[32914]212 "/images/cloud0.png"))),
[23190]213 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
214 WMSRacer.class.getResource(
[32914]215 "/images/cloud1.png"))),
[23190]216 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
217 WMSRacer.class.getResource(
[32914]218 "/images/cloud2.png"))),
[23190]219 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
220 WMSRacer.class.getResource(
[32914]221 "/images/cloud3.png"))),
[23190]222 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
223 WMSRacer.class.getResource(
[32914]224 "/images/cloud4.png"))),
[23190]225 };
226 protected static final ImageIcon aircraft[] = new ImageIcon[] {
227 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
228 WMSRacer.class.getResource(
[32914]229 "/images/aircraft0.png"))),
[23190]230 };
231 protected static final ImageIcon loading = new ImageIcon(
232 Toolkit.getDefaultToolkit().createImage(
233 WMSRacer.class.getResource(
[32914]234 "/images/loading.png")));
[23190]235 protected static Toolkit s = Toolkit.getDefaultToolkit();
236 protected int current_bg = 0;
237 protected int current_car = 0;
238 protected boolean cacti_on = true;
[30737]239 protected List<EastNorth> cacti = new ArrayList<>();
240 protected List<EastNorth> todelete = new ArrayList<>();
[23190]241 protected int splashframe = -1;
242 protected EastNorth splashcactus;
[19990]243
[23190]244 protected Layer ground;
245 protected double heading = 0.0;
246 protected double wheelangle = 0.0;
247 protected double speed = 0.0;
248 protected boolean key_down[] = new boolean[] {
[32914]249 false, false, false, false, };
[19990]250
[23190]251 protected void move() {
252 /* Left */
253 /* (At high speeds make more gentle turns) */
254 if (key_down[0])
255 wheelangle -= 0.1 / (1.0 + Math.abs(speed));
256 /* Right */
257 if (key_down[1])
258 wheelangle += 0.1 / (1.0 + Math.abs(speed));
259 if (wheelangle > 0.3)
260 wheelangle = 0.3; /* Radians */
261 if (wheelangle < -0.3)
262 wheelangle = -0.3;
[19990]263
[23190]264 wheelangle *= 0.7;
[19990]265
[23190]266 /* Up */
267 if (key_down[2])
268 speed += speed >= 0.0 ? 1.0 / (2.0 + speed) : 0.5;
[32914]269 /* Down */
270 if (key_down[3]) {
271 if (speed >= 0.5) /* Brake (TODO: sound) */
272 speed -= 0.5;
273 else if (speed >= 0.01) /* Brake (TODO: sound) */
274 speed = 0.0;
275 else /* Reverse */
276 speed -= 0.5 / (4.0 - speed);
277 }
[19990]278
[32914]279 speed *= 0.97;
280 car_engine.set_speed(speed);
[19990]281
[32914]282 if (speed > -0.1 && speed < 0.1)
283 speed = 0;
[19990]284
[32914]285 heading += wheelangle * speed;
[19990]286
[32914]287 boolean chop = false;
288 double newlat = lat + Math.cos(heading) * speed * ele * 0.2;
289 double newlon = lon + Math.sin(heading) * speed * ele * 0.2;
290 for (EastNorth pos : cacti) {
291 double alat = Math.abs(pos.north() - newlat);
292 double alon = Math.abs(pos.east() - newlon);
293 if (alat + alon < ele * 1.0) {
294 if (Math.abs(speed) < 2.0) {
295 if (speed > 0.0)
296 speed = -0.5;
297 else
298 speed = 0.3;
299 newlat = lat;
300 newlon = lon;
301 break;
302 }
303
304 chop = true;
305 splashframe = 0;
306 splashcactus = pos;
307 todelete.add(pos);
[23190]308 }
309 }
[19990]310
[32914]311 lat = newlat;
312 lon = newlon;
[19990]313
[32914]314 /* Seed a new cactus if we're moving.
315 * TODO: hook into data layers and avoid putting the cactus on
316 * the road!
317 */
318 if (cacti_on && Math.random() * 30.0 < speed) {
319 double left_x = maxdist * (width - centre) / height;
320 double right_x = maxdist * (0 - centre) / height;
321 double x = left_x + Math.random() * (right_x - left_x);
322 double clat = lat + (maxdist - cardist) *
323 Math.cos(heading) - x * Math.sin(heading);
324 double clon = lon + (maxdist - cardist) *
325 Math.sin(heading) + x * Math.cos(heading);
[19990]326
[32914]327 cacti.add(new EastNorth(clon, clat));
328 chop = true;
329 }
[19990]330
[32914]331 /* Chop down any cactus far enough that it can't
332 * be seen. ``If a cactus falls in a forest and
333 * there is nobody around did it make a sound?''
334 */
335 if (chop) {
336 for (EastNorth pos : cacti) {
337 double alat = Math.abs(pos.north() - lat);
338 double alon = Math.abs(pos.east() - lon);
339 if (alat + alon > 2 * maxdist)
340 todelete.add(pos);
341 }
342 cacti.removeAll(todelete);
343 todelete = new ArrayList<>();
[23190]344 }
345 }
[19990]346
[23190]347 int frame;
348 boolean downloading = false;
[33342]349
[23190]350 protected void screen_repaint() {
351 /* Draw background first */
352 sky_paint();
[19990]353
[23190]354 /* On top of it project the floor */
355 ground_paint();
[19990]356
[23190]357 /* Messages */
[33342]358 frame++;
359 if ((frame & 8) == 0 && downloading) {
[23190]360 screen.drawImage(loading.getImage(), centre -
361 loading.getIconWidth() / 2, 50, this);
[33342]362 }
[19990]363
[23190]364 /* Sprites */
365 sprites_paint();
366 }
[19990]367
[23190]368 static double max3(double x[]) {
369 return x[0] > x[1] ? x[2] > x[0] ? x[2] : x[0] :
370 (x[2] > x[1] ? x[2] : x[1]);
371 }
372 static double min3(double x[]) {
373 return x[0] < x[1] ? x[2] < x[0] ? x[2] : x[0] :
374 (x[2] < x[1] ? x[2] : x[1]);
375 }
[19990]376
[23190]377 protected void ground_paint() {
378 double sin = Math.sin(heading);
379 double cos = Math.cos(heading);
[19990]380
[23190]381 /* First calculate the bounding box for the visible area.
382 * The area will be (nearly) a triangle, so calculate the
383 * EastNorth for the three corners and make a bounding box.
384 */
385 double left_x = maxdist * (width - centre) / height;
386 double right_x = maxdist * (0 - centre) / height;
387 double e_lat[] = new double[] {
[32914]388 lat + (maxdist - cardist) * cos - left_x * sin,
389 lat + (maxdist - cardist) * cos - right_x * sin,
390 lat - cardist * cos, };
[23190]391 double e_lon[] = new double[] {
[32914]392 lon + (maxdist - cardist) * sin + left_x * cos,
393 lon + (maxdist - cardist) * sin + right_x * cos,
394 lon - cardist * sin, };
[23190]395 ground_view.setProjectionBounds(new ProjectionBounds(
396 new EastNorth(min3(e_lon), min3(e_lat)),
397 new EastNorth(max3(e_lon), max3(e_lat))));
[19990]398
[23190]399 /* If the layer is a WMS layer, check if any tiles are
400 * missing */
[31307]401 /* FIXME: the code below is commented to fix compilation problems. Not sure if the code below is needed
[24999]402 if (ground instanceof WMSLayer) {
403 WMSLayer wms = (WMSLayer) ground;
[23190]404 downloading = wms.hasAutoDownload() && (
405 null == wms.findImage(new EastNorth(
406 e_lon[0], e_lat[0])) ||
407 null == wms.findImage(new EastNorth(
408 e_lon[0], e_lat[0])) ||
409 null == wms.findImage(new EastNorth(
410 e_lon[0], e_lat[0])));
411 }
[32914]412 */
[23190]413 /* Request the image from ground layer */
414 ground.paint(ground_view.graphics, ground_view, null);
[19990]415
[33342]416 for (int y = (int) (height * horizon + 0.1); y < height; y++) {
[23190]417 /* Assume a 60 deg vertical Field of View when
418 * calculating the distance at given pixel. */
419 double dist = ele / (1.0 * y / height - 0.6);
420 double lat_off = lat + (dist - cardist) * cos;
421 double lon_off = lon + (dist - cardist) * sin;
[19990]422
[33342]423 for (int x = 0; x < width; x++) {
[23190]424 double p_x = dist * (x - centre) / height;
[19990]425
[23190]426 EastNorth en = new EastNorth(
427 lon_off + p_x * cos,
428 lat_off - p_x * sin);
[19990]429
[23190]430 Point pt = ground_view.getPoint(en);
[19990]431
[23190]432 int rgb = ground_view.ground_image.getRGB(
433 pt.x, pt.y);
434 screen_image.setRGB(x, y, rgb);
435 }
436 }
437 }
[19990]438
[23190]439 protected BufferedImage sky_image;
440 protected Graphics sky;
441 public void generate_sky() {
442 sky_image = new BufferedImage(sw, 70,
443 BufferedImage.TYPE_INT_ARGB);
444 sky = sky_image.getGraphics();
[19990]445
[23190]446 int n = (int) (Math.random() * sw * 0.03);
[33342]447 for (int i = 0; i < n; i++) {
[23190]448 int t = (int) (Math.random() * 5.0);
449 int x = (int) (Math.random() *
450 (sw - cloud[t].getIconWidth()));
451 int y = (int) ((1 - Math.random() * Math.random()) *
452 (70 - cloud[t].getIconHeight()));
453 sky.drawImage(cloud[t].getImage(), x, y, this);
454 }
[19990]455
[23190]456 if (Math.random() < 0.5) {
457 int t = 0;
458 int x = (int) (300 + Math.random() * (sw - 500 -
[32914]459 aircraft[t].getIconWidth()));
[23190]460 sky.drawImage(aircraft[t].getImage(), x, 0, this);
461 }
462 }
[19990]463
[23190]464 public void sky_paint() {
465 /* for x -> 0, lim sin(x) / x = 1 */
466 int hx = (int) (-heading * maxdist * pixelperlat);
467 int hw = skyline[current_bg].getIconWidth();
468 hx = ((hx % hw) - hw) % hw;
[19990]469
[23190]470 int sx = (int) (-heading * maxdist * pixelperlat * sratio);
471 sx = ((sx % sw) - sw) % sw;
[19990]472
[23190]473 screen.drawImage(bg[current_bg].getImage(), 0, 0, this);
474 screen.drawImage(sky_image, sx, 50, this);
475 if (sw + sx < width)
476 screen.drawImage(sky_image, sx + sw, 50, this);
477 screen.drawImage(skyline[current_bg].getImage(), hx, 66, this);
478 if (hw + hx < width)
479 screen.drawImage(skyline[current_bg].getImage(),
480 hx + hw, 66, this);
481 }
[19990]482
[32914]483 protected static class sprite_pos implements Comparable<sprite_pos> {
[23190]484 double dist;
[19990]485
[23190]486 int x, y, sx, sy;
487 Image sprite;
[19990]488
[23190]489 public sprite_pos() {
490 }
[19990]491
[32914]492 @Override
[29854]493 public int compareTo(sprite_pos x) {
494 return (int) ((x.dist - this.dist) * 1000000.0);
[23190]495 }
496 }
[19990]497
[33342]498 /** sizes decides how many zoom levels the sprites have. We
[23190]499 * could do just normal scalling according to distance but
500 * that's not what old games did, they had prescaled sprites
501 * for the different distances and you could see the feature
502 * grow discretely as you approached it. */
[33342]503 protected static final int sizes = 8;
[19990]504
[33342]505 protected static final int maxsprites = 32;
[23190]506 protected sprite_pos sprites[] = new sprite_pos[maxsprites];
[19990]507
[23190]508 protected void sprites_paint() {
509 /* The vehicle */
510 int orientation = (wheelangle > -0.02 ? wheelangle < 0.02 ?
511 1 : 2 : 0) + current_car * 3;
512 sprites[0].sprite = car[orientation].getImage();
513 sprites[0].dist = cardist;
514 sprites[0].sx = car[orientation].getIconWidth();
515 sprites[0].x = centre - sprites[0].sx / 2;
516 sprites[0].sy = car[orientation].getIconHeight();
517 sprites[0].y = height - sprites[0].sy - 10; /* TODO */
[19990]518
[23190]519 /* The cacti */
520 double sin = Math.sin(-heading);
521 double cos = Math.cos(-heading);
522 int i = 1;
[19990]523
[23190]524 for (EastNorth ll : cacti) {
525 double clat = ll.north() - lat;
526 double clon = ll.east() - lon;
527 double dist = (clat * cos - clon * sin) + cardist;
528 double p_x = clat * sin + clon * cos;
[19990]529
[23190]530 if (dist * 8 <= cardist || dist > maxdist)
531 continue;
[19990]532
[23190]533 int x = (int) (p_x * height / dist + centre);
534 int y = (int) ((ele / dist + 0.6) * height);
[19990]535
[23190]536 if (i >= maxsprites)
537 break;
538 if (x < -10 || x > width + 10)
539 continue;
[19990]540
[23190]541 int type = (((int) (ll.north() * 10000000.0) & 31) % 3);
542 int sx = cactus[type].getIconWidth();
543 int sy = cactus[type].getIconHeight();
[19990]544
[33342]545 sprite_pos pos = sprites[i++];
[23190]546 pos.dist = dist;
547 pos.sprite = cactus[type].getImage();
548 pos.sx = (int) (sx * cardist * 0.7 / dist);
549 pos.sy = (int) (sy * cardist * 0.7 / dist);
550 pos.x = x - pos.sx / 2;
551 pos.y = y - pos.sy;
552 }
[19990]553
[23190]554 Arrays.sort(sprites, 0, i);
555 for (sprite_pos sprite : sprites)
[33342]556 if (i-- > 0)
[23190]557 screen.drawImage(sprite.sprite,
558 sprite.x, sprite.y,
559 sprite.sx, sprite.sy, this);
560 else
561 break;
[19990]562
[23190]563 if (splashframe >= 0) {
[33342]564 splashframe++;
[23190]565 if (splashframe >= 8)
566 splashframe = -1;
[19990]567
[23190]568 int type = (((int) (splashcactus.north() *
[32914]569 10000000.0) & 31) % 3);
[23190]570 int sx = cactus[type].getIconWidth();
571 int sy = cactus[type].getIconHeight();
572 Image image = cactus[type].getImage();
[19990]573
[33342]574 for (i = 0; i < 50; i++) {
[23190]575 int x = (int) (Math.random() * sx);
576 int y = (int) (Math.random() * sy);
577 int w = (int) (Math.random() * 20);
578 int h = (int) (Math.random() * 20);
579 int nx = centre + splashframe * (x - sx / 2);
580 int ny = height - splashframe * (sy - y);
581 int nw = w + splashframe;
582 int nh = h + splashframe;
[19990]583
[23190]584 screen.drawImage(image,
585 nx, ny, nx + nw, ny + nh,
586 x, y, x + w, y + h, this);
587 }
588 }
589 }
[19990]590
[23190]591 public boolean no_super_repaint = false;
[33342]592
[23190]593 protected class GamePanel extends JPanel {
594 public GamePanel() {
595 setBackground(Color.BLACK);
596 setDoubleBuffered(true);
597 }
[19990]598
[24999]599 @Override
[23190]600 public void paint(Graphics g) {
601 int w = (int) getSize().getWidth();
602 int h = (int) getSize().getHeight();
[19990]603
[23190]604 if (no_super_repaint)
605 no_super_repaint = false;
606 else
607 super.paint(g);
[19990]608
[23190]609 g.drawImage(screen_image, (w - width * scale) / 2,
610 (h - height * scale) / 2,
611 width * scale, height * scale, this);
[19990]612
[23190]613 Toolkit.getDefaultToolkit().sync();
614 }
615 }
[33342]616
[23190]617 JPanel panel = new GamePanel();
[19990]618
[23190]619 protected void quit() {
620 timer.stop();
[19990]621
[23190]622 car_engine.stop();
[19990]623
[23190]624 car_gps.stop();
625 car_gps.save_trace();
[19990]626
[23190]627 setVisible(false);
628 panel = null;
629 screen_image = null;
630 screen = null;
631 dispose();
632 }
[19990]633
[23190]634 /*
635 * Supposedly a thread drawing frames and sleeping in a loop is
636 * better than for animating than swing Timers. For the moment
637 * I'll use a timer because I don't want to deal with all the
638 * potential threading issues.
639 */
640 protected Timer timer;
[33342]641
[32914]642 @Override
[23190]643 public void actionPerformed(ActionEvent e) {
644 move();
645 screen_repaint();
[19990]646
[23190]647 no_super_repaint = true;
648 panel.repaint();
649 }
[19990]650
[23190]651 protected class TAdapter extends KeyAdapter {
[24999]652 @Override
[23190]653 public void keyPressed(KeyEvent e) {
654 int key = e.getKeyCode();
[19990]655
[23190]656 if (key == KeyEvent.VK_LEFT && !key_down[0]) {
657 wheelangle -= 0.02;
658 key_down[0] = true;
659 }
[19990]660
[23190]661 if (key == KeyEvent.VK_RIGHT && !key_down[1]) {
662 wheelangle += 0.02;
663 key_down[1] = true;
664 }
[19990]665
[23190]666 if (key == KeyEvent.VK_UP)
667 key_down[2] = true;
[19990]668
[23190]669 if (key == KeyEvent.VK_DOWN)
670 key_down[3] = true;
[19990]671
[23190]672 if (key == KeyEvent.VK_ESCAPE)
673 quit();
[19990]674
[23190]675 /* Toggle sound */
676 if (key == KeyEvent.VK_S) {
677 if (car_engine.is_on())
678 car_engine.stop();
679 else
680 car_engine.start();
681 }
[19990]682
[23190]683 /* Toggle cacti */
684 if (key == KeyEvent.VK_C) {
685 cacti_on = !cacti_on;
686 if (!cacti_on)
[30737]687 cacti = new ArrayList<>();
[23190]688 }
[19990]689
[23190]690 /* Switch vehicle */
691 if (key == KeyEvent.VK_V)
[33342]692 if (current_car++ >= 1)
[23190]693 current_car = 0;
694 }
[19990]695
[24999]696 @Override
[23190]697 public void keyReleased(KeyEvent e) {
698 int key = e.getKeyCode();
[19990]699
[23190]700 if (key == KeyEvent.VK_LEFT)
701 key_down[0] = false;
[19990]702
[23190]703 if (key == KeyEvent.VK_RIGHT)
704 key_down[1] = false;
[19990]705
[23190]706 if (key == KeyEvent.VK_UP)
707 key_down[2] = false;
[19990]708
[23190]709 if (key == KeyEvent.VK_DOWN)
710 key_down[3] = false;
711 }
712 }
[33342]713
[29854]714 protected FakeMapView ground_view;
[19990]715}
Note: See TracBrowser for help on using the repository browser.