No Description

maingamewindow.cpp 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. // Todo implement game modes: 1= square upper left, 2 = rect upper left, etc..
  2. #include "maingamewindow.h"
  3. #include <QDebug>
  4. #include <QTimer>
  5. #include <QTime>
  6. #include <QEventLoop>
  7. #include <QApplication>
  8. //
  9. // Initialices some of the data members
  10. //
  11. void MainGameWindow::initMembers() {
  12. s = new QGraphicsScene(this);
  13. s->setSceneRect(0,0,600,600);
  14. this->setGeometry(0,0,600,600);
  15. v = new QGraphicsView(s,this);
  16. v->setGeometry(0,0,600,600);
  17. pct_margin = .1;
  18. srand(time(NULL));
  19. }
  20. //
  21. // Starts the timer that is used for animation purposes.
  22. //
  23. void MainGameWindow::startTheTimer() {
  24. timer = new QTimer(s);
  25. timer->connect(timer, SIGNAL(timeout()), s, SLOT(advance()));
  26. timer->start(10);
  27. }
  28. //
  29. // Constructor that accepts a game mode argument. See the modes
  30. // definition in the .h.
  31. //
  32. MainGameWindow::MainGameWindow(Mode gameMode) : QMainWindow(0) {
  33. initMembers();
  34. // the initial row/col positions of the robot
  35. uint initialX, initialY;
  36. _rows = rand() % 9 + 2;
  37. switch (gameMode) {
  38. case Mode::SQUARE_TOP_LEFT:
  39. _cols = _rows;
  40. initialX = initialY = 0;
  41. break;
  42. case Mode::RECT_TOP_LEFT:
  43. _cols = rand() % 9 + 2;
  44. initialX = initialY = 0;
  45. break;
  46. case Mode::RECT_RANDOM:
  47. _cols = rand() % 9 + 2;
  48. initialX = rand() % _cols;
  49. initialY = rand() % _rows;
  50. break;
  51. case Mode::PYRAMID_RANDOM:
  52. _cols = (rand() % 4 + 2) * 2 + 1;
  53. createPiramid();
  54. assignValidPos(initialX, initialY);
  55. break;
  56. }
  57. // This creates rectangular mazes
  58. if (_maze == "") {
  59. for (uint r = 0; r < _rows; r++) {
  60. for (uint c = 0; c < _cols; c++) {
  61. _maze.push_back('x');
  62. }
  63. _maze.push_back('\n');
  64. }
  65. }
  66. qDebug() << "MainGameWindow::MainGameWindow(): width: " << this->width();
  67. qDebug() << "_maze: " << _maze;
  68. paintMaze(initialX, initialY);
  69. startTheTimer();
  70. v->show();
  71. }
  72. // Creates this type of pyramid, e.g. _cols = 7
  73. // 000x000
  74. // 00xxx00
  75. // 0xxxxx0
  76. // xxxxxxx
  77. void MainGameWindow::createPiramid() {
  78. _maze = "";
  79. _rows = _cols/2;
  80. for (uint r = 0; r <= _rows + 1; r++) {
  81. for (uint c = 0; c < _cols; c++) {
  82. _maze.push_back( abs((int)c - (int)_rows) <= (int)r ? 'x':' ');
  83. }
  84. _maze.push_back('\n');
  85. }
  86. _rows++;
  87. }
  88. //
  89. // Randomly determines a valid initial position for the robot
  90. //
  91. void MainGameWindow::assignValidPos(uint &initialX, uint &initialY) {
  92. qDebug() << _maze;
  93. if (_cols <= 0 || _rows <= 0) {
  94. qDebug() << "assignValidPos was called with 0 rows or cols!";
  95. exit(1);
  96. }
  97. // throw the dice to determine initial random position
  98. do {
  99. initialX = rand() % _cols;
  100. initialY = rand() % _rows;
  101. } while (_maze.toStdString()[initialY * (_cols + 1) + initialX] != 'x');
  102. }
  103. //
  104. // Constructor that accepts number of rows and columns.
  105. //
  106. MainGameWindow::MainGameWindow(uint rows, uint cols) : QMainWindow(0) {
  107. _rows = rows;
  108. _cols = cols;
  109. initMembers();
  110. _maze = "";
  111. for (uint r = 0; r < _rows; r++) {
  112. for (uint c = 0; c < _cols; c++) {
  113. _maze.push_back('x');
  114. }
  115. _maze.push_back('\n');
  116. }
  117. qDebug() << "MainGameWindow::MainGameWindow(): width: " << this->width();
  118. qDebug() << "_maze: " << _maze;
  119. paintMaze(0,0);
  120. startTheTimer();
  121. v->show();
  122. }
  123. MainGameWindow::MainGameWindow(const QString &maze) {
  124. _maze = maze;
  125. initMembers();
  126. if (validMaze() ) {
  127. qDebug() << "valid maze!!!!";
  128. paintMaze(0,0);
  129. startTheTimer();
  130. }
  131. }
  132. //
  133. // Given a string that represents the maze, determines the number
  134. // of rows and cols. Returns false if the maze is malformed.
  135. //
  136. bool MainGameWindow::validMaze() {
  137. char c;
  138. uint ctr = 0;
  139. _cols = 0; _rows = 0;
  140. for (int i = 0; i < _maze.length(); i++){
  141. c = _maze.toStdString()[i];
  142. if (c == 'x' || c == ' ') ctr++;
  143. else if (c == '\n') {
  144. if (_cols == 0) _cols = ctr;
  145. else if (_cols != ctr) return false;
  146. ctr = 0;
  147. _rows++;
  148. }
  149. }
  150. qDebug() << "rows:" << _rows << " cols: " << _cols;
  151. return true;
  152. }
  153. //
  154. // This is a delay that lets other events in the event loop
  155. // continue executing.
  156. //
  157. void delay(int ms)
  158. {
  159. QTime dieTime= QTime::currentTime().addMSecs(ms);
  160. while( QTime::currentTime() < dieTime )
  161. QApplication::processEvents(QEventLoop::AllEvents,10);
  162. }
  163. //
  164. // Determines the underlying character of the maze.
  165. // This is used to determine if the robot is off the grid
  166. // or has entered a wall.
  167. //
  168. char MainGameWindow::posToChar() {
  169. uint r, c;
  170. posToRC(r, c);
  171. if (r >= _rows || c >= _cols) return -1;
  172. return _maze.toStdString()[r * (_cols + 1) + c];
  173. }
  174. //
  175. // Determines the poisition in row, column, based on the x, y position
  176. // of the robot.
  177. //
  178. void MainGameWindow::posToRC(uint &r, uint &c) {
  179. uint realX = robot->myX - s->width() * pct_margin;
  180. uint realY = robot->myY - s->height() * pct_margin ;
  181. r = round(static_cast<float>(realY) / rowHeight);
  182. c = round(static_cast<float>(realX) / colWidth);
  183. }
  184. //
  185. // Given the direction determines if the robot may move in that
  186. // direction.
  187. //
  188. bool MainGameWindow::canMove(char dir) {
  189. uint r, c;
  190. posToRC(r, c);
  191. switch(dir) {
  192. case 'W': c--; break;
  193. case 'E': c++; break;
  194. case 'N': r--; break;
  195. case 'S': r++; break;
  196. default:
  197. display("Bad direction: " + QString(dir));
  198. return false;
  199. }
  200. if (r >= _rows || c >= _cols) return false;
  201. else return _maze.toStdString()[r * (_cols + 1) + c] == 'x';
  202. }
  203. //
  204. // Given a character 'N', 'S', 'E', or 'W', moves the robot
  205. // one cell in that direction. If the target cell was invalid
  206. // then it destroys the robot.
  207. //
  208. void MainGameWindow::moveRobot(char dir) {
  209. if (robot->isAlive()) {
  210. uint deltaX = colWidth / 10;
  211. uint deltaY = rowHeight / 10;
  212. qDebug() << "car at:" << robot->myX;
  213. switch(dir) {
  214. case 'N': robot->toY = robot->myY - rowHeight; robot->myDirY = -deltaY; break;
  215. case 'S': robot->toY = robot->myY + rowHeight; robot->myDirY = +deltaY; break;
  216. case 'E': robot->toX = robot->myX + colWidth; robot->myDirX = +deltaX; break;
  217. case 'W': robot->toX = robot->myX - colWidth; robot->myDirX = -deltaX; break;
  218. default: display("Bad direction: " + QString(dir)); return;
  219. }
  220. qDebug() <<"colwidth" << colWidth;
  221. qDebug() << "move to at:" << robot->toX;
  222. while (robot->myDirX != 0 || robot->myDirY != 0)
  223. delay(500);
  224. robot->myDirX = robot->myDirY = 0;
  225. if (posToChar() != 'x')
  226. robot->kill();
  227. }
  228. }
  229. //
  230. // Given a string, displays it in large letters.
  231. //
  232. void MainGameWindow::display(const QString &st) {
  233. if (robot->isAlive()) {
  234. msg->setHtml("<center>" + st + "</center>");
  235. msg->show();
  236. delay(500);
  237. msg->hide();
  238. }
  239. }
  240. //
  241. // Given an int, displays it in big letters.
  242. //
  243. void MainGameWindow::display(int n) {
  244. display(QString::number(n));
  245. }
  246. // Paints the maze based on the contents of the _maze string.
  247. // Also creates the robot and the text box for display.
  248. void MainGameWindow::paintMaze(uint initialX, uint initialY) {
  249. pct_margin = 1.0/( _cols > _rows ? _cols + 2 : _rows + 2);
  250. qDebug() << "pct_margin " << pct_margin;
  251. uint fromY = s->height()*pct_margin, toY = s->height()*(1-pct_margin);
  252. qDebug() << "toX, toY" << fromY << "," << toY ;
  253. uint fromX = s->width()*pct_margin, toX = s->width()*(1-pct_margin);
  254. rowHeight = (toY - fromY) / _rows;
  255. colWidth = (toX - fromX) / _cols;
  256. uint strPos = 0;
  257. QBrush black(Qt::black);
  258. QBrush white(Qt::white);
  259. for (uint i = 0; i < _rows; i++) {
  260. uint y = i * rowHeight + s->height()*pct_margin;
  261. for (uint j = 0; j < _cols; j++) {
  262. uint x = j * colWidth + s->width() * pct_margin;
  263. qDebug() << x << " " << y;
  264. s->addRect(x, y, colWidth, rowHeight, QPen(Qt::SolidLine),
  265. _maze.at(strPos) == 'x' ? white : black);
  266. strPos++;
  267. }
  268. strPos++;
  269. }
  270. // // Create the robot
  271. //
  272. // int initialX, initialY;
  273. //
  274. // // throw the dice to determine initial random position
  275. // do {
  276. // initialX = rand() % _cols;
  277. // initialY = rand() % _rows;
  278. //
  279. // } while (_maze.toStdString()[initialY * (_cols + 1) + initialX] != 'x');
  280. robot = new GenericScrollingObject(":robot.png", s,
  281. colWidth * initialX + s->width() * pct_margin,
  282. rowHeight * initialY + s->height() * pct_margin, colWidth,rowHeight,
  283. QColor(Qt::white), this);
  284. // Create the text box that will be used for the display
  285. msg = new QGraphicsTextItem;
  286. msg->setPos(0, s->height()/2);
  287. msg->setTextWidth(s->width());
  288. msg->setHtml("<center>Barev</center>");
  289. msg->setFont(QFont("Helvetica",90));
  290. msg->setDefaultTextColor(Qt::green);
  291. msg->hide();
  292. s->addItem(msg);
  293. }