Caleb
Caleb

Reputation: 11

Making RPG text based game in Ruby. How to store and run controls and scenes?

I am very new to Ruby and have been going through a couple of sources to try and learn. I finished Codecadamy's Ruby class and I am about 75% through Learn Ruby the Hard Way. Also I've read about 100 pages of both Eloquent Ruby and the pickaxe Ruby book (but those aren't clicking for me as of yet).

I am trying to make a text based RPG game in Ruby for practice. I decided to recreate Chrono Trigger, as I know the game well and I don't want to take time thinking of characters and stories; just want to practice coding.

I tried to make four simple controls for the player to use, however I am finding it very difficult to incorporate in scenes.

For example I have the control "talk" and I use 'if/else' statements to run the scenes based on what the user inputs. I find myself having to go through endless if/else scenarios if the user types "talk" multiple times.

Below is my code. It's extremely messy as I am a beginner, but if someone could look at it and give me some advice on how to make it work that would be great!

---------Welcome Method-----------

def welcome
    puts "Welcome to Chrono Trigger: Ruby Edition!"
    puts "Let's discuss the controls to help you become familiar with the game."
    puts ""
    puts "We are going to break the controls down into categories to help make it easier to understand"
    puts "Anytime you get stuck just type 'help' to bring the controls back up."
    puts ""
    puts "The controls are 'talk' 'action' 'attack' 'flee'."
    puts ""
    puts "Simple enough? Type 'start' to begin!"

    print "> "
    response = $stdin.gets.chomp
        if response == "start" then chapter_1_start end
end

---------What should Crono do next?------

def crono_next
    puts "What should Crono do next?"
    @next_task = $stdin.gets.chomp
end


def chapter_1_start
    puts "(Bells Ringing)"
    puts "\"Crono....Crono...\""
    puts "\"Time to get up!\""
    puts ""
    puts "Crono wakes up from bed."
    puts "Crono is standing in the middle of his bedroom"
    print "> "
    response = $stdin.gets.chomp
    if response == "help"
        help
    elsif response == "action"
        puts "Crono closes the curtains."
        puts "Then he leaves the room"
        chapter_1_start2
    elsif response == "talk"
        puts "Crono talks to himself"
    else
        puts "..."
    end    
end

def chapter_1_start2

    def talk
        puts "Mom: \"Oh Crono, don't forget to stop by your friend Lucca's house before you head to the Millenial Fair.\""
        crono_next
        if @next_task == "talk"
            puts "Mom: \"I almost forgot. Here's 200 gil to buys some cat food while you're out.\""
            crono_next
            if @next_task == "talk"
                puts "Mom: \"You really should be leaving now Crono\""
                chapter_1_start3
            elsif @next_task == "action"
                puts "Crono pets his cat."
                puts "'Meow'" 
                chapter_1_start3
            else
                chapter_1_start3
            end    

        elsif @next_task == "action"
            action
        else
            "Mom: \"You really should be leaving now Crono\""
            chapter_1_start3
        end
    end

    def action
        puts "Crono pets his cat."
        puts "'Meow'" 
        crono_next
        if @next_task == "talk"
            talk
        elsif @next_task == "action"
            action
        else
            "Crono does nothing."
        end    
    end
    puts "Crono heads downstairs and sees his mom in the kitchen and his cat in the living room."
    crono_next
    if @next_task == "talk"
        talk
    elsif @next_task == "action"
        action
    else
        puts "Let's try that again."
        chapter_1_start2
    end    
end

def chapter_1_start3
    puts ""
    puts "Crono begins walking away from his house"
    puts "If he travels West he will be heading in the direction of Lucca's house."
    puts "If he travels East he will be headed to the Millenial Fair."
    puts crono_next   

----------------Help Menu----------------

def help
    puts "What do you need help with? 'controls', 'hints', 'quit'"
    print "> "
    help_subject = $stdin.gets.chomp
    if help_subject == "controls"
        puts "The controls are 'talk' 'action' 'attack' 'flee'."
    elsif help_subject == "hints"
        puts "I got nothing"
    elsif help_subject == "quit"
        puts "Are you sure you want to quit?(Your game will not be saved)"
        print "> "
        sure_quit = $stdin.gets.chomp
        if sure_quit.include? "y"
            exit(0)
        else
            help
        end
    else
        puts "Guess you didn't really need help after all."
    end
end

----------------Help Menu-----------------

def talk(person)
    @person = person
end

welcome

Upvotes: 0

Views: 1587

Answers (1)

eiko
eiko

Reputation: 5345

Text-based games are actually quite complicated and end up following many of the same logic and design patterns as traditional video games. You may want to google around for guides on game design- there are lots of them and the fundamentals apply to any programming language.

That being said, if you want to continue with your game as it is without getting lost in endless if-statements, you should use classes to manage your scenes.

Every game has a main loop, which is an endless loop which handles 3 main tasks: displaying stuff to the screen, collecting user input, and calculating changes in the game state. That happens over and over again:

#main.rb
scene = Scene.new(:chapter_1)
while true
  scene.display
  print "> "
  action = $stdin.gets.chomp
  if command == 'talk'
    scene = scene.talk
  elsif command == 'action'
    scene = scene.action
  elsif command = 'attack'
    scene = scene.attack
  elsif command = 'flee'
    scene = scene.flee
  else
    puts 'unknown command!'
  end
end

The scene class basically just holds the text for each scene as well as which actions link which scenes to which other scenes. This structure is called a state machine, and it's the simplest way to keep track of a game's state:

#scene.rb
class Scene
  def initialize beginning_state
    @state = beginning_state
    @scenes = {
      chapter_1: [
        "Hello and welcome to chapter 1 of my game!", 
        :ch1_talk, 
        :ch1_action,
        :ch1_attack,
        :chapter_2],
      ch1_talk: [
        "Please stop talking while I'm talking!",
        :ch1_talk, 
        :ch1_action,
        :ch1_attack,
        :chapter_2],
      ch1_action: [
        "W-what are you doing?!",
        :ch1_talk, 
        :ch1_action,
        :ch1_attack,
        :chapter_2],
      ch1_attack: [ 
        "Stop, that hurts :c",
        :ch1_talk, 
        :ch1_action,
        :ch1_attack,
        :chapter_2],
      chapter_2: [ 
        "Congratulations, you have entered...\n chapter 2!",
        :ch2_talk, 
        :ch2_action,
        :ch2_attack,
        :ch2_flee],
      ch2_talk: [
        "I'm ignoring you",
        :ch2_talk, 
        :ch2_action,
        :ch2_attack,
        :ch2_flee],
      ch2_action: [
        "I don't even care",
        :ch2_talk, 
        :ch2_action,
        :ch2_attack,
        :ch2_flee],
      ch2_attack: [ 
        "You're no match for me",
        :ch2_talk, 
        :ch2_action,
        :ch2_attack,
        :ch2_flee],
      ch2_flee: [
        "Okay, goodbye!",
        :ch2_talk, 
        :ch2_action,
        :ch2_attack,
        :ch2_flee],
    }
  end

  def display
    puts @scenes[@state][0]
  end

  def talk
    @state = @scenes[@state][1]
  end

  def action
    @state = @scenes[@state][2]
  end

  def attack
    @state = @scenes[@state][3]
  end

  def flee
    @state = @scenes[@state][4]
  end
end

Sorry that's a bit complicated, but games are a bit complicated. Also ideally, you would save your scenes in specially-formatted text files and then load them into the game, instead of defining them in source code like I did.

Upvotes: 2

Related Questions