source: trunk/MagicSoft/Mars/mtools/MagicSnake.cc@ 2162

Last change on this file since 2162 was 1533, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 14.0 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 07/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MagicSnake
28// ----------
29//
30// Camera Display Games: Snake
31//
32// Start the game by:
33// MagicSnake snake;
34//
35// Controll the worm using right/left. Make sure, that the mouse pointer
36// is inside the canvas.
37//
38// Move the mouse pointer outside the canvas to pause the game.
39//
40// The pixel colors have the following meaning:
41// --------------------------------------------
42// Green: Food, collect all packages.
43// Red: Bombs, don't touch it!
44// Yellow: Transport, try it.
45// Magenta: Home, touch it to win the game.
46//
47// To restart the game use the context menu. It can only be accessed if
48// the game has been stopped (either because you win the game or because
49// you hit a bomb) With the context menu you can also toggle between
50// different camera layouts.
51//
52////////////////////////////////////////////////////////////////////////////
53#include "MagicSnake.h"
54
55#include <iostream.h>
56
57#include <KeySymbols.h>
58
59#include <TColor.h>
60#include <TCanvas.h>
61#include <TMarker.h>
62#include <TRandom.h>
63#include <TInterpreter.h>
64
65#include "MHexagon.h"
66
67#include "MGeomPix.h"
68#include "MGeomCamCT1.h"
69#include "MGeomCamMagic.h"
70
71ClassImp(MagicSnake);
72
73void MagicSnake::Free()
74{
75 if (!fGeomCam)
76 return;
77
78 fPixels->Delete();
79
80 delete fPixels;
81
82 delete fGeomCam;
83
84 delete fArray;
85}
86
87// ------------------------------------------------------------------------
88//
89// Draw all pixels of the camera
90// (means apend all pixelobjects to the current pad)
91//
92void MagicSnake::DrawHexagons()
93{
94 for (UInt_t i=0; i<fNumPixels; i++)
95 (*this)[i].Draw();
96}
97
98void MagicSnake::ChangeCamera()
99{
100 if (!fDone)
101 Done("Changing Camera...", 22);
102
103 static Bool_t ct1=kFALSE;
104
105 cout << "Change to " << (ct1?"Magic":"CT1") << endl;
106
107 if (ct1)
108 SetNewCamera(new MGeomCamMagic);
109 else
110 SetNewCamera(new MGeomCamCT1);
111
112 ct1 = !ct1;
113
114 Reset();
115 DrawHexagons();
116}
117
118void MagicSnake::SetNewCamera(MGeomCam *geom)
119{
120 Free();
121
122 //
123 // Reset the display geometry
124 //
125 fW=0;
126 fH=0;
127
128 //
129 // Set new camera
130 //
131 fGeomCam = geom;
132
133 //
134 // create the hexagons of the display
135 //
136 fNumPixels = fGeomCam->GetNumPixels();
137 fRange = fGeomCam->GetMaxRadius();
138
139 //
140 // Construct all hexagons. Use new-operator with placement
141 //
142 fPixels = new TClonesArray("MHexagon", fNumPixels);
143
144 for (UInt_t i=0; i<fNumPixels; i++)
145 {
146 MHexagon &h = *new ((*fPixels)[i]) MHexagon((*fGeomCam)[i]);
147#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
148 h.SetBit(kNoContextMenu|kCannotPick);
149#endif
150 }
151}
152
153// ------------------------------------------------------------------------
154//
155// default constructor
156//
157MagicSnake::MagicSnake()
158 : fTimer(this, 500, kTRUE), fGeomCam(NULL), fDone(NULL), fPaused(NULL), fW(0), fH(0)
159{
160 SetNewCamera(new MGeomCamMagic);
161
162 //
163 // Make sure, that the object is destroyed when the canvas/pad is
164 // destroyed. Make also sure, that the interpreter doesn't try to
165 // delete it a second time.
166 //
167 SetBit(kCanDelete);
168 gInterpreter->DeleteGlobal(this);
169
170 Draw();
171
172 Pause();
173
174 fTimer.TurnOn();
175}
176
177void MagicSnake::Pause(Bool_t yes)
178{
179 if (yes && !fPaused)
180 {
181 fPaused = new TText(0, 0, "Paused!");
182 fPaused->SetTextColor(kWhite);
183 fPaused->SetTextAlign(22);
184 fPaused->SetTextSize(0.05); // white
185 fPaused->Draw();
186#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
187 fPaused->SetBit(kNoContextMenu|kCannotPick);
188 fDrawingPad->ResetBit(kNoContextMenu);
189 ResetBit(kNoContextMenu);
190#endif
191 fDrawingPad->Update();
192 }
193
194 if (yes)
195 return;
196
197 if (!fDone)
198 {
199#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
200 fDrawingPad->SetBit(kNoContextMenu);
201 SetBit(kNoContextMenu);
202#endif
203 }
204 if (!fPaused)
205 return;
206
207 Remove(fPaused);
208
209 fDrawingPad->Update();
210
211 delete fPaused;
212 fPaused=NULL;
213}
214
215// ------------------------------------------------------------------------
216//
217// Destructor. Deletes TClonesArrays for hexagons and legend elements.
218//
219MagicSnake::~MagicSnake()
220{
221 Free();
222 Pause(kFALSE);
223
224 if (fDone)
225 delete fDone;
226
227 if (fDrawingPad->GetListOfPrimitives()->FindObject(this)==this)
228 {
229 fDrawingPad->RecursiveRemove(this);
230 delete fDrawingPad;
231 }
232}
233
234// ------------------------------------------------------------------------
235//
236// This is called at any time the canvas should get repainted.
237// Here we maintain an aspect ratio of 5/4=1.15. This makes sure,
238// that the camera image doesn't get distorted by resizing the canvas.
239//
240void MagicSnake::Paint(Option_t *opt)
241{
242 const UInt_t w = (UInt_t)(gPad->GetWw()*gPad->GetAbsWNDC());
243 const UInt_t h = (UInt_t)(gPad->GetWh()*gPad->GetAbsHNDC());
244
245 //
246 // Check for a change in width or height, and make sure, that the
247 // first call also sets the range
248 //
249 if (w*fH == h*fW && fW && fH)
250 return;
251
252 //
253 // Calculate aspect ratio (5/4=1.25 recommended)
254 //
255 const Double_t ratio = (Double_t)w/h;
256
257 Float_t x;
258 Float_t y;
259
260 if (ratio>1.0)
261 {
262 x = fRange*(ratio*2-1);
263 y = fRange;
264 }
265 else
266 {
267 x = fRange;
268 y = fRange/ratio;
269 }
270
271 fH = h;
272 fW = w;
273
274 //
275 // Set new range
276 //
277 fDrawingPad->Range(-fRange, -y, x, y);
278}
279
280// ------------------------------------------------------------------------
281//
282// Call this function to draw the camera layout into your canvas.
283// Setup a drawing canvas. Add this object and all child objects
284// (hexagons, etc) to the current pad. If no pad exists a new one is
285// created.
286//
287void MagicSnake::Draw(Option_t *option)
288{
289 //
290 // if no canvas is yet existing to draw into, create a new one
291 //
292 /*TCanvas *c =*/ new TCanvas("MagicSnake", "Magic Snake", 0, 0, 800, 800);
293 //c->ToggleEventStatus();
294
295 fDrawingPad = gPad;
296 fDrawingPad->SetBorderMode(0);
297
298 //
299 // Append this object, so that the aspect ratio is maintained
300 // (Paint-function is called)
301 //
302 AppendPad(option);
303
304 //
305 // Reset the game pad
306 //
307 Reset();
308 DrawHexagons();
309
310 fShow.SetTextAlign(23); // centered/bottom
311#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
312 fShow.SetBit(kNoContextMenu|kCannotPick);
313#endif
314 fShow.Draw();
315}
316
317void MagicSnake::Update()
318{
319 TString txt = "Pixels: ";
320 txt += fNumPixels;
321 txt += " Bombs: ";
322 txt += fNumBombs;
323 txt += " Food: ";
324 txt += fNumFood;
325
326 fShow.SetText(0, fRange, txt);
327}
328
329// ------------------------------------------------------------------------
330//
331// reset the all pixel colors to a default value
332//
333void MagicSnake::Reset()
334{
335 fDirection = fGeomCam->InheritsFrom("MGeomCamCT1") ? kLeft : kRight;
336 fLength = 2;
337
338 for (UInt_t i=0; i<fNumPixels; i++)
339 {
340 (*this)[i].SetFillColor(kBackground);
341 (*fGeomCam)[i].ResetBit(kUserBits);
342 }
343
344 (*fGeomCam)[0].SetBit(kHasWorm);
345
346 fNumBombs = fNumPixels/30;
347
348 TRandom rnd(0);
349 for (int i=0; i<fNumBombs; i++)
350 {
351 Int_t idx;
352
353 do idx = (Int_t)rnd.Uniform(fNumPixels);
354 while ((*fGeomCam)[idx].TestBits(kHasBomb|kHasWorm));
355
356 (*fGeomCam)[idx].SetBit(kHasBomb);
357 (*this)[idx].SetFillColor(kRed);
358 }
359
360 fNumFood = fNumPixels/6;
361
362 fArray = new Int_t[fNumFood+3];
363
364 fArray[0] = 0;
365 fArray[1] = 1;
366
367 for (int i=0; i<fNumFood+3; i++)
368 {
369 Float_t f = (float)i/(fNumFood+3);
370 gROOT->GetColor(51+i)->SetRGB(f, f, f);
371 }
372 for (int i=0; i<fNumFood; i++)
373 {
374 Int_t idx;
375
376 do idx = (Int_t)rnd.Uniform(fNumPixels);
377 while ((*fGeomCam)[idx].TestBits(kHasBomb|kHasFood|kHasWorm));
378
379 (*fGeomCam)[idx].SetBit(kHasFood);
380 (*this)[idx].SetFillColor(kGreen);
381 }
382
383 SetWormColor();
384
385 for (int i=0; i<2; i++)
386 {
387 Int_t idx;
388
389 do idx = (Int_t)rnd.Uniform(fNumPixels);
390 while ((*fGeomCam)[idx].TestBits(kHasBomb|kHasFood|kHasWorm|kHasTransport));
391
392 fTransport[i] = idx;
393 (*fGeomCam)[idx].SetBit(kHasTransport);
394 (*this)[idx].SetFillColor(kYellow);
395 }
396
397 fDrawingPad->SetFillColor(22);
398
399#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
400 fDrawingPad->SetBit(kNoContextMenu);
401 SetBit(kNoContextMenu);
402#endif
403
404 if (!fDone)
405 return;
406
407 delete fDone;
408 fDone = NULL;
409}
410
411void MagicSnake::Done(TString txt, Int_t col)
412{
413 //(*this)[fArray[fLength-1]].SetFillColor(kBlue);
414
415 fDone = new TText(0, 0, txt);
416 fDone->SetTextColor(kWhite); // white
417 fDone->SetTextAlign(22); // centered/centered
418 fDone->SetTextSize(0.05); // white
419 fDone->Draw();
420 fDrawingPad->SetFillColor(col);
421#if ROOT_VERSION_CODE > ROOT_VERSION(3,01,06)
422 fDone->SetBit(kNoContextMenu|kCannotPick);
423 fDrawingPad->ResetBit(kNoContextMenu);
424 ResetBit(kNoContextMenu);
425#endif
426}
427
428void MagicSnake::Remove(TObject *obj)
429{
430 fDrawingPad->RecursiveRemove(obj);
431}
432
433// ------------------------------------------------------------------------
434//
435// Execute a mouse event on the camera
436//
437void MagicSnake::ExecuteEvent(Int_t event, Int_t keycode, Int_t keysym)
438{
439 if (event==kMouseEnter || event==kMouseMotion)
440 {
441 Pause(kFALSE);
442 return;
443 }
444
445 if (fDone)
446 return;
447
448 if (event==kMouseLeave)
449 {
450 Pause();
451 return;
452 }
453 if (event!=kKeyPress)
454 return;
455
456 switch (keysym)
457 {
458 case kKey_Left:
459 fDirection --;
460 break;
461
462 case kKey_Right:
463 fDirection ++;
464 break;
465
466 case kKey_Escape:
467 Done("Reset...", 22);
468 Reset();
469 return;
470
471 default:
472 cout << "Keysym=0x" << hex << keysym << endl;
473 }
474
475 if (fDirection < kRightTop)
476 fDirection = kLeftTop;
477 if (fDirection > kLeftTop)
478 fDirection = kRightTop;
479}
480
481void MagicSnake::Step(Int_t newpix)
482{
483 if ((*fGeomCam)[newpix].TestBit(kHasTransport))
484 {
485 (*this)[fArray[0]].SetFillColor(kBackground);
486 (*fGeomCam)[fArray[0]].ResetBit(kHasWorm);
487
488 for (int i=1; i<fLength; i++)
489 fArray[i-1] = fArray[i];
490
491 fArray[fLength-1] = newpix==fTransport[0]?fTransport[1]:fTransport[0];
492
493 return;
494 }
495
496 if (!(*fGeomCam)[newpix].TestBit(kHasFood))
497 {
498 MGeomPix &pix = (*fGeomCam)[fArray[0]];
499
500 if (!pix.TestBit(kHasTransport))
501 if (pix.TestBit(kHasDoor))
502 (*this)[fArray[0]].SetFillColor(kMagenta);
503 else
504 (*this)[fArray[0]].SetFillColor(kBackground);
505
506 pix.ResetBit(kHasWorm);
507
508 for (int i=1; i<fLength; i++)
509 fArray[i-1] = fArray[i];
510
511 fArray[fLength-1] = newpix;
512 }
513 else
514 {
515 fArray[fLength++] = newpix;
516 (*fGeomCam)[newpix].ResetBit(kHasFood);
517
518 fNumFood--;
519
520 if (fNumFood==0)
521 for (int i=1; i<7; i++)
522 {
523 (*this)[i].SetFillColor(kMagenta);
524 (*fGeomCam)[i].SetBit(kHasDoor);
525 }
526 }
527
528 SetWormColor();
529}
530
531void MagicSnake::SetWormColor()
532{
533 for (int i=0; i<fLength; i++)
534 {
535 const Int_t idx = fArray[i];
536
537 MGeomPix &pix = (*fGeomCam)[idx];
538
539 if (pix.TestBit(kHasTransport))
540 continue;
541
542 pix.SetBit(kHasWorm);
543
544 Int_t color = 51+fLength-i;
545 (*this)[idx].SetFillColor(color);
546 }
547}
548
549Int_t MagicSnake::ScanNeighbours()
550{
551 const Int_t first = fArray[fLength-1];
552
553 const MGeomPix &pix=(*fGeomCam)[first];
554
555 Double_t dx = pix.GetX();
556 Double_t dy = pix.GetY();
557
558 Int_t newpix = -1;
559 for (int i=0; i<pix.GetNumNeighbors(); i++)
560 {
561 const Int_t idx = pix.GetNeighbor(i);
562 const MGeomPix &next = (*fGeomCam)[idx];
563
564 const Double_t x = next.GetX();
565 const Double_t y = next.GetY();
566
567 switch (fDirection)
568 {
569 case kRightTop: if (x>=dx && y>dy) { newpix=idx; dy=y; } continue;
570 case kRight: if (x>dx) { newpix=idx; dx=x; } continue;
571 case kRightBottom: if (x>=dx && y<dy) { newpix=idx; dy=y; } continue;
572 case kLeftTop: if (x<=dx && y>dy) { newpix=idx; dy=y; } continue;
573 case kLeft: if (x<dx) { newpix=idx; dx=x; } continue;
574 case kLeftBottom: if (x<=dx && y<dy) { newpix=idx; dy=y; } continue;
575 }
576 }
577
578 if (newpix<0)
579 return -1;
580
581 const MGeomPix &np = (*fGeomCam)[newpix];
582
583 if (fNumFood==0 && np.TestBit(kHasDoor))
584 return -4;
585
586 if (np.TestBit(kHasBomb))
587 return -2;
588
589 if (np.TestBit(kHasWorm))
590 return -3;
591
592 return newpix;
593}
594
595Bool_t MagicSnake::HandleTimer(TTimer *timer)
596{
597 if (fDone || fPaused)
598 return kTRUE;
599
600 const Int_t newpix = ScanNeighbours();
601
602 switch (newpix)
603 {
604 case -1:
605 Done("You crashed! Don't drink and drive!", kRed);
606 break;
607 case -2:
608 Done("Ouch, you found the bomb!", kRed);
609 break;
610 case -3:
611 Done("Argh... don't eat yourself!", kRed);
612 break;
613 case -4:
614 Done("Congratulations! You won the game!", kGreen);
615 break;
616 default:
617 Step(newpix);
618 }
619
620 Update();
621
622 //cout << "Update " << flush;
623
624 fDrawingPad->Modified();
625 fDrawingPad->Update();
626
627 //cout << "Done." << endl;
628
629 return kTRUE;
630}
Note: See TracBrowser for help on using the repository browser.