Visvesvaraya Technological University Belagavi-590 018, Karnataka
Visvesvaraya Technological University Belagavi-590 018, Karnataka
“PAC-MAN GAME”
Mini Project Report submitted in partial fulfilment of the requirement for the
Computer Graphics Laboratory with Mini Project [18CSL67]
Bachelor of Engineering
in
Computer Science and Engineering
Submitted by
Satvik R K 1JT19CS082
Ranjith Kumar 1JT19CS071
CERTIFICATE
Certified that the mini project work entitled “Pac-man game” carried out by
Satvik R Kundargi[1JT19CS082],Ranjith Kumar R [1JT19CS071],
bonafide students of Jyothy Institute of Technology, in partial fulfilment for
the award of Bachelor of Engineering in Computer Science and
Engineering department of the Visvesvaraya Technological University,
Belagavi during academic the year 2021-2022. It is certified that all
corrections/suggestions indicated for Internal Assessment have been
incorporated in the Report deposited in the departmental library. The project
report has been approved as it satisfies the academic requirements in respect of
Project work prescribed for the said Degree.
2
ACKNOWLEDGEMENT
Firstly, we are very grateful to this esteemed institution “Jyothy Institute of Technology”
for providing us an opportunity to complete our project.
We express our sincere thanks to our Principal Dr. Gopalakrishna K for providing us with
adequate facilities to undertake this project.
We would like to thank Dr. Prabhanjan S, Professor and Head of Computer Science and
Engineering Department for providing his valuable support.
We would like to thank our guide Mr. Vallabh Mahale, Assistant Professor for his keen
interest and guidance in preparing this work.
Finally, we would thank all our friends who have helped us directly or indirectly in this
project.
Satvik R Kundargi-1JT19CS082
Ranjith Kumar R-1JT19CS071
3
ABSTRACT
In this mini project we have a created a simple game which is easy to play and user friendly.
For this game we have used open gl library functions and few glut library to make it creative
and interacting. “Pacman Game” is CG game where the player controls Pac-Man through a
maze, eating dots. When all dots are eaten, Pac-Man game is over. Four ghosts roam the
maze, trying to catch Pac-Man. If a ghost touches Pac-Man, a life is lost. When all lives
have been lost, the game ends. Near the corners of the maze are four larger, flashing dots
known as “Energizers” or “Power Pills”, which provide Pac-Man with the temporary ability
to eat the ghosts.
4
Table of Contents
5
CHAPTER 1
INTRODUCTION
6
1.1 Introduction to CG
• The manipulation and the representation of the image or the data in a graphical
manner.
• Various technologies required for the creation and manipulation.
• Digital synthesis and its manipulation.
Applications
• Computer Graphics are used for aided design for engineering and architectural
system- These are used in electrical automobile, electro-mechanical, mechanical,
electronic devices. For example: gears and bolts.
• Computer Art – MS Paint, Adobe Photoshop.
• Presentation Graphics – It is used to summarize financial statistical scientific or
economic data. For example- Bar chart, Line chart.
• Entertainment- It is used in motion picture, music video, television gaming.
• Education and training- It is used to understand operations of complex system. It is
also used for specialized system such for framing for captains, pilots and so on.
• Visualization- To study trends and patterns. For example- Analyzing satellite photo of
earth.
7
1.2 Introduction to OpenGL
Interface
OpenGL is an application program interface (API) offering various functions to implement
primitives, models and images. This offers functions to create and manipulate render lighting,
colouring, viewing the models. OpenGL offers different coordinate system and frames.
OpenGL offers translation, rotation and scaling of objects. Functions in the main GL library
have names that begin with gl and are stored in a library usually referred to as GL. The second
is the OpenGL Utility Library (GLU). The library uses only GL functions but contains code
for creating common objects and simplifying viewing. All functions in GLU can be created
from the core GL library but application programmers prefer not to write the code repeatedly.
The GLU library is available in all OpenGL implementations; functions in the GLU library
begin with the letter glu. Rather than using a different library for each system we use a readily
available library called OpenGL Utility Toolkit (GLUT), which provides the minimum
functionality that should be expected in any modern windowing system.
Overview
• OpenGL (Open Graphics Library) is the interface between a graphics program and
graphics hardware. It is streamlined. In other words, it provides low-level
functionality. For example, all objects are built from points, lines and convex
polygons. Higher level objects like cubes are implemented as six four-sided polygons.
• OpenGL supports features like 3-dimensions, lighting, anti-aliasing, shadows,
textures, depth effects, etc.
• It is system-independent. It does not assume anything about hardware or operating
system and is only concerned with efficiently rendering mathematically described
scenes. As a result, it does not provide any windowing capabilities.
• It is a state machine. At any moment during the execution of a program there is a
current model transformation.
• It is a rendering pipeline. The rendering pipeline consists of the following steps:
8
1.3 Introduction to Project-title
The mini-project, ”Pac-man game”, allows the player to play with the objects. The following
details about the game is listed below.
Step1: Initialize the graphics window and its size using GLUT functions.
Step 2: Register the keyboard and display call backs in main function.
Step3: When arrow keys are pressed ghosts are released from jail
Step 4: If left arrow is pressed the Pac-man move towards left in the maze eating the pebbles
simultaneously points are incremented, when points becomes 260 the game is restored.
Step 5: If right, up, down arrows is pressed Pac-man moves in respective direction eating pebbles.
Step 6: If Pac-man eats super pebbles ghosts become edible and vulnerable function is called
Step 7: If Pac-man collides the ghosts in vulnerable state ghosts go to jail. If the ghosts are uneaten
in vulnerable state update function is called.
Step 8: If Pac-man collides with ghosts provided ghosts are not in vulnerable state Pacman
becomes edible and lives are decremented by one. If lives becomes zero the game is over.
9
CHAPTER 2
OpenGL Architecture
10
2. OpenGL Architecture
1) Pipeline Architectures
• Display Lists: All data, whether it describes geometry or pixels, can be saved in a
display list for current or later use. (1 alternative to retaining data in a display list is
processing the data immediately - also known as immediate mode.) When a display
list is executed, the retained data is sent from the display list just as if it were sent by
the application in immediate mode.
• Evaluators: All geometric primitives are eventually described by vertices. Parametric
curves and surfaces may be initially described by control points and polynomial
functions called basis functions. Evaluators provide a method to derive the vertices
used to represent the surface from the control points. The method is a polynomial
mapping, which can produce surface normal, texture coordinates, colors, and spatial
coordinate values from the control points.
• Per-Vertex Operations: For vertex data, next is the "per-vertex operations" stage,
which converts. The vertices into primitives. Some vertex data (for example, spatial
coordinates) are transformed by 4 x 4 floating-point matrices. Spatial coordinates are
projected from a position in the 3D world to a position on your screen. If advanced
features are enabled, this stage is even busier. If texturing is used, texture coordinates
may be generated and transformed here. If lighting is enabled, the lighting calculations
are performed using the transformed vertex, surface normal, light source position,
material properties, and other lighting information to produce a color value.
• Primitive Assembly: Clipping, a major part of primitive assembly, is the elimination
of portions of geometry which fall outside a half-space, defined by a plane. Point
clipping simply passes or rejects vertices; line or polygon clipping can add additional
11
vertices depending upon how the line or polygon is clipped. In some cases, this is
followed by perspective division, which makes distant geometric objects appear
smaller than closer objects. Then view port and depth (z coordinate) operations are
applied. If culling is enabled and the primitive is a polygon, it then may be rejected by
a culling test. Depending upon the polygon mode, a polygon may be drawn as points
or lines. The results or this stage are complete geometric primitives, which are the
transformed and clipped vertices with related color, depth, and sometimes texture-
coordinate values and guidelines for the rasterization step.
• Pixel Operations: While geometric data takes one path through the OpenGL
rendering pipeline, pixel data takes a different route. Pixels from an array in system
memory are first unpacked from one of a variety of formats into the proper number of
components. Next the data is scaled, biased, and processed by a pixel map. The results
are clamped and then either written into texture memory or sent to the rasterization
step. If pixel data is read from the frame buffer, pixel-transfer operations (scale, bias,
mapping, and clamping) are performed. Then these results are packed into an
appropriate format and returned to an array in system memory. There are special pixel
copy operations to copy data in the frame buffer to other parts of the frame buffer or
to the texture memory. A single pass is made through the pixel transfer operations
before the data is written to the texture memory or back to the frame buffer.
• Texture Assembly: An OpenGL application may wish to apply texture images onto
geometric objects to make them look more realistic. If several texture images are used,
it's wise to put them into texture objects so that you can easily switch among them.
Some OpenGL implementations may have special resources to accelerate texture
performance. There may be specialized, high-performance texture memory. If this
memory is available, the texture objects may be prioritized to control the use of this
limited and valuable resource.
• Rasterization: Rasterization is the conversion of both geometric and pixel data into
fragments. Each fragment square corresponds to a pixel in the frame buffer. Line and
polygon stipples, line width, point size, shading model, and coverage calculations to
support ant aliasing are taken into consideration as vertices are connected into lines or
the interior pixels are calculated for a filled polygon. Color and depth values are
assigned for each fragment square.
12
2) OpenGL Engine and Drivers
CPU-GPU Cooperation
Modeling, rendering, and interaction is very much a cooperative process between the CPU
client program and the GPU server programs written in GLSL. An important part of the design
process is to decide how best to divide the work and how best to package and communicate
required information from the CPU to the GPU. There is no standard "best way" to do this
that is applicable to all programs, but we will study a few very common approaches.
OpenGL is a pure output-oriented modeling and rendering API. It has no facilities for creating
and managing windows, obtaining runtime events, or any other such window system
dependent operation. OpenGL implicitly assumes a window-system interface that fills these
needs and invokes user-written event handlers as appropriate.
It is beyond the scope of these notes to list, let alone compare and contrast, all window
manager interfaces that can be used with OpenGL. Two very common window system
interfaces are:
13
GLFW: Runs on Linux, Macintosh, and Windows.
GLUT: (actually freeglut): A window interface that used to be the most common one used
when teaching OpenGL. It, too, runs on Linux, Macintosh, and Windows.
3) Application Development-API’s
This diagram demonstrates the relationship between OpenGL GLU and windowing APIs.
Leading software developers use OpenGL, with its robust rendering libraries, as the 2D/3D
graphics foundation for higher-level APIs. Developers leverage the capabilities of OpenGL
to deliver highly differentiated, yet widely supported vertical market solutions. For example,
Open Inventor provides a cross-platform user interface and flexible scene graph that makes it
easy to create OpenGL applications. IRIS Performer < leverages OpenGL functionality and
delivers additional features tailored for the demanding high frame rate markets such as visual
simulation and virtual sets OpenGL Optimizer is a toolkit for real-time interaction,
modification, and rendering of complex surface-based models such as those found in
CAD/CAM and special effects creation. OpenGL Volumizer is a high-level immediate mode
volume rendering API for the energy, medical and sciences markets. OpenGL Shader provides
a common interface to support realistic visual effects, bump mapping, multiple textures,
environment maps, volume shading and an unlimited array of new effects using hardware
acceleration on standard OpenGL graphics cards.
14
CHAPTER 3
IMPLEMENTATION
15
Code section:
#include<ctype.h>
#include<GL/glut.h>
#include<math.h>
#include<stdio.h>
#define M_PI 3.141596667
#define false 0
#define true 1
const int BOARD_X = 31;
const int BOARD_Y = 28;
int board_array[BOARD_X][BOARD_Y] =
{{8,5,5,5,5,5,5,5,5,5,5,5,5,1,1,5,5,5,5,5,5,5,5,5,5,5,5,7},
{6,0,0,0,0,0,0,0,0,0,0,0,0,2,4,0,0,0,0,0,0,0,0,0,0,0,0,6},
{6,0,8,1,1,7,0,8,1,1,1,7,0,2,4,0,8,1,1,1,7,0,8,1,1,7,0,6},
{6,0,2,11,11,4,0,2,11,11,11,4,0,2,4,0,2,11,11,11,4,0,2,11,11,4,0,6},
{6,0,9,3,3,10, 0,9,3,3,3,10,0,9,10,0,9,3,3,3,10,0,9,3,3,10,0,6},
{6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6},
{6,0,8,1,1,7,0,8,7,0,8,1,1,1,1,1,1,7,0,8,7,0,8,1,1,7,0,6},
{6,0,9,3,3,10,0,2,4,0,9,3,3,11,11,3,3,10,0,2,4,0,9,3,3,10,0,6},
{6,0,0,0,0,0,0,2,4,0,0,0,0,2,4,0,0,0,0,2,4,0,0,0,0,0,0,6},
{9,5,5,5,5,7,0,2,11,1,1,7,0,2,4,0,8,1,1,11,4,0,8,5,5,5,5,10},
{0,0,0,0,0,6,0,2,11,3,3,10,0,9,10,0,9,3,3,11,4,0,6,0,0,0,0,0},
{0,0,0,0,0,6,0,2,4,0,0,0,0,0,0,0,0,0,0,2,4,0,6,0,0,0,0,0},
{0,0,0,0,0,6,0,2,4,0,8,5,5,1,1,5,5,7,0,2,4,0,6,0,0,0,0,0},
{5,5,5,5,5,10,0,9,10,0,6,0,0,0,0,0,0,6,0,9,10,0,9,5,5,5,5,5},
{0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0},
{5,5,5,5,5,7,0,8,7,0,6,0,0,0,0,0,0,6,0,8,7,0,8,5,5,5,5,5},
{0,0,0,0,0,6,0,2,4,0,9,5,5,5,5,5,5,10,0,2,4,0,6,0,0,0,0,0},
{0,0,0,0,0,6,0,2,4,0,0,0,0,0,0,0,0,0,0,2,4,0,6,0,0,0,0,0},
{0,0,0,0,0,6,0,2,4,0,8,1,1,1,1,1,1,7,0,2,4,0,6,0,0,0,0,0},
{8,5,5,5,5,10,0,9,10,0,9,3,3,11,11,3,3,10,0,9,10,0,9,5,5,5,5,7},
{6,0,0,0,0,0,0,0,0,0,0,0,0,2,4,0,0,0,0,0,0,0,0,0,0,0,0,6},
{6,0,8,1,1,7,0,8,1,1,1,7,0,2,4,0,8,1,1,1,7,0,8,1,1,7,0,6},
{6,0,9,3,11,4,0,9,3,3,3,10,0,9,10,0,9,3,3,3,10,0,2,11,3,10,0,6},
{6,0,0,0,2,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,4,0,0,0,6},
{2,1,7,0,2,4,0,8,7,0,8,1,1,1,1,1,1,7,0,8,7,0,2,4,0,8,1,4},
{2,3,10,0,9,10,0,2,4,0,9,3,3,11,11,3,3,10,0,2,4,0,9,10,0,9,3,4},
{6,0,0,0,0,0,0,2,4,0,0,0,0,2,4,0,0,0,0,2,4,0,0,0,0,0,0,6},
{6,0,8,1,1,1,1,11,11,1,1,7,0,2,4,0,8,1,1,11,11,1,1,1,1,7,0,6},
{6,0,9,3,3,3,3,3,3,3,3,10,0,9,10,0,9,3,3,3,3,3,3,3,3,10,0,6},
{6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6},
{9,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,10}};
int pebble_array[BOARD_X][BOARD_Y] =
{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0},
{0,3,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,3,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
16
{0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0},
{0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0},
{0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0},
{0,1,0,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,0,1,0},
{0,3,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,3,0},
{0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0},
{0,0,0,1,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,0,1,0,0,1,0,0,0},
{0,1,1,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,0,0,1,1,1,1,1,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
GLubyte list[5];
int tp_array[31][28];
int pebbles_left;
double speed1 = 0.1;
double angle1 = 90;
double a=13.5, b=23;
bool animate = false;
int lives=3;
int points=0;
void keys();
unsigned char ckey='w';
void mykey(unsigned char key,int x,int y);
bool Open(int a,int b);
void Move()
{
a += speed1*cos(M_PI/180*angle1);
b += speed1*sin(M_PI/180*angle1);
if(animate&&ckey==GLUT_KEY_UP&& (int) a - a > -0.1 && angle1 != 270)
{
if (Open(a,b-1))
{
animate = true;
angle1 = 270;
}
}
else if(animate&&ckey==GLUT_KEY_DOWN&& (int) a - a > -0.1 && angle1 != 90)// s
17
{
if (Open(a,b+1))
{
animate = true;
angle1= 90;
}
}
else if(animate&&ckey==GLUT_KEY_LEFT&& (int) b - b > -0.1 && angle1 != 180)//a
{
if (Open(a-1,b))
{
animate = true;
angle1 = 180;
}
}
else if(animate&&ckey==GLUT_KEY_RIGHT&& (int) b - b > -0.1 && angle1 != 0)//d
{
if (Open(a+1,b))
{
animate = true;
angle1 = 0;
}
}
}
void Pac(void)
{
//Draw Pacman
glColor3f(0,1,1);
glPushMatrix();
glTranslatef(a,-b,0);
glTranslatef(0.5,0.6,0);
glTranslatef((float)BOARD_X/-2.0f,(float)BOARD_Y/2.0f,0.5);
glutSolidSphere(0.5,15,10);
glPopMatrix();
}
//Monster Drawing And Moving Begins
bool open_move[4];
bool gameover = false;int num_ghosts = 4;
int start_timer=3;
class Ghost
{
private:
public:
bool edible;
int edible_max_time;
int edible_timer;
bool eaten;
bool transporting;
float color[3];
double speed;
double max_speed;
18
bool in_jail;
int jail_timer;
double angle;
double x, y;
Ghost(double, double);
~Ghost(void);
void Move(); //Move the Monster
void Update(void); //Update Monster State
void Chase(double, double, bool*); //Chase Pacman
bool Catch(double, double);
//collision detection
void Reinit(void);
void Vulnerable(void);
void Draw(void); //Draw the Monster
void game_over(void);
};
Ghost *ghost[4];
Ghost::~Ghost(void){}
Ghost::Ghost(double tx, double ty)
{
tx = x;
ty = y;
angle = 90;
speed = max_speed=1;color[0] = 1;
color[1] = 0;
color[2] = 0;
eaten = false;
edible_max_time =300;
edible = false;
in_jail = true;
jail_timer = 30;
}
void Ghost::Reinit(void)
{
edible = false;
in_jail = true;
angle = 90;
}
//Move Monster
void Ghost::Move()
{
x += speed*cos(M_PI/180*angle);
y += speed*sin(M_PI/180*angle);
}
void Ghost::game_over()
{
}
void Ghost::Update(void)
{
if ((int)x == 0 && (int) y == 14 && (!(transporting)))
{
19
angle=180;
}
if (x < 0.1 && (int) y == 14)
{
x = 26.9;
transporting = true;
}
if ((int)x == 27 && (int) y == 14 && (!(transporting)))
{
angle=0;
}
if (x > 26.9 && (int) y == 14)
{
x = 0.1;
transporting = true;
}if ((int)x == 2 || (int)x == 25)
transporting = false;
if (((int) x < 5 || (int) x > 21) && (int) y == 14 && !edible && !eaten)
speed = max_speed/2;
speed = max_speed;
//edibility
if (edible_timer == 0 && edible && !eaten)
{
edible = false;
speed = max_speed;
}
if (edible)
edible_timer--;
//JAIL
if (in_jail && (int) (y+0.9) == 11)
{
in_jail = false;
angle = 180;
}
if (in_jail && ((int)x == 13 || (int)x == 14))
{
angle = 270;
}
//if time in jail is up, position for exit
if (jail_timer == 0 && in_jail)
{
//move right to exit
if (x < 13)
angle = 0;
if (x > 14)
angle = 180;
}
//decrement time in jail counter
if (jail_timer > 0)
jail_timer--;
//EATEN GHOST SEND TO JAIL
20
if (eaten && ((int) x == 13 || (int) (x+0.9) == 14) && ((int)y > 10 && (int) y < 15))
{
in_jail = true;
angle = 90;
if((int) y == 14)
{
eaten = false;
speed = max_speed;
jail_timer = 66;
x = 11;}
}
}
bool Ghost::Catch(double px, double py)
{
// Collision Detection
if (px - x < 0.2 && px - x > -0.2 && py - y < 0.2 && py - y > -0.2)
{
return true;
}
return false;
}
//called when pacman eats a super pebble
void Ghost::Vulnerable(void)
{
if (!(edible))
{
angle = ((int)angle + 180)%360;
speed = max_speed;
}
edible = true;
edible_timer = edible_max_time;
//speed1=0.15;
}
void Ghost::Chase(double px, double py, bool *open_move)
{
int c;
if (edible)
c = -1;
else
c = 1;
bool moved = false;
if ((int) angle == 0 || (int) angle == 180)
{
if ((int)c*py > (int)c*y && open_move[1])
angle = 90;
else if ((int)c*py < (int)c*y && open_move[3])
angle = 270;
}
else if ((int) angle == 90 || (int) angle == 270)
{
if ((int)c*px > (int)c*x && open_move[0])angle = 0;
21
else if ((int)c*px < (int)c*x && open_move[2])
angle = 180;
}
//Random Moves Of Monsters
if ((int) angle == 0 && !open_move[0])
angle = 90;
if ((int) angle == 90 && !open_move[1])
angle = 180;
if ((int) angle == 180 && !open_move[2])
angle = 270;
if ((int) angle == 270 && !open_move[3])
angle = 0;
if ((int) angle == 0 && !open_move[0])
angle = 90;
}
void Ghost::Draw(void)
{
if (!edible)
glColor3f(color[0],color[1],color[2]);
else
{
if (edible_timer < 150)
glColor3f((edible_timer/10)%2,(edible_timer/10)%2,1);
if (edible_timer >= 150)
glColor3f(0,0,1);
}
if (eaten)
glColor3f(1,1,0); //When Eaten By PacMan Change Color To Yellow
glPushMatrix();
glTranslatef(x,-y,0);
glTranslatef(0.5,0.6,0);
glTranslatef((float)BOARD_X/-2.0f, (float)BOARD_Y/2.0f,0.5);
glutSolidSphere(.5,10,10);
glPopMatrix();
}
void tp_restore(void){
for (int ISO = 0; ISO < BOARD_X; ISO++)
{
for (int j = 0; j < BOARD_Y; j++)
{
tp_array[ISO][j] = pebble_array[ISO][j];
}
}
pebbles_left = 244;
}
void Draw(void)
{
glColor3f(1,0,1);
//split board drawing in half to avoid issues with depth
for (int ISO = 0; ISO < BOARD_X; ISO++)
{
22
for (int j = 0; j < BOARD_Y/2; j++)
{
glColor3f(0,0,1);
int call_this = 0;
glPushMatrix();
glTranslatef(-(float) BOARD_X / 2.0f,-(float) BOARD_Y / 2.0f, 0);
glTranslatef(j, BOARD_Y - ISO,0);
glPushMatrix();
glTranslatef(0.5,0.5,0);
switch (board_array[ISO][j])
{
case 4:
glRotatef(90.0,0,0,1);
case 3:
glRotatef(90.0,0,0,1);
case 2:
glRotatef(90.0,0,0,1);
case 1:
call_this = 1;
break;
case 6:
glRotatef(90.0,0,0,1);
case 5:
call_this = 2;
break;
case 10:
glRotatef(90.0,0,0,1);
case 9:glRotatef(90.0,0,0,1);
case 8:
glRotatef(90.0,0,0,1);
case 7:
call_this = 3;
break;
}
glScalef(1,1,0.5);
glTranslatef(-0.5,-0.5,0);
glCallList(list[call_this]);
glPopMatrix();
//now put on the top of the cell
if (call_this != 0 || board_array[ISO][j] == 11)
{
glTranslatef(0,0,-0.5);
glCallList(list[4]);
}
glPopMatrix();
if (tp_array[ISO][j] > 0)
{
glColor3f(0,300,1/(float)tp_array[ISO][j]);
glPushMatrix();
glTranslatef(-(float) BOARD_X / 2.0f,-(float) BOARD_Y / 2.0f, 0);
glTranslatef(j, BOARD_Y - ISO,0);
23
glTranslatef(0.5,0.5,0.5);
glutSolidSphere(0.1f*((float)tp_array[ISO][j]),6,6);
glPopMatrix();
}
}
}
int ISO;
for (ISO= 0; ISO< BOARD_X; ISO++)
{
for (int j = BOARD_Y-1; j >= BOARD_Y/2; j--)
{
glColor3f(0,0,1);
int call_this = 0;
glPushMatrix();
glTranslatef(-(float) BOARD_X / 2.0f,-(float) BOARD_Y / 2.0f, 0);
glTranslatef(j, BOARD_Y - ISO,0);
glPushMatrix();
glTranslatef(0.5,0.5,0);
switch (board_array[ISO][j])
{
case 4:
glRotatef(90.0,0,0,1);case 3:
glRotatef(90.0,0,0,1);
case 2:
glRotatef(90.0,0,0,1);
case 1:
call_this = 1;
break;
case 6:
glRotatef(90.0,0,0,1);
case 5:
call_this = 2;
break;
case 10:
glRotatef(90.0,0,0,1);
case 9:
glRotatef(90.0,0,0,1);
case 8:
glRotatef(90.0,0,0,1);
case 7:
call_this = 3;
break;
}
glScalef(1,1,0.5);
glTranslatef(-0.5,-0.5,0);
glCallList(list[call_this]);
glPopMatrix();
//now put on top
if (call_this != 0 || board_array[ISO][j] == 11)
{
glTranslatef(0,0,-0.5);
24
glCallList(list[4]);
}
glPopMatrix();
if (tp_array[ISO][j] > 0)
{
glColor3f(0,300,1/(float)tp_array[ISO][j]);
glPushMatrix();
glTranslatef(-(float) BOARD_X / 2.0f,-(float) BOARD_Y / 2.0f, 0);
glTranslatef(j, BOARD_Y - ISO,0);
glTranslatef(0.5,0.5,0.5);
glutSolidSphere(0.1f*((float)tp_array[ISO][j]),6,6);
glPopMatrix();
}
}
}
Pac();
}
bool Open(int a, int b)
{
if (board_array[b][a] > 0){
return false;
}
return true;
}
void RenderScene();
void mykey(unsigned char key,int x,int y)
{
if (start_timer > 0)
{
start_timer--;
}
}
void specialDown(int key,int x,int y)
{
if (start_timer > 0)
start_timer--;
ckey=key;
if(key==GLUT_KEY_UP&& (int) a - a > -0.1 && angle1 != 270)
{
if (Open(a, b - 1))
{
//w
animate = true;
angle1 = 270;
}
}
else if(key==GLUT_KEY_DOWN&& (int) a - a > -0.1 && angle1 != 90)// s
{
if (Open(a,b + 1))
{
animate = true;
25
angle1= 90;
}
}
else if(key==GLUT_KEY_LEFT&& (int) b - b > -0.1 && angle1 != 180)//a
{
if (Open(a-1,b))
{
animate = true;
angle1 = 180;
}
}else if(key==GLUT_KEY_RIGHT&& (int) b - b > -0.1 && angle1 != 0)//d
{
if (Open(a+1, b))
{
animate = true;
angle1 = 0;
}
}
}
void specialUp(int key,int x,int y)
{
}
void P_Reinit()
{
a = 13.5;
b = 23;
angle1 = 90;
animate = false;
Pac();
}
void G_Reinit(void)
{
start_timer = 3;
//ghost initial starting positions
int start_x[4] = {11,12,15,16};
float ghost_colors[4][3] = {{255,0,0},{120,240,120},{255,200,200},{255,125,0}};
for (int i = 0; i < num_ghosts; i++)
{
ghost[i]->Reinit();
ghost[i]->x = start_x[i];
ghost[i]->y = 14;
ghost[i]->eaten = false;
ghost[i]->jail_timer = i*33 + 66;
ghost[i]->max_speed = 0.1 - 0.01*(float)i;
ghost[i]->speed = ghost[i]->max_speed;
//colorize ghosts
for (int j = 0; j < 3; j++)
ghost[i]->color[j] = ghost_colors[i][j]/255.0f;
}
}void renderBitmapString(float x, float y, void *font, char *string)
{
26
char *c;
glRasterPos2f(x,y);
for (c=string; *c != '\0'; c++)
{
glutBitmapCharacter(font, *c);
}
}
void Write(char *string)
{
while(*string)
glutBitmapCharacter(GLUT_BITMAP_HELVETICA_18, *string++);
}
void print(char *string)
{
while(*string)
glutBitmapCharacter(GLUT_BITMAP_TIMES_ROMAN_24, *string++);
}
//Display Function->This Function Is Registered in glutDisplayFunc
void RenderScene()
{
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
//Through Movement->From One End To The Other
if ((int)a == 27 && (int) b == 14 && angle1 == 0)
{
a = 0;
animate = true;
}
else
if ((int)(a + 0.9) == 0 && (int) b == 14 && angle1 == 180)
{
a = 27;
animate = true;
}
//Collision Detection For PacMan
if (animate)
Move();
if(!(Open((int)(a + cos(M_PI/180*angle1)),
(int)(b + sin(M_PI/180*angle1)))) &&
a - (int)a < 0.1 && b - (int)b < 0.1)
animate = false;if (tp_array[(int)(b+0.5)][(int)(a+0.5)]== 1)
{
tp_array[(int)(b+0.5)][(int)(a+0.5)]= 0;
pebbles_left--;
points+=1;
}
//Super Pebble Eating
else if(tp_array[(int)(b+0.5)][(int)(a+0.5)] == 3)
{
tp_array[(int)(b+0.5)][(int)(a+0.5)]= 0;
pebbles_left--;
points+=5;
27
for (int i = 0; i < 4; i++)
{
if (!ghost[i]->eaten)
ghost[i]->Vulnerable(); //Calls A Function To Make Monster Weak
}
}
//All The Pebbles Have Been Eaten
if (pebbles_left == 0)
{
G_Reinit();
P_Reinit();
tp_restore();
points=0;
lives=3;
}
if (!gameover)
Draw();
for (int d = 0; d < num_ghosts; d++)
{
if (!gameover && start_timer == 0)
ghost[d]->Update();
if (!ghost[d]->in_jail &&
ghost[d]->x - (int)ghost[d]->x < 0.1 && ghost[d]->y - (int)ghost[d]->y < 0.1)
{
bool open_move[4];
//Finding Moves
for (int ang = 0; ang < 4; ang++)
{
open_move[ang] = Open((int)(ghost[d]->x + cos(M_PI/180*ang*90)),
(int)(ghost[d]->y + sin(M_PI/180*ang*90)));}
//Chase Pac Man
if (!ghost[d]->eaten)
{
if(ghost[d]->x - (int)ghost[d]->x < 0.1 && ghost[d]->y - (int)ghost[d]->y < 0.1)
ghost[d]->Chase(a, b, open_move);
}
else
{
if(ghost[d]->x - (int)ghost[d]->x < 0.1 && ghost[d]->y - (int)ghost[d]->y < 0.1)
ghost[d]->Chase(13, 11, open_move);
}
}
if (ghost[d]->in_jail && !(Open((int)(ghost[d]->x + cos(M_PI/180*ghost[d]->angle)),
(int)(ghost[d]->y + sin(M_PI/180*ghost[d]->angle)))) && ghost[d]->jail_timer > 0
&&ghost[d]->x - (int)ghost[d]->x < 0.1 && ghost[d]->y - (int)ghost[d]->y < 0.1)
{
ghost[d]->angle = (double)(((int)ghost[d]->angle + 180)%360);
}
if (!gameover && start_timer == 0)
ghost[d]->Move();
ghost[d]->Draw();
28
if(!(ghost[d]->eaten))
{
bool collide = ghost[d]->Catch(a,b);
//Monster Eats PacMan
if (collide && !(ghost[d]->edible))
{
lives--;
if (lives == 0)
{
gameover = true;
lives=0;
ghost[d]->game_over();
}
P_Reinit();
d = 4;
}
//PacMan Eats Monster And Sends It To Jail
else if (collide && ((ghost[d]->edible)))
{ghost[d]->edible = false;
ghost[d]->eaten = true;
ghost[d]->speed = 1;
}
}
}
if(gameover==true)
{
glColor3f(1,0,0);
renderBitmapString(-5, 0.5,GLUT_BITMAP_HELVETICA_18 ,"GAME OVER");
}
char tmp_str[40];
glColor3f(1, 1, 0);
glRasterPos2f(10, 18);
sprintf(tmp_str, "Points: %d", points);
Write(tmp_str);
glColor3f(1, 0, 0);
glRasterPos2f(-5, 18);
sprintf(tmp_str, "PAC MAN");
print(tmp_str);
glColor3f(1, 1, 0);
glRasterPos2f(-12, 18);
sprintf(tmp_str, "Lives: %d", lives);
Write(tmp_str);
glutPostRedisplay();
glutSwapBuffers();
}
void create_list_lib()
{
//Set Up Maze Using Lists
list[1] = glGenLists(1);
glNewList(list[1], GL_COMPILE);
//North Wall
29
glBegin(GL_QUADS);
glColor3f(0,0,1);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glVertex3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 1.0, 1.0);
glEnd();
glEndList();
list[2] = glGenLists(1);
glNewList(list[2], GL_COMPILE);
glBegin(GL_QUADS);
//North Wall
glColor3f(0,0,1);
glNormal3f(0.0, 1.0, 0.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glVertex3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 1.0, 1.0);
//South Wall
glColor3f(0,0,1);
glNormal3f(0.0, -1.0, 0.0);
glVertex3f(1.0, 0.0, 0.0);
glVertex3f(1.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 1.0);
glVertex3f(0.0, 0.0, 0.0);
glEnd();
glEndList();
list[3] = glGenLists(1);
glNewList(list[3], GL_COMPILE);
glBegin(GL_QUADS);
//North Wall
glColor3f(0,0,1);
glNormal3f(0.0f, 1.0f, 0.0f);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, 1.0, 0.0);
glVertex3f(0.0, 1.0, 0.0);
glVertex3f(0.0, 1.0, 1.0);
//East Wall
glColor3f(0,0,1);
glNormal3f(1.0, 0.0, 0.0);
glVertex3f(1.0, 1.0, 0.0);
glVertex3f(1.0, 1.0, 1.0);
glVertex3f(1.0, 0.0, 1.0);
glVertex3f(1.0, 0.0, 0.0);
glEnd();
glEndList();
list[4] = glGenLists(1);
glNewList(list[4], GL_COMPILE);
glBegin(GL_QUADS);
//Top Wall
30
glColor3f(-1,0.3,0);
glNormal3f(1.0, 0.0, 1.0);
glVertex3f(1, 1, 1.0);
glVertex3f(0, 1, 1.0);glVertex3f(0, 0, 1.0);
glVertex3f(1, 0, 1.0);
glEnd();
glEndList();
}
void init()
{
/* float color[4];
Enable Lighting.
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);
Ambient And Diffuse Lighting
glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);
color[0] = 1.0f; color[1] = 1.0f; color[2] = 0.0f; color[3] = 0.0f;
glLightfv(GL_LIGHT0, GL_DIFFUSE, color);
color[0] = 1.0f; color[1] = 0.0f; color[2] = 1.0f; color[3] = 1.0f;
glLightfv(GL_LIGHT0, GL_AMBIENT, color);*/
glEnable(GL_NORMALIZE);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60,1.33,0.005,100);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(-1.5, 0, 40, -1.5, 0, 0, 0.0f,1.0f,0.0f);
}
void erase()
{
glColor3f(0.1,0.0,0.0);
glBegin(GL_POLYGON);
glVertex2f(0,0);
glVertex2f(0.5,0);
glVertex2f(0.25,0.5);
glEnd();
}
int main(int argc,char **argv)
{
glutInit(&argc,argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH );
glutInitWindowSize(1200, 780);
glutInitWindowPosition(0,0);
glutCreateWindow("Pac GL 3D");
init();
glutDisplayFunc(RenderScene);
create_list_lib();
glutKeyboardFunc(mykey);
glutSpecialFunc(specialDown);
glutSpecialUpFunc(specialUp);
31
glEnable(GL_DEPTH_TEST);
int start_x[4] = {11,12,15,16};
for (int ISO = 0; ISO < num_ghosts; ISO++)
{
ghost[ISO] = new Ghost(start_x[ISO],14);
}
float ghost_colors[4][3] = {{255,0,0},{120,240,120},{255,200,200},{255,125,0}};
int ISO;
for (ISO = 0; ISO < num_ghosts; ISO++)
{
ghost[ISO]->x = start_x[ISO];
ghost[ISO]->y = 14;
ghost[ISO]->eaten = false;
ghost[ISO]->max_speed = 0.1 - 0.01*(float)ISO;
ghost[ISO]->speed = ghost[ISO]->max_speed;
//colorize ghosts
for (int j = 0; j < 3; j++)
ghost[ISO]->color[j] = ghost_colors[ISO][j]/255.0f;
}
for ( ISO = 0; ISO < BOARD_X; ISO++)
{
for (int j = 0; j < BOARD_Y; j++)
{
tp_array[ISO][j] = pebble_array[ISO][j];
}
}
pebbles_left = 244;
glShadeModel(GL_SMOOTH);
glutMainLoop();
return 0;
}
Command to compile:
./a.out
32
CHAPTER 4
RESULTS AND SNAPSHOTS
33
Design preview:
35
Summary:
The summary of the project explains the animations object in the game such as Pac-man by the
implementation of open GL functionalities .
The project overview explains how the pac-man can be moved in different directions eating the
pebbles When arrow keys are pressed ghosts are released from jail
If left arrow is pressed the Pac-man move towards left in the maze eating the pebbles
simultaneously points are incremented, when points becomes 260 the game is restored.
If right, up, down arrows is pressed Pac-man moves in respective direction eating pebbles.
If Pac-man eats super pebbles ghosts become edible and vulnerable function is called
If Pac-man collides the ghosts in vulnerable state ghosts go to jail. If the ghosts are uneaten in
vulnerable state update function is called.
If Pac-man collides with ghosts provided ghosts are not in vulnerable state Pacman becomes edible
and lives are decremented by one. If lives becomes zero the game is over.
36
CHAPTER 5
CONCLUSION
37
CONCLUSION:
We have successfully implemented various opengl functions to complete our project that is
Pac-man you can reach the possibilities of maximum points against the ghost.
In the process of completion of project we have learned to implement many openGL
Libraries and it’s role in the process of this game we were able to focus on the Pac-man
being chased by the ghost and to reach the highest score.
38
REFERENCES
39