Cześć jak można ulepszyć kod tej tekstowej gry rpg w stylu Diablo, Path of Exile.
Enemy.cpp
#include "Enemy.h"
void Enemy::createEnemy(int type)
{
if (type == 0) {
name = "Zombie";
maxHealth = 50;
damage = 5;
} else if (type == 1) {
name = "Szkieletor";
maxHealth = 35;
damage = 8;
} else if (type == 2) {
name = "Goblinek";
maxHealth = 30;
damage = 10;
} else {
name = "Zombiak";
maxHealth = 50;
damage = 5;
}
currentHealth = maxHealth;
}
void Enemy::SetLevel(int enemyLevel)
{
level = enemyLevel;
maxHealth += (level - 1) * 10;
damage += (level - 1) * 2;
currentHealth = maxHealth;
}
Enemy.h
#pragma once
#include <string>
class Enemy {
public:
std::string name { }; // nowa składnia C++23
int maxHealth { 0 };
int currentHealth { 0 };
int level { 1 };
int damage { 0 };
void createEnemy(int type);
void SetLevel(int enemyLevel);
};
main.cpp
#include "Enemy.h"
#include "Player.h"
#include "Print.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
// Stany gry
enum class GameState { MainMenu,
CharacterSelect,
Playing,
Exit };
// Funkcje losujące przeciwników
int GetEnemyCount()
{
int roll = rand() % 100;
if (roll < 50)
return 1;
if (roll < 75)
return 2;
if (roll < 90)
return 3;
return 4;
}
int GetEnemyType() { return rand() % 3; } // 0-Zombie,1-Szkieletor,2-Goblin
int GetEnemyLevel() { return 1 + rand() % 3; }
// Funkcja losująca obrażenia z możliwością krytyka
int DealDamage(int baseDamage)
{
int roll = rand() % 100;
if (roll < 10)
return baseDamage * 2; // 10% krytyk
return baseDamage;
}
int main()
{
srand(time(0));
Player player;
bool running = true;
GameState state = GameState::MainMenu;
while (running) {
if (state == GameState::MainMenu) {
Print::WriteColor("====UpiornePotyczki====\n\n", Color::Red);
Print::Write("1. Nowa Gra\n");
Print::Write("2. Wyjście\n");
Print::WriteColor("\nWybierz opcję: ", Color::Yellow);
int choice;
std::cin >> choice;
if (choice == 1)
state = GameState::CharacterSelect;
else if (choice == 2)
state = GameState::Exit;
Print::Clear();
}
else if (state == GameState::CharacterSelect) {
Print::WriteColor("Wybierz klasę postaci:\n\n", Color::Yellow);
Print::Write("1. Wojownik\n");
Print::Write("2. Łotrzyk\n");
Print::Write("3. Mag\n");
Print::WriteColor("\nOpcja: ", Color::Yellow);
int choice;
std::cin >> choice;
player.SetClass(choice);
player.DisplayPickedCharacter();
int continueChoice;
std::cin >> continueChoice;
Print::Clear();
state = GameState::Playing;
}
else if (state == GameState::Playing) {
std::vector<Enemy> enemies;
int enemyCount = GetEnemyCount();
for (int i = 0; i < enemyCount; i++) {
Enemy enemy;
enemy.createEnemy(GetEnemyType());
enemy.SetLevel(GetEnemyLevel());
enemies.push_back(enemy);
}
bool inCombat = true;
while (inCombat) {
Print::Clear();
Print::WriteColor("Pojawiają się przeciwnicy!\n\n", Color::Red);
Print::Write("Twoje zdrowie:\n");
Print::DrawHPBar(player.currentHealth, player.maxHealth, 20, Color::Green);
for (size_t i = 0; i < enemies.size(); i++) {
Print::Write(enemies[i].name + " (Poziom " + std::to_string(enemies[i].level) + "):\n");
Color hpColor = enemies[i].currentHealth > 0 ? Color::Yellow : Color::Red;
Print::DrawHPBar(enemies[i].currentHealth, enemies[i].maxHealth, 20, hpColor);
}
Print::Write("\n1. Atak\n2. Ucieczka\n");
Print::WriteColor("Opcja: ", Color::Yellow);
int choice;
std::cin >> choice;
if (choice == 1) {
Print::WriteColor("\nWybierz przeciwnika do ataku: ", Color::Yellow);
int targetChoice;
std::cin >> targetChoice;
size_t targetIndex = targetChoice - 1;
if (targetIndex < enemies.size()) {
int dmg = DealDamage(player.damage);
enemies[targetIndex].currentHealth -= dmg;
Print::Write("\nUderzasz ");
Print::WriteColor(enemies[targetIndex].name, Color::Yellow);
if (dmg > player.damage)
Print::WriteColor(" krytycznie! ", Color::Red);
Print::Write(" za " + std::to_string(dmg) + " obrażeń!\n");
if (enemies[targetIndex].currentHealth <= 0) {
enemies[targetIndex].currentHealth = 0;
Print::WriteColor("\n" + enemies[targetIndex].name + " został pokonany!\n", Color::Green);
enemies.erase(enemies.begin() + targetIndex);
}
if (enemies.empty()) {
Print::WriteColor("\nWygrałeś walkę!\n", Color::Green);
inCombat = false;
} else {
Print::Write("\nPrzeciwnicy atakują!\n");
for (size_t i = 0; i < enemies.size(); i++) {
int enemyDmg = DealDamage(enemies[i].damage);
player.currentHealth -= enemyDmg;
if (player.currentHealth < 0)
player.currentHealth = 0;
Print::WriteColor(enemies[i].name, Color::Red);
Print::Write(" uderza cię za " + std::to_string(enemyDmg) + " obrażeń!\n");
if (player.currentHealth <= 0) {
Print::WriteColor("\nZostałeś pokonany..\n", Color::Red);
inCombat = false;
state = GameState::Exit;
break;
}
}
}
} else {
Print::Write("\nNieprawidłowy cel!\n");
}
} else if (choice == 2) {
Print::WriteColor("\nUciekasz jak tchórz!\n", Color::Yellow);
inCombat = false;
} else {
Print::Write("\nNieprawidłowy wybór!\n");
}
Print::WriteColor("\nNaciśnij Enter, aby kontynuować...", Color::Cyan);
std::cin.ignore();
std::cin.get();
}
state = GameState::Exit;
}
else if (state == GameState::Exit) {
running = false;
}
}
Print::WriteColor("\n************************************\n", Color::Magenta);
Print::WriteColor("* Dzięki za grę w UpiornePotyczki! *\n", Color::Magenta);
Print::WriteColor("************************************\n", Color::Magenta);
return 0;
}
Player.cpp
#include "Player.h"
#include "Print.h"
void Player::SetClass(int choice)
{
name = "Bohater";
if (choice == 1) {
playerClass = "Wojownik";
strength = 10;
intelligence = 2;
vitality = 8;
} else if (choice == 2) {
playerClass = "Łotrzyk";
strength = 6;
intelligence = 5;
vitality = 6;
} else if (choice == 3) {
playerClass = "Mag";
strength = 2;
intelligence = 10;
vitality = 5;
}
CalculateStats();
}
void Player::CalculateStats()
{
maxHealth = 50 + vitality * 10;
currentHealth = maxHealth;
maxMana = 30 + intelligence * 10;
currentMana = maxMana;
if (playerClass == "Wojownik")
damage = strength * 2;
else if (playerClass == "Łotrzyk")
damage = strength * 2 + 2;
else if (playerClass == "Mag")
damage = intelligence * 2;
else
damage = 5;
}
void Player::DisplayPickedCharacter()
{
Print::Clear();
Print::Write("Wybrałeś ");
Print::WriteColor(playerClass, Color::Cyan);
Print::Write("!\n\n");
Print::Write("Siła: " + std::to_string(strength) + "\n");
Print::Write("Inteligencja: " + std::to_string(intelligence) + "\n");
Print::Write("Witalność: " + std::to_string(vitality) + "\n");
Print::Write("Zdrowie: ");
Print::WriteColor(std::to_string(currentHealth), Color::Green);
Print::Write("\nMana: ");
Print::WriteColor(std::to_string(currentMana), Color::Cyan);
Print::Write("\n\nNaciśnij 1, aby kontynuować: ");
}
Player.h
#pragma once
#include <string>
class Player {
public:
std::string name { }; // nowa składnia C++23
std::string playerClass { };
int strength { 0 };
int intelligence { 0 };
int vitality { 0 };
int maxHealth { 0 };
int currentHealth { 0 };
int maxMana { 0 };
int currentMana { 0 };
int damage { 0 };
void SetClass(int choice);
void CalculateStats();
void DisplayPickedCharacter();
};
Print.cpp
#include "Print.h"
#include <cstdlib>
void Print::Write(const std::string& text) { std::print("{}", text); }
void Print::SetColor(Color color)
{
switch (color) {
case Color::Red:
std::print("\033[31m");
break;
case Color::Green:
std::print("\033[32m");
break;
case Color::Yellow:
std::print("\033[33m");
break;
case Color::Cyan:
std::print("\033[36m");
break;
case Color::Blue:
std::print("\033[34m");
break;
case Color::Magenta:
std::print("\033[35m");
break;
case Color::White:
std::print("\033[37m");
break;
case Color::Black:
std::print("\033[30m");
break;
default:
std::print("\033[0m");
break;
}
}
void Print::WriteColor(const std::string& text, Color color)
{
SetColor(color);
std::print("{}", text);
SetColor(Color::Default);
}
void Print::Clear() { system("clear"); }
void Print::DrawHPBar(int current, int max, int width, Color color)
{
int filled = (current * width) / max;
SetColor(color);
std::print("[");
for (int i = 0; i < filled; i++)
std::print("█");
for (int i = filled; i < width; i++)
std::print(" ");
std::print("] {}/{}\n", current, max);
SetColor(Color::Default);
}
Print.h
#pragma once
#include <print>
enum class Color { Default,
Red,
Green,
Yellow,
Cyan,
Blue,
Magenta,
White,
Black };
class Print {
public:
static void Write(const std::string& text);
static void SetColor(Color color);
static void WriteColor(const std::string& text, Color color);
static void Clear();
static void DrawHPBar(int current, int max, int width, Color color);
};
Makefile
# Kompilator i flagi
CXX = clang++
CXXFLAGS = -std=c++23 -Wall -Wextra -I./src
# Katalogi
SRC_DIR = src
BIN_DIR = bin
# Pliki źródłowe
SRCS = $(SRC_DIR)/main.cpp \
$(SRC_DIR)/Player.cpp \
$(SRC_DIR)/Enemy.cpp \
$(SRC_DIR)/Print.cpp
# Plik wynikowy
TARGET = $(BIN_DIR)/UpiornePotyczki
# Domyślna akcja
all: $(TARGET)
# Kompilacja plików źródłowych i linkowanie
$(TARGET): $(SRCS)
@mkdir -p $(BIN_DIR)
$(CXX) $(CXXFLAGS) $^ -o $@
# Czyszczenie plików obiektowych i binarnych
clean:
rm -rf $(BIN_DIR)/*.o $(TARGET)
CMakeLists.txt
cmake_minimum_required(VERSION 4.3.1)
project(UpiornePotyczki)
set(CMAKE_CXX_STANDARD 23)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Dodajemy wszystkie pliki źródłowe
file(GLOB SOURCES "src/*.cpp")
add_executable(UpiornePotyczki ${SOURCES})
README.md
# UpiornePotyczki
Konsolowa gra RPG w C++.
## Funkcje
- Wybór klasy: Wojownik, Łotrzyk, Mag
- Walki z losowymi przeciwnikami (Zombie, Szkieletor, Goblin)
- Paski HP w konsoli, kolory i komunikaty o krytykach
- System poziomów przeciwników i skalowanie obrażeń
## Kompilacja i uruchamianie
### Wymagania
- Kompilator C++23 (np. `clang++` lub `g++` obsługujący C++23)
- Użyłem Clang 22.1.5
- System Linux lub Mac (komenda `system("clear")` używana do czyszczenia konsoli)
### Kompilacja za pomocą Makefile
1. Przejdź do katalogu projektu:
```bash
cd /ścieżka/do/project
## Kompilacja
```bash
mkdir build
cd build
cmake ..
make
./bin/UpiornePotyczki
Możesz też na szybko skompilować za pomocą polecenia w rozszerzeniu VSCode o nazwie Code Runner.
"code-runner.executorMap": {
"cpp": "clear && cd $dir && mkdir -p bin && cd bin && clang++ -std=c++23 ../Player.cpp ../Enemy.cpp ../Print.cpp ../$fileName -o $fileNameWithoutExt && ./$fileNameWithoutExt",
}