Hi. I'm Cyberarm.

I make games and other things with Ruby and Gosu. 🕹️

Gosu Tutorial: Using the :multiply blend mode

May 12 2021



This tutorial assumes you already have Ruby and Gosu installed.


Here are the two images that are required

The background image

The scope mask image

This tutorial assumes the following directory structure

assets/
  background.png
  scope_mask.png
tutorial.rb

Create a Window

1
2
3
4
require "gosu"

class Window < Gosu::Window
end

Implement Window#initialize

1
2
3
4
5
6
7
require "gosu"

class Window < Gosu::Window
  def initialize(*args)
    super(*args)
  end
end

Load images and add instance variables

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
require "gosu"

class Window < Gosu::Window
  def initialize(*args)
    super(*args)

    @background = Gosu::Image.new("assets/background.png")
    @scope_mask = Gosu::Image.new("assets/scope_mask.png")

    @show_scope = true
    @scope_scale = 1.0

    # Make background image fit to the window's height
    @background_scale = self.height / @background.height.to_f
  end
end

Hide cursor and draw background

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
require "gosu"

class Window < Gosu::Window
  def initialize(*args)
    super(*args)

    @background = Gosu::Image.new("assets/background.png")
    @scope_mask = Gosu::Image.new("assets/scope_mask.png")

    @show_scope = true
    @scope_scale = 1.0

    # Make background image fit to the window's height
    @background_scale = self.height / @background.height.to_f
  end

  def needs_cursor?
    false
  end

  def draw
    @background.draw(0, 0, 0, @background_scale, @background_scale)
  end
end

And finally create the mask image by using Gosu.render to draw a fullscreen black background then draw our scope mask on top of it then finally draw the rendered image using the :multiply blendmode.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
require "gosu"

class Window < Gosu::Window
  def initialize(*args)
    super(*args)

    @background = Gosu::Image.new("assets/background.png")
    @scope_mask = Gosu::Image.new("assets/scope_mask.png")

    @show_scope = true
    @scope_scale = 1.0

    # Make background image fit to the window's height
    @background_scale = self.height / @background.height.to_f
  end

  def needs_cursor?
    false
  end

  def draw
    @background.draw(0, 0, 0, @background_scale, @background_scale)

    draw_mask if @show_scope_mask
  end

  def draw_mask
    Gosu.render(self.width, self.height) do
      Gosu.draw_rect(0, 0, self.width, self.height, Gosu::Color::BLACK)
      @scope_mask.draw_rot(self.mouse_x, self.mouse_y, 0, 0, 0.5, 0.5, @scope_scale, @scope_scale)
    end.draw(0, 0, 0, 1.0, 1.0, Gosu::Color::WHITE, :multiply)
  end
end

Lastly use the right mouse button to toggle the scope on and off. Finally create a new instance of the Window class and show it.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
require "gosu"

class Window < Gosu::Window
  def initialize(*args)
    super(*args)

    @background = Gosu::Image.new("assets/background.png")
    @scope_mask = Gosu::Image.new("assets/scope_mask.png")

    @show_scope = true
    @scope_scale = 1.0

    # Make background image fit to the window's height
    @background_scale = self.height / @background.height.to_f
  end

  def needs_cursor?
    false
  end

  def draw
    @background.draw(0, 0, 0, @background_scale, @background_scale)

    draw_mask if @show_scope_mask
  end

  def draw_mask
    Gosu.render(self.width, self.height) do
      Gosu.draw_rect(0, 0, self.width, self.height, Gosu::Color::BLACK)
      @scope_mask.draw_rot(self.mouse_x, self.mouse_y, 0, 0, 0.5, 0.5, @scope_scale, @scope_scale)
    end.draw(0, 0, 0, 1.0, 1.0, Gosu::Color::WHITE, :multiply)
  end

  def button_down(id)
    @show_scope_mask = !@show_scope_mask if id == Gosu::MS_RIGHT
  end
end

Window.new(1280, 720, false).show