圖形函式庫

林品儒

2017/03/17

Gosu

前情提要

上次已經講過畫圖和貼圖

這次會用到滑鼠和畫線

今天目標

使用鍵盤輸入圖檔檔名

避免載入錯誤

滑鼠拖曳圖片端點

基本框架

#coding: utf-8
require 'gosu'
class GameWindow < Gosu::Window
  def initialize
    super(800,600)
  end
  def update
  end
  def draw
  end
end
game = GameWindow.new
game.show

顯示滑鼠

Gosu預設隱藏滑鼠

需要重定義方法來設定顯示滑鼠

class GameWindow < Gosu::Window
..
def needs_cursor?
  return true
end

文字輸入

Gosu::TextInput

直接鍵盤輸入的文字輸入

這算是基本架構不會直接拿來用

def initialize
  ...
  self.caption = "請直接輸入圖檔檔名"
  self.text_input = Gosu::TextInput.new
end
def update
  text_input and 
  if button_down?(Gosu::KbReturn)
    @path = text_input.text
    self.text_input = nil
    @text = nil
  else        
    @text = text_input.text
  end
end

顯示文字

文字輸入只是輸入不提供繪圖

保留了操作上的彈性

可是顯示就要自己想辦法了

def initialize
  ...
  @font = Gosu::Font.new(24)
  @Zorder = { Pic: 0,Point: 1, Font: 2}
end
def draw
  @font.draw(@text, 10, 10, @Zorder[:Font])
end

載入圖檔

這次是使用外部輸入當作路徑

而不是使用指定的路徑

特別提醒

載入部份是新增在結束文字輸入後

def update
  ...
  @text = nil
  if File.exists?(@path)
    @pic = Gosu::Image.new(self, @path)
    @text = "你是擅長載入圖片的朋友呢:#{@path}"
  else
    @text = "你是擅長錯誤處理的朋友呢"
  end
else        
  @text = text_input.text
end

建立點的類別

因為希望可以用滑鼠拖曳圖形的4個角

需要新增一個符合該功能的類別

...
require 'gosu'
class Point
  attr_reader :x,:y
  def initialize(x,y)
    @x,@y = x,y
  end
  def update(x,y)
    @x,@y = x,y
  end
end
class GameWindow < Gosu::Window...

實體化各點

建立類別後還要產生實體才有效果

class GameWindow < Gosu::Window
  def initialize
    ..
    @points = [
      Point.new(200, 200), Point.new(600, 200),
      Point.new(600, 400), Point.new(200, 400)
    ]
  end
end

點類別顯示

建立了實體但是還需要實際畫出來才能被看到

繪圖需要額外把window自己傳進去

class Point
  ...
  def draw(window,z)
    window.draw_line(@x-5,@y-5,Gosu::Color::RED,@x+5,@y+5,Gosu::Color::RED,z)
    window.draw_line(@x-5,@y+5,Gosu::Color::RED,@x+5,@y-5,Gosu::Color::RED,z)
  end
end
class GameWindow < Gosu::Window
  def draw
    @points.each{|point| point.draw(self,@Zorder[:Point])}
    ...
  end
end

顯示圖片

這次我們要使用畫4邊形的方法來貼圖

假如沒有圖片就自動不畫

class GameWindow < Gosu::Window
  def draw
    ...
    @pic&.draw_as_quad(@points[0].x, @points[0].y, 0xFFFFFFFF,
                       @points[1].x, @points[1].y, 0xFFFFFFFF,
                       @points[2].x, @points[2].y, 0xFFFFFFFF,
                       @points[3].x, @points[3].y, 0xFFFFFFFF, 
                       @Zorder[:Pic])
  end
end

滑鼠拖曳功能

先講解原理

有拖曳物更新拖曳物座標

有拖曳物且滑鼠左鍵沒有按下則取消拖曳

沒有拖曳物且滑鼠左鍵按著時尋找拖曳物

大家可以想想其他狀況會如何?

未初始化實體變數

未初始化的實體變數可以取用

預設會為nil

class GameWindow < Gosu::Window
  def update
    ...
    if @drag
      @drag.update(mouse_x, mouse_y)
      button_down?(Gosu::MsLeft) or @drag = nil
    else
      button_down?(Gosu::MsLeft) and @drag = @points.select{|point| 
        (point.x - mouse_x)**2 + (point.y - mouse_y)**2 < 100
      }.first
    end
  end
end

程式完成

大家來觀察點的拖曳會有什麼效果吧

感謝大家參與社課