|
@@ -0,0 +1,693 @@
|
|
|
+/*
|
|
|
+CS 349 A1 Skeleton Code - Snake
|
|
|
+
|
|
|
+- - - - - - - - - - - - - - - - - - - - - -
|
|
|
+
|
|
|
+Commands to compile and run:
|
|
|
+
|
|
|
+ g++ -o snake snake.cpp -L/usr/X11R6/lib -lX11 -lstdc++
|
|
|
+ ./snake
|
|
|
+
|
|
|
+Note: the -L option and -lstdc++ may not be needed on some machines.
|
|
|
+*/
|
|
|
+
|
|
|
+#include <iostream>
|
|
|
+#include <list>
|
|
|
+#include <vector>
|
|
|
+#include <cstdlib>
|
|
|
+#include <sys/time.h>
|
|
|
+#include <math.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <unistd.h>
|
|
|
+
|
|
|
+/*
|
|
|
+ * Header files for X functions
|
|
|
+ */
|
|
|
+#include <X11/Xlib.h>
|
|
|
+#include <X11/Xutil.h>
|
|
|
+
|
|
|
+using namespace std;
|
|
|
+
|
|
|
+// Globals for xlib
|
|
|
+Colormap colours;
|
|
|
+XColor xcolour;
|
|
|
+char black[] = "rgb:00/00/00";
|
|
|
+char white[] = "rgb:ff/ff/ff";
|
|
|
+char lblue[] = "rgb:00/ff/ff";
|
|
|
+char orange[] = "rgb:FF/45/00";
|
|
|
+
|
|
|
+/*
|
|
|
+ * Global game state variables
|
|
|
+ */
|
|
|
+const int Border = 1;
|
|
|
+const int BufferSize = 10;
|
|
|
+int FPS = 30;
|
|
|
+const int width = 800;
|
|
|
+const int height = 600;
|
|
|
+const int blockSize = 25;
|
|
|
+int velocity = 5;
|
|
|
+bool paused = true;
|
|
|
+bool starting = true;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Information to draw on the window.
|
|
|
+ */
|
|
|
+typedef struct XInfo
|
|
|
+{
|
|
|
+ Display * display;
|
|
|
+ int screen;
|
|
|
+ Window window;
|
|
|
+ GC gc[3];
|
|
|
+ int width; // size of window
|
|
|
+ int height;
|
|
|
+ Pixmap buffer;
|
|
|
+} Xinfo;
|
|
|
+
|
|
|
+
|
|
|
+// get microseconds
|
|
|
+unsigned long now()
|
|
|
+{
|
|
|
+ timeval tv;
|
|
|
+ gettimeofday(&tv, NULL);
|
|
|
+ return tv.tv_sec * 1000000 + tv.tv_usec;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Function to put out a message on error exits.
|
|
|
+ */
|
|
|
+void error(string str)
|
|
|
+{
|
|
|
+ cerr << str << endl;
|
|
|
+ exit(0);
|
|
|
+}
|
|
|
+
|
|
|
+// change the drawing coloursvoid changecolour(char colour[])
|
|
|
+void changecolour(XInfo & xinfo, char colour[])
|
|
|
+{
|
|
|
+ XParseColor(xinfo.display, colours, colour, &xcolour);
|
|
|
+ XAllocColor(xinfo.display, colours, &xcolour);
|
|
|
+ XSetForeground(xinfo.display, xinfo.gc[0], xcolour.pixel);
|
|
|
+ XFreeColormap(xinfo.display, colours);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * An abstract class representing displayable things.
|
|
|
+ */
|
|
|
+class Displayable
|
|
|
+{
|
|
|
+ public:
|
|
|
+ virtual void paint(XInfo & xinfo) = 0;
|
|
|
+};
|
|
|
+
|
|
|
+class Fruit : public Displayable
|
|
|
+{
|
|
|
+ public:
|
|
|
+ virtual void paint(XInfo & xinfo)
|
|
|
+ {
|
|
|
+ changecolour(xinfo, orange);
|
|
|
+ XFillArc(xinfo.display, xinfo.buffer, xinfo.gc[0], x, y, 25, 25, 0, 360 * 64);
|
|
|
+ }
|
|
|
+
|
|
|
+ Fruit()
|
|
|
+ {
|
|
|
+ newspot();
|
|
|
+ }
|
|
|
+
|
|
|
+ int getx()
|
|
|
+ {
|
|
|
+ return x;
|
|
|
+ }
|
|
|
+
|
|
|
+ int gety()
|
|
|
+ {
|
|
|
+ return y;
|
|
|
+ }
|
|
|
+
|
|
|
+ void newspot()
|
|
|
+ {
|
|
|
+ x = (rand() % 32) * 25;
|
|
|
+ y = (rand() % 24) * 25;
|
|
|
+ }
|
|
|
+ // ** ADD YOUR LOGIC **
|
|
|
+ /*
|
|
|
+ * The fruit needs to be re-generated at new location every time a snake eats it. See the assignment webpage for more details.
|
|
|
+ */
|
|
|
+
|
|
|
+ private:
|
|
|
+ int x;
|
|
|
+ int y;
|
|
|
+};
|
|
|
+
|
|
|
+class Section: public Displayable
|
|
|
+{
|
|
|
+ public:
|
|
|
+ virtual void paint(XInfo & xinfo)
|
|
|
+ {
|
|
|
+ changecolour(xinfo, black);
|
|
|
+ switch(direction)
|
|
|
+ {
|
|
|
+ case 1:
|
|
|
+ XFillRectangle(xinfo.display, xinfo.buffer, xinfo.gc[0], x, y, blockSize, (len + 1) * blockSize);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ XFillRectangle(xinfo.display, xinfo.buffer, xinfo.gc[0], (x - len * blockSize), y, (1 + len) * blockSize, blockSize);
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ XFillRectangle(xinfo.display, xinfo.buffer, xinfo.gc[0], x, (y - len * blockSize), blockSize, ((1 + len) * blockSize));
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4:
|
|
|
+ XFillRectangle(xinfo.display, xinfo.buffer, xinfo.gc[0], x, y, (len + 1) * blockSize, blockSize);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void increment(int x)
|
|
|
+ {
|
|
|
+ len += x;
|
|
|
+ }
|
|
|
+
|
|
|
+ void decrement()
|
|
|
+ {
|
|
|
+ --len;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool empty()
|
|
|
+ {
|
|
|
+ return (!len);
|
|
|
+ }
|
|
|
+
|
|
|
+ void grow()
|
|
|
+ {
|
|
|
+ switch(direction)
|
|
|
+ {
|
|
|
+ case 1:
|
|
|
+ y -= blockSize;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ x += blockSize;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ y += blockSize;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4:
|
|
|
+ x -= blockSize;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ ++len;
|
|
|
+ }
|
|
|
+
|
|
|
+ int getx()
|
|
|
+ {
|
|
|
+ return x;
|
|
|
+ }
|
|
|
+
|
|
|
+ int gety()
|
|
|
+ {
|
|
|
+ return y;
|
|
|
+ }
|
|
|
+
|
|
|
+ int getdir()
|
|
|
+ {
|
|
|
+ return direction;
|
|
|
+ }
|
|
|
+
|
|
|
+ int getlen()
|
|
|
+ {
|
|
|
+ return len;
|
|
|
+ }
|
|
|
+
|
|
|
+ Section(int x, int y, int dir, int len = 1): x(x), y(y), direction(dir), len(len)
|
|
|
+ {
|
|
|
+ blockSize = 25;
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ int x;
|
|
|
+ int y;
|
|
|
+ int len;
|
|
|
+ int blockSize;
|
|
|
+ int direction;
|
|
|
+};
|
|
|
+
|
|
|
+class Snake : public Displayable
|
|
|
+{
|
|
|
+ public:
|
|
|
+ virtual void paint(XInfo & xinfo)
|
|
|
+ {
|
|
|
+ for (Section * each: sections)
|
|
|
+ {
|
|
|
+ each->paint(xinfo);
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ void move(XInfo & xinfo)
|
|
|
+ {
|
|
|
+ if ((now() - lastmove < speed) || paused)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ // turn if a turn happens
|
|
|
+ if (direction)
|
|
|
+ {
|
|
|
+ Section * newsec = new Section(sections.front()->getx(), sections.front()->gety(), direction, 0);
|
|
|
+ direction = 0;
|
|
|
+ sections.insert(sections.begin(), newsec);
|
|
|
+ }
|
|
|
+
|
|
|
+ // move 1 block forwards
|
|
|
+ sections.front()->grow();
|
|
|
+
|
|
|
+ // see if fruit was eaten
|
|
|
+ if (sections.front()->getx() == fruity->getx() && sections.front()->gety() == fruity->gety())
|
|
|
+ {
|
|
|
+ fruit = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ // add fruit, remove 1 from end, delete if empty
|
|
|
+ sections.back()->increment(fruit);
|
|
|
+ if (fruit) fruity->newspot();
|
|
|
+ fruit = 0;
|
|
|
+ sections.back()->decrement();
|
|
|
+ if (sections.back()->empty())
|
|
|
+ {
|
|
|
+ delete sections.back();
|
|
|
+ sections.pop_back();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sections.front()->getx() > width || sections.front()->gety() < 0)
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ delete this;
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sections.front()->getx() < 0 || sections.front()->gety() > height)
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ delete this;
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sections.size() <= 3) goto SKIP;
|
|
|
+ for (auto each = sections.begin() + 1; each != sections.end(); ++each)
|
|
|
+ {
|
|
|
+ int tempdir = (*each)->getdir();
|
|
|
+ int frontx = sections.front()->getx();
|
|
|
+ int fronty = sections.front()->gety();
|
|
|
+ int eachx = (*each)->getx();
|
|
|
+ int eachy = (*each)->gety();
|
|
|
+ int eachlen = (*each)->getlen();
|
|
|
+
|
|
|
+ switch(tempdir)
|
|
|
+ {
|
|
|
+ case 1:
|
|
|
+ if (frontx == eachx && (fronty >= eachy && fronty <= (eachy + blockSize * eachlen)))
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ delete this;
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 2:
|
|
|
+ if ((frontx >= (eachx - eachlen * blockSize) && frontx <= eachx) && fronty == eachy)
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ delete this;
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3:
|
|
|
+ if (frontx == eachx && (fronty <= eachy && fronty >= (eachy - blockSize * eachlen)))
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ delete this;
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 4:
|
|
|
+ if ((frontx <= (eachx - eachlen * blockSize) && frontx >= eachx) && fronty == eachy)
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ delete this;
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ SKIP:
|
|
|
+ lastmove = now();
|
|
|
+ }
|
|
|
+
|
|
|
+ void moveup()
|
|
|
+ {
|
|
|
+ if (direction == 4 || direction == 2 || direction == 0) direction = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ void moveright()
|
|
|
+ {
|
|
|
+ if (direction == 1 || direction == 3 || direction == 0) direction = 2;
|
|
|
+ }
|
|
|
+
|
|
|
+ void movedown()
|
|
|
+ {
|
|
|
+ if (direction == 4 || direction == 2 || direction == 0) direction = 3;
|
|
|
+ }
|
|
|
+
|
|
|
+ void moveleft()
|
|
|
+ {
|
|
|
+ if (direction == 1 || direction == 3 || direction == 0) direction = 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ void changespeed(unsigned long x)
|
|
|
+ {
|
|
|
+ speed = 250000 / x;
|
|
|
+ }
|
|
|
+
|
|
|
+ void reset(int fast)
|
|
|
+ {
|
|
|
+ int size = sections.size();
|
|
|
+
|
|
|
+ for (int i = 0; i < size; i++)
|
|
|
+ {
|
|
|
+ delete sections.at(i);
|
|
|
+ sections.erase(sections.begin() + i);
|
|
|
+ }
|
|
|
+
|
|
|
+ Section * newsec = new Section(x, y, 2, 2);
|
|
|
+ sections.insert(sections.begin(), newsec);
|
|
|
+ direction = 0;
|
|
|
+ blockSize = 25;
|
|
|
+ speed = 250000 / fast;
|
|
|
+ lastmove = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ Snake(int x, int y, Fruit * fruity, unsigned long fast): x(x), y(y), fruity(fruity)
|
|
|
+ {
|
|
|
+ Section * newsec = new Section(x, y, 2, 2);
|
|
|
+ sections.insert(sections.begin(), newsec);
|
|
|
+ direction = 0;
|
|
|
+ blockSize = 25;
|
|
|
+ speed = 250000 / fast;
|
|
|
+ lastmove = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ ~Snake()
|
|
|
+ {
|
|
|
+ int size = sections.size();
|
|
|
+
|
|
|
+ for (int i = 0; i < size; i++)
|
|
|
+ {
|
|
|
+ delete sections.at(i);
|
|
|
+ sections.erase(sections.begin() + i);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private:
|
|
|
+ int x;
|
|
|
+ int y;
|
|
|
+ vector<Section *> sections;
|
|
|
+ int blockSize;
|
|
|
+ int direction;
|
|
|
+ unsigned long speed;
|
|
|
+ int fruit;
|
|
|
+ Fruit * fruity;
|
|
|
+ unsigned long lastmove;
|
|
|
+};
|
|
|
+
|
|
|
+list<Displayable *> dList; // list of Displayables
|
|
|
+Fruit fruity;
|
|
|
+Snake snake(100, 450, &fruity, velocity);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Initialize X and create a window
|
|
|
+ */
|
|
|
+void initX(int argc, char * argv[], XInfo & xInfo)
|
|
|
+{
|
|
|
+ XSizeHints hints;
|
|
|
+ unsigned long white, black;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Display opening uses the DISPLAY environment variable.
|
|
|
+ * It can go wrong if DISPLAY isn't set, or you don't have permission.
|
|
|
+ */
|
|
|
+ xInfo.display = XOpenDisplay("");
|
|
|
+ if (!xInfo.display)
|
|
|
+ {
|
|
|
+ error("Can't open display.");
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Find out some things about the display you're using.
|
|
|
+ */
|
|
|
+ xInfo.screen = DefaultScreen(xInfo.display);
|
|
|
+
|
|
|
+ colours = DefaultColormap(xInfo.display, xInfo.screen);
|
|
|
+ white = XWhitePixel(xInfo.display, xInfo.screen);
|
|
|
+ black = XBlackPixel(xInfo.display, xInfo.screen);
|
|
|
+
|
|
|
+ hints.x = 100;
|
|
|
+ hints.y = 100;
|
|
|
+ hints.width = 800;
|
|
|
+ hints.height = 600;
|
|
|
+ hints.flags = PPosition | PSize;
|
|
|
+
|
|
|
+ xInfo.window = XCreateSimpleWindow
|
|
|
+ (
|
|
|
+ xInfo.display, // display where window appears
|
|
|
+ DefaultRootWindow( xInfo.display ), // window's parent in window tree
|
|
|
+ hints.x, hints.y, // upper left corner location
|
|
|
+ hints.width, hints.height, // size of the window
|
|
|
+ Border, // width of window's border
|
|
|
+ black, // window border colour
|
|
|
+ white
|
|
|
+ ); // window background colour
|
|
|
+
|
|
|
+ XSetStandardProperties
|
|
|
+ (
|
|
|
+ xInfo.display, // display containing the window
|
|
|
+ xInfo.window, // window whose properties are set
|
|
|
+ "animation", // window's title
|
|
|
+ "Animate", // icon's title
|
|
|
+ None, // pixmap for the icon
|
|
|
+ argv, argc, // applications command line args
|
|
|
+ &hints
|
|
|
+ ); // size hints for the window
|
|
|
+
|
|
|
+ int depth = DefaultDepth(xInfo.display, DefaultScreen(xInfo.display));
|
|
|
+ xInfo.buffer = XCreatePixmap(xInfo.display, xInfo.window, hints.width, hints.height, depth);
|
|
|
+ /*
|
|
|
+ * Create Graphics Contexts
|
|
|
+ */
|
|
|
+ int i = 0;
|
|
|
+ xInfo.gc[i] = XCreateGC(xInfo.display, xInfo.window, 0, 0);
|
|
|
+ XSetBackground(xInfo.display, xInfo.gc[0], WhitePixel(xInfo.display, xInfo.screen));
|
|
|
+ XSetFillStyle(xInfo.display, xInfo.gc[i], FillSolid);
|
|
|
+ XSetLineAttributes(xInfo.display, xInfo.gc[i],
|
|
|
+ 1, LineSolid, CapButt, JoinRound);
|
|
|
+
|
|
|
+ XSelectInput(xInfo.display, xInfo.window,
|
|
|
+ ButtonPressMask | KeyPressMask |
|
|
|
+ PointerMotionMask |
|
|
|
+ EnterWindowMask | LeaveWindowMask); // for resize events
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Put the window on the screen.
|
|
|
+ */
|
|
|
+ XMapRaised( xInfo.display, xInfo.window );
|
|
|
+ XFlush(xInfo.display);
|
|
|
+}
|
|
|
+
|
|
|
+void splash(XInfo & xinfo)
|
|
|
+{
|
|
|
+ //char * title = {'S', 'n', 'a', 'k', 'e', '\0'};
|
|
|
+ changecolour(xinfo, white);
|
|
|
+ XFillRectangle(xinfo.display, xinfo.buffer, xinfo.gc[0], 100, 100, 600, 400);
|
|
|
+ changecolour(xinfo, black);
|
|
|
+ XFontStruct * font = XLoadQueryFont(xinfo.display, "12x24");
|
|
|
+ XSetFont(xinfo.display, xinfo.gc[0], font->fid);
|
|
|
+ XDrawString(xinfo.display, xinfo.buffer, xinfo.gc[0], 350, 200, "Snake", 5);
|
|
|
+ XDrawString(xinfo.display, xinfo.buffer, xinfo.gc[0], 340, 240, "tsdedhar", 8);
|
|
|
+ XDrawString(xinfo.display, xinfo.buffer, xinfo.gc[0], 340, 280, "20621325", 8);
|
|
|
+ XDrawString(xinfo.display, xinfo.buffer, xinfo.gc[0], 265, 320, "Use arrow keys to turn", 22);
|
|
|
+ XDrawString(xinfo.display, xinfo.buffer, xinfo.gc[0], 200, 360, "Collect fruit to grow your snake", 32);
|
|
|
+}
|
|
|
+/*
|
|
|
+ * Function to repaint a display list
|
|
|
+ */
|
|
|
+void repaint(XInfo & xinfo)
|
|
|
+{
|
|
|
+ list<Displayable *>::const_iterator begin = dList.begin();
|
|
|
+ list<Displayable *>::const_iterator end = dList.end();
|
|
|
+
|
|
|
+ // get height and width of window (might have changed since last repaint)
|
|
|
+ XWindowAttributes windowInfo;
|
|
|
+ XGetWindowAttributes(xinfo.display, xinfo.window, &windowInfo);
|
|
|
+ unsigned int height = windowInfo.height;
|
|
|
+ unsigned int width = windowInfo.width;
|
|
|
+ changecolour(xinfo, lblue);
|
|
|
+ XFillRectangle(xinfo.display, xinfo.buffer, xinfo.gc[0], 0, 0, width, height);
|
|
|
+ changecolour(xinfo, black);
|
|
|
+
|
|
|
+ // draw display list
|
|
|
+ while (begin != end)
|
|
|
+ {
|
|
|
+ Displayable * d = *begin;
|
|
|
+ d->paint(xinfo);
|
|
|
+ begin++;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (starting) splash(xinfo);
|
|
|
+}
|
|
|
+
|
|
|
+void handleKeyPress(XInfo & xinfo, XEvent & event)
|
|
|
+{
|
|
|
+ KeySym key;
|
|
|
+ char text[BufferSize];
|
|
|
+ int i = XLookupString
|
|
|
+ (
|
|
|
+ (XKeyEvent *)&event, // the keyboard event
|
|
|
+ text, // buffer when text will be written
|
|
|
+ BufferSize, // size of the text buffer
|
|
|
+ &key, // workstation-independent key symbol
|
|
|
+ NULL
|
|
|
+ );
|
|
|
+
|
|
|
+ if (i == 1)
|
|
|
+ {
|
|
|
+ printf("Got key press -- %c\n", text[0]);
|
|
|
+
|
|
|
+ switch(text[0])
|
|
|
+ {
|
|
|
+ case 'q':
|
|
|
+ error("Terminating normally.");
|
|
|
+ break;
|
|
|
+
|
|
|
+ case ' ':
|
|
|
+ paused = !paused;
|
|
|
+ starting = false;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 'r':
|
|
|
+ snake.reset(velocity);
|
|
|
+ paused = true;
|
|
|
+ starting = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key == XK_Up)
|
|
|
+ {
|
|
|
+ snake.moveup();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key == XK_Right)
|
|
|
+ {
|
|
|
+ snake.moveright();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key == XK_Down)
|
|
|
+ {
|
|
|
+ snake.movedown();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (key == XK_Left)
|
|
|
+ {
|
|
|
+ snake.moveleft();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void handleAnimation(XInfo & xinfo, int inside)
|
|
|
+{
|
|
|
+ snake.move(xinfo);
|
|
|
+}
|
|
|
+
|
|
|
+void eventLoop(XInfo & xinfo)
|
|
|
+{
|
|
|
+ // Add stuff to paint to the display list
|
|
|
+ dList.push_front(&snake);
|
|
|
+ dList.push_front(&fruity);
|
|
|
+ XEvent event;
|
|
|
+ unsigned long lastRepaint = 0;
|
|
|
+ int inside = 0;
|
|
|
+ XWindowAttributes w;
|
|
|
+ XGetWindowAttributes(xinfo.display, xinfo.window, &w);
|
|
|
+
|
|
|
+ while(1)
|
|
|
+ {
|
|
|
+ if (XPending(xinfo.display) > 0)
|
|
|
+ {
|
|
|
+ XNextEvent(xinfo.display, &event);
|
|
|
+
|
|
|
+ switch(event.type)
|
|
|
+ {
|
|
|
+ case KeyPress:
|
|
|
+ handleKeyPress(xinfo, event);
|
|
|
+ break;
|
|
|
+ case EnterNotify:
|
|
|
+ inside = 1;
|
|
|
+ break;
|
|
|
+ case LeaveNotify:
|
|
|
+ inside = 0;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ unsigned long end = now();
|
|
|
+
|
|
|
+ if (end - lastRepaint > 1000000 / FPS)
|
|
|
+ {
|
|
|
+ handleAnimation(xinfo, inside);
|
|
|
+ repaint(xinfo);
|
|
|
+ XCopyArea(xinfo.display, xinfo.buffer, xinfo.window, xinfo.gc[0], 0, 0 , w.width, w.height, 0, 0);
|
|
|
+ XFlush(xinfo.display);
|
|
|
+ lastRepaint = now();
|
|
|
+ }
|
|
|
+
|
|
|
+ if (XPending(xinfo.display) == 0)
|
|
|
+ {
|
|
|
+ usleep(1000000 / FPS - (end - lastRepaint));
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * Start executing here.
|
|
|
+ * First initialize window.
|
|
|
+ * Next loop responding to events.
|
|
|
+ * Exit forcing window manager to clean up - cheesy, but easy.
|
|
|
+ */
|
|
|
+int main (int argc, char * argv[])
|
|
|
+{
|
|
|
+ if (argc == 1)
|
|
|
+ {
|
|
|
+ }
|
|
|
+ else if (argc == 3)
|
|
|
+ {
|
|
|
+ FPS = atoi(argv[1]);
|
|
|
+ velocity = atoi(argv[2]);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ printf("you're shit\n");
|
|
|
+ exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ snake.changespeed(velocity);
|
|
|
+ XInfo xInfo;
|
|
|
+ initX(argc, argv, xInfo);
|
|
|
+ eventLoop(xInfo);
|
|
|
+ XCloseDisplay(xInfo.display);
|
|
|
+}
|