snake.cpp 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. CS 349 A1 Skeleton Code - Snake
  3. - - - - - - - - - - - - - - - - - - - - - -
  4. Commands to compile and run:
  5. g++ -o snake snake.cpp -L/usr/X11R6/lib -lX11 -lstdc++
  6. ./snake
  7. Note: the -L option and -lstdc++ may not be needed on some machines.
  8. */
  9. #include <iostream>
  10. #include <list>
  11. #include <cstdlib>
  12. #include <sys/time.h>
  13. #include <math.h>
  14. #include <stdio.h>
  15. #include <unistd.h>
  16. /*
  17. * Header files for X functions
  18. */
  19. #include <X11/Xlib.h>
  20. #include <X11/Xutil.h>
  21. using namespace std;
  22. /*
  23. * Global game state variables
  24. */
  25. const int Border = 1;
  26. const int BufferSize = 10;
  27. const int FPS = 30;
  28. const int width = 800;
  29. const int height = 600;
  30. /*
  31. * Information to draw on the window.
  32. */
  33. struct XInfo {
  34. Display *display;
  35. int screen;
  36. Window window;
  37. GC gc[3];
  38. int width; // size of window
  39. int height;
  40. };
  41. /*
  42. * Function to put out a message on error exits.
  43. */
  44. void error( string str ) {
  45. cerr << str << endl;
  46. exit(0);
  47. }
  48. /*
  49. * An abstract class representing displayable things.
  50. */
  51. class Displayable {
  52. public:
  53. virtual void paint(XInfo &xinfo) = 0;
  54. };
  55. class Snake : public Displayable {
  56. public:
  57. virtual void paint(XInfo &xinfo) {
  58. XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, 25, blockSize);
  59. }
  60. void move(XInfo &xinfo) {
  61. x = x + direction;
  62. if (x < 0 || x > width) {
  63. direction = -direction;
  64. }
  65. // ** ADD YOUR LOGIC **
  66. // Here, you will be performing collision detection between the snake,
  67. // the fruit, and the obstacles depending on what the snake lands on.
  68. }
  69. int getX() {
  70. return x;
  71. }
  72. int getY() {
  73. return y;
  74. }
  75. /*
  76. * ** ADD YOUR LOGIC **
  77. * Use these placeholder methods as guidance for implementing the snake behaviour.
  78. * You do not have to use these methods, feel free to implement your own.
  79. */
  80. void didEatFruit() {
  81. }
  82. void didHitObstacle() {
  83. }
  84. void turnLeft() {
  85. }
  86. void turnRight() {
  87. }
  88. Snake(int x, int y): x(x), y(y) {
  89. direction = 5;
  90. blockSize = 10;
  91. }
  92. private:
  93. int x;
  94. int y;
  95. int blockSize;
  96. int direction;
  97. };
  98. class Fruit : public Displayable {
  99. public:
  100. virtual void paint(XInfo &xinfo) {
  101. XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, 10, 10);
  102. }
  103. Fruit() {
  104. // ** ADD YOUR LOGIC **
  105. // generate the x and y value for the fruit
  106. x = 50;
  107. y = 50;
  108. }
  109. // ** ADD YOUR LOGIC **
  110. /*
  111. * The fruit needs to be re-generated at new location every time a snake eats it. See the assignment webpage for more details.
  112. */
  113. private:
  114. int x;
  115. int y;
  116. };
  117. list<Displayable *> dList; // list of Displayables
  118. Snake snake(100, 450);
  119. Fruit fruit;
  120. /*
  121. * Initialize X and create a window
  122. */
  123. void initX(int argc, char *argv[], XInfo &xInfo) {
  124. XSizeHints hints;
  125. unsigned long white, black;
  126. /*
  127. * Display opening uses the DISPLAY environment variable.
  128. * It can go wrong if DISPLAY isn't set, or you don't have permission.
  129. */
  130. xInfo.display = XOpenDisplay( "" );
  131. if ( !xInfo.display ) {
  132. error( "Can't open display." );
  133. }
  134. /*
  135. * Find out some things about the display you're using.
  136. */
  137. xInfo.screen = DefaultScreen( xInfo.display );
  138. white = XWhitePixel( xInfo.display, xInfo.screen );
  139. black = XBlackPixel( xInfo.display, xInfo.screen );
  140. hints.x = 100;
  141. hints.y = 100;
  142. hints.width = 800;
  143. hints.height = 600;
  144. hints.flags = PPosition | PSize;
  145. xInfo.window = XCreateSimpleWindow(
  146. xInfo.display, // display where window appears
  147. DefaultRootWindow( xInfo.display ), // window's parent in window tree
  148. hints.x, hints.y, // upper left corner location
  149. hints.width, hints.height, // size of the window
  150. Border, // width of window's border
  151. black, // window border colour
  152. white ); // window background colour
  153. XSetStandardProperties(
  154. xInfo.display, // display containing the window
  155. xInfo.window, // window whose properties are set
  156. "animation", // window's title
  157. "Animate", // icon's title
  158. None, // pixmap for the icon
  159. argv, argc, // applications command line args
  160. &hints ); // size hints for the window
  161. /*
  162. * Create Graphics Contexts
  163. */
  164. int i = 0;
  165. xInfo.gc[i] = XCreateGC(xInfo.display, xInfo.window, 0, 0);
  166. XSetForeground(xInfo.display, xInfo.gc[i], BlackPixel(xInfo.display, xInfo.screen));
  167. XSetBackground(xInfo.display, xInfo.gc[i], WhitePixel(xInfo.display, xInfo.screen));
  168. XSetFillStyle(xInfo.display, xInfo.gc[i], FillSolid);
  169. XSetLineAttributes(xInfo.display, xInfo.gc[i],
  170. 1, LineSolid, CapButt, JoinRound);
  171. XSelectInput(xInfo.display, xInfo.window,
  172. ButtonPressMask | KeyPressMask |
  173. PointerMotionMask |
  174. EnterWindowMask | LeaveWindowMask |
  175. StructureNotifyMask); // for resize events
  176. /*
  177. * Put the window on the screen.
  178. */
  179. XMapRaised( xInfo.display, xInfo.window );
  180. XFlush(xInfo.display);
  181. }
  182. /*
  183. * Function to repaint a display list
  184. */
  185. void repaint( XInfo &xinfo) {
  186. list<Displayable *>::const_iterator begin = dList.begin();
  187. list<Displayable *>::const_iterator end = dList.end();
  188. XClearWindow( xinfo.display, xinfo.window );
  189. // get height and width of window (might have changed since last repaint)
  190. XWindowAttributes windowInfo;
  191. XGetWindowAttributes(xinfo.display, xinfo.window, &windowInfo);
  192. unsigned int height = windowInfo.height;
  193. unsigned int width = windowInfo.width;
  194. // big black rectangle to clear background
  195. // draw display list
  196. while( begin != end ) {
  197. Displayable *d = *begin;
  198. d->paint(xinfo);
  199. begin++;
  200. }
  201. XFlush( xinfo.display );
  202. }
  203. void handleKeyPress(XInfo &xinfo, XEvent &event) {
  204. KeySym key;
  205. char text[BufferSize];
  206. /*
  207. * Exit when 'q' is typed.
  208. * This is a simplified approach that does NOT use localization.
  209. */
  210. int i = XLookupString(
  211. (XKeyEvent *)&event, // the keyboard event
  212. text, // buffer when text will be written
  213. BufferSize, // size of the text buffer
  214. &key, // workstation-independent key symbol
  215. NULL ); // pointer to a composeStatus structure (unused)
  216. if ( i == 1) {
  217. printf("Got key press -- %c\n", text[0]);
  218. if (text[0] == 'q') {
  219. error("Terminating normally.");
  220. }
  221. }
  222. }
  223. void handleAnimation(XInfo &xinfo, int inside) {
  224. /*
  225. * ADD YOUR OWN LOGIC
  226. * This method handles animation for different objects on the screen and readies the next frame before the screen is re-painted.
  227. */
  228. snake.move(xinfo);
  229. }
  230. // get microseconds
  231. unsigned long now() {
  232. timeval tv;
  233. gettimeofday(&tv, NULL);
  234. return tv.tv_sec * 1000000 + tv.tv_usec;
  235. }
  236. void eventLoop(XInfo &xinfo) {
  237. // Add stuff to paint to the display list
  238. dList.push_front(&snake);
  239. dList.push_front(&fruit);
  240. XEvent event;
  241. unsigned long lastRepaint = 0;
  242. int inside = 0;
  243. while( true ) {
  244. /*
  245. * This is NOT a performant event loop!
  246. * It needs help!
  247. */
  248. if (XPending(xinfo.display) > 0) {
  249. XNextEvent( xinfo.display, &event );
  250. cout << "event.type=" << event.type << "\n";
  251. switch( event.type ) {
  252. case KeyPress:
  253. handleKeyPress(xinfo, event);
  254. break;
  255. case EnterNotify:
  256. inside = 1;
  257. break;
  258. case LeaveNotify:
  259. inside = 0;
  260. break;
  261. }
  262. }
  263. usleep(1000000/FPS);
  264. handleAnimation(xinfo, inside);
  265. repaint(xinfo);
  266. }
  267. }
  268. /*
  269. * Start executing here.
  270. * First initialize window.
  271. * Next loop responding to events.
  272. * Exit forcing window manager to clean up - cheesy, but easy.
  273. */
  274. int main ( int argc, char *argv[] ) {
  275. XInfo xInfo;
  276. initX(argc, argv, xInfo);
  277. eventLoop(xInfo);
  278. XCloseDisplay(xInfo.display);
  279. }