Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • main
1 result

Target

Select target project
  • cpp-programmering/klocka
1 result
Select Git revision
  • main
1 result
Show changes
Commits on Source (4)
Showing
with 68 additions and 1122 deletions
{
"files.associations": {
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"cwchar": "cpp",
"array": "cpp",
"atomic": "cpp",
"hash_map": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"chrono": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdint": "cpp",
"cwctype": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"random": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"initializer_list": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"ctime": "cpp",
"deque": "cpp",
"optional": "cpp",
"ratio": "cpp",
"fstream": "cpp",
"iomanip": "cpp",
"stop_token": "cpp",
"bitset": "cpp"
}
}
\ No newline at end of file
#ifndef CONSTANTS_H
#define CONSTANTS_H
/*
Konstanter för olika aspekter av spelet. Dessa borde läsas från en fil.
(inline använd för att slippa lägga definitionen av konstanterna i en cc-fil. Ej en del av
kursen!)
*/
inline int const WIDTH { 19 };
inline int const HEIGHT { 22 };
inline int TILE_SIZE { 20 };
inline int const SCREEN_WIDTH { WIDTH * (TILE_SIZE + 1) };
inline int const SCREEN_HEIGHT { HEIGHT * (TILE_SIZE + 1) };
inline int const FPS { 60 };
#endif
#include "entity.h"
#include "constants.h"
Entity::Entity(sf::Vector2f const& start_position, Grid& grid, int speed, sf::Color const& color)
: current_target { start_position },
previous_target {},
current_direction {},
grid { grid },
speed { speed }
{
setPosition(start_position);
setFillColor(color);
}
void Entity::update()
{
if (at_target_position())
{
sf::Vector2f tmp { current_target };
select_new_target(current_target, current_direction);
previous_target = tmp;
}
move_forward();
time_passed += 1.0 / FPS;
}
bool Entity::at_target_position() const
{
return abs(getPosition().x - current_target.x) < 0.1 and
abs(getPosition().y - current_target.y) < 0.1;
}
void Entity::move_forward()
{
move(static_cast<sf::Vector2f>(current_direction * speed));
}
#ifndef ENTITY_H
#define ENTITY_H
#include <SFML/Graphics.hpp>
#include <cmath>
#include "grid.h"
/*
Typdeklaration för att representera en position i kartan. Går i diskreta steg där varje steg representerar
en ruta.
*/
using Point = sf::Vector2i;
/*
Basklass som representerar alla ritbara rörliga objekt i spelet. Har härledda klasser för pacman och spöken.
*/
class Entity : public sf::ConvexShape
{
public:
Entity(sf::Vector2f const& start_position, Grid& grid, int speed, sf::Color const& color);
virtual ~Entity() = default;
/*
Uppdaterar objektets position. Varje Entity väljer en position en ruta framåt eller bakåt i x-
eller y-led och flyttar sig sedan med en jämn hastighet dit. När den når den rutan väljer den
en ny ruta och börjar om. Sättet den väljer en ruta sker med select_new_target() och
implementeras av den härledda klassen.
*/
virtual void update();
protected:
bool at_target_position() const;
virtual void move_forward();
/*
Uppdaterar current_target till en ny position. Ska vara en ruta horisontellt eller vertikalt
bort från nuvarande position.
*/
virtual void select_new_target(sf::Vector2f& current_target,
sf::Vector2i& current_direction) const = 0;
sf::Vector2f current_target;
sf::Vector2f previous_target;
sf::Vector2i current_direction;
Grid& grid;
int speed;
float time_passed {};
};
#endif
#include "game.h"
#include "ghost.h"
Game::Game()
: grid{"map.txt"},
pacman {{200, 340}, grid},
ghosts {},
window {sf::VideoMode {static_cast<unsigned>(SCREEN_WIDTH), static_cast<unsigned>(SCREEN_HEIGHT)}, "Pacman" }
{
// Lägger till tre dynamiskt allokerade spöken i en vektor.
// Ett spökes konstruktor tar argumenten (pacman, startposition, scatterposition, + speciella argument).
ghosts.emplace_back(sf::Vector2f{360, 40}, grid, new Blinky{pacman, Point{}, Point{WIDTH, 0}});
ghosts.emplace_back(sf::Vector2f{40 , 40}, grid, new Pinky {pacman, Point{}, Point{0, 0}});
ghosts.emplace_back(sf::Vector2f{360, 420}, grid, new Clyde{pacman, Point{}, Point{0, HEIGHT}, 8});
window.setFramerateLimit(FPS);
}
void Game::run()
{
bool running {true};
while (running)
{
window.clear();
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
{
window.close();
running = false;
}
}
update();
draw();
if (check_collision())
{
std::cout << "Du kolliderade med ett spöke..." << std::endl;
running = false;
}
if (grid.food_count() == 0)
{
std::cout << "Du åt upp all mat! Bra jobbat!!" << std::endl;
running = false;
}
}
}
void Game::update()
{
pacman.update();
for (Ghost_Wrapper & g : ghosts)
{
g.update();
}
}
bool Game::check_collision() const
{
for (Ghost_Wrapper const& g : ghosts)
{
if (pacman.getGlobalBounds().intersects(g.getGlobalBounds()))
{
return true;
}
}
return false;
}
void Game::draw()
{
grid.draw(window);
window.draw(pacman);
for (Ghost_Wrapper const& g : ghosts)
{
window.draw(g);
}
window.display();
}
int Game::get_score()
{
return pacman.get_score();
}
#ifndef GAME_H
#define GAME_H
#include "grid.h"
#include "entity.h"
#include "pacman.h"
#include "ghost_wrapper.h"
#include "constants.h"
/*
Spelklassen har det yttersta ansvaret för spelet. Klassen sköter huvudloopen och deligerar ansvar till andra klasser.
*/
class Game
{
public:
/*
Skapa en spelinstans och alla objekt i spelvärden. De är just nu hårdkodade till specifika
positioner. Detta borde läsas från kart-filen på ett snyggt sätt.
*/
Game();
/*
Huvudloopen i spelet. Det är här allt utgår ifrån. Hanterar användarindata, deligerar till andra
funktioner för att uppdatera spellogik och rendera till fönster. Gör också checkar för om spelet
är slut.
*/
void run();
/*
Uppdatera spellogik. tex flytta pacman och alla spöken.
*/
void update();
/*
Kolla om pacman har kolliderat med någon av spökena.
*/
bool check_collision() const;
/*
Rendera alla objekt i spelfönstret.
*/
void draw();
/*
Beräkna antal poäng spelaren har samlat på sig just nu.
*/
int get_score();
private:
Grid grid;
Pacman pacman;
std::vector<Ghost_Wrapper> ghosts;
sf::RenderWindow window;
};
#endif
#include "ghost_wrapper.h"
#include <cmath>
#include <algorithm>
#include "constants.h"
Ghost_Wrapper::Ghost_Wrapper(sf::Vector2f const& start_position, Grid& grid, Ghost* ghost)
: Entity {start_position, grid, 1, get_sfml_color(ghost)}, ghost {ghost}
{
setPointCount(7);
// Plockar fram ett antal punkter runt en cirkel för att skapa den ikoniska pacman-formen.
float radius { static_cast<float>(TILE_SIZE) / 2 };
int no_points { 5 };
for (int i {}; i < no_points; ++i)
{
setPoint(i, sf::Vector2f{ std::cos(3.14f / (no_points - 1) * i) * radius,
-std::sin(3.14f / (no_points - 1) * i) * radius });
}
setPoint(5, {-radius, radius});
setPoint(6, { radius, radius});
}
void Ghost_Wrapper::update()
{
if ((chase_mode && time_passed > 10) or
(!chase_mode && time_passed > 5))
{
chase_mode = !chase_mode;
time_passed = 0;
current_direction = -current_direction;
std::swap(current_target, previous_target);
}
Entity::update();
}
// Ghost AI genomgång: https://gameinternals.com/understanding-pac-man-ghost-behavior
void Ghost_Wrapper::select_new_target(sf::Vector2f& current_target,
sf::Vector2i& current_direction) const
{
sf::Vector2i curr { to_grid_pos(current_target) };
sf::Vector2i goal {};
// Plocka fram den nya 'goal'-punkten. Detta är olika för alla spöken.
ghost->set_position(to_grid_pos(getPosition()));
if (chase_mode)
{
goal = ghost->get_chase_point();
}
else
{
goal = ghost ->get_scatter_point();
}
// Hitta alla punkter precis brevid spöket. Detta är de möjliga nästa destinationerna.
std::vector<sf::Vector2i> potential_points { {curr.x + 1, curr.y}, {curr.x - 1, curr.y},
{curr.x, curr.y + 1}, {curr.x, curr.y - 1} };
// Sortera punkterna så att punkten närmast 'goal'-punkten är först.
std::sort(potential_points.begin(), potential_points.end(),
[&goal](sf::Vector2i const& p1, sf::Vector2i const& p2)
{
double p1_dist { pow(p1.x - goal.x, 2) + pow(p1.y - goal.y, 2) };
double p2_dist { pow(p2.x - goal.x, 2) + pow(p2.y - goal.y, 2) };
return p1_dist < p2_dist;
});
// Hitta den första punkten som inte är en vägg, eller positionen som spöket precis var på.
sf::Vector2i best_point = *std::find_if(potential_points.begin(), potential_points.end(),
[this](sf::Vector2i const& p)
{
return not grid.wall_at(p) and p != to_grid_pos(previous_target);
});
// Uppdatera spökets riktningsvariabel. Kollar om spöket står stilla för att undvika division med noll.
sf::Vector2f new_direction = (to_world_pos(best_point) - current_target);
float length = sqrt( (new_direction.x * new_direction.x) +
(new_direction.y * new_direction.y));
if (length != 0)
{
current_target = to_world_pos(best_point);
current_direction = static_cast<sf::Vector2i>(new_direction / length);
}
else
{
current_direction = {};
}
}
sf::Color Ghost_Wrapper::get_sfml_color(Ghost* ghost) const
{
std::string color {ghost->get_color()};
if (color == "red" ) return sf::Color::Red;
if (color == "green" ) return sf::Color::Green;
if (color == "blue" ) return sf::Color::Blue;
if (color == "orange") return sf::Color{255,165,0};
if (color == "yellow") return sf::Color::Yellow;
if (color == "pink" ) return sf::Color{255,105,180};
if (color == "purple") return sf::Color{128,0,128};
if (color == "brown" ) return sf::Color{139,69,19};
if (color == "gray" ) return sf::Color{128,128,128};
if (color == "black" ) return sf::Color::Black;
return sf::Color::White;
}
#ifndef GHOST_WRAPPER_H
#define GHOST_WRAPPER_H
#include <SFML/Graphics.hpp>
#include <memory>
#include "entity.h"
#include "grid.h"
#include "YOUR_CODE_HERE/ghost.h"
/*
En klass som äger ett objekt av den studentskapade datatypen "Ghost". Se detta som en klass som
lägger till grafikelement och sökalgoritm till klasserna som studenten skapat.
*/
class Ghost_Wrapper : public Entity
{
public:
Ghost_Wrapper(sf::Vector2f const& start_position, Grid& grid, Ghost* ghost);
/*
Utökar Entitys update med funktionallitet för att byta mellan chase och scatter.
Anropar sedan Entitys update. Kolla där för detaljer.
*/
void update() override;
protected:
/*
Väljer en ny punkt för spöket att gå till. Detta görs när spöket har nått sitt förra mål.
Notera att detta inte är samma sak som det studenten ska implementera. Detta är ruta för ruta
och använder sig av studentkod, men de är inte samma.
*/
void select_new_target(sf::Vector2f& current_target,
sf::Vector2i& current_direction) const override;
private:
/*
Konverterar den färg-strängen som spöket sparar till en faktiskt sfml-färg.
Följ mönstret för att lägga till fler färger.
*/
sf::Color get_sfml_color(Ghost* ghost) const;
std::unique_ptr<Ghost> ghost;
bool chase_mode {true};
};
#endif
/*
Detta är en liten wrapper för att studentkoden inte ska behöva ändras för den läggs in i spelet.
Utan detta skulle man behöva ändra vilka filer som inkluderas i studentkoden.
*/
#include "constants.h"
#include "pacman.h"
#include "grid.h"
#include <fstream>
#include <deque>
#include <algorithm>
#include "constants.h"
std::istream& operator>>(std::istream& is, Row& row)
{
std::string line {};
getline(is, line);
std::istringstream iss {line};
if (line.size() != WIDTH)
{
is.setstate(std::ios::failbit);
}
row.clear();
char c {};
while(iss >> c)
{
row.push_back(c);
}
if ( row.size() != 0 and row.size() != WIDTH )
{
throw std::runtime_error{"wrong width [" + std::to_string(row.size()) + "] of row. Expected " + std::to_string(WIDTH)};
}
return is;
}
sf::Vector2i to_grid_pos(sf::Vector2f const& pos)
{
return { static_cast<int>((pos.x - TILE_SIZE) / TILE_SIZE),
static_cast<int>((pos.y - TILE_SIZE) / TILE_SIZE) };
}
sf::Vector2f to_world_pos(sf::Vector2i const& pos)
{
return { static_cast<float>(pos.x * TILE_SIZE + TILE_SIZE),
static_cast<float>(pos.y * TILE_SIZE + TILE_SIZE) };
}
Grid::Grid(std::string const& map_file)
{
std::ifstream ifs {map_file};
Row row {};
while (ifs >> row)
{
rows.push_back(row);
}
if (rows.size() != HEIGHT)
{
throw std::runtime_error{"wrong height [" + std::to_string(rows.size()) + "] of map. Expected " + std::to_string(HEIGHT)};
}
}
void Grid::draw(sf::RenderWindow& window) const
{
// Skapa en rektangel med rätt storlek och färg. Flyttas till olika positioner och ritas ut
// en gång för varje vägg.
sf::RectangleShape box {{TILE_SIZE / 1.5f, TILE_SIZE / 1.5f}};
box.setFillColor(sf::Color::Blue);
box.setOrigin(box.getSize().x / 2,box.getSize().y / 2);
// Skapa en cirkel med rätt storlek och färg. Flyttas till olika positioner och ritas ut en gång
// för varje mat.
sf::CircleShape food {2};
food.setFillColor(sf::Color::White);
food.setOrigin(food.getRadius(), food.getRadius());
for (unsigned i {}; i < rows.size(); ++i)
{
for (unsigned j {}; j < rows[i].size(); ++j)
{
switch (rows[i][j])
{
case 'w':
box.setPosition((j + 1) * TILE_SIZE, (i + 1) * TILE_SIZE);
window.draw(box);
break;
case 'f':
food.setPosition((j + 1) * TILE_SIZE, (i + 1) * TILE_SIZE);
window.draw(food);
break;
default:
break;
}
}
}
}
bool Grid::wall_at(sf::Vector2i const& grid_pos) const
{
if (grid_pos.x < 0 or grid_pos.x >= static_cast<int>(rows[0].size()) or
grid_pos.y < 0 or grid_pos.y >= static_cast<int>(rows.size()) )
{
return true;
}
return rows[grid_pos.y][grid_pos.x] == 'w';
}
bool Grid::eat_food(sf::Vector2i const& grid_pos)
{
if (rows[grid_pos.y][grid_pos.x] == 'f')
{
rows[grid_pos.y][grid_pos.x] = 'e';
return true;
}
return false;
}
int Grid::food_count() const
{
int count {};
for (unsigned i {}; i < rows.size(); ++i)
{
for (unsigned j {}; j < rows[i].size(); ++j)
{
if (rows[i][j] == 'f')
{
++count;
}
}
}
return count;
}
#ifndef GRID_H
#define GRID_H
#include <SFML/Graphics.hpp>
#include <iostream>
#include <sstream>
#include <string>
/*
Datatyp för att representera en rad i rutnätet som är kartan.
*/
using Row = std::vector<char>;
std::istream& operator>>(std::istream& is, Row& row);
/*
Hjälpfunktioner för att konvertera mellan två olika coordinatsystem.
'grid' är ett coordinatsystem där varje ruta på spelplanen är en coordinat.
'world' är ett coordinatsystem där varje pixel på skärmen är en coordinat.
*/
sf::Vector2i to_grid_pos(sf::Vector2f const& pos);
sf::Vector2f to_world_pos(sf::Vector2i const& pos);
/*
Klass som representerar hela kartan. Dvs håller koll på alla positioner för väggar och mat på
kartan.
*/
class Grid
{
public:
Grid(std::string const& map_file);
/*
Rendera alla väggar och all mat.
*/
void draw(sf::RenderWindow& window) const;
/*
Ger sant om det är en vägg på given position. Notera att positionen måste anges i
'grid'-systemet.
*/
bool wall_at(sf::Vector2i const& grid_pos) const;
/*
Ger sant om det var en mat på given position. Plockar då också bort maten. Notera att
positionen måste anges i 'grid'-systemet.
Om det inte var en mat på positionen returneras 'false' och inget mer händer.
*/
bool eat_food(sf::Vector2i const& grid_pos);
int food_count() const;
private:
std::vector<Row> rows {};
};
#endif
#include "pacman.h"
#include <cmath>
#include "constants.h"
Pacman::Pacman(sf::Vector2f const& start_position, Grid& grid)
: Entity{start_position, grid, 2, sf::Color::Yellow},
next_direction {}, score {}
{
int no_points { 8 };
float radius { 10 };
setPointCount(no_points);
for (int i {}; i < no_points; ++i)
{
setPoint(i, sf::Vector2f{ std::cos(6.28f / (no_points) * i) * radius,
std::sin(6.28f / (no_points) * i) * radius });
}
}
void Pacman::update()
{
handle_input();
if (next_direction == -current_direction)
{
current_direction = next_direction;
std::swap(current_target, previous_target);
}
if (grid.eat_food(to_grid_pos(getPosition())))
{
score += 10;
}
Entity::update();
}
Point Pacman::get_position() const
{
return { static_cast<int>((getPosition().x - TILE_SIZE) / TILE_SIZE),
static_cast<int>((getPosition().y - TILE_SIZE) / TILE_SIZE) };
}
Point Pacman::get_direction() const
{
return { current_direction.x, current_direction.y };
}
void Pacman::select_new_target(sf::Vector2f& current_target,
sf::Vector2i& current_direction) const
{
// Plockar fram potentiella nästa punkter. Det är antingen en position framåt i spelarens
// riktning, eller stå stilla.
std::vector<sf::Vector2i> candidates { next_direction, current_direction };
// Stega igenom listan med potentiella punkter och plocka den första som inte är en vägg.
for (sf::Vector2i const& candidate : candidates)
{
sf::Vector2f new_target { current_target + static_cast<sf::Vector2f>(candidate * static_cast<int>(TILE_SIZE)) };
if ( not grid.wall_at(to_grid_pos(new_target)) )
{
current_direction = candidate;
current_target = new_target;
return;
}
}
current_direction = {};
}
void Pacman::handle_input()
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up))
{
next_direction = {0, -1};
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Down))
{
next_direction = {0, 1};
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
next_direction = {-1, 0};
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
next_direction = {1, 0};
}
}
#ifndef PACMAN_H
#define PACMAN_H
#include <SFML/Graphics.hpp>
#include "entity.h"
#include "grid.h"
/*
Pacmanklassen representerar spelarefiguren i spelet. Den innehåller funktionallitet för att flytta och rendera spelarefiguren.
Är en specialicering av basklassen Entity.
*/
class Pacman : public Entity
{
public:
Pacman(sf::Vector2f const& start_position, Grid& grid);
/*
Uppdatera pacmans position och riktning.
*/
void update() override;
/*
Hämta ut olika egenskaper från pacman.
*/
unsigned get_score() const { return score; };
Point get_position() const;
Point get_direction() const;
protected:
/*
Använder användainmatning för att beräkna vilken nästa ruta spelare ska röra sig till är.
*/
void select_new_target(sf::Vector2f& current_target,
sf::Vector2i& current_direction) const override;
private:
/*
Kollar vilka knappar som är nedtryckta och uppdaterar variabeln next_direction baserat på det.
Ändra i denna om du vill ha andra knappar som styr spelaren.
*/
void handle_input();
sf::Vector2i next_direction;
unsigned score;
};
#endif
FLAGS = -std=c++17 -Wall -Wextra -Wpedantic -Weffc++ -g -I. -ICode -IYOUR_CODE_HERE
LIB = -lsfml-graphics -lsfml-system -lsfml-window
pacman: main.cc game.o entity.o pacman.o ghost_wrapper.o grid.o student_code.o
g++ $(FLAGS) -o pacman main.cc game.o entity.o pacman.o ghost_wrapper.o grid.o student_code.o $(LIB)
student_code.o: $(shell find YOUR_CODE_HERE -type f)
g++ -o student_code.o $(FLAGS) -c YOUR_CODE_HERE/*.cc
%.o: Code/%.cc Code/%.h
g++ $(FLAGS) -o $@ -c $<
.PHONY: clean
clean:
rm -f *.o ./pacman
Steg för att spela pacman med dina egna spöken.
1. Lägg en (1) headerfil med kod för alla spöken i mappen YOUR_CODE_HERE. Den ska heta ghost.h.
2. Lägg en (1) implemenationsfil med kod för alla spöken i mappen YOUR_CODE_HERE.
3. Flytta *inte* med huvudprogrammet eller de givna filerna till mappen.
4. Stå i mappen med filen som heter Makefile och skriv 'make' i terminalen.
5. Kör programmet med './pacman'.
6. Fly från dina spöken.
Om du har problem med att kompilera koden, se till att alla klasser och funktioner heter som angivet
i labbinstruktionen. Det går också att gå in i spelkoden och kolla vad som väntas. Det är primärt
filerna Code/ghost_wrapper.h och Code/game.h som är relevanta.
Prata med en assistent om ni inte får det att kompilera.
#include <SFML/Graphics.hpp>
#include <iostream>
#include "game.h"
using namespace std;
int main()
{
cout << "Välkommen till Pacman\nTryck 'Enter' för att starta";
cin.get();
Game game {};
game.run();
cout << "Du fick " << game.get_score() << " poäng" << std::endl;
cout << "Tryck 'Enter' för att avsluta" << std::endl;
cin.get();
}
wwwwwwwwwwwwwwwwwww
wffffffffwffffffffw
wfwwfwwwfwfwwwfwwfw
wfwwfwwwfwfwwwfwwfw
wfffffffffffffffffw
wfwwfwfwwwwwfwfwwfw
wffffwfffwfffwffffw
wwwwfwwwewewwwfwwww
wwwwfweeeeeeewfwwww
wwwwfwewwwwwewfwwww
eeeefeewwwwweefeeee
wwwwfwewwwwwewfwwww
wwwwfweeeeeeewfwwww
wwwwfwewwwwwewfwwww
wffffffffwffffffffw
wfwwfwwwfwfwwwfwwfw
wffwfffffffffwfwffw
wwfwfwfwwwwwfwfwfww
wffffwfffwffffffffw
wfwwwwwwfwfwwwwwwfw
wfffffffffffffffffw
wwwwwwwwwwwwwwwwwww
#include "ghost.h"
//ghost
Ghost::Ghost(std::string const &color, Point const &start_pos):
color_index(color), pos(start_pos)
{}
void Ghost::set_pos( Point &new_pos)
{
new_pos.x = pos.x;
new_pos.y = pos.y;
}
Point Ghost::get_pos()
{
return Point{pos.x, pos.y};
}
//clyde
Clyde::Clyde(std::string const &color, Point const &start_pos):
Ghost("orange", start_pos)
{}
Point Clyde::get_scatter(const Point &pos_pacman)
{
return Point{0,0};
}
Point Clyde::get_pos()
{
return Point{pos.x, pos.y};
}
void Clyde::set_pos( Point &new_pos)
{
Ghost::set_pos(new_pos);
}
string Clyde::get_color() const
{
return "orange";
}
Point Clyde::get_chase(const Point &pos_pacman, const Point &dir_pacman)
{
int proximity = abs(pos.x - pos_pacman.x) + abs(pos.y - pos_pacman.y);
if (proximity >= 2)
{
return pos_pacman;
}
else
{
return Point{0,0};
}
}
//pinky
Pinky::Pinky(std::string const &color, Point const &start_pos):
Ghost("pink", start_pos)
{}
Point Pinky::get_scatter(const Point &pos_pacman)
{
return Point{0,21};
}
Point Pinky::get_pos()
{
return Point{pos.x, pos.y};
}
void Pinky::set_pos( Point &new_pos)
{
Ghost::set_pos(new_pos);
}
string Pinky::get_color() const
{
return "pink";
}
Point Pinky::get_chase(const Point &pos_pacman, const Point &dir_pacman) //skriv om allt typ
{
Point target = pos_pacman;
if(dir_pacman.x == 0 && dir_pacman.y == -1)
{
target.y = (target.y - 2);
}
else if(dir_pacman.x == 0 && dir_pacman.y == 1)
{
target.y = (target.y + 2);
}
else if(dir_pacman.x == -1 && dir_pacman.y == 0)
{
target.x = (target.x -2 );
}
else if(dir_pacman.x == 1 && dir_pacman.y == 0);
{
target.x = (target.x -2);
}
return target;
}
//blinky
Blinky::Blinky(std::string const &color, Point const &start_pos)
: Ghost("red", start_pos)
{}
void Blinky::set_pos(Point &new_pos) {
set_pos(new_pos);
}
Point Blinky::get_scatter(const Point &pos_pacman) {
if (angry == true)
{
return Point{pos_pacman.x, pos_pacman.y}; // stämmer?
} else
{
return Point{6, 6};
}
}
Point Blinky::get_chase(const Point &pos_pacman, const Point &dir_pacman) {
return Point{pos_pacman.x, pos_pacman.y};
}
Point Blinky::get_pos() {
return pos;
}
std::string Blinky::get_color()const
{
return "pink";
}
bool Blinky::get_angry(){
return angry;
}
void Blinky::set_angry(bool state) {
angry = state;
}
#ifndef GHOST_H
#define GHOST_H
#include "given.h"
//#include "given.h"
#include "string"
using namespace std;
class Ghost
{
public:
Ghost(std::string const &color, Point const &start_pos);
virtual void set_pos( Point &new_pos);
virtual Point get_scatter(const Point &pos_pacman) = 0;
virtual Point get_chase(const Point &pos_pacman, const Point &dir_pacman) = 0;
virtual Point get_pos();
virtual std::string get_color()const = 0;
virtual ~Ghost() = default;
public:
std::string color_index;
Point pos;
};
class Clyde: public Ghost
{
public:
Clyde(std::string const &color, Point const &start_pos);
void set_pos(Point &new_pos);
Point get_scatter(const Point &pos_pacman);
Point get_chase(const Point &pos_pacman, const Point &dir_pacman);
Point get_pos();
std::string get_color()const;
};
class Pinky: public Ghost
{
public:
Pinky(std::string const &color, Point const &start_pos);
void set_pos(Point &new_pos);
Point get_scatter(const Point &pos_pacman);
Point get_chase(const Point &pos_pacman, const Point &dir_pacman);
Point get_pos();
std::string get_color()const;
};
class Blinky : public Ghost
{
public:
bool get_angry();
void set_angry(bool state);
Blinky(std::string const &color, Point const &start_pos);
void set_pos(Point &new_pos);
Point get_scatter(const Point &pos_pacman);
Point get_chase(const Point &pos_pacman, const Point &dir_pacman);
Point get_pos();
std::string get_color()const;
private:
bool angry = false ;
};
#endif
\ No newline at end of file
#include "given.h"
int WIDTH = 19;
int HEIGHT = 22;
bool operator==(Point const& lhs, Point const& rhs)
{
return lhs.x == rhs.x && lhs.y == rhs.y;
}
std::istream& operator>>(std::istream& is, Point& rhs)
{
return is >> rhs.x >> rhs.y;
}
Pacman::Pacman()
: pos {}, dir {1,0}
{}
Point Pacman::get_position() const
{
return pos;
}
void Pacman::set_position(Point const& p)
{
if (p.x > WIDTH or p.x < 0 or p.y > HEIGHT or p.y < 0)
{
throw std::runtime_error("position outside valid range");
}
pos = p;
}
Point Pacman::get_direction() const
{
return dir;
}
void Pacman::set_direction(Point const& p)
{
if (p.x > 1 or p.x < -1 or p.y > 1 or p.y < -1 or abs(p.x + p.y) != 1)
{
throw std::runtime_error("direction outside valid range");
}
dir = p;
}