Open-Source Internship opportunity by OpenGenus for programmers. Apply now.
Content
- Introduction
- Summary
- Ruby2d
- Hangman
- initialize
- key press events
- guesses/ win or lose
- compare word and letters
- display
- stick figure
- guesses remaining/gameover/message
- call game and key events
- Conclusion
Introduction
In this article at OpenGenus, we will be building a traditional hangman game with the use of ruby2d as the GUI, the game will choose a random word from an array and the user will have to guess what that word is. The user will have 6 chances to guess the word, before it is GAME OVER!!!.
Summary
The Game is built using ruby2d. The main window has a white background, the game starts by introducing a blue line where your correct guess will appear, below that is an empty array to store your incorrect guesses , then the remaining number of guesses and a hint to help you guess the correct word. When you fill the blue line with the correct word a 'won' message appears, if you dont get the correct word before you run out of guesses you would see the fully drawn hangman on the game window then 'game over' appears. This game was implemented using one class with a number of methods to handle specific tasks that were needed in the game, an initialize method with default variables for when the game starts, a method to randomly select a word for the user to guess, another to deal with key that is pressed to enter the letter, a couple of methods that deal with comparing if that letter is correct or not and a another set of methods, that deal with the overall display of the game we see, when it is in progress and when it has been completed or game over.
Ruby2d
Ruby2D is a simple and lightweight 2D game development framework for the Ruby programming language. It provides an easy-to-use interface for creating graphics, handling user input, playing audio, and managing windowing and event-driven programming.
Hangman
Firstly we start by loading the required gem "ruby2d", we do this by adding it to the GEM file gem'ruby2d'
and then we run bundle install
in our terminal after this we create a new file and add our first line require 'ruby2d'
, we then use the set method of ruby2d to add the title and background of our GUI
require 'ruby2d'
set title: "Hangman"
set background: 'white'
initialize
Next we create our Hangman class and add our initialize method, this will have five variables @word
to store our randomly selected word which is chosen from our select_word
method, @incorrect_guesses
to store our wrong guesses, likewise correct_guesses
to store our right guesses, @max_guesses
to compare when we reached our guess limit and @game_over
to let us know when the game has ended.
class Hangman
def initialize
@word = select_word
@incorrect_guesses = []
@correct_guesses = []
@max_guesses = 6
@game_over = false
end
def select_word
words = ["ruby", "hangman", "games", "programming", "openai"]
words.sample
end
key press events
We continue with our next method handle_key_press
which takes one argument event
, now we are going to add a few methods here which we will create later so dont be alarmed. First we have a guess variable that is equal to the lowercase of whatever key we press, then we make our condition and say if we have a valid guess and our game is not over and our word includes our guess then we add our guess to our @correct_guesses
array and if we have won our @game_over
become true else if the guess is incorrect we add our guess to our @incorrect_guesses
array and if it is a loss our game_over will still be true.
---previous code---
def handle_key_press(event)
guess = event.key.downcase
if valid_guess?(guess) && !@game_over
if @word.include?(guess)
@correct_guesses << guess
if won?
@game_over = true
end
else
@incorrect_guesses << guess
if loss?
@game_over = true
end
end
end
end
guesses/ win or lose
Here we will add the mothods that were mentioned previously, valid_guess?
, won?
, loss?
. Our valid_guess
method takes one argument guess
and says if our guess
length is the same as 1 and our guess
matches any lowercase letter from a to z and our guess
is included in our @correct_guesses
or @incorrect_guesses
then this is what makes a valid guess. Our won?
method just checks to see if visible_word
(a method we will add next) matches our @word
(chosen word), and finally our loss
method check the length of our @incorrect_guesses
variable to see if it is greater or equal to our @max_guesses
variable.
----previous code----
def valid_guess?(guess)
guess.length == 1 && guess.match?(/[a-z]/) && !(@correct_guesses.include?(guess) || @incorrect_guesses.include?(guess))
end
def won?
visible_word == @word
end
def loss?
@incorrect_guesses.length >= @max_guesses
end
compare word and letters
The next method we have is visible_word
, this compare our completed input to @word
so we would know if we have won. we declare visible
as and empty string then we check to see if each letter of @word
is in @correct_guesses
we then add those letter to visible
to form our word.
----previous code----
def visible_word
visible = ""
@word.chars.each do |char|
visible << (@correct_guesses.include?(char) ? char : "_")
end
visible
end
display
We will now create 2 methods to display the game when it is in play and when it is game over. The first one is display_board
this includes the hints for the user, we simply say if @word
is a particular word then the hint
should be a particular hint. Then we use the Text method of ruby2d to display the text we want in the game, Text.new(visible_word, ....)
displays the letters for the word when we input the correct letter,Text.new("Incorrect Guesses:...)
displays the incorrect letters the user has inputted,Text.new("Guesses Remaining:...)
displays the amount of guesses remaining and Text.new("A hint: #{hint}",...)
displays the hint for the correct word.
----previous code----
def display_board
hint = ""
if @word == "ruby"
hint = "computer language"
elsif
@word == "hangman"
hint = "swinging male"
elsif
@word == "games"
hint = "what we play"
elsif
@word == "programming"
hint = "make the computer speak"
else
@word == 'openai'
hint = "artificial intelligence"
end
Text.new(visible_word, color: 'blue', x: 10, y: 10, size: 50)
Text.new("Incorrect Guesses: #{@incorrect_guesses}", color:'black', x: 10, y: 100)
Text.new("Guesses Remaining: #{guesses_remaining}", color:'black', x: 10, y: 130)
Text.new("A hint: #{hint}", color: 'blue', x: 10, y: 160)
stick_figure
end
This next method shows text for when you win or lose. Our method display_game_over
is just a condition that says if loss?
display these set of text else(if won?
) display these text instead.
----previous code----
def display_game_over
if lost?
Text.new("GAME OVER", color:'red', x: 200, y: 100, size: 60)
Text.new("The word was: #{@word}", color:'black', x: 220, y: 200, size: 30)
Text.new(message, color:'black', x: 220, y: 300, size: 30)
stick_figure
else
Text.new("YOU WON, CONGRATS", color: 'blue', x: 80, y: 100, size: 60)
Text.new(message, color:'black', x: 250, y: 300, size: 30)
end
end
stick figure
This method uses different aspects of ruby2d to draw the hangman on the window. We begin with setting the base with a Square
and a few Lines
, these will be shown by default from the start of the game. We then proceed to create the body by using Circle.new
and Line.new
, these objects are put into variables to be used withing the coming if
statement. In this if
statement we use the length of the @incorrect_guesses array to say which part of the hangman body we will shown, if the length is zero then no part is shown, we do this by using the remove
method of ruby2d and if the length is one then we show the head by using the add
method on the head
variable but leave the rest of the body parts as remove
. This trend continues as the length of the @incorrect_guesses increases until all the body parts are added to the window, which will mean "GAME OVER".
----previous code----
def stick_figure
Square.new(
x: 300, y: 500,
size: 50,
color: 'blue',
z: 10
)
Line.new(
x1: 325, y1: 300,
x2: 325, y2: 500,
width: 10,
color: 'lime',
z: 20
)
Line.new(
x1: 325, y1: 300,
x2: 450, y2: 300,
width: 10,
color: 'lime',
z: 20
)
Line.new(
x1: 450, y1: 300,
x2: 450, y2: 350,
width: 10,
color: 'lime',
z: 20
)
head = Circle.new(
x: 450, y: 370,
radius: 20,
sectors: 32,
color: 'fuchsia',
z: 10
)
body = Line.new(
x1: 450, y1: 390,
x2: 450, y2: 500,
width: 10,
color: 'fuchsia',
z: 20
)
arm_one = Line.new(
x1: 450, y1: 410,
x2: 375, y2: 410,
width: 10,
color: 'fuchsia',
z: 20
)
arm_two = Line.new(
x1: 450, y1: 410,
x2: 525, y2: 410,
width: 10,
color: 'fuchsia',
z: 20
)
leg_one = Line.new(
x1: 450, y1: 500,
x2: 400, y2: 575,
width: 10,
color: 'fuchsia',
z: 20
)
leg_two = Line.new(
x1: 450, y1: 500,
x2: 500, y2: 575,
width: 10,
color: 'fuchsia',
z: 20
)
if @incorrect_guesses.length == 0
head.remove
body.remove
arm_one.remove
arm_two.remove
leg_one.remove
leg_two.remove
elsif
@incorrect_guesses.length == 1
head.add
body.remove
arm_one.remove
arm_two.remove
leg_one.remove
leg_two.remove
elsif
@incorrect_guesses.length == 2
head.add
body.add
arm_one.remove
arm_two.remove
leg_one.remove
leg_two.remove
elsif
@incorrect_guesses.length == 3
head.add
body.add
arm_one.add
arm_two.remove
leg_one.remove
leg_two.remove
elsif
@incorrect_guesses.length == 4
head.add
body.add
arm_one.add
arm_two.add
leg_one.remove
leg_two.remove
elsif
@incorrect_guesses.length == 5
head.add
body.add
arm_one.add
arm_two.add
leg_one.add
leg_two.remove
else
@incorrect_guesses.length == 6
head.add
body.add
arm_one.add
arm_two.add
leg_one.add
leg_two.add
end
end
guesses remaining/gameover/message
The next few methods are pretty self explanatory, guesses_remaining
minus the length of @incorrect_guesses
from the @max_guesses
, game_over
simply calls the @game_over
variable and message
has a string letting the user know which button to press to restart the game. We then just set the width and height of our display screen/ game area, this is done outside of our Hangman class
----previous code----
def guesses_remaining
@max_guesses - @incorrect_guesses.length
end
def game_over
@game_over
end
def message
"Press 'spacebar' to restart"
end
end
set width: 800, height: 600
call game and key events
This Last part is done outside of our Hangman class, we first call a new game game = Hangman.new
, then we use 2 of the ruby2d methods on :key_down
and update
. With on :key_down
we call the handle_key_press
method this lets the program know which keys have been pressed and we also say if the key is space(spacebar) then we call a new hangman game(restart the game). Our update
method is saying if the game is over we clear
the window and call our display_game_over
method else we just call our display_board
method, we then wrap it all up with our ruby2d show
method at the end.
----previous code----
game = Hangman.new
on :key_down do |event|
game.handle_key_press(event)
if event.key == 'space'
game = Hangman.new
end
end
update do
clear
if game.game_over
game.display_game_over
else
game.display_board
end
end
show
complete code below
require 'ruby2d'
set title: "Hangman"
set background: 'white'
class Hangman
def initialize
@word = select_word
@incorrect_guesses = []
@correct_guesses = []
@max_guesses = 6
@game_over = false
end
def select_word
words = ["ruby", "hangman", "games", "programming", "openai"]
words.sample
end
def handle_key_press(event)
guess = event.key.downcase
if valid_guess?(guess) && !@game_over
if @word.include?(guess)
@correct_guesses << guess
if won?
@game_over = true
end
else
@incorrect_guesses << guess
if loss?
@game_over = true
end
end
end
end
def valid_guess?(guess)
guess.length == 1 && guess.match?(/[a-z]/) && !(@correct_guesses.include?(guess) || @incorrect_guesses.include?(guess))
end
def won?
visible_word == @word
end
def loss?
@incorrect_guesses.length >= @max_guesses
end
def visible_word
visible = ""
@word.chars.each do |char|
visible << (@correct_guesses.include?(char) ? char : "_")
end
visible
end
def display_board
hint = ""
if @word == "ruby"
hint = "computer language"
elsif
@word == "hangman"
hint = "swinging male"
elsif
@word == "games"
hint = "what we play"
elsif
@word == "programming"
hint = "make the computer speak"
else
@word == 'openai'
hint = "artificial intelligence"
end
Text.new(visible_word, color: 'blue', x: 10, y: 10, size: 50)
Text.new("Incorrect Guesses: #{@incorrect_guesses}", color:'black', x: 10, y: 100)
Text.new("Guesses Remaining: #{guesses_remaining}", color:'black', x: 10, y: 130)
Text.new("A hint: #{hint}", color: 'blue', x: 10, y: 160)
end
def display_game_over
if loss?
Text.new("GAME OVER", color:'red', x: 200, y: 100, size: 60)
Text.new("The word was: #{@word}", color:'black', x: 220, y: 200, size: 30)
Text.new(message, color:'black', x: 220, y: 300, size: 30)
else
Text.new("YOU WON, CONGRATS", color: 'blue', x: 80, y: 100, size: 60)
Text.new(message, color:'black', x: 250, y: 300, size: 30)
end
end
def guesses_remaining
@max_guesses - @incorrect_guesses.length
end
def game_over
@game_over
end
def message
"Press 'spacebar' to restart"
end
end
set width: 800, height: 600
game = Hangman.new
on :key_down do |event|
game.handle_key_press(event)
if event.key == 'space'
game = Hangman.new
end
end
update do
clear
if game.game_over
game.display_game_over
else
game.display_board
end
end
show
Conclusion
With this article at OpenGenus, you have just created a hangman game using ruby CONGRATULATIONS, now you can explore more with ruby and ruby2d to make even more games.