xxxxxxxxxx
// This project is inspired from the work of PacMan game by Kaelinator
// Source code can be found at: https://github.com/Kaelinator/AGAD/tree/master/Pac-Man
// Original idea to make the ghosts move automatically
// Currently other players control the ghosts too
// Only PacMan and Blinky are working in present game
// To be continued in future
// Characters
var pinky;
var blinky;
var clyde;
var inky;
var pacman;
// Global Parameters
var startPosition;
var grid;
var tiles;
var lives = 2;
var gameOver = false;
function preload() {
img = loadImage('map.jpg');
}
function setup() {
createCanvas(448, 516);
// Layout of the map in grid form
grid = [
[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, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1],
[1, 8, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 8, 1],
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 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, 1],
[1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1],
[1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 6, 1, 1, 6, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 6, 1, 1, 6, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 6, 6, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 6, 6, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 1, 1, 1, 1, 1, 0, 1, 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, 6, 1, 1, 0, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1],
[1, 8, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 8, 1],
[1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1],
[1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1],
[1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1],
[1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 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, 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, 1, 1, 1]
];
// Creating an empty 2D array
tiles = [];
for (var i = 0; i < 31; i++) {
tiles[i] = [];
}
// defining what number represent what tile
for (var i = 0; i < 28; i++) {
for (var j = 0; j < 31; j++) {
tiles[j][i] = new Tile(16 * i + 8, 16 * j + 8);
switch (grid[j][i]) {
case 1: // 1 is a wall
tiles[j][i].wall = true;
break;
case 0: // 0 is a dot
tiles[j][i].dot = true;
break;
case 8: // 8 is a big dot
tiles[j][i].bigDot = true;
break;
case 6: // 6 is a blank space
tiles[j][i].eaten = true;
break;
}
}
}
// Initial Values
startPosition = createVector(13 * 16 + 8, 23 * 16 + 8);
pacman = new PacMan();
pinky = new Pinky();
blinky = new Blinky();
clyde = new Clyde();
inky = new Inky();
}
function draw() {
//print("Score: " + pacman.score);
if ((!gameOver)) { // If game not over
if (pacman.score < 242) { // If max score not achieved
background(0);
image(img, 0, 0, 448, 496);
textSize(20);
text('Lives: ' + lives, 10, 514);
text('Score: ' + pacman.score, 350, 514);
for (var i = 0; i < 28; i++) {
for (var j = 0; j < 31; j++) {
tiles[j][i].show();
}
}
pacman.move();
pacman.show();
blinky.move();
blinky.show();
}
else {
background(0);
text('PacMan Won!', width/2 - 50, height/2 - 100);
var displayText = 'Score: ' + pacman.score;
textSize(32);
text(displayText, width/2 - 50, height/2);
}
}
else {
background(0);
text('PacMan Lost!', width/2 - 50, height/2 - 100);
var displayText = 'Score: ' + pacman.score;
textSize(32);
text(displayText, width/2 - 50, height/2);
}
}
function keyPressed() {
switch (keyCode) {
case UP_ARROW:
pacman.turnTo = createVector(0, -1);
pacman.turn = true;
break;
case DOWN_ARROW:
pacman.turnTo = createVector(0, 1);
pacman.turn = true;
break;
case LEFT_ARROW:
pacman.turnTo = createVector(-1, 0);
pacman.turn = true;
break;
case RIGHT_ARROW:
pacman.turnTo = createVector(1, 0);
pacman.turn = true;
break;
case 87:
blinky.turnTo = createVector(0, -1);
blinky.turn = true;
break;
case 83:
blinky.turnTo = createVector(0, 1);
blinky.turn = true;
break;
case 65:
blinky.turnTo = createVector(-1, 0);
blinky.turn = true;
break;
case 68:
blinky.turnTo = createVector(1, 0);
blinky.turn = true;
break;
}
}
function PacMan() {
this.pos = startPosition // Start position of Pacman
this.vel = createVector(-1, 0); // Initial speed of pacman
this.lives = 2;
this.score = 0;
this.gameOver = false;
this.turnTo = createVector(-1, 0); // Initial direction of pacman
this.turn = false; // check if turned
// draw function
this.show = function() {
fill(255, 255, 0);
stroke(255, 255, 0);
ellipse(this.pos.x, this.pos.y, 20, 20);
}
// check the position and find what action to do
this.checkPosition = function() {
var xGrid = floor((this.pos.x - 8) / 16);
var yGrid = floor((this.pos.y - 8) / 16);
if ((this.pos.x - 8) % 16 === 0 && (this.pos.y - 8) % 16 === 0) { // Edge of grid blocks
// find paths for all ghosts
pinky.findPath();
clyde.findPath();
inky.findPath();
// if the dot is not eaten
if (!tiles[yGrid][xGrid].eaten) {
if (tiles[yGrid][xGrid].bigDot) {
this.score += 1;
//blinky.frightened = true;
// Add timer
//clyde.frightened = true;
// Add timer
//pinky.frightened = true;
// Add timer
//inky.frightened = true;
// Add timer
}
tiles[yGrid][xGrid].eaten = true;
this.score += 1;
}
// next tile on tern
var xTurnToGrid = floor(xGrid + this.turnTo.x);
var yTurnToGrid = floor(yGrid + this.turnTo.y);
if (tiles[yTurnToGrid][xTurnToGrid].wall) { // check if the turn to grid is wall
if (tiles[yGrid + this.vel.y][xGrid + this.vel.x].wall) // check if next grid is wall
return false;
else // free to move forward
return true;
} else { // free to turn
this.vel = this.turnTo;
return true;
}
} else { // Not on the edge of the grid
if ((this.pos.x + (10 * this.vel.x) - 8) % 16 === 0 && (this.pos.y + (10 * this.vel.y) - 8) % 16 === 0) { // 10 points away from the edge of the grid block
if (!tiles[yGrid][xGrid].eaten) { // check if the dot on the grid block is not eaten
tiles[yGrid][xGrid].eaten = true; // eat it
this.score += 1;
if (tiles[yGrid][xGrid].bigDot) { // if the dot is bigDot
blinky.frightened = true;
// Add timer
clyde.frightened = true;
// Add timer
pinky.frightened = true;
// Add timer
inky.frightened = true;
// Add timer
}
}
}
if (this.turnTo.x + this.vel.x === 0 && this.turnTo.y + this.vel.y === 0) { // Turn 180 degree
vel = createVector(this.turnTo.x, this.turnTo.y);
return true;
}
return true;
}
}
// move function for pacman
this.move = function() {
if (this.checkPosition()) {
this.pos.add(this.vel);
}
}
// check if the ghosts and pacman hit each other
this.hitPacMan = function(GhostPos) {
if (dist(this.pos.x, this.pos.y, GhostPos.x, GhostPos.y) < 10)
return true;
else
return false;
}
// kill pacman
this.kill = function() {
lives -= 1;
if (lives < 0) // if out of lives game over
gameOver = true;
else { // reset the position of all the characters
this.pos = startPosition;
// this.vel = createVector(-1, 0);
// this.turnTo = createVector(-1, 0);
blinky = new Blinky();
clyde = new Clyde();
pinky = new Pinky();
inky = new Inky();
}
}
}
function Blinky() {
this.pos = createVector(13 * 16 + 8, 11 * 16 + 8); // Start position of blinky
this.vel = createVector(1, 0); // Initial speed of blinky
this.turnTo = createVector(-1, 0); // Initial direction of blinky
this.turn = false; // check if turned
// draw function
this.show = function() {
fill(255, 0, 0);
stroke(255, 0, 0);
ellipse(this.pos.x, this.pos.y, 20, 20);
}
// check the position and find what action to do
this.checkPosition = function() {
var xGrid = floor((this.pos.x - 8) / 16);
var yGrid = floor((this.pos.y - 8) / 16);
if (pacman.hitPacMan(this.pos)) {
pacman.kill();
}
else {
if ((this.pos.x - 8) % 16 === 0 && (this.pos.y - 8) % 16 === 0) { // Edge of grid blocks
// next tile on tern
var xTurnToGrid = floor(xGrid + this.turnTo.x);
var yTurnToGrid = floor(yGrid + this.turnTo.y);
if (tiles[yTurnToGrid][xTurnToGrid].wall) { // check if the turn to grid is wall
if (tiles[yGrid + this.vel.y][xGrid + this.vel.x].wall) // check if next grid is wall
return false;
else // free to move forward
return true;
} else { // free to turn
this.vel = this.turnTo;
return true;
}
}
else { // Not on the edge of the grid
if (this.turnTo.x + this.vel.x === 0 && this.turnTo.y + this.vel.y === 0) { // Turn 180 degree
vel = createVector(this.turnTo.x, this.turnTo.y);
return true;
}
return true;
}
}
}
// move function for blinky
this.move = function() {
if (this.checkPosition()) {
this.pos.add(this.vel);
}
}
// Part of future project
/*
this.findPath = function() {
}
*/
this.frightened = function() {
}
}
// Part of future project
function Clyde() {
this.show = function() {
}
this.move = function() {
}
this.findPath = function() {
}
this.frightened = function() {
}
}
// Part of future project
function Pinky() {
this.show = function() {
}
this.move = function() {
}
this.findPath = function() {
}
this.frightened = function() {
}
}
// Part of future project
function Inky() {
this.show = function() {
}
this.move = function() {
}
this.findPath = function() {
}
this.frightened = function() {
}
}
function Tile(x, y) {
this.wall = false;
this.dot = false;
this.bigDot = false;
this.eaten = false;
this.pos = createVector(x, y);
this.show = function() {
if (this.dot) {
if (!this.eaten) { //draw dot
fill(255, 255, 0);
noStroke();
ellipse(this.pos.x, this.pos.y, 3, 3);
}
} else if (this.bigDot) {
if (!this.eaten) { //draw big dot
fill(255, 255, 0);
noStroke();
ellipse(this.pos.x, this.pos.y, 10, 10);
}
}
}
}
// Part of future project
/*
function Node(_x, _y) {
this.edges = [];
this. x = _x;
this.y = _y;
this.smallestDistToPoint = 10000; // the distance of smallest path from the start to this node
this.degree;
this.value;
this.checked = false;
this.addEdges = function(nodes) {
for (var i = 0; i < nodes.length; i++) {
if (nodes[i].y == this.y ^ nodes[i].x == this.x) { // XOR
if (nodes[i].y == this.y) { // if the node is on the same line horizontally
var mostLeft = (min(nodes[i].x, this.x)) + 1;
var max = max(nodes[i].x, this.x);
var edge = true;
while (mostLeft < max) {//look from the one node to the other looking for a wall
if (tiles[floor(this.y)][floor(mostLeft)].wall) {
edge = false; // not an edge since there is a wall in the way
break;
}
mostLeft++; // move 1 step closer to the other node
}
if (edge) {
append(this.edges, nodes[i]); // add the node as an edge
}
}
else if (nodes[i].x == this.x) { // same line vertically
var mostUp = (min(nodes[i].y, this.y)) + 1;
var max = max(nodes[i].y, this.y);
var edge = true;
while (mostUp < max) {
if (tiles[floor(mostUp)][floor(this.x)].wall) {
edge = false;
break;
}
mostUp++;
}
if (edge) {
append(this.edges, nodes[i]);
}
}
}
}
}
}
function Path() {
this.path = [];
this.distance = 0; // length of path
this.distToFinish = 0;
this.velAtLast; // direction of ghost at last point of path
this.addToTail = function(n, endNode) {
if(path.length > 0)
distance += dist(path[path.length - 1].x, path[path.length - 1].y, n.x, n.y); // add the distance from the current last element in the path to the new node to the overall distance
append(path, n);
distToFinish = dist(path[path.length - 1].x, path[path.length - 1].y, endNode.x, endNode.y); // recalculate the distance to the finish
}
this.clone = function() {
// ToDo
}
this.clear = function() {
distance = 0;
distToFinish = 0;
path = [];
}
}
function getNearestNonWallTile() {
var min = 10000;
var minIndexj = 0;
var minIndexi = 0;
for (var i = 0; i < 28; i++) {
for (var j = 0; j < 31; j++) {
if (!tiles[j][i].wall) { // if its not a wall
if (dist(i, j, target.x, target.y) < min) { // if its the current closest to target
min = dist(i, j, target.x, target.y);
minIndexj = j;
minIndexi = i;
}
}
}
}
return createVector(minIndexi, minIndexj); // return a vector to the tile
}
*/