Ghosts
This commit is contained in:
parent
fcffbc85f7
commit
ebc3d155de
10 changed files with 268 additions and 47 deletions
BIN
assets/atlas.png
BIN
assets/atlas.png
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
62
assets/map
62
assets/map
|
|
@ -1,31 +1,31 @@
|
||||||
#############--##############
|
############################
|
||||||
# #
|
# ## #
|
||||||
# #
|
# #### ##### ## ##### #### #
|
||||||
# #
|
#C#### ##### ## ##### ####C#
|
||||||
# #
|
# #### ##### ## ##### #### #
|
||||||
# #
|
# #
|
||||||
# #
|
# #### ## ######## ## #### #
|
||||||
# #
|
# #### ## ######## ## #### #
|
||||||
# #
|
# ## ## ## #
|
||||||
# #
|
###### ##### ## ##### ######
|
||||||
# #
|
###### ##### ## ##### ######
|
||||||
# #
|
###### ## ## ######
|
||||||
# #
|
###### ## #++# ## ######
|
||||||
# #
|
###### ## #__# ## ######
|
||||||
- -
|
- #GG# -
|
||||||
- -
|
###### ## #GG# ## ######
|
||||||
# #
|
###### ## #### ## ######
|
||||||
# #
|
###### ## ## ######
|
||||||
# #
|
###### ## ######## ## ######
|
||||||
# #
|
###### ## ######## ## ######
|
||||||
# #
|
# ## #
|
||||||
# #
|
# #### ##### ## ##### #### #
|
||||||
# #
|
# #### ##### ## ##### #### #
|
||||||
# #
|
#C ## P ## C#
|
||||||
# #
|
### ## ## ######## ## ## ###
|
||||||
# #
|
### ## ## ######## ## ## ###
|
||||||
# #
|
# ## ## ## #
|
||||||
# #
|
# ########## ## ########## #
|
||||||
# #
|
# ########## ## ########## #
|
||||||
# P #
|
# #
|
||||||
############--###############
|
############################
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@
|
||||||
#include <raymath.h>
|
#include <raymath.h>
|
||||||
|
|
||||||
class Entity{
|
class Entity{
|
||||||
|
protected:
|
||||||
|
Vector2 project_position(int direction, int distance);
|
||||||
public:
|
public:
|
||||||
virtual ~Entity(){}
|
virtual ~Entity(){}
|
||||||
|
|
||||||
|
|
@ -44,7 +46,10 @@ class Pacman : public Entity{
|
||||||
void collision(Entity* with) override;
|
void collision(Entity* with) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Wall : public Entity {
|
class PacmanWall{};
|
||||||
|
class GhostWall{};
|
||||||
|
|
||||||
|
class Wall : public Entity,public PacmanWall,public GhostWall{
|
||||||
private:
|
private:
|
||||||
TextureAtlas texture;
|
TextureAtlas texture;
|
||||||
public:
|
public:
|
||||||
|
|
@ -53,6 +58,9 @@ class Wall : public Entity {
|
||||||
void draw() const override;
|
void draw() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Door : public Entity, public PacmanWall{};
|
||||||
|
class Portal : public Entity, public GhostWall{};
|
||||||
|
|
||||||
class Scorepoint : public Entity {
|
class Scorepoint : public Entity {
|
||||||
private:
|
private:
|
||||||
TextureAtlas texture;
|
TextureAtlas texture;
|
||||||
|
|
@ -61,4 +69,22 @@ class Scorepoint : public Entity {
|
||||||
void draw() const override;
|
void draw() const override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Ghost : public Entity {
|
||||||
|
private:
|
||||||
|
static unsigned int color_decision;
|
||||||
|
TextureAtlas texture;
|
||||||
|
const int speed = 16;
|
||||||
|
Color color;
|
||||||
|
int direction = 1;
|
||||||
|
Vector2 start_position;
|
||||||
|
void recalculate_direction();
|
||||||
|
void try_to_chase();
|
||||||
|
public:
|
||||||
|
Ghost();
|
||||||
|
void ready() override;
|
||||||
|
void tick() override;
|
||||||
|
void draw() const override;
|
||||||
|
void collision(Entity* with) override;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
#include "components.h"
|
#include "components.h"
|
||||||
|
#include "world.h"
|
||||||
|
|
||||||
void Entity::queue_free() {
|
void Entity::queue_free() {
|
||||||
if (this->free_queued)
|
if (this->free_queued)
|
||||||
|
|
@ -10,3 +11,10 @@ void Entity::queue_free() {
|
||||||
bool Entity::get_free_flag() {
|
bool Entity::get_free_flag() {
|
||||||
return this->free_queued;
|
return this->free_queued;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vector2 Entity::project_position(int direction, int distance) {
|
||||||
|
double angle = PI/2.0*direction;
|
||||||
|
Vector2 vector_direction = {(float)(cos(angle)),(float)(sin(-angle))};
|
||||||
|
return Vector2Add(this->position,Vector2Scale(vector_direction, (float)distance*CELL_SIZE));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
88
src/ghost.cpp
Normal file
88
src/ghost.cpp
Normal file
|
|
@ -0,0 +1,88 @@
|
||||||
|
#include "components.h"
|
||||||
|
#include "world.h"
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <raylib.h>
|
||||||
|
|
||||||
|
unsigned int Ghost::color_decision = 0;
|
||||||
|
|
||||||
|
Ghost::Ghost() {
|
||||||
|
this->texture = {get_world().get_atlas(),64,64,32,16};
|
||||||
|
if (color_decision > 3)
|
||||||
|
color_decision = 0;
|
||||||
|
switch(this->color_decision++){
|
||||||
|
case 0:
|
||||||
|
this->color = ORANGE;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
this->color = PINK;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
this->color = RED;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
this->color = BLUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ghost::ready() {
|
||||||
|
this->start_position = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ghost::tick() {
|
||||||
|
try_to_chase();
|
||||||
|
Vector2 check_position = project_position(direction, 1);
|
||||||
|
|
||||||
|
World& world = get_world();
|
||||||
|
|
||||||
|
if(dynamic_cast<GhostWall*>(world.grid[world.indexify_position(check_position)]) != nullptr){
|
||||||
|
recalculate_direction();
|
||||||
|
check_position = project_position(direction, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
position = check_position;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ghost::try_to_chase(){
|
||||||
|
// Todo
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ghost::recalculate_direction(){
|
||||||
|
World& world = get_world();
|
||||||
|
|
||||||
|
switch (rand()%3) {
|
||||||
|
case 0:
|
||||||
|
direction = (direction+2)%4;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if(dynamic_cast<GhostWall*>(world.grid[world.indexify_position(project_position((direction+1)%4, 1))]) == nullptr){
|
||||||
|
direction = (direction+1)%4;
|
||||||
|
}
|
||||||
|
else if(dynamic_cast<GhostWall*>(world.grid[world.indexify_position(project_position((direction-1)%4,1))]) == nullptr){
|
||||||
|
direction = (direction-1)%4;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
direction = (direction-2)%4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if(dynamic_cast<GhostWall*>(world.grid[world.indexify_position(project_position((direction-1)%4, 1))]) == nullptr){
|
||||||
|
direction = (direction-1)%4;
|
||||||
|
}
|
||||||
|
else if(dynamic_cast<GhostWall*>(world.grid[world.indexify_position(project_position((direction+1)%4,1))]) == nullptr){
|
||||||
|
direction = (direction+1)%4;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
direction = (direction-2)%4;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ghost::draw() const {
|
||||||
|
DrawTextureRec(this->texture.get_texture(), this->texture.rect_view(0,0,16, 16), this->position, this->color);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Ghost::collision(Entity* with) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "world.h"
|
#include "world.h"
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
create_world_with(1./10.);
|
create_world_with(1./5.);
|
||||||
|
|
||||||
World& world = get_world();
|
World& world = get_world();
|
||||||
Vector2i window_size = get_map_size("assets/map");
|
Vector2i window_size = get_map_size("assets/map");
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,15 @@ void load_world(World& world,const char* path) {
|
||||||
x++;
|
x++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
{
|
||||||
|
Ghost* ghost = new Ghost;
|
||||||
|
ghost->position = {(float)x*16,(float)y*16};
|
||||||
|
world.entities.push_back(ghost);
|
||||||
|
|
||||||
|
}
|
||||||
|
x++;
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
|
|
||||||
|
|
@ -39,9 +48,22 @@ void load_world(World& world,const char* path) {
|
||||||
y++;
|
y++;
|
||||||
break;
|
break;
|
||||||
case '-':
|
case '-':
|
||||||
|
{
|
||||||
|
Portal* portal = new Portal;
|
||||||
|
portal->position = {(float)x*16,(float)y*16};
|
||||||
|
world.entities.push_back(portal);
|
||||||
|
}
|
||||||
x++;
|
x++;
|
||||||
break;
|
break;
|
||||||
default:
|
case '+':
|
||||||
|
{
|
||||||
|
Door* door = new Door;
|
||||||
|
door->position = {(float)x*16,(float)y*16};
|
||||||
|
world.entities.push_back(door);
|
||||||
|
}
|
||||||
|
x++;
|
||||||
|
break;
|
||||||
|
case ' ':
|
||||||
{
|
{
|
||||||
Scorepoint* point = new Scorepoint;
|
Scorepoint* point = new Scorepoint;
|
||||||
point->position = {(float)x*16,(float)y*16};
|
point->position = {(float)x*16,(float)y*16};
|
||||||
|
|
@ -49,6 +71,9 @@ void load_world(World& world,const char* path) {
|
||||||
}
|
}
|
||||||
x++;
|
x++;
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
x++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,20 +24,35 @@ Pacman::Pacman(Vector2 position) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Pacman::tick() {
|
void Pacman::tick() {
|
||||||
|
World& world = get_world();
|
||||||
// Input handling
|
// Input handling
|
||||||
if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP)) {this->facing=1;}
|
if (
|
||||||
if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT)) {this->facing=2;}
|
(IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))
|
||||||
if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN)) {this->facing=3;}
|
&& dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(project_position(1, 1))]) == nullptr
|
||||||
if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) {this->facing=0;}
|
)
|
||||||
|
this->facing=1;
|
||||||
|
|
||||||
|
else if (
|
||||||
|
(IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))
|
||||||
|
&& dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(project_position(2, 1))]) == nullptr
|
||||||
|
)
|
||||||
|
this->facing=2;
|
||||||
|
|
||||||
|
else if ((IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))
|
||||||
|
&& dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(project_position(3, 1))]) == nullptr
|
||||||
|
)
|
||||||
|
this->facing=3;
|
||||||
|
|
||||||
|
else if (
|
||||||
|
(IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))
|
||||||
|
&& dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(project_position(0, 1))]) == nullptr
|
||||||
|
)
|
||||||
|
this->facing=0;
|
||||||
|
|
||||||
// Movement in direction
|
// Movement in direction
|
||||||
double angle = PI/2.0*facing;
|
Vector2 new_position = project_position(this->facing, 1);
|
||||||
Vector2 direction = {(float)(cos(angle)),(float)(sin(-angle))};
|
|
||||||
Vector2 new_position = Vector2Add(this->position,Vector2Scale(direction, (float)speed));
|
|
||||||
|
|
||||||
World& world = get_world();
|
if (dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(new_position)]) == nullptr){
|
||||||
|
|
||||||
if (dynamic_cast<Wall*>(world.grid[world.indexify_position(new_position)]) == nullptr){
|
|
||||||
this->position=new_position;
|
this->position=new_position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -79,7 +94,11 @@ void Pacman::collision(Entity* with){
|
||||||
score->queue_free();
|
score->queue_free();
|
||||||
get_world().points+=10;
|
get_world().points+=10;
|
||||||
}
|
}
|
||||||
|
Ghost* ghost = dynamic_cast<Ghost*>(with);
|
||||||
|
if (ghost != nullptr){
|
||||||
|
queue_free();
|
||||||
|
get_world().lose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,22 @@
|
||||||
#include <raylib.h>
|
#include <raylib.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
void init_world() {
|
||||||
|
create_world_with(1./5.);
|
||||||
|
|
||||||
|
World& world = get_world();
|
||||||
|
Vector2i window_size = get_map_size("assets/map");
|
||||||
|
|
||||||
|
world.load_atlas();
|
||||||
|
world.set_size(window_size);
|
||||||
|
load_world(world,"assets/map");
|
||||||
|
|
||||||
|
world.setup();
|
||||||
|
}
|
||||||
|
|
||||||
World::World(){
|
World::World(){
|
||||||
this->entities = {};
|
this->entities = {};
|
||||||
|
this->grid = new Entity*[get_capacity()];
|
||||||
this->seconds_per_tick = 0;
|
this->seconds_per_tick = 0;
|
||||||
this->clock = 0;
|
this->clock = 0;
|
||||||
this->debug = false;
|
this->debug = false;
|
||||||
|
|
@ -16,7 +30,6 @@ World::~World(){
|
||||||
for(int i = 0; i < this->entities.size();i++) {
|
for(int i = 0; i < this->entities.size();i++) {
|
||||||
delete this->entities[i];
|
delete this->entities[i];
|
||||||
}
|
}
|
||||||
delete [] this->grid;
|
|
||||||
UnloadTexture(this->texture_atlas);
|
UnloadTexture(this->texture_atlas);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,6 +50,14 @@ void World::process(){
|
||||||
if(IsKeyPressed(KEY_F3))
|
if(IsKeyPressed(KEY_F3))
|
||||||
this->seconds_per_tick+=0.025;
|
this->seconds_per_tick+=0.025;
|
||||||
|
|
||||||
|
if(state != LevelState::NotFinished){
|
||||||
|
if(IsKeyPressed(KEY_Q))
|
||||||
|
CloseWindow();
|
||||||
|
if(IsKeyPressed(KEY_R))
|
||||||
|
init_world();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this->update_grid();
|
this->update_grid();
|
||||||
|
|
||||||
for(int i = 0; i < this->entities.size(); i++) {
|
for(int i = 0; i < this->entities.size(); i++) {
|
||||||
|
|
@ -75,6 +96,21 @@ void World::draw() const {
|
||||||
for(int i = 0; i < this->entities.size(); i++) {
|
for(int i = 0; i < this->entities.size(); i++) {
|
||||||
this->entities[i]->draw();
|
this->entities[i]->draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(state != LevelState::NotFinished) {
|
||||||
|
if(state == LevelState::Won)
|
||||||
|
{
|
||||||
|
DrawText("You won!", 16, 16, 24, WHITE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DrawText("You lost!",16,16,24,WHITE);
|
||||||
|
}
|
||||||
|
DrawText("q to quit, r to restart",0,40,16,WHITE);
|
||||||
|
DrawText(TextFormat("Score: %i",this->points),16,56,16,WHITE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if (this->debug == false)
|
if (this->debug == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -122,7 +158,7 @@ void World::set_size(Vector2i size){
|
||||||
this->width = size.x;
|
this->width = size.x;
|
||||||
this->height = size.y;
|
this->height = size.y;
|
||||||
if(this->grid != nullptr)
|
if(this->grid != nullptr)
|
||||||
delete [] this->grid;
|
delete [] grid;
|
||||||
this->grid = new Entity*[this->get_capacity()];
|
this->grid = new Entity*[this->get_capacity()];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,11 +174,20 @@ int World::get_columns() const{
|
||||||
return this->width/CELL_SIZE;
|
return this->width/CELL_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void World::lose(){
|
||||||
|
state = LevelState::Lost;
|
||||||
|
}
|
||||||
|
|
||||||
|
void World::win(){
|
||||||
|
state = LevelState::Won;
|
||||||
|
}
|
||||||
|
|
||||||
Texture2D* World::get_atlas() {
|
Texture2D* World::get_atlas() {
|
||||||
return &this->texture_atlas;
|
return &this->texture_atlas;
|
||||||
}
|
}
|
||||||
|
|
||||||
void create_world_with(float seconds_per_tick){
|
void create_world_with(float seconds_per_tick){
|
||||||
|
get_world() = World();
|
||||||
get_world().seconds_per_tick = seconds_per_tick;
|
get_world().seconds_per_tick = seconds_per_tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
10
src/world.h
10
src/world.h
|
|
@ -14,6 +14,12 @@ struct Vector2i{
|
||||||
int y;
|
int y;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum LevelState{
|
||||||
|
NotFinished = 0,
|
||||||
|
Won = 1,
|
||||||
|
Lost = 2,
|
||||||
|
};
|
||||||
|
|
||||||
/// Class that holds information about game world
|
/// Class that holds information about game world
|
||||||
class World {
|
class World {
|
||||||
public:
|
public:
|
||||||
|
|
@ -40,16 +46,20 @@ class World {
|
||||||
int get_columns() const;
|
int get_columns() const;
|
||||||
int get_rows() const;
|
int get_rows() const;
|
||||||
void load_atlas();
|
void load_atlas();
|
||||||
|
void lose();
|
||||||
|
void win();
|
||||||
Texture2D* get_atlas();
|
Texture2D* get_atlas();
|
||||||
int indexify_position(Vector2 vector);
|
int indexify_position(Vector2 vector);
|
||||||
int points = 0;
|
int points = 0;
|
||||||
private:
|
private:
|
||||||
float clock = 0.;
|
float clock = 0.;
|
||||||
|
int state = 0;
|
||||||
void update_grid();
|
void update_grid();
|
||||||
Texture2D texture_atlas;
|
Texture2D texture_atlas;
|
||||||
};
|
};
|
||||||
|
|
||||||
void create_world_with(float seconds_per_tick);
|
void create_world_with(float seconds_per_tick);
|
||||||
|
void init_world();
|
||||||
World& get_world(); // Thanks, 2ndbeam, helps a lot
|
World& get_world(); // Thanks, 2ndbeam, helps a lot
|
||||||
Vector2i get_map_size(const char* path);
|
Vector2i get_map_size(const char* path);
|
||||||
void load_world(World& world, const char* path);
|
void load_world(World& world, const char* path);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue