Simple juego RPG en Python

Con ganas de profundizar en la Prgramación Orientada a Objetos con Python, hoy quiero compartirles el código de un simple juego RPG y su análisis para mejor comprensión.

Si eres nuevo en el tema, te dejo un par de enlaces que pueden ser de ayuda:

1 - Programación Orientada a Objetos en Python
1 - Herencia y Polimorfismo en Python

El código no es de mi autoría, hice la traducción al español del código y su correspondiente análisis. En el código y al final del artículo sito la fuente.

Simple RPG en Python
Simple RPG en Python

No se guíen por la imagen jeje, el juego está diseñado para utilizar en Consola, pero más allá de que sea o no gráfico, el código está excelente para analizarlo y aprender de el.

El juego correo con Python 2.x


Juego Completo:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Autor: https://balau82.wordpress.com/about-me/
# Articulo original: https://balau82.wordpress.com/2010/06/28/simplest-rpg-game-in-python/

# Traduccion y Analisis del codigo
# https://www.pythondiario.com/2016/10/simple-juego-rpg-en-python.html
# Diego Caraballo
 
from random import randint
 
class Personaje:
  def __init__(self):
    self.nombre = ""
    self.salud = 1
    self.salud_max = 1
    
  def hacer_danio(self, Enemigo):
    danio = min(max(randint(0, self.salud) - randint(0, Enemigo.salud), 0), Enemigo.salud)
    Enemigo.salud = Enemigo.salud - danio
    if danio == 0: print "%s evade el ataque de %s" % (Enemigo.nombre, self.nombre)
    else: 
  print "%s acierta un golpe %s!" % (self.nombre, Enemigo.nombre)
    return Enemigo.salud <= 0
 
class Enemigo(Personaje):
  def __init__(self, Jugador):
    Personaje.__init__(self)
    self.nombre = 'un Orco'
    self.salud = randint(1, Jugador.salud)
 
class Jugador(Personaje):
  def __init__(self):
    Personaje.__init__(self)
    self.estado = 'normal'
    self.salud = 10
    self.salud_max = 10
    
  def salir(self):
    print "%s no puede encontrar el camino de vuelta a casa y muere de inanicion.nR.I.P." % self.nombre
    self.salud = 0
    
  def ayuda(self): 
   print Commands.keys()
  
  def estado(self): 
   print "%s - salud: %d/%d" % (self.nombre, self.salud, self.salud_max)
  
  def cansancio(self):
    print "%s siente cansancio." % self.nombre
    self.salud = max(1, self.salud - 1)
    
  def descanso(self):
    if self.estado != 'normal': 
  print "%s no puede descansar ahora!" % self.nombre; self.Enemigo_ataques()
    else:
      print "%s descansa." % self.nombre
      if randint(0, 1):
        self.Enemigo = Enemigo(self)
        print "%s se desperto de golpe por %s!" % (self.nombre, self.Enemigo.nombre)
        self.estado = 'lucha'
        self.Enemigo_ataques()
      else:
        if self.salud < self.salud_max:
          self.salud = self.salud + 1
        else: 
   print "%s a dormido demasiado." % self.nombre; self.salud = self.salud - 1
        
  def explorar(self):
    if self.estado != 'normal':
      print "%s esta demasiado ocupado en este momento!" % self.nombre
      self.Enemigo_ataques()
    else:
      print "%s explora un pasaje sinuoso." % self.nombre
      if randint(0, 1):
        self.Enemigo = Enemigo(self)
        print "%s encuentra %s!" % (self.nombre, self.Enemigo.nombre)
        self.estado = 'lucha'
      else:
        if randint(0, 1): self.cansancio()
        
  def huir(self):
    if self.estado != 'lucha': 
  print "%s corre en circulos durante un tiempo." % self.nombre 
  self.cansancio()
    else:
      if randint(1, self.salud + 5) > randint(1, self.Enemigo.salud):
        print "%s huye de %s." % (self.nombre, self.Enemigo.nombre)
        self.Enemigo = None
        self.estado = 'normal'
      else: 
    print "%s no puede escapar de %s!" % (self.nombre, self.Enemigo.nombre) 
    self.Enemigo_ataques()
      
  def atacar(self):
    if self.estado != 'lucha': 
  print "%s golpea con fuerza pero sin resultados." % self.nombre 
  self.cansancio()
    else:
      if self.hacer_danio(self.Enemigo):
        print "%s aniquila %s!" % (self.nombre, self.Enemigo.nombre)
        self.Enemigo = None
        self.estado = 'normal'
        if randint(0, self.salud) < 10:
          self.salud = self.salud + 1
          self.salud_max = self.salud_max + 1
          print "%s se siente mas fuerte!" % self.nombre
      else: 
    self.enemigo_ataques()
      
  def enemigo_ataques(self):
    if self.Enemigo.hacer_danio(self): 
  print "%s fue sacrificado por %s!!!nR.I.P." %(self.nombre, self.Enemigo.nombre)
 
Commands = {
  'salir': Jugador.salir,
  'ayuda': Jugador.ayuda,
  'estado': Jugador.estado,
  'descanso': Jugador.descanso,
  'explorar': Jugador.explorar,
  'huir': Jugador.huir,
  'atacar': Jugador.atacar,
  }
 
p = Jugador()
p.nombre = raw_input("Cual es el nombre del personaje? ")
print "(Escribe ayuda para obtener una lista de acciones)n"
print "%s entra en una cueva oscura en busca de aventura." % p.nombre
 
while(p.salud > 0):
  line = raw_input("> ")
  args = line.split()
  if len(args) > 0:
    commandFound = False
    for c in Commands.keys():
      if args[0] == c[:len(args[0])]:
        Commands(p)
        commandFound = True
        break
    if not commandFound:
      print "%s no se entiende la accion." % p.nombre
 
"""
Copyright 2010 Francesco Balducci
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
See  for a copy of the GNU General Public License.
"""

Análisis del Juego

El código arranca importando la librería random (es la única que necesitamos importar), esta librería nos permite trabajar con datos aleatorios. Si quieres conocer más acerca de esta librería puedes ver un artículo que publique ya hace algún tiempo: Modulo random en Python con ejemplos

Luego se define la clase Personaje() que más tarde va a ser heredada por la clase Jugador() y Enemigo().
En la clase Personaje() se define el constructor __init__ y se inicializan algunos parámetros (nombre, salud, etc), también se define un método hacer_danio() que nos dará un valor aleatorio del daño provocado en el ataque.

Luego se define la clase Enemigo() que como mencione más arriba, hereda la clase Personaje(). Esta clase contiene solo el constructor __init__ que inicializa el nombre del enemigo (un Orco) y la salud, que va a ser entre 1 y la salud del Jugador.

Luego viene la clase Jugador(), esta clase contiene una gran cantidad de método, iré explicándolos de a uno:

Método __init__: este es el constructor de la clase, inicializa el estado, la salud y la salud máxima del jugador.

Método salir: cuando en el juego tecleamos "salir" este método es llamado, despliega un mensaje y pone en 0 la salud del jugador, por lo tanto sale del bucle y se cierra el programa.

Método ayuda: cuando en el juego tecleamos "ayuda" este método es llamado y muestra en pantalla las keys del diccionario "commands".

Método estado: cuando en el juego tecleamos "estado" este método es llamado y devuelve la salud del jugador.

Método cansancio: cuando este método es llamado, se despliega un mensaje de "siente cansancio" y la propiedad salud del jugador bajará 1 punto.

Método descanso: cuando este método es llamado se plantea una condición: si el estado del jugador es distinto de "normal" el personaje no va a poder descansar (se supone que esta en "lucha"), si no, el personaje se pone a descansar. Si el personaje se pone a descansar pueden ocurrir dos cosas: que el personaje se despierte de golpe porque lo quieren atacar o que logre descansar plácidamente y recupere un punto de salud.

Método explorar: cuando este método es llamado, se plantea una condición: si el estado del jugador es distinto de "normal" el personaje no va a poder explorar(se supone que esta en "lucha"), si no, el personaje explora "un pasaje sinuoso" y puede ocurrir (de forma aleatoria) que encuentre un enemigo (el estado cambia a "lucha") o que sufra cansancio (pierde un punto de salud).

Método huir: si el estado del jugador es distinto de "lucha" el personaje comienza correr y llama al método cansancio(). De lo contrario, si el estado está en "lucha" se plantea una condición: dependiendo de un valor aleatorio el jugador podrá huir o no del enemigo. En caso de huir, el enemigo desaparece y el estado cambia a "normal", si no puede huir, el enemigo ataca.

Método atacar: cuando este método es llamado, se plantea una condición: si el estado del jugador es distinto de "lucha", se despliega un mensaje y el método cansancio() es llamado. De lo contrario se plantea una condición: si el método hacer_danio() es True, el enemigo es destruido y el estado cambia a normal (y en caso de tener suerte la salud y salud_maxima suben a 1), de lo contrario el método enemigo_ataques() es llamado.

Método enemigo_ataques: este método es llamado cuando el Jugador se queda sin puntos de salud.

Por último se define un diccionario Commands, que contiene las acciones que el jugador puede escribir en consola para ir interactuando en el juego. Puedes ver más sobre diccionarios en la siguiente entrada: Tipos de datos en Python

Ahora toca la parte de inicializar un jugador (en este se crea el objeto "p") y se hace una pequeña introducción preguntando el nombre del personaje, dando datos de ayuda y el primer ingreso en la cueva "buuuuuuu".

El bucle "while" hará que se ejecute el juego  mientras que la salud del jugador sea mayor a 0.

Hasta acá el análisis, espero lo puedan comprender, lo puedan modificar a su gusto (la mejor forma de aprender) y por supuesto, que les sea de ayuda.

Cualquier consulta, duda o sugerencia siempre es bienvenida y alentadora!!!

Saludos, Diego.

Fuente: https://balau82.wordpress.com/2010/06/28/simplest-rpg-game-in-python/

  1. Anónimo dice:

    excelente articulo!!

    1. PythonDiario dice:

      Gracias por comentar y visitar el blog!!!

  2. Anónimo dice:

    Hola! Muchas gracias por esta nueva entrada de Python. Es de mucha ayuda explicar la POO usando ejemplos que se salgan un poco de lo convencional. Se hace mas divertido aprender este paradigma de esta manera. Por otro lado, yo tengo en mente crear un juego conversacional. Pero me queda implementar el uso de localidades. Es decir, que el personaje se pueda mover dentro de un mapa con comandos como nortes, sur, este, oeste, arriba, abajo, etc... Y luego el uso de inventario de objetos. Seria otro buen tutorial para el blog y aprovechar la POO. Saludos y gracias!!!

    1. PythonDiario dice:

      Hola, gracias por tomarte un tiempo para pasarte y comentar en el blog. Como tu dices, la idea de la entrada era salir un poco de lo convencional para hacerlo más divertido.
      Siempre me gustó la idea de hacer un jugo RPG 2D en PyGame pero por falta de tiempo no he podido. Con respecto a lo del inventario, quizá ya lo hallas visto, pero por las dudas puedes darte una vuelta por este entrada: Ver Link

      Saludos!!!

    2. Anónimo dice:

      Muchas gracias por el link. Aunque por eso visito tu blog....de ingles no entiendo ni jota 😉
      En todo caso, viendo el script, algo aprovechare. Gracias!

  3. Unknown dice:

    Excelente para aprender

  4. Unknown dice:

    Quiero correr el código para hacerle pruebas y utilizarlo como base para mi propio código y juego de batalla pero no puedo, todo esta correcto pero no sé porqué no puedo correrlo.

  5. Unknown dice:

    el codigo no está completo, por eso no puedes correrlo

  6. Negocios para emprendedores dice:

    Necesito hacer un juego de guerras de los mundos alguno que pueda ayudar..

  7. Unknown dice:

    yo quiero hacer un juego de rol por fases, en el que dependiendo de la opcion que elijas, tomara un camino u otro...pero no se como hacerlo xd

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Subir
White Monkey