snake.cc 7.6 KB

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