|
@@ -13,6 +13,7 @@ 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>
|
|
@@ -32,9 +33,10 @@ using namespace std;
|
|
|
*/
|
|
|
const int Border = 1;
|
|
|
const int BufferSize = 10;
|
|
|
-const int FPS = 60;
|
|
|
-const int width = 600;
|
|
|
+const int FPS = 30;
|
|
|
+const int width = 800;
|
|
|
const int height = 600;
|
|
|
+const int blockSize = 25;
|
|
|
|
|
|
/*
|
|
|
* Information to draw on the window.
|
|
@@ -69,7 +71,35 @@ class Displayable
|
|
|
virtual void paint(XInfo & xinfo) = 0;
|
|
|
};
|
|
|
|
|
|
-class Snake : public Displayable
|
|
|
+class Fruit : public Displayable
|
|
|
+{
|
|
|
+ public:
|
|
|
+ virtual void paint(XInfo & xinfo)
|
|
|
+ {
|
|
|
+ XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, 25, 25);
|
|
|
+ }
|
|
|
+
|
|
|
+ Fruit()
|
|
|
+ {
|
|
|
+ newspot();
|
|
|
+ }
|
|
|
+
|
|
|
+ void newspot()
|
|
|
+ {
|
|
|
+ x = (rand() % 800);
|
|
|
+ y = (rand() % 600);
|
|
|
+ }
|
|
|
+ // ** 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)
|
|
@@ -77,174 +107,210 @@ class Snake : public Displayable
|
|
|
switch(direction)
|
|
|
{
|
|
|
case 1:
|
|
|
- XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, blockSize, 25);
|
|
|
+ XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, blockSize, len * blockSize);
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
- XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, 25, blockSize);
|
|
|
+ XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], (x - len * blockSize), y, len * blockSize, blockSize);
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
- XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, blockSize, 25);
|
|
|
+ XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, (y - len * blockSize), blockSize, len * blockSize);
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
- XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, 25, blockSize);
|
|
|
+ XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, len * blockSize, blockSize);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- void move(XInfo &xinfo)
|
|
|
+ void increment(int x)
|
|
|
+ {
|
|
|
+ len += x;
|
|
|
+ }
|
|
|
+
|
|
|
+ void decrement()
|
|
|
+ {
|
|
|
+ --len;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool empty()
|
|
|
+ {
|
|
|
+ return (!len);
|
|
|
+ }
|
|
|
+
|
|
|
+ void grow()
|
|
|
{
|
|
|
switch(direction)
|
|
|
{
|
|
|
case 1:
|
|
|
- y -= speed;
|
|
|
+ y -= blockSize;
|
|
|
break;
|
|
|
|
|
|
case 2:
|
|
|
- x += speed;
|
|
|
+ x += blockSize;
|
|
|
break;
|
|
|
|
|
|
case 3:
|
|
|
- y += speed;
|
|
|
+ y += blockSize;
|
|
|
break;
|
|
|
|
|
|
case 4:
|
|
|
- x -= speed;
|
|
|
+ x -= blockSize;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (x > width || y < 0)
|
|
|
+ ++len;
|
|
|
+ }
|
|
|
+
|
|
|
+ int getx()
|
|
|
+ {
|
|
|
+ return x;
|
|
|
+ }
|
|
|
+
|
|
|
+ int gety()
|
|
|
+ {
|
|
|
+ return y;
|
|
|
+ }
|
|
|
+
|
|
|
+ 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)
|
|
|
+ {
|
|
|
+ // 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() == 50 || sections.front()->gety() == 50)
|
|
|
+ {
|
|
|
+ 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())
|
|
|
{
|
|
|
- direction += 2;
|
|
|
+ delete sections.back();
|
|
|
+ sections.pop_back();
|
|
|
}
|
|
|
|
|
|
- if (x < 0 || y > height)
|
|
|
+ if (sections.front()->getx() > width || sections.front()->gety() < 0)
|
|
|
{
|
|
|
- direction -= 2;
|
|
|
+ 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);
|
|
|
+ }
|
|
|
// ** ADD YOUR LOGIC **
|
|
|
// Here, you will be performing collision detection between the snake,
|
|
|
// the fruit, and the obstacles depending on what the snake lands on.
|
|
|
}
|
|
|
|
|
|
- int getX()
|
|
|
+ /*
|
|
|
+ * ** ADD YOUR LOGIC **
|
|
|
+ * Use these placeholder methods as guidance for implementing the snake behaviour.
|
|
|
+ * You do not have to use these methods, feel free to implement your own.
|
|
|
+ */
|
|
|
+ void didEatFruit()
|
|
|
{
|
|
|
- return x;
|
|
|
- }
|
|
|
|
|
|
- int getY()
|
|
|
+ }
|
|
|
+
|
|
|
+ void didHitObstacle()
|
|
|
{
|
|
|
- return y;
|
|
|
- }
|
|
|
|
|
|
- /*
|
|
|
- * ** ADD YOUR LOGIC **
|
|
|
- * Use these placeholder methods as guidance for implementing the snake behaviour.
|
|
|
- * You do not have to use these methods, feel free to implement your own.
|
|
|
- */
|
|
|
- void didEatFruit()
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- void didHitObstacle()
|
|
|
- {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- void moveup()
|
|
|
- {
|
|
|
- if (direction == 4 || direction == 2) direction = 1;
|
|
|
- }
|
|
|
-
|
|
|
- void moveright()
|
|
|
- {
|
|
|
- if (direction == 1 || direction == 3) direction = 2;
|
|
|
- }
|
|
|
-
|
|
|
- void movedown()
|
|
|
- {
|
|
|
- if (direction == 4 || direction == 2) direction = 3;
|
|
|
- }
|
|
|
-
|
|
|
- void moveleft()
|
|
|
- {
|
|
|
- if (direction == 1 || direction == 3) direction = 4;
|
|
|
- }
|
|
|
-
|
|
|
- void turnLeft()
|
|
|
- {
|
|
|
- if (direction != 1)
|
|
|
- {
|
|
|
- --direction;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- direction = 4;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- void turnRight()
|
|
|
- {
|
|
|
- if (direction != 4)
|
|
|
- {
|
|
|
- ++direction;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- direction = 1;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- Snake(int x, int y): x(x), y(y)
|
|
|
+ }
|
|
|
+
|
|
|
+ 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()
|
|
|
{
|
|
|
- direction = 2;
|
|
|
- blockSize = 10;
|
|
|
- speed = 5;
|
|
|
+ if (direction == 1 || direction == 3 || direction == 0) direction = 4;
|
|
|
+ }
|
|
|
+
|
|
|
+ Snake(int x, int y, Fruit * fruity): x(x), y(y), fruity(fruity)
|
|
|
+ {
|
|
|
+ Section * newsec = new Section(x, y, 2, 2);
|
|
|
+ sections.insert(sections.begin(), newsec);
|
|
|
+ direction = 0;
|
|
|
+ blockSize = 25;
|
|
|
+ speed = 1;
|
|
|
}
|
|
|
|
|
|
+ ~Snake()
|
|
|
+ {
|
|
|
+ for (auto each = sections.begin(); each != sections.end(); ++each)
|
|
|
+ {
|
|
|
+ delete *(sections.erase(each));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
private:
|
|
|
int x;
|
|
|
int y;
|
|
|
+ vector<Section *> sections;
|
|
|
int blockSize;
|
|
|
int direction;
|
|
|
int speed;
|
|
|
+ int fruit;
|
|
|
+ Fruit * fruity;
|
|
|
};
|
|
|
|
|
|
-class Fruit : public Displayable
|
|
|
-{
|
|
|
- public:
|
|
|
- virtual void paint(XInfo & xinfo)
|
|
|
- {
|
|
|
- XFillRectangle(xinfo.display, xinfo.window, xinfo.gc[0], x, y, 10, 10);
|
|
|
- }
|
|
|
-
|
|
|
- Fruit()
|
|
|
- {
|
|
|
- // ** ADD YOUR LOGIC **
|
|
|
- // generate the x and y value for the fruit
|
|
|
- x = 50;
|
|
|
- y = 50;
|
|
|
- }
|
|
|
-
|
|
|
- // ** 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;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
list<Displayable *> dList; // list of Displayables
|
|
|
-Snake snake(100, 450);
|
|
|
-Fruit fruit;
|
|
|
-
|
|
|
+Fruit fruity;
|
|
|
+Snake snake(100, 450, &fruity);
|
|
|
|
|
|
/*
|
|
|
* Initialize X and create a window
|
|
@@ -274,7 +340,7 @@ void initX(int argc, char * argv[], XInfo & xInfo)
|
|
|
|
|
|
hints.x = 100;
|
|
|
hints.y = 100;
|
|
|
- hints.width = 600;
|
|
|
+ hints.width = 800;
|
|
|
hints.height = 600;
|
|
|
hints.flags = PPosition | PSize;
|
|
|
|
|
@@ -425,7 +491,7 @@ void eventLoop(XInfo & xinfo)
|
|
|
{
|
|
|
// Add stuff to paint to the display list
|
|
|
dList.push_front(&snake);
|
|
|
- dList.push_front(&fruit);
|
|
|
+ dList.push_front(&fruity);
|
|
|
|
|
|
XEvent event;
|
|
|
unsigned long lastRepaint = 0;
|