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

View file

@ -6,6 +6,8 @@
#include <raymath.h>
class Entity{
protected:
Vector2 project_position(int direction, int distance);
public:
virtual ~Entity(){}
@ -44,7 +46,10 @@ class Pacman : public Entity{
void collision(Entity* with) override;
};
class Wall : public Entity {
class PacmanWall{};
class GhostWall{};
class Wall : public Entity,public PacmanWall,public GhostWall{
private:
TextureAtlas texture;
public:
@ -53,6 +58,9 @@ class Wall : public Entity {
void draw() const override;
};
class Door : public Entity, public PacmanWall{};
class Portal : public Entity, public GhostWall{};
class Scorepoint : public Entity {
private:
TextureAtlas texture;
@ -61,4 +69,22 @@ class Scorepoint : public Entity {
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

View file

@ -1,4 +1,5 @@
#include "components.h"
#include "world.h"
void Entity::queue_free() {
if (this->free_queued)
@ -10,3 +11,10 @@ void Entity::queue_free() {
bool Entity::get_free_flag() {
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"
int main() {
create_world_with(1./10.);
create_world_with(1./5.);
World& world = get_world();
Vector2i window_size = get_map_size("assets/map");

View file

@ -32,6 +32,15 @@ void load_world(World& world,const char* path) {
x++;
}
break;
case 'G':
{
Ghost* ghost = new Ghost;
ghost->position = {(float)x*16,(float)y*16};
world.entities.push_back(ghost);
}
x++;
break;
case '\n':
@ -39,9 +48,22 @@ void load_world(World& world,const char* path) {
y++;
break;
case '-':
{
Portal* portal = new Portal;
portal->position = {(float)x*16,(float)y*16};
world.entities.push_back(portal);
}
x++;
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;
point->position = {(float)x*16,(float)y*16};
@ -49,6 +71,9 @@ void load_world(World& world,const char* path) {
}
x++;
break;
default:
x++;
break;
}

View file

@ -24,20 +24,35 @@ Pacman::Pacman(Vector2 position) {
}
void Pacman::tick() {
// Input handling
if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP)) {this->facing=1;}
if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT)) {this->facing=2;}
if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN)) {this->facing=3;}
if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) {this->facing=0;}
// Movement in direction
double angle = PI/2.0*facing;
Vector2 direction = {(float)(cos(angle)),(float)(sin(-angle))};
Vector2 new_position = Vector2Add(this->position,Vector2Scale(direction, (float)speed));
World& world = get_world();
// Input handling
if (
(IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))
&& dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(project_position(1, 1))]) == nullptr
)
this->facing=1;
if (dynamic_cast<Wall*>(world.grid[world.indexify_position(new_position)]) == nullptr){
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
Vector2 new_position = project_position(this->facing, 1);
if (dynamic_cast<PacmanWall*>(world.grid[world.indexify_position(new_position)]) == nullptr){
this->position=new_position;
}
@ -79,7 +94,11 @@ void Pacman::collision(Entity* with){
score->queue_free();
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 <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(){
this->entities = {};
this->grid = new Entity*[get_capacity()];
this->seconds_per_tick = 0;
this->clock = 0;
this->debug = false;
@ -16,7 +30,6 @@ World::~World(){
for(int i = 0; i < this->entities.size();i++) {
delete this->entities[i];
}
delete [] this->grid;
UnloadTexture(this->texture_atlas);
}
@ -36,6 +49,14 @@ void World::process(){
this->seconds_per_tick-=0.025;
if(IsKeyPressed(KEY_F3))
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();
@ -75,6 +96,21 @@ void World::draw() const {
for(int i = 0; i < this->entities.size(); i++) {
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)
return;
@ -122,7 +158,7 @@ void World::set_size(Vector2i size){
this->width = size.x;
this->height = size.y;
if(this->grid != nullptr)
delete [] this->grid;
delete [] grid;
this->grid = new Entity*[this->get_capacity()];
}
@ -138,11 +174,20 @@ int World::get_columns() const{
return this->width/CELL_SIZE;
}
void World::lose(){
state = LevelState::Lost;
}
void World::win(){
state = LevelState::Won;
}
Texture2D* World::get_atlas() {
return &this->texture_atlas;
}
void create_world_with(float seconds_per_tick){
get_world() = World();
get_world().seconds_per_tick = seconds_per_tick;
}

View file

@ -14,6 +14,12 @@ struct Vector2i{
int y;
};
enum LevelState{
NotFinished = 0,
Won = 1,
Lost = 2,
};
/// Class that holds information about game world
class World {
public:
@ -40,16 +46,20 @@ class World {
int get_columns() const;
int get_rows() const;
void load_atlas();
void lose();
void win();
Texture2D* get_atlas();
int indexify_position(Vector2 vector);
int points = 0;
private:
float clock = 0.;
int state = 0;
void update_grid();
Texture2D texture_atlas;
};
void create_world_with(float seconds_per_tick);
void init_world();
World& get_world(); // Thanks, 2ndbeam, helps a lot
Vector2i get_map_size(const char* path);
void load_world(World& world, const char* path);