Pacman With Classes practice

Hey first post here so let me know if I'm doing something wrong.
I wanted to practice classes with a fun game aspect (shit pacman) but for some reason I can't properly remove a life when I hit a ghost. I'm far from done. I know there is a lot wrong but I'd like to focus on removing a life.

I have the project in github https://github.com/Doraonroids/Pucker

I use the line player1.setLives(player1.getLives() - 1); in pacmain.cpp
to remove a life from the player1 object created as a man object witch is kid class of the parent Entity class. the parent Has the get and set lives functions both defined as public inside the Entity.h file.

I run the line above when the ghost and man are on the same space. I know this if statement works because the other lines inside execute.

Is there an conceptual issue I'm not understanding? or maybe my method is poor?
----------------Inside my Entity.cpp---------------------------
1
2
3
4
5
6
7
8
9
10

void Entity::setLives(int val)
{
	lives = val;
}

int Entity::getLives() const
{
	return lives;
}

--------------Inside my main funciton-------------------------
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


if (Blinky.getX() == player1.getX() && Blinky.getY() == player1.getY())
			{
				player1.setLives(player1.getLives() - 1);
				Sleep(10000);
				player1.displayLives(h);
				player1.reset();
				Blinky.display(h.getmapat(Blinky.getY(), Blinky.getX()));
				Blinky.reset();
				
			
				
				if (player1.getLives() == 0)
				{
					running2 = false;
				
				}
			}



Complete Entity.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#pragma once

#include <Windows.h>
#include <iostream>
#include <string>

#include "map.h"
class Entity
{
private:
	int x, y, lives;
	char symbol;
public:
	Entity();
	Entity(int, int, int, char);
	void setX(int); //sets x value
	void setY(int); //sets y value
	void setLives(int); //sets lives variable
	void setSymbol(char);   //sets symbol variable
	int getX() const; //returns x value
	int getY() const; //returns y value
	int getLives() const;   //returns lives
	char getSymbol() const; // returns symbol
	void gotoxy(short, short) const;
	void display() const;
	void display(char) const;
	void replace() const;
};


Complete Entity.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include "Entity.h"
Entity::Entity()
{
	x = 0;
	y = 0;
	lives = 1;
	symbol = '%';

}

Entity::Entity(int X, int Y, int L, char S)
{
	x = X;
	y = Y;
	lives = L;
	symbol = S;
}

void Entity::setX(int val)
{
	x = val;
}

void Entity::setY(int val)
{
	y = val;
}

void Entity::setLives(int val)
{
	lives = val;
}

void Entity::setSymbol(char val)
{
	symbol = val;
}

int Entity::getX() const
{
	return x;
}

int Entity::getY() const
{
	return y;
}

int Entity::getLives() const
{
	return lives;
}

char Entity::getSymbol() const
{
	return symbol;
}

void Entity::gotoxy(short i, short j) const
{
	HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
	COORD position = { i, j };
	SetConsoleCursorPosition(hStdout, position);
}
void Entity::display() const {
	gotoxy(x, y);
	std::cout << symbol;
}

void Entity::display(char c) const {
	gotoxy(x, y);
	std::cout << c;
	
}

void Entity::replace() const {
	gotoxy(x, y);
	
}


Complete man.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
#include "Entity.h"
#include "map.h"
class man :
	public Entity
{
	private:
		short points, dotsate;
	public:
		man();
		void setDotsate(short);
		short getDotsate() const;
		void displayPoints(map&) const;
		void displayLives(map&);
		void reset();
		void move_up(map&);
		void move_down(map&);
		void move_left(map&);
		void move_right(map&);
};

Complete man.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "man.h"

man::man()
{
	setX(12);
	setY(15);
	setLives(3);
	setSymbol('@');
	points = 0;
	dotsate = 1;
}

void man::setDotsate(short d)
{
	dotsate = d;
}

short man::getDotsate() const
{
	return dotsate;
}



void man::displayPoints(map& m) const {
	gotoxy(m.getWidth() + 1, m.getHeight());
	std::cout << "Points: "<< points;
}

void man::displayLives(map& m)
{
	gotoxy(m.getWidth() + 1, m.getHeight() - 1);
	std::cout << "Lives: " ;
	for (short i = getLives(); i > 0; i--) {
		std::cout << " @ ";
	}
}

void man::reset()
{
	setX(12);
	setY(15);
	
}

void man::move_up(map& m)
{
	if (m.getmapat(getY() - 1,getX()) == '.')
	{
		setY(getY() - 1);
		points++;
		dotsate++;
	}
	else if (m.getmapat(getY() - 1,getX()) == ' ')
	{
		setY(getY() - 1);
	}
	//else
	//{
		//std::cout << "/n/nMove_up() Error/n/n";
		////exit(-1);
	//}
}

void man::move_down(map& m)
{
	if (m.getmapat(getY() + 1,getX()) == '.')
	{
		setY(getY() + 1);
		points++;
		dotsate++;
	}
	else if (m.getmapat(getY() + 1, getX()) == ' ')
	{
		setY(getY() + 1);
	}
	//else
	//{
		//std::cout << "/n/nMove_down() Error/n/n";
		//exit(-1);
	//}
}

void man::move_left(map& m)
{
	if (m.getmapat(getY(), getX() - 1) == '.')
	{
		setX(getX() - 1);
		points++;
		dotsate++;
	}
	else if (m.getmapat(getY(), getX() - 1) == ' ')
	{
		setX(getX() - 1);
	}
	//else
	//{
		//std::cout << "/n/nMove_left() Error/n/n";
		//exit(-1);
	//}
}
void man::move_right(map& m)
{
	if (m.getmapat(getY(),getX() + 1) == '.')
	{
		setX(getX() + 1);
		points++;
		dotsate++;
	}
	else if (m.getmapat(getY(),getX() + 1) == ' ')
	{
		setX(getX() + 1);
	}
	//else
	//{
		//std::cout << "/n/nMove_right() Error/n/n";
		//exit(-1);
	//}
}

Complete pacmain.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
#include <iostream>
#include <windows.h>
#include <string>
#include "ghost.h"
#include "man.h"
#include "map.h"



int main()
{
	long long int frame = 0;
	srand(time(NULL));
	bool running = true;
	bool running2 = true;
	man player1;
	ghost Blinky;
	map h;
	h.fillmap();
	
	while (running2) {
		h.ShowMap();
		player1.displayLives(h);

		player1.display();//display pacman symbol at his x y
		h.setmapat(player1.getY(), player1.getX(), player1.getSymbol());

		Blinky.display();
		
	
		while (running)
		{
			
			player1.display(' ');
			h.setmapat(player1.getY(), player1.getX(), ' ');
			Blinky.display(h.getmapat(Blinky.getY(), Blinky.getX()));
			if (GetAsyncKeyState(VK_UP)) {
				player1.move_up(h);
			}
			else if (GetAsyncKeyState(VK_DOWN)) {
				player1.move_down(h);
			}
			else if (GetAsyncKeyState(VK_LEFT)) {
				player1.move_left(h);
			} 
			else if (GetAsyncKeyState(VK_RIGHT)) {
				player1.move_right(h);
			}
			
			if (player1.getDotsate() % 192 == 0) {
				h.ResetMap();
				player1.reset();
				Blinky.reset();
				running = false;
			}

			player1.display();

			if (frame % 3 == 0)
			{
				
				Blinky.move_rand(h); 
			}
			Blinky.display(); 
			
			if (Blinky.getX() == player1.getX() && Blinky.getY() == player1.getY())
			{
				player1.setLives(player1.getLives() - 1);
				Sleep(10000);
				player1.displayLives(h);
				player1.reset();
				Blinky.display(h.getmapat(Blinky.getY(), Blinky.getX()));
				Blinky.reset();
				
			
				
				if (player1.getLives() == 0)
				{
					running2 = false;
				
				}
			}
			
			Sleep(50);
			player1.displayPoints(h);
			
			frame++;
		}
	}
	
	return 0;
}


Last edited on
you have the right idea.
trimming the fat, you want to see this?

so your idea works fine. Something else is wrong. I didn't see it, but I didn't dig either, its a bit to muddle through.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class entity
 {
   int lives;	 
   public:
   void setLives(int val)
	{
		lives = val;
	}	 
	int getLives() const
	{
		return lives;
	}
 };
 
 int main()
 {
    entity pm;
    pm.setLives(3);
	cout << pm.getLives() << endl;
	while(pm.getLives())
	{
	  pm.setLives(pm.getLives() - 1);
	  cout << pm.getLives() << endl;
	}	 
 }


In at least one point the code has a minor error .. it assumes short is ok for lives where they are of size int. Keep the sizes the same unless you have a really good reason to change it, and in that case, you are usually promoting to a larger type. If going large type to small for a reason, this requires a comment as to why, for you are doing something weird (possibly valid bitwise logic by chopping the data, but say so!).
Last edited on
yes except I want Entity to be a parent class and use its functions through the man class.

Oh yeah I didn't notice that. So in my setLives(int val) the parameter should be a short?

and yes I need A LOT of comments but I wrote this very fast. If I can have it work properly I'll go back to add them.
it can be int, just be consistent and not change types. If its like 3 lives per quarter arcade game stuff, it will even fit in a char, but saving a byte or two isn't really a big deal anymore.

Inheritance won't change your idea; if it isn't working, its not the getter/setter use that is breaking it.

I can make a micro example with the inheritance, but that won't fix whatever isn't working for you. It will look a lot like what you have, and you will still have to debug yours... This does exactly the same output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

class entity
 {
   int lives;	 
   public:
   void setLives(int val)
	{
		lives = val;
	}	 
	int getLives() const
	{
		return lives;
	}
 };
 
 class man : public entity
 {
   private:
   int things;	 
	 
 };
 
 int main()
 {
    man pm;
    pm.setLives(3);
	cout << pm.getLives() << endl;
	while(pm.getLives())
	{
	  pm.setLives(pm.getLives() - 1);
	  cout << pm.getLives() << endl;
	}	 
 }


basically, yes, you did something wrong, but no, its not the way you used getter/setter.
Last edited on
I think ghost::move_rand can be simplified to this (untested):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void ghost::move_rand(map& m) {
    int direction = lastmove;
    while (true) {
        int nextX, nextY;
        switch (direction) {
        case 0: nextY = getY() - 1; nextX = getX();     break;
        case 1: nextY = getY() + 1; nextX = getX();     break;
        case 2: nextY = getY();     nextX = getX() - 1; break;
        case 3: nextY = getY();     nextX = getX() + 1; break;
        }
        if (m.getmapat(nextY, nextX) != '#') {
            setY(nextY);
            setX(nextX);
            lastmove = direction;
            break;
        }
        else
            direction = rand % 4;
    }
}

Yeah this does the same thing mine does, thanks! Only error is rand is rand() for my IDE. I'd like to make the ghost smarter though. Currently the ghost only changes direction when it hits a wall rather than anytime it could change direction. Also, it will do the same thing over and over rather than 'learning'.
It's always rand(), actually. That's just a typo. As I said, I didn't test it (or even try to compile it) since I don't usually use Windows.

To make the ghost move a little more randomly, not just changing direction when it hits a wall, you could do something like this. It's still not "smart", though. (Still untested, though.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
void ghost::move_rand(map& m) {
    // try lastmove 80 percent of the time (plus chance of randomly selecting lastmove)
    int direction = (rand() % 5 == 0) ? rand() % 4 : lastmove;
    while (true) {
        int nextX, nextY;
        switch (direction) {
        case 0: nextY = getY() - 1; nextX = getX();     break;
        case 1: nextY = getY() + 1; nextX = getX();     break;
        case 2: nextY = getY();     nextX = getX() - 1; break;
        case 3: nextY = getY();     nextX = getX() + 1; break;
        }
        if (m.getmapat(nextY, nextX) != '#') {
            setY(nextY);
            setX(nextX);
            lastmove = direction;
            break;
        }
        else
            direction = rand() % 4;
    }
}

I try to take a look at the rest of the code later today. Maybe I'll try making it run on Linux or possibly fire up Windows.
the classic, they chased you down and ran away if you had activated the corner pellet. That may be fun to put in later... path finding is good to study.
@jonnin
It works! Thanks for looking it over. I hadn't displayed the lives properly.
Topic archived. No new replies allowed.