[MULTI-MODE PACMAN · Our game offers the player(s) the choice of playing alone or one-on –one....
Transcript of [MULTI-MODE PACMAN · Our game offers the player(s) the choice of playing alone or one-on –one....
CEDT OSCILLOSCOPE GAME-DESIGN CONTEST
TEAM MEMBERS: DIBAKAR BARUA ECE 2nd year PRANSHU JAIN ECE 2nd year JITESH GUPTA ECE 2nd year
[MULTI-MODE PACMAN] MODERN RENDITION OF PACMAN WHICH ALLOWS SINGLE AND MULTIPLAYER GAMEPLAY (displayed on an oscilloscope)
2
S.NO.
CHAPTER
PAGE NO.
1.
Introduction
3`
2.
Hardware
4
3.
Software Implementation
7
4.
Appendix (A)
8
5.
Appendix (B)
9
6.
Appendix (C)
38
3
INTRODUCTION
The 80’s were considered the golden age of Arcade games, an era which saw the
gaming industry grow and experience a revolution. At the forefront of this
revolution was Pacman. One of the most popular and highest selling games of all
time, Pacman is considered one of the landmarks in Video Game development
history. That is why, for our CEDT Oscilloscope Design project, we decided to
recreate the magic of pacman, but on an oscilloscope instead of a television
screen. Our game offers the player(s) the choice of playing alone or one-on –one.
In the multiplayer mode, the players take turns playing as the ghost and the
pacman. The player who eats the maximum food before being eaten by the ghost
(opponent), wins. In the single player mode, the player is supposed to eat the
maximum amount of food possible, as the ghost chases him.
(SNAPSHOT OF THE GAME)
4
HARDWARE
1. Microcontroller
The control unit for our project was the Arduino Uno board, an open source
protoryping platform. Based upon the ATmega 328 microcontroller, the Arduino
comes with a 16MHZ crystal oscillator, which created some hurdles for us as our
Oscilloscope had a much higher sampling rate. However as an advantage we did
not have to include a delay in any of the instructions as the screen refresh rate
was perfect with the higher oscilloscope sampling rate.
2. Interfacing
We used two 8 bit DAC’s (Digital to Analog Converters) to interface our Arduino
board with the oscilloscope. For this 14 of the digital pins and 4 of the analog pins
were used. The schematic for the same is shown below.
The D0-D7 pins correspond to the digital/analog pins on the arduino.
For interfacing the controllers, which were simple 4/5 pushbutton based, we used
a simple resistive network as shown below.
5
3. OSCILLOSCOPE
Conventional usage of the oscilloscope runs in YT mode, where each voltage
signal detected on the various probes is displayed as a function of time. However,
most oscilloscopes also have an XY mode, which allows inputs to be plotted as
functions of each other; the voltage reading on one probe determines the
horizontal component and the reading on the other determines the vertical
component. According to common oscilloscope manuals, the XY mode is used
primarily for measuring the phase shift of two input waveforms.
(THE ENTIRE SETUP)
6
4. BLOCK DIAGRAM
ARDUINO
CONTROLLER 1
CONTROLLER 2
OSCILLOSCOPE DISPLAY
DAC2
DAC1
7
SOFTWARE IMPLEMENTATION
The code for the software implementation for our Pacman was written on the
Arduino IDE version 1.0. We used a down-top approach to code as the most basic
parts of the program were written first. The entire basis of our code is the
point(x,y) function that we have used. It sends 8 bit digital values to the 2 DAC’s
which after being converted to a value between 0 and Vcc(5v) is displayed on the
Oscilloscope as a point. Using the point function we wrote several other functions
for drawing other figures such as a line, a circle and the pacman.
A major hurdle was to optimize the code to reduce the number of samples being
processed so that the final image on the oscilloscope would not flicker.
The basic process for our software (as displayed on the oscilloscope) is detailed
below. The entire code is provided in Appendix B.
GAME PROCESS:
1. Display PACMAN on oscilloscope screen for 10 seconds.
2. Ask user to choose from single/multiplayer modes. If user chooses, start
the game and if he doesn’t, then start the Single player mode.
3. Pacman eats as many food counters as possible out of a maximum five as
the ghost chases him. The food counters are displayed after the last one is
eaten.
4. In multiplayer mode the players take turns in controlling the pacman and
the ghost respectively.
After one player’s turn is over, display his score. After both player’s turn is
over, display which player wins.
5. After the game is over, pressing the red button restarts the game.
8
APPENDIX (A)
CODE TAGS:
Here we have listed some of the important functions that we have implemented
in our code and their usages.
1. void point (x,y)
Undoubtedly the backbone of program, this small function convert any value from
0 to 255 to an analog voltage by digitally writing the output pins of our arduino
onto our DACs. We have implemented the bit masking process for the same.
Bit masking: To turn certain bits on, the bitwise OR operation can be used, following the principle that Y OR 1 = 1 and Y OR 0 = Y. Therefore, to make sure a bit is on, OR can be used with a 1. To leave a bit unchanged, OR is used with a 0.
2. void pacman (t1,t2)
This function simply generates the pacman on any of the 4 phases (up, down, left, right) by taking two arguments for its start and end angles.
3. Void line (x1,y1,x2,y2)
The most frequently called function in our program, this function generated a line between 2 points. An initial hurdle was to reduce the number of samples being processed as it depended upon the distance between the points. So we fixed this at 20 samples hence reducing the number of clock cycles and screen flickering. This function allowed us to create all the text characters on our oscilloscope screen.
9
APPENDIX (B)
CODE:
#include<avr/io.h>
#define pin A0
#define pin1 A1
byte a,b;
float t=0;
float t1=PI/4;
float t2=7*PI/4;
int i;
int
x,y,xfood1=198,yfood1=54,xfood2=198,yfood2=198,xfood3=54,yfood3=198,xfood
4=40,yfood4=40,xfood5=170,yfood5=170;
int xc=128;
int diff1, diff2;
int yc = 128;
int r = 20;
int rf;
char d,w,q,s;
int visible1=1;
int visible2=0;
int visible3=0;
10
int visible4=0;
int visible5=0;
int count = 0;
int countfood2 = 0;
int countfood3 = 0;
int countfood4 = 0;
int countfood5 = 0;
int value;
int value2;
int timestart;
int gx=40;
int gy=80;
int gx2=40;
int gy2=40;
int scorecount=0;
int gametype =0; //to identify 1 player game or 2 player game(not same as
"count")
int runcount =0; // a counter to run multiplayer game only 2 times
int score1;
int score2;
void setup()
{
11
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
pinMode(16,OUTPUT);
pinMode(17,OUTPUT);
pinMode(18,OUTPUT);
pinMode(19,OUTPUT);
value = analogRead(A0);
value2 = analogRead(A1);
timestart = millis();
while((millis() - timestart) <= 5000)
{
//openscreen
12
for(x=10;x<=250;x++)
{
line(x,90,x,150);
line(x,150,x+30,150);
line(x+30,120,x+30,150);
line(x,120,x+30,150);
line(x+40,90,x+40,150);
line(x+40,150,x+70,150);
line(x+40,120,x+70,120);
line(x+70,90,x+70,150);
line(x+80,90,x+80,150);
line(x+80,90,x+110,90);
line(x+80,150,x+110,150);
line(x+120,90,x+120,150);
line(x+120,150,x+135,120);
line(x+135,120,x+150,150);
line(x+150,90,x+150,150);
line(x+160,90,x+175,150);
line(x+175,150,x+190,90);
line(x+170,120,x+180,120);
line(x+200,90,x+200,150);
line(x+200,150,x+230,90);
13
line(x+230,90,x+230,150);
}
}
timestart = millis();
while((millis() - timestart) <= 10000)
{
value = analogRead(A0);
//displaysingleplayer
line(30,170,45,200);
line(45,140,45,200);
line(30,140,60,140);
point(75,140);
line(90,140,120,140);
line(120,140,120,170);
line(90,170,120,170);
line(90,170,90,200);
line(90,200,120,200);
point(135,140);
line(150,140,150,200);
line(150,170,180,170);
line(150,200,180,200);
line(180,170,180,200);
14
//displaymultiplayer
line(30,60,30,90);
line(30,60,60,60);
line(30,90,60,90);
line(30,120,60,120);
line(60,90,60,120);
point(75,60);
line(90,60,90,120);
line(90,120,105,90);
line(105,90,120,120);
line(120,60,120,120);
point(135,60);
line(150,60,150,120);
line(150,90,180,90);
line(150,120,180,120);
line(180,90,190,120);
if(value<950)
{
if ((value>450)&&(value<550))
{
count = 0;
break;
15
}
else if((value>750)&&(value<850))
{
count = 1;
break;
}
}
}
}
void loop()
{
maze();
for(x=gx-r;x<=gx+r;x++)
{
for(y = gy-r; y<=gy + r;y++)
{
if((x==xc) && (y==yc))
{
count=count + 2;
}
}
}
16
for(x=gx2-r;x<=gx2+r;x++)
{
for(y = gy2-r; y<=gy2 + r;y++)
{
if((x==xc) && (y==yc))
{
count++;
}
}
}
if(count == 0)
{
gametype=0;
value = analogRead(A0);
if(value<950)
{
if ((value>450)&&(value<550))
{
t1=PI/4;
t2=7*PI/4;
xc+=2;
}
17
else if((value>750)&&(value<850))
{
t1=5*PI/4;
t2=11*PI/4;
xc-=2;
}
else if((value>=0)&&(value<100))
{
t1=3*PI/4;
t2=9*PI/4;
yc+=2;
}
else if((value>600)&&(value<700))
{
t1=7*PI/4;
t2=13*PI/4;
yc-=2;
}
}
pacman(xc,yc);
18
ghost(gx,gy);
value2=analogRead(A1);
if(value2<850)
{
if((value2<370)&&(value2>300))
{
gx+=2;
}
else if((value2<710)&&(value2>650))
{
gx-=2;
}
else if((value2<100)&&(value2>=0))
{
gy+=2;
}
else if((value2<550)&&(value2>490))
{
gy-=2;
}
19
}
for(x= xc - r;x <= xc + r; x++)
{
for(y = yc - r; y <= yc + r; y++)
{
if((x == xfood1)&&(y == yfood1)&&(visible1==1))
{
visible1=0;
visible2=1;
scorecount++;
}
}
}
if(visible1)
{
drawcircle(xfood1,yfood1);
}
for(x = xc - r; x<= xc + r; x++)
{
for(y = yc - r; y<= yc + r; y++)
{
if((x == xfood2)&&(y == yfood2)&&(visible2==1))
20
{
visible2 = 0;
visible3 = 1;
scorecount++;
}
}
}
if(visible2)
{
drawcircle(xfood2,yfood2);
}
for(x = xc - r; x <= xc + r; x++)
{
for(y = yc -r; y <= yc + r; y++)
{
if((x == xfood3)&&(y==yfood3)&&(visible3==1))
{
visible3 = 0;
visible4 = 1;
scorecount++;
}
}
21
}
if (visible3)
{
drawcircle(xfood3,yfood3);
}
for(x = xc - r; x <= xc + r; x++)
{
for(y = yc -r; y <= yc + r; y++)
{
if((x == xfood4)&&(y==yfood4)&&(visible4==1))
{
visible4 = 0;
visible5 = 1;
scorecount++;
}
}
}
if(visible4)
{
drawcircle(xfood4,yfood4);
}
for(x = xc - r; x <= xc + r; x++)
22
{
for(y = yc -r; y <= yc + r; y++)
{
if((x == xfood5)&&(y==yfood5)&&(visible5==1))
{
visible5 = 0;
scorecount++;
count++;
}
}
}
if(visible5)
{
drawcircle(xfood5,yfood5);
}
}
else if(count == 1)
{
gametype=1;
value = analogRead(A0);
int speedghost = 1;
23
if(value<950)
{
if ((value>450)&&(value<550))
{
t1=PI/4;
t2=7*PI/4;
xc+=2;
}
else if((value>750)&&(value<850))
{
t1=5*PI/4;
t2=11*PI/4;
xc-=2;
}
else if((value>=0)&&(value<100))
{
t1=3*PI/4;
t2=9*PI/4;
yc+=2;
}
24
else if((value>600)&&(value<700))
{
t1=7*PI/4;
t2=13*PI/4;
yc-=2;
}
}
pacman(xc,yc);
ghost2(gx2,gy2);
diff1 = xc - gx2;
diff2 = yc - gy2;
if((diff1 == 0) && (diff2 == 0))
{
speedghost = 0;
}
if((diff1 >= 0) && (diff2 >= 0))
{
gx2 += speedghost;
gy2 += speedghost;
}
if((diff1 >= 0) && (diff2 <= 0))
{
25
gx2 += speedghost;
gy2 -= speedghost;
}
if((diff1 <= 0) && (diff2 >= 0))
{
gx2 -= speedghost;
gy2 += speedghost;
}
if((diff1 <= 0) && (diff2 <= 0))
{
gx2 -= speedghost;
gy2 -= speedghost;
}
for(x= xc - r;x <= xc + r; x++)
{
for(y = yc - r; y <= yc + r; y++)
{
if((x == xfood1)&&(y == yfood1)&&(visible1==1))
{
visible1=0;
visible2=1;
scorecount++;
26
}
}
}
if(visible1)
{
drawcircle(xfood1,yfood1);
}
for(x = xc - r; x<= xc + r; x++)
{
for(y = yc - r; y<= yc + r; y++)
{
if((x == xfood2)&&(y == yfood2)&&(visible2==1))
{
visible2 = 0;
visible3 = 1;
scorecount++;
}
}
}
if(visible2)
{
drawcircle(xfood2,yfood2);
27
}
for(x = xc - r; x <= xc + r; x++)
{
for(y = yc -r; y <= yc + r; y++)
{
if((x == xfood3)&&(y==yfood3)&&(visible3==1))
{
visible3 = 0;
visible4 = 1;
scorecount++;
}
}
}
if (visible3)
{
drawcircle(xfood3,yfood3);
}
for(x = xc - r; x <= xc + r; x++)
{
for(y = yc -r; y <= yc + r; y++)
{
if((x == xfood4)&&(y==yfood4)&&(visible4==1))
28
{
visible4 = 0;
visible5 = 1;
scorecount++;
}
}
}
if(visible4)
{
drawcircle(xfood4,yfood4);
}
for(x = xc - r; x <= xc + r; x++)
{
for(y = yc -r; y <= yc + r; y++)
{
if((x == xfood5)&&(y==yfood5)&&(visible5==1))
{
visible5 = 0;
scorecount++;
count++;
}
29
}
}
if(visible5)
{
drawcircle(xfood5,yfood5);
}
}
else if(count == 2)
{
value2 = analogRead(A1);
timestart = millis();
while((millis() - timestart) <= 5000)
{
line(30,60,60,60);
line(30,60,30,120);
line(30,120,60,120);
line(60,60,60,120);
line(70,120,85,60);
line(85,60,100,120);
line(110,60,110,120);
line(110,120,140,120);
line(110,90,140,90);
30
line(110,60,140,60);
line(150,60,150,120);
line(150,120,180,120);
line(180,90,180,120);
line(150,90,180,90);
line(150,90,180,60);
score(scorecount);
}
if((gametype == 0) && (runcount == 0))
{
count = 0;
gx= 40;
gy= 80;
xc = 128;
yc = 128;
runcount++;
score1 = scorecount;
scorecount = 0;
timestart = millis();
while((millis() - timestart) <= 3000)
{
line(30,150,60,150);
31
line(30,180,60,180);
line(30,120,30,180);
line(60,150,60,180);
line(70,180,100,180);
line(70,150,100,150);
line(70,120,100,120);
line(70,120,70,150);
line(100,150,100,180);
}
}
else if((gametype == 0) && (runcount == 1))
{
score2 = scorecount;
scorecount=0;
timestart = millis();
while((millis() - timestart) <= 3000)
{
winner(score1,score2);
}
count = 0;
gx= 40;
gy= 80;
32
xc = 128;
yc = 128;
setup();
}
else if(gametype == 1)
{
scorecount = 0;
gx= 40;
gy= 80;
xc = 128;
yc = 128;
setup();
}
}
}
void winner(int score1,int score2)
{
if(score1>score2)
{
//print "P1 WINS"
line(30,150,60,150);
33
line(30,180,60,180);
line(30,120,30,180);
line(60,150,60,180);
line(70,120,100,120);
line(85,120,85,180);
line(70,150,85,180);
line(110,120,110,180);
line(140,120,140,180);
line(110,120,125,150);
line(125,150,140,120);
line(165,120,165,180);
line(180,120,180,180);
line(180,180,210,120);
line(210,120,210,180);
line(220,120,250,120);
line(220,180,250,180);
line(220,150,250,150);
line(220,150,220,180);
line(250,120,250,150);
}
else if(score2>score1)
{
34
//print "P2 WINS"
line(30,150,60,150);
line(30,180,60,180);
line(30,120,30,180);
line(60,150,60,180);
line(70,180,100,180);
line(70,150,100,150);
line(70,120,100,120);
line(70,120,70,150);
line(100,150,100,180);
line(110,120,110,180);
line(140,120,140,180);
line(110,120,125,150);
line(125,150,140,120);
line(165,120,165,180);
line(180,120,180,180);
line(180,180,210,120);
line(210,120,210,180);
line(220,120,250,120);
line(220,180,250,180);
line(220,150,250,150);
line(220,150,220,180);
35
line(250,120,250,150);
}
else if(score1==score2)
{
//print "TIE"
line(90,180,120,180);
line(105,120,105,180);
line(145,120,145,180);
line(170,120,200,120);
line(170,150,200,150);
line(170,180,200,180);
line(170,120,170,180);
}
}
void score(int scorecount)
{
if(scorecount == 0)
{
line(200,2,230,2);
line(200,2,200,50);
line(200,50,230,50);
line(230,2,230,50);
36
}
else if(scorecount == 1)
{
line(200,25,215,50);
line(215,2,215,50);
line(200,2,230,2);
}
else if(scorecount == 2)
{
line(200,50,230,50);
line(230,25,230,50);
line(200,25,230,25);
line(200,2,200,25);
}
else if(scorecount == 3)
{
line(200,50,230,50);
line(200,25,230,25);
line(200,2,230,2);
line(230,2,230,50);
}
else if(scorecount == 4)
37
{
line(200,25,200,50);
line(200,25,230,25);
line(230,2,230,50);
}
else if(scorecount == 5)
{
line(200,50,230,50);
line(200,2,230,2);
line(200,25,200,50);
line(200,25,230,25);
line(230,2,230,25);
}
}
inline void maze()
{
line(0,0,0,252);
line(0,252,252,252);
line(252,0,252,252);
line(0,0,252,0);
}
void drawcircle(int xc, int yc)
38
{
int j;
rf=5;
for(t=0;t<=(2*PI);t=t+(PI/16))
{
x = xc + rf*cos(t);
y = yc + rf*sin(t);
point(x,y);
}
}
void pacman(int xc, int yc)
{
int j;
float te,ts;
for(te=t1,ts=t2;te>=0;te = te - (PI/8),ts = ts + (PI/8))
{
for(t=te;t<=ts;t=t+(PI/8))
{
x = xc + r*cos(t);
y = yc + r*sin(t);
point(x,y);
}
39
line(xc,yc,(xc + r*cos(t1)),(yc + r*sin(t1)));
line(xc,yc,(xc + r*cos(t2)),(yc + r*sin(t2)));
}
}
void ghost2(int gx2, int gy2)
{
int j;
for(t=0;t<=PI;t=t+(PI/8))
{
x = gx2 + r*cos(t);
y = gy2 + r*sin(t);
point(x,y);
}
line(gx2-r,gy2,gx2+r,gy2);
}
void ghost(int gx, int gy)
{
int j;
for(t=0;t<=PI;t=t+(PI/8))
{
x = gx + r*cos(t);
y = gy + r*sin(t);
40
point(x,y);
}
line(gx-r,gy,gx+r,gy);
}
void line(int x1, int y1, int x2, int y2)
{
int c;
for(c=0;c<=20;c++)
{
x = x1 + (c*(x2 - x1)/20);
y = y1 + (c*(y2 - y1)/20);
point(x,y);
}
}
void point(int x,int y)
{
a=byte(x);
b=byte(y);
digitalWrite(13,(x&128)>0);
digitalWrite(12,(x&64)>0);
41
digitalWrite(11,(x&32)>0);
digitalWrite(10,(x&16)>0);
digitalWrite(9,(x&8)>0);
digitalWrite(8,(x&4)>0);
digitalWrite(7,(x&2)>0);
digitalWrite(6,(x&1)>0);
digitalWrite(16,(y&128)>0);
digitalWrite(17,(y&64)>0);
digitalWrite(18,(y&32)>0);
digitalWrite(19,(y&16)>0);
digitalWrite(2,(y&8)>0);
digitalWrite(3,(y&4)>0);
digitalWrite(4,(y&2)>0);
digitalWrite(5,(y&1)>0);
}
42
APPENDIX (C)
ARDUINO SCHEMATIC: