├── .readme_pics └── classes.png ├── LICENSE ├── README.md ├── character.py ├── health_bar.py ├── main.py └── weapon.py /.readme_pics/classes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/orkslayergamedev/python-classes-text-battle/9b17da4556d7ed1645ab8c52dc98386823ed570d/.readme_pics/classes.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Adrian (Ork Slayer Gamedev) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Python Classes - Text-Based Battle Scene 2 | =========================== 3 | My most recent and well-built tutorial about Object-Oriented Programming (OOP) in Python. All in a fun way of creating a text-based ASCII battle scene, featuring Character subclasses, different Weapons and dynamic HealthBars. 4 | 5 | https://youtu.be/0e2DexQlDYk 6 | 7 | ![img.png](.readme_pics/classes.png) 8 | -------------------------------------------------------------------------------- /character.py: -------------------------------------------------------------------------------- 1 | # ------------ imports ------------ 2 | from weapon import fists 3 | from health_bar import HealthBar 4 | 5 | 6 | # ------------ parent class setup ------------ 7 | class Character: 8 | def __init__(self, 9 | name: str, 10 | health: int, 11 | ) -> None: 12 | self.name = name 13 | self.health = health 14 | self.health_max = health 15 | 16 | self.weapon = fists 17 | 18 | def attack(self, target) -> None: 19 | target.health -= self.weapon.damage 20 | target.health = max(target.health, 0) 21 | target.health_bar.update() 22 | print(f"{self.name} dealt {self.weapon.damage} damage to " 23 | f"{target.name} with {self.weapon.name}") 24 | 25 | 26 | # ------------ subclass setup ------------ 27 | class Hero(Character): 28 | def __init__(self, 29 | name: str, 30 | health: int 31 | ) -> None: 32 | super().__init__(name=name, health=health) 33 | 34 | self.default_weapon = self.weapon 35 | self.health_bar = HealthBar(self, color="green") 36 | 37 | def equip(self, weapon) -> None: 38 | self.weapon = weapon 39 | print(f"{self.name} equipped a(n) {self.weapon.name}!") 40 | 41 | def drop(self) -> None: 42 | print(f"{self.name} dropped the {self.weapon.name}!") 43 | self.weapon = self.default_weapon 44 | 45 | 46 | # ------------ subclass setup ------------ 47 | class Enemy(Character): 48 | def __init__(self, 49 | name: str, 50 | health: int, 51 | weapon, 52 | ) -> None: 53 | super().__init__(name=name, health=health) 54 | self.weapon = weapon 55 | 56 | self.health_bar = HealthBar(self, color="red") 57 | -------------------------------------------------------------------------------- /health_bar.py: -------------------------------------------------------------------------------- 1 | # ------------ imports ------------ 2 | import os 3 | 4 | # ------------ setup ------------ 5 | os.system("") 6 | 7 | 8 | # ------------ class setup ------------ 9 | class HealthBar: 10 | symbol_remaining: str = "█" 11 | symbol_lost: str = "_" 12 | barrier: str = "|" 13 | colors: dict = {"red": "\033[91m", 14 | "purple": "\33[95m", 15 | "blue": "\33[34m", 16 | "blue2": "\33[36m", 17 | "blue3": "\33[96m", 18 | "green": "\033[92m", 19 | "green2": "\033[32m", 20 | "brown": "\33[33m", 21 | "yellow": "\33[93m", 22 | "grey": "\33[37m", 23 | "default": "\033[0m" 24 | } 25 | 26 | def __init__(self, 27 | entity, 28 | length: int = 20, 29 | is_colored: bool = True, 30 | color: str = "") -> None: 31 | self.entity = entity 32 | self.length = length 33 | self.max_value = entity.health_max 34 | self.current_value = entity.health 35 | 36 | self.is_colored = is_colored 37 | self.color = self.colors.get(color) or self.colors["default"] 38 | 39 | def update(self) -> None: 40 | self.current_value = self.entity.health 41 | 42 | def draw(self) -> None: 43 | remaining_bars = round(self.current_value / self.max_value * self.length) 44 | lost_bars = self.length - remaining_bars 45 | print(f"{self.entity.name}'s HEALTH: {self.entity.health}/{self.entity.health_max}") 46 | print(f"{self.barrier}" 47 | f"{self.color if self.is_colored else ''}" 48 | f"{remaining_bars * self.symbol_remaining}" 49 | f"{lost_bars * self.symbol_lost}" 50 | f"{self.colors['default'] if self.is_colored else ''}" 51 | f"{self.barrier}") 52 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # ------------ imports ------------ 2 | import os 3 | from character import Hero, Enemy 4 | from weapon import short_bow, iron_sword 5 | 6 | # ------------ setup ------------ 7 | hero = Hero(name="Hero", health=100) 8 | hero.equip(iron_sword) 9 | enemy = Enemy(name="Enemy", health=100, weapon=short_bow) 10 | 11 | # ------------ game loop ------------ 12 | while True: 13 | os.system("cls") 14 | 15 | hero.attack(enemy) 16 | enemy.attack(hero) 17 | 18 | hero.health_bar.draw() 19 | enemy.health_bar.draw() 20 | 21 | input() 22 | -------------------------------------------------------------------------------- /weapon.py: -------------------------------------------------------------------------------- 1 | # ------------ class setup ------------ 2 | class Weapon: 3 | def __init__(self, 4 | name: str, 5 | weapon_type: str, 6 | damage: int, 7 | value: int 8 | ) -> None: 9 | self.name = name 10 | self.weapon_type = weapon_type 11 | self.damage = damage 12 | self.value = value 13 | 14 | 15 | # ------------ object creation ------------ 16 | iron_sword = Weapon(name="Iron Sword", 17 | weapon_type="sharp", 18 | damage=5, 19 | value=10) 20 | 21 | short_bow = Weapon(name="Short Bow", 22 | weapon_type="ranged", 23 | damage=4, 24 | value=8) 25 | 26 | fists = Weapon(name="Fists", 27 | weapon_type="blunt", 28 | damage=2, 29 | value=0) 30 | --------------------------------------------------------------------------------