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

Last change on this file was 36483, checked in by stoecker, 8 months ago

set eol-style, fix checkstyle issues, add ignores

  • Property svn:eol-style set to native
File size: 24.1 KB
RevLine 
[36483]1// License: GPL. For details, see LICENSE file.
[19990]2package wmsturbochallenge;
3
[26174]4import static org.openstreetmap.josm.tools.I18n.tr;
5
[24999]6import java.awt.Color;
7import java.awt.Graphics;
8import java.awt.Image;
[19990]9import java.awt.Point;
[24999]10import java.awt.Toolkit;
[19990]11import java.awt.event.ActionEvent;
12import java.awt.event.ActionListener;
[24999]13import java.awt.event.KeyAdapter;
[19990]14import java.awt.event.KeyEvent;
15import java.awt.image.BufferedImage;
[24999]16import java.util.ArrayList;
17import java.util.Arrays;
18import java.util.Collection;
19import java.util.HashMap;
20import java.util.List;
[19990]21
[24999]22import javax.swing.ImageIcon;
[19990]23import javax.swing.JFrame;
24import javax.swing.JPanel;
25import javax.swing.Timer;
26
[24999]27import org.openstreetmap.josm.data.ProjectionBounds;
28import org.openstreetmap.josm.data.coor.EastNorth;
29import org.openstreetmap.josm.data.gpx.GpxData;
[35939]30import org.openstreetmap.josm.data.gpx.GpxTrack;
[24999]31import org.openstreetmap.josm.data.gpx.WayPoint;
[34570]32import org.openstreetmap.josm.data.projection.ProjectionRegistry;
[33837]33import org.openstreetmap.josm.gui.MainApplication;
[24999]34import org.openstreetmap.josm.gui.layer.GpxLayer;
35import org.openstreetmap.josm.gui.layer.Layer;
36
[33342]37/**
38 * This implements the game logic.
[36483]39 * @author Andrzej Zaborowski
[33342]40 */
[19990]41public class GameWindow extends JFrame implements ActionListener {
[23190]42 public GameWindow(Layer ground) {
[26174]43 setTitle(tr("The Ultimate WMS Super-speed Turbo Challenge II"));
[23190]44 setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
45 setUndecorated(true);
46 setSize(s.getScreenSize().width, s.getScreenSize().height);
47 setLocationRelativeTo(null);
48 setResizable(false);
[19990]49
[23190]50 while (s.getScreenSize().width < width * scale ||
[33342]51 s.getScreenSize().height < height * scale) {
52 scale--;
53 }
[23190]54 add(panel);
[19990]55
[23190]56 setVisible(true);
[19990]57
[23190]58 /* TODO: "Intro" screen perhaps with "Hall of Fame" */
[19990]59
[23190]60 screen_image = new BufferedImage(width, height,
61 BufferedImage.TYPE_INT_RGB);
62 screen = screen_image.getGraphics();
[19990]63
[23190]64 this.ground = ground;
[33837]65 ground_view = new FakeMapView(MainApplication.getMap().mapView, 0.0000001);
[19990]66
[23190]67 /* Retrieve start position */
68 EastNorth start = ground_view.parent.getCenter();
69 lat = start.north();
70 lon = start.east();
[19990]71
[23190]72 addKeyListener(new TAdapter());
[19990]73
[23190]74 timer = new Timer(80, this);
75 timer.start();
[19990]76
[23190]77 car_gps = new gps();
78 car_gps.start();
[19990]79
[32322]80 car_engine = new EngineSound();
[23190]81 car_engine.start();
[19990]82
[33342]83 for (int i = 0; i < maxsprites; i++) {
[23190]84 sprites[i] = new sprite_pos();
[33342]85 }
[19990]86
[23190]87 generate_sky();
88 }
[19990]89
[32322]90 protected EngineSound car_engine;
[19990]91
[23190]92 protected gps car_gps;
93 protected class gps extends Timer implements ActionListener {
94 public gps() {
95 super(1000, null);
96 addActionListener(this);
[19990]97
[30737]98 trackSegs = new ArrayList<>();
[23190]99 }
[19990]100
[23190]101 protected Collection<WayPoint> segment;
102 protected Collection<Collection<WayPoint>> trackSegs;
[19990]103
[32914]104 @Override
[23190]105 public void actionPerformed(ActionEvent e) {
106 /* We should count the satellites here, see if we
107 * have a fix and add any distortions. */
[19990]108
[34570]109 segment.add(new WayPoint(ProjectionRegistry.getProjection().eastNorth2latlon(
[23190]110 new EastNorth(lon, lat))));
111 }
[19990]112
[24999]113 @Override
[23190]114 public void start() {
115 super.start();
[19990]116
[23190]117 /* Start recording */
[30737]118 segment = new ArrayList<>();
[23190]119 trackSegs.add(segment);
120 actionPerformed(null);
121 }
[19990]122
[23190]123 public void save_trace() {
124 int len = 0;
[33342]125 for (Collection<WayPoint> seg : trackSegs) {
[23190]126 len += seg.size();
[33342]127 }
[19990]128
[23190]129 /* Don't save traces shorter than 5s */
130 if (len <= 5)
131 return;
[19990]132
[23190]133 GpxData data = new GpxData();
[35939]134 data.tracks.add(new GpxTrack(trackSegs, new HashMap<>()));
[19990]135
[32518]136 ground_view.parent.getLayerManager().addLayer(
[23190]137 new GpxLayer(data, "Car GPS trace"));
138 }
139 }
[19990]140
[23190]141 /* These are EastNorth, not actual LatLon */
142 protected double lat, lon;
143 /* Camera's altitude above surface (same units as lat/lon above) */
144 protected double ele = 0.000003;
145 /* Cut off at ~75px from bottom of the screen */
146 protected double horizon = 0.63;
147 /* Car's distance from the camera lens */
148 protected double cardist = ele * 3;
[19990]149
[23190]150 /* Pixels per pixel, the bigger the more oldschool :-) */
151 protected int scale = 5;
[19990]152
[23190]153 protected BufferedImage screen_image;
154 protected Graphics screen;
155 protected int width = 320;
156 protected int height = 200;
157 protected int centre = width / 2;
[19990]158
[23190]159 double maxdist = ele / (horizon - 0.6);
160 double realwidth = maxdist * width / height;
161 double pixelperlat = 1.0 * width / realwidth;
162 double sratio = 0.85;
163 protected int sw = (int) (2 * Math.PI * maxdist * pixelperlat * sratio);
[19990]164
[23190]165 /* TODO: figure out how to load these dynamically after splash
166 * screen is shown */
[36483]167 protected static final ImageIcon[] car = new ImageIcon[] {
[23190]168 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
169 WMSRacer.class.getResource(
[32914]170 "/images/car0-l.png"))),
[23190]171 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
172 WMSRacer.class.getResource(
[32914]173 "/images/car0.png"))),
[23190]174 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
175 WMSRacer.class.getResource(
[32914]176 "/images/car0-r.png"))),
[23190]177 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
178 WMSRacer.class.getResource(
[32914]179 "/images/car1-l.png"))),
[23190]180 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
181 WMSRacer.class.getResource(
[32914]182 "/images/car1.png"))),
[23190]183 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
184 WMSRacer.class.getResource(
[32914]185 "/images/car1-r.png"))),
[23190]186 };
[36483]187 protected static final ImageIcon[] bg = new ImageIcon[] {
[23190]188 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
189 WMSRacer.class.getResource(
[32914]190 "/images/bg0.png"))),
[23190]191 };
[36483]192 protected static final ImageIcon[] skyline = new ImageIcon[] {
[23190]193 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
194 WMSRacer.class.getResource(
[32914]195 "/images/horizon.png"))),
[23190]196 };
[36483]197 protected static final ImageIcon[] cactus = new ImageIcon[] {
[23190]198 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
199 WMSRacer.class.getResource(
[32914]200 "/images/cactus0.png"))),
[23190]201 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
202 WMSRacer.class.getResource(
[32914]203 "/images/cactus1.png"))),
[23190]204 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
205 WMSRacer.class.getResource(
[32914]206 "/images/cactus2.png"))),
[23190]207 };
[36483]208 protected static final ImageIcon[] cloud = new ImageIcon[] {
[23190]209 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
210 WMSRacer.class.getResource(
[32914]211 "/images/cloud0.png"))),
[23190]212 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
213 WMSRacer.class.getResource(
[32914]214 "/images/cloud1.png"))),
[23190]215 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
216 WMSRacer.class.getResource(
[32914]217 "/images/cloud2.png"))),
[23190]218 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
219 WMSRacer.class.getResource(
[32914]220 "/images/cloud3.png"))),
[23190]221 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
222 WMSRacer.class.getResource(
[32914]223 "/images/cloud4.png"))),
[23190]224 };
[36483]225 protected static final ImageIcon[] aircraft = new ImageIcon[] {
[23190]226 new ImageIcon(Toolkit.getDefaultToolkit().createImage(
227 WMSRacer.class.getResource(
[32914]228 "/images/aircraft0.png"))),
[23190]229 };
230 protected static final ImageIcon loading = new ImageIcon(
231 Toolkit.getDefaultToolkit().createImage(
232 WMSRacer.class.getResource(
[32914]233 "/images/loading.png")));
[23190]234 protected static Toolkit s = Toolkit.getDefaultToolkit();
235 protected int current_bg = 0;
236 protected int current_car = 0;
237 protected boolean cacti_on = true;
[30737]238 protected List<EastNorth> cacti = new ArrayList<>();
239 protected List<EastNorth> todelete = new ArrayList<>();
[23190]240 protected int splashframe = -1;
241 protected EastNorth splashcactus;
[19990]242
[23190]243 protected Layer ground;
244 protected double heading = 0.0;
245 protected double wheelangle = 0.0;
246 protected double speed = 0.0;
[36483]247 protected boolean[] key_down = new boolean[] {
[32914]248 false, false, false, false, };
[19990]249
[23190]250 protected void move() {
251 /* Left */
252 /* (At high speeds make more gentle turns) */
253 if (key_down[0])
254 wheelangle -= 0.1 / (1.0 + Math.abs(speed));
255 /* Right */
256 if (key_down[1])
257 wheelangle += 0.1 / (1.0 + Math.abs(speed));
258 if (wheelangle > 0.3)
259 wheelangle = 0.3; /* Radians */
260 if (wheelangle < -0.3)
261 wheelangle = -0.3;
[19990]262
[23190]263 wheelangle *= 0.7;
[19990]264
[23190]265 /* Up */
266 if (key_down[2])
267 speed += speed >= 0.0 ? 1.0 / (2.0 + speed) : 0.5;
[32914]268 /* Down */
269 if (key_down[3]) {
270 if (speed >= 0.5) /* Brake (TODO: sound) */
271 speed -= 0.5;
272 else if (speed >= 0.01) /* Brake (TODO: sound) */
273 speed = 0.0;
274 else /* Reverse */
275 speed -= 0.5 / (4.0 - speed);
276 }
[19990]277
[32914]278 speed *= 0.97;
279 car_engine.set_speed(speed);
[19990]280
[32914]281 if (speed > -0.1 && speed < 0.1)
282 speed = 0;
[19990]283
[32914]284 heading += wheelangle * speed;
[19990]285
[32914]286 boolean chop = false;
287 double newlat = lat + Math.cos(heading) * speed * ele * 0.2;
288 double newlon = lon + Math.sin(heading) * speed * ele * 0.2;
289 for (EastNorth pos : cacti) {
290 double alat = Math.abs(pos.north() - newlat);
291 double alon = Math.abs(pos.east() - newlon);
292 if (alat + alon < ele * 1.0) {
293 if (Math.abs(speed) < 2.0) {
294 if (speed > 0.0)
295 speed = -0.5;
296 else
297 speed = 0.3;
298 newlat = lat;
299 newlon = lon;
300 break;
301 }
302
303 chop = true;
304 splashframe = 0;
305 splashcactus = pos;
306 todelete.add(pos);
[23190]307 }
308 }
[19990]309
[32914]310 lat = newlat;
311 lon = newlon;
[19990]312
[32914]313 /* Seed a new cactus if we're moving.
314 * TODO: hook into data layers and avoid putting the cactus on
315 * the road!
316 */
317 if (cacti_on && Math.random() * 30.0 < speed) {
318 double left_x = maxdist * (width - centre) / height;
319 double right_x = maxdist * (0 - centre) / height;
320 double x = left_x + Math.random() * (right_x - left_x);
321 double clat = lat + (maxdist - cardist) *
322 Math.cos(heading) - x * Math.sin(heading);
323 double clon = lon + (maxdist - cardist) *
324 Math.sin(heading) + x * Math.cos(heading);
[19990]325
[32914]326 cacti.add(new EastNorth(clon, clat));
327 chop = true;
328 }
[19990]329
[32914]330 /* Chop down any cactus far enough that it can't
331 * be seen. ``If a cactus falls in a forest and
332 * there is nobody around did it make a sound?''
333 */
334 if (chop) {
335 for (EastNorth pos : cacti) {
336 double alat = Math.abs(pos.north() - lat);
337 double alon = Math.abs(pos.east() - lon);
338 if (alat + alon > 2 * maxdist)
339 todelete.add(pos);
340 }
341 cacti.removeAll(todelete);
342 todelete = new ArrayList<>();
[23190]343 }
344 }
[19990]345
[23190]346 int frame;
347 boolean downloading = false;
[33342]348
[23190]349 protected void screen_repaint() {
350 /* Draw background first */
351 sky_paint();
[19990]352
[23190]353 /* On top of it project the floor */
354 ground_paint();
[19990]355
[23190]356 /* Messages */
[33342]357 frame++;
358 if ((frame & 8) == 0 && downloading) {
[23190]359 screen.drawImage(loading.getImage(), centre -
360 loading.getIconWidth() / 2, 50, this);
[33342]361 }
[19990]362
[23190]363 /* Sprites */
364 sprites_paint();
365 }
[19990]366
[36483]367 static double max3(double[] x) {
[23190]368 return x[0] > x[1] ? x[2] > x[0] ? x[2] : x[0] :
369 (x[2] > x[1] ? x[2] : x[1]);
370 }
[36483]371
372 static double min3(double[] x) {
[23190]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;
[36483]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, };
[36483]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;
[36483]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);
[36483]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;
[36483]562 }
[19990]563
[23190]564 if (splashframe >= 0) {
[33342]565 splashframe++;
[23190]566 if (splashframe >= 8)
567 splashframe = -1;
[19990]568
[23190]569 int type = (((int) (splashcactus.north() *
[32914]570 10000000.0) & 31) % 3);
[23190]571 int sx = cactus[type].getIconWidth();
572 int sy = cactus[type].getIconHeight();
573 Image image = cactus[type].getImage();
[19990]574
[33342]575 for (i = 0; i < 50; i++) {
[23190]576 int x = (int) (Math.random() * sx);
577 int y = (int) (Math.random() * sy);
578 int w = (int) (Math.random() * 20);
579 int h = (int) (Math.random() * 20);
580 int nx = centre + splashframe * (x - sx / 2);
581 int ny = height - splashframe * (sy - y);
582 int nw = w + splashframe;
583 int nh = h + splashframe;
[19990]584
[23190]585 screen.drawImage(image,
586 nx, ny, nx + nw, ny + nh,
587 x, y, x + w, y + h, this);
588 }
589 }
590 }
[19990]591
[23190]592 public boolean no_super_repaint = false;
[33342]593
[23190]594 protected class GamePanel extends JPanel {
595 public GamePanel() {
596 setBackground(Color.BLACK);
597 setDoubleBuffered(true);
598 }
[19990]599
[24999]600 @Override
[23190]601 public void paint(Graphics g) {
602 int w = (int) getSize().getWidth();
603 int h = (int) getSize().getHeight();
[19990]604
[23190]605 if (no_super_repaint)
606 no_super_repaint = false;
607 else
608 super.paint(g);
[19990]609
[23190]610 g.drawImage(screen_image, (w - width * scale) / 2,
611 (h - height * scale) / 2,
612 width * scale, height * scale, this);
[19990]613
[23190]614 Toolkit.getDefaultToolkit().sync();
615 }
616 }
[33342]617
[23190]618 JPanel panel = new GamePanel();
[19990]619
[23190]620 protected void quit() {
621 timer.stop();
[19990]622
[23190]623 car_engine.stop();
[19990]624
[23190]625 car_gps.stop();
626 car_gps.save_trace();
[19990]627
[23190]628 setVisible(false);
629 panel = null;
630 screen_image = null;
631 screen = null;
632 dispose();
633 }
[19990]634
[23190]635 /*
636 * Supposedly a thread drawing frames and sleeping in a loop is
637 * better than for animating than swing Timers. For the moment
638 * I'll use a timer because I don't want to deal with all the
639 * potential threading issues.
640 */
641 protected Timer timer;
[33342]642
[32914]643 @Override
[23190]644 public void actionPerformed(ActionEvent e) {
645 move();
646 screen_repaint();
[19990]647
[23190]648 no_super_repaint = true;
649 panel.repaint();
650 }
[19990]651
[23190]652 protected class TAdapter extends KeyAdapter {
[24999]653 @Override
[23190]654 public void keyPressed(KeyEvent e) {
655 int key = e.getKeyCode();
[19990]656
[23190]657 if (key == KeyEvent.VK_LEFT && !key_down[0]) {
658 wheelangle -= 0.02;
659 key_down[0] = true;
660 }
[19990]661
[23190]662 if (key == KeyEvent.VK_RIGHT && !key_down[1]) {
663 wheelangle += 0.02;
664 key_down[1] = true;
665 }
[19990]666
[23190]667 if (key == KeyEvent.VK_UP)
668 key_down[2] = true;
[19990]669
[23190]670 if (key == KeyEvent.VK_DOWN)
671 key_down[3] = true;
[19990]672
[23190]673 if (key == KeyEvent.VK_ESCAPE)
674 quit();
[19990]675
[23190]676 /* Toggle sound */
677 if (key == KeyEvent.VK_S) {
678 if (car_engine.is_on())
679 car_engine.stop();
680 else
681 car_engine.start();
682 }
[19990]683
[23190]684 /* Toggle cacti */
685 if (key == KeyEvent.VK_C) {
686 cacti_on = !cacti_on;
687 if (!cacti_on)
[30737]688 cacti = new ArrayList<>();
[23190]689 }
[19990]690
[23190]691 /* Switch vehicle */
692 if (key == KeyEvent.VK_V)
[33342]693 if (current_car++ >= 1)
[23190]694 current_car = 0;
695 }
[19990]696
[24999]697 @Override
[23190]698 public void keyReleased(KeyEvent e) {
699 int key = e.getKeyCode();
[19990]700
[23190]701 if (key == KeyEvent.VK_LEFT)
702 key_down[0] = false;
[19990]703
[23190]704 if (key == KeyEvent.VK_RIGHT)
705 key_down[1] = false;
[19990]706
[23190]707 if (key == KeyEvent.VK_UP)
708 key_down[2] = false;
[19990]709
[23190]710 if (key == KeyEvent.VK_DOWN)
711 key_down[3] = false;
712 }
713 }
[33342]714
[29854]715 protected FakeMapView ground_view;
[19990]716}
Note: See TracBrowser for help on using the repository browser.