This commit is contained in:
Rendo 2026-03-14 20:37:34 +05:00
commit ebc3d155de
10 changed files with 268 additions and 47 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Before After
Before After

View file

@ -1,31 +1,31 @@
#############--############## ############################
# # # ## #
# # # #### ##### ## ##### #### #
# # #C#### ##### ## ##### ####C#
# # # #### ##### ## ##### #### #
# # # #
# # # #### ## ######## ## #### #
# # # #### ## ######## ## #### #
# # # ## ## ## #
# # ###### ##### ## ##### ######
# # ###### ##### ## ##### ######
# # ###### ## ## ######
# # ###### ## #++# ## ######
# # ###### ## #__# ## ######
- - - #GG# -
- - ###### ## #GG# ## ######
# # ###### ## #### ## ######
# # ###### ## ## ######
# # ###### ## ######## ## ######
# # ###### ## ######## ## ######
# # # ## #
# # # #### ##### ## ##### #### #
# # # #### ##### ## ##### #### #
# # #C ## P ## C#
# # ### ## ## ######## ## ## ###
# # ### ## ## ######## ## ## ###
# # # ## ## ## #
# # # ########## ## ########## #
# # # ########## ## ########## #
# P # # #
############--############### ############################

View file

@ -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

View file

@ -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
View 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) {
}

View file

@ -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");

View file

@ -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;
} }

View file

@ -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();
}
} }

View file

@ -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;
} }

View file

@ -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);