Continue with Game development with Ruby
Bài đăng này đã không được cập nhật trong 3 năm
In this post we will continue with game development with Ruby. This time we will focus on UI design with Gosu, a library for game development. Let's go step by step and implement our sokoban game.
Game.rb
We create a file game.rb
with the following content:
require 'gosu' # add gosu gem
class GameWindow < Gosu::Window
def initialize
super 500, 500
self.caption = "Sokoban with Gosu"
end
end
window = GameWindow.new
window.show
we initialize a window for game with width and height of 500 pixels. The window has title Sokoban with Gosu
.
Then we create an instance of the window and display it.
we get a black screen like this.
We need some ways to record the map of the game and then we translate it to build the UI of the game.
Now let's create a file called levels.rb
.
Levels.rb
module Levels
L1 = [
{x: 0, y: 0, type: :wall},
{x: 50, y: 0, type: :wall},
{x: 100, y: 0, type: :wall},
{x: 150, y: 0, type: :wall},
{x: 200, y: 0, type: :wall},
{x: 0, y: 50, type: :wall},
{x: 200, y: 50, type: :wall},
{x: 250, y: 50, type: :wall},
{x: 300, y: 50, type: :wall},
{x: 0, y: 100, type: :wall},
{x: 300, y: 100, type: :wall},
{x: 350, y: 100, type: :wall},
{x: 400, y: 100, type: :wall},
{x: 450, y: 100, type: :wall},
{x: 0, y: 150, type: :wall},
{x: 50, y: 150, type: :wall},
{x: 150, y: 150, type: :wall},
{x: 200, y: 150, type: :wall},
{x: 450, y: 150, type: :wall},
{x: 0, y: 200, type: :wall},
{x: 450, y: 200, type: :wall},
{x: 0, y: 250, type: :wall},
{x: 450, y: 250, type: :wall},
{x: 0, y: 300, type: :wall},
{x: 50, y: 300, type: :wall},
{x: 100, y: 300, type: :wall},
{x: 250, y: 300, type: :wall},
{x: 300, y: 300, type: :wall},
{x: 350, y: 300, type: :wall},
{x: 400, y: 300, type: :wall},
{x: 450, y: 300, type: :wall},
{x: 100, y: 350, type: :wall},
{x: 250, y: 350, type: :wall},
{x: 100, y: 400, type: :wall},
{x: 150, y: 400, type: :wall},
{x: 200, y: 400, type: :wall},
{x: 250, y: 400, type: :wall},
{x: 100, y: 200, type: :dest},
{x: 150, y: 200, type: :dest},
{x: 200, y: 200, type: :dest},
{x: 250, y: 200, type: :dest},
{x: 150, y: 250, type: :dest},
{x: 150, y: 300, type: :dest},
{x: 100, y: 150, type: :box},
{x: 250, y: 150, type: :box},
{x: 300, y: 150, type: :box},
{x: 200, y: 250, type: :box},
{x: 250, y: 250, type: :box},
{x: 350, y: 250, type: :box},
{x: 100, y: 100, type: :player}
]
Stage = [L1]
end
Plan.rb
Here we create a level which is an array of hashes, each of which has x, y coordinate and types of object as :box, :wall, :player, :dest (destination).
We will create another file called plan.rb
to translate each level to reality.
But before translation can be realized we need some images. We create an image folder with image of size 50x50 with the name:
background.jpg
, box.png
, player.png
, wall.png
and destination.png
.
Now let's create plan.rb
to do the translation and draw to the screen.
class Plan
attr_accessor :moves #number of moves
def initialize
@level = @score = @moves = 0 #initialize level, score and moves to 0
#instantiate object for player, background, wall, destination and box
@player = Gosu::Image.new("img/player.png")
@bg = Gosu::Image.new("img/bg.jpg", :tileable => true)
@wall = Gosu::Image.new("img/wall.jpg")
@dest = Gosu::Image.new("img/destination.png")
@box = Gosu::Image.new("img/box.png")
@info = Gosu::Font.new(20) #intantiate object for writing
end
#load levels in file `levels.rb` into @map object using Marshal load and dump
#increment level if we have to go to next level else do nothing, and reset moves number
def load_level(next_level = false)
@level += 1 if next_level
@map = Marshal.load( Marshal.dump(Levels::Stages[@level]) ) # deep copy
@moves = 0
end
#draw is Gosu method for drawing image and characters to screen
#draw has parameters text, x coordinate, y coordinate, z value, x scale, y scale and color
def draw
@bg.draw(0, 0, 0)
@info.draw("Level: #{@level} | Score: #{@score} | Moves: #{@moves}", 10, 480, 1, 1.0, 1.0, 0xff_ff0000)
@info.draw("Esc- exit | Space - reset", 280, 480, 1, 1.0, 1.0, 0xff_808080)
#The actual translation happens here
@map.each do |cell|
case cell[:type]
when :wall
@wall.draw(cell[:x], cell[:y], 0)
when :dest
@dest.draw(cell[:x], cell[:y], 1)
when :box
@box.draw(cell[:x], cell[:y], 0)
when :player
@player.draw(cell[:x], cell[:y], 2)
end
end
end
end
We need to require some files in game.rb
require_relative 'levels'
require_relative 'plan'
Let run the game again: ruby game.rb
we get something like this:
This is quite a lot now. I think we can add some movement in the next post. Hope you enjoy.
Reference
http://dreamingechoes.github.io/game/gosu/ruby/become-a-videogame-developer-master-with-gosu-and-ruby/ https://www.libgosu.org/
All rights reserved