Napisałem prostą konsolową grę rpg typu Diablo, Path of Exiloe, Titan Quest. Potrzebuję porady jak ulepszyć ten kod? Czy wykorzystać coś z nowszych standardów i funkcji języka C++?
Program kompiluje tak:
"code-runner.executorMap": {
"cpp": "clear && cd $dir && mkdir -p bin && cd bin && clang++ -stdlib=libc++ -std=c++23 ../$fileName ../Enemy.cpp ../Player.cpp ../Print.cpp -o $fileNameWithoutExt && ./$fileNameWithoutExt"
}
Main.cpp
#include "Enemy.h"
#include "Player.h"
#include "Print.h"
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <string>
#include <vector>
// Stany gry
enum class GameState {
MainMenu,
CharacterSelect,
Playing,
Exit
};
// Losuje liczbę przeciwników
int GetEnemyCount()
{
int roll = rand() % 100;
if (roll < 50) {
return 1;
}
else if (roll < 75) {
return 2;
}
else if (roll < 90) {
return 3;
}
else {
return 4;
}
}
// Losuje typ przeciwnika
int GetEnemyType()
{
return rand() % 4;
}
// Losuje poziom przeciwnika
int GetEnemyLevel()
{
return 1 + rand() % 3;
}
Player player;
int main()
{
srand(time(0));
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;
}
if (choice == 2) {
state = GameState::Exit;
}
Print::Clear();
}
else if (state == GameState::CharacterSelect) {
Print::WriteColor("Wybierz swoją klasę:\n\n", Color::Yellow);
Print::Write("1. Wojownik\n");
Print::Write("2. Łotrzyk\n");
Print::Write("3. Mag\n");
Print::WriteColor("\nWybierz opcję: ", 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();
// Tworzenie przeciwników
for (int i = 0; i < enemyCount; i++) {
Enemy enemy;
int type = GetEnemyType();
int level = GetEnemyLevel();
enemy.createEnemy(type);
enemy.SetLevel(level);
enemies.push_back(enemy);
}
bool inCombat = true;
// Pętla walki
while (inCombat) {
Print::Clear();
Print::WriteColor("Pojawiają się przeciwnicy!\n\n", Color::Red);
for (int i = 0; i < enemies.size(); i++) {
Print::Write("Przeciwnik " + std::to_string(i + 1) + ": ");
Print::WriteColor(enemies[i].name, Color::Yellow);
Print::Write(" Poziom. " + std::to_string(enemies[i].level));
Print::Write(" - Zdrowie: " + std::to_string(enemies[i].currentHealth) + "\n");
}
Print::Write("\nTwoje zdrowie: ");
Print::WriteColor(std::to_string(player.currentHealth), Color::Green);
Print::Write("\n");
Print::Write("\n1. Atak\n");
Print::Write("2. Ucieczka\n");
Print::WriteColor("\nWybierz opcję: ", Color::Yellow);
int choice;
std::cin >> choice;
if (choice == 1) {
Print::WriteColor("\nWybierz przeciwnika do ataku: ", Color::Yellow);
int targetChoice;
std::cin >> targetChoice;
int targetIndex = targetChoice - 1;
if (targetIndex >= 0 && targetIndex < enemies.size()) {
enemies[targetIndex].currentHealth -= player.damage;
Print::Write("\nUderzasz ");
Print::WriteColor(enemies[targetIndex].name, Color::Yellow);
Print::Write(" za " + std::to_string(player.damage) + " obrażeń!\n");
if (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 (int i = 0; i < enemies.size(); i++) {
player.currentHealth -= enemies[i].damage;
if (player.currentHealth < 0) {
player.currentHealth = 0;
inCombat = false;
state = GameState::Exit;
Print::WriteColor("\nZostałeś pokonany\n", Color::Red);
break;
}
Print::WriteColor(enemies[i].name, Color::Red);
Print::Write(" uderza cię za " + std::to_string(enemies[i].damage) + " 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");
}
}
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);
}
Player.cpp
#include "Player.h"
// Ustawia klasę postaci na podstawie wyboru gracza
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;
}
// Przelicz statystyki po wyborze klasy
CalculateStats();
}
// Oblicza statystyki postaci na podstawie atrybutów
void Player::CalculateStats()
{
int baseHealth = 50;
int baseMana = 30;
// Obliczanie zdrowia
maxHealth = baseHealth + (vitality * 10);
currentHealth = maxHealth;
// Obliczanie many
maxMana = baseMana + (intelligence * 10);
currentMana = maxMana;
// Obliczanie obrażeń w zależności od klasy
if (playerClass == "Wojownik") {
damage = strength * 2;
}
else if (playerClass == "Łotrzyk") {
damage = strength * 2 + 2;
}
else if (playerClass == "Mag") {
damage = intelligence * 2;
}
else {
damage = 5;
}
}
// Wyświetla wybraną postać i jej statystyki
void Player::DisplayPickedCharacter()
{
Print::Clear();
Print::Write("Wybrałeś ");
Print::WriteColor(playerClass, Color::Cyan);
Print::Write("!\n\n");
Print::Write("Siła: ");
Print::Write(std::to_string(strength) + "\n");
Print::Write("Inteligencja: ");
Print::Write(std::to_string(intelligence) + "\n");
Print::Write("Witalność: ");
Print::Write(std::to_string(vitality) + "\n");
Print::Write("Zdrowie: ");
Print::WriteColor(std::to_string(currentHealth), Color::Green);
Print::Write("\n");
Print::Write("Mana: ");
Print::WriteColor(std::to_string(currentMana), Color::Cyan);
Print::Write("\n");
Print::Write("\nNaciśnij 1, aby kontynuować: ");
}
Print.cpp
#include "Print.h"
// Wyświetla tekst bez zmiany koloru
void Print::Write(const std::string& text)
{
std::print("{}", text);
}
// Ustawia kolor tekstu w konsoli
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;
case Color::Default:
default:
std::print("\033[0m"); // reset do domyślnego koloru
break;
}
}
// Wyświetla tekst w wybranym kolorze
void Print::WriteColor(const std::string& text, Color color)
{
SetColor(color);
std::print("{}", text);
SetColor(Color::Default); // przywraca domyślny kolor
}
// Czyści ekran konsoli
void Print::Clear()
{
system("clear"); // działa głównie na Linux/Mac
}
Enemy.cpp
#include "Enemy.h"
// Funkcja tworząca przeciwnika na podstawie typu
void Enemy::createEnemy(int type)
{
if (type == 0) {
name = "Zombiak";
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 {
// Domyślny przeciwnik, jeśli typ jest nieznany
name = "Zombiak";
maxHealth = 50;
damage = 5;
}
// Ustaw aktualne zdrowie na maksymalne
currentHealth = maxHealth;
}
// Funkcja ustawiająca poziom przeciwnika
void Enemy::SetLevel(int enemyLevel)
{
level = enemyLevel;
maxHealth += (level - 1) * 10;
damage += (level - 1) * 2;
// Po zmianie poziomu przeciwnik odzyskuje pełne zdrowie
currentHealth = maxHealth;
}
Player.h
#pragma once
#include <print>
#include "Print.h"
// Klasa reprezentująca gracza
class Player {
public:
// Imię postaci
std::string name;
// Klasa postaci (np. Wojownik, Łotrzyk, Mag)
std::string playerClass;
// Podstawowe atrybuty
int strength = 0;
int intelligence = 0;
int vitality = 0;
// Zdrowie
int maxHealth = 0;
int currentHealth = 0;
// Mana
int maxMana = 0;
int currentMana = 0;
// Obrażenia zadawane przez gracza
int damage = 0;
// Ustawia klasę postaci na podstawie wyboru
void SetClass(int choice);
// Oblicza statystyki na podstawie atrybutów
void CalculateStats();
// Wyświetla informacje o wybranej postaci
void DisplayPickedCharacter();
};
Print.h
#pragma once
#include <print>
// Enum reprezentujący kolory tekstu w konsoli
enum class Color {
Default, // domyślny kolor
Red,
Green,
Yellow,
Cyan,
Blue,
Magenta,
White,
Black
};
// Klasa odpowiedzialna za wyświetlanie tekstu w konsoli
class Print {
public:
// Wyświetla tekst w konsoli
static void Write(const std::string& text);
// Ustawia kolor tekstu
static void SetColor(Color color);
// Wyświetla tekst w wybranym kolorze
static void WriteColor(const std::string& text, Color color);
// Czyści ekran konsoli
static void Clear();
};
Enemy.h
#pragma once
#include <print>
// Klasa reprezentująca przeciwnika w grze
class Enemy {
public:
// Nazwa przeciwnika
std::string name;
// Maksymalne zdrowie przeciwnika
int maxHealth = 0;
// Aktualne zdrowie przeciwnika
int currentHealth = 0;
// Poziom przeciwnika (domyślnie 1)
int level = 1;
// Obrażenia zadawane przez przeciwnika
int damage = 0;
// Tworzy przeciwnika na podstawie typu (np. 0 = Zombie, 1 = Szkielet, 2 = Goblin)
void createEnemy(int type);
// Ustawia poziom przeciwnika i skaluje jego statystyki
void SetLevel(int enemyLevel);
};