lib/ruby2d/window.rb in ruby2d-0.5.1 vs lib/ruby2d/window.rb in ruby2d-0.6.0
- old
+ new
@@ -1,39 +1,72 @@
-# window.rb
+# Ruby2D::Window
+# Represents a window on screen, responsible for storing renderable graphics,
+# event handlers, the update loop, showing and closing the window.
module Ruby2D
class Window
- attr_reader :objects
- attr_accessor :mouse_x, :mouse_y, :frames, :fps
-
+ # Event structures
EventDescriptor = Struct.new(:type, :id)
MouseEvent = Struct.new(:type, :button, :direction, :x, :y, :delta_x, :delta_y)
KeyEvent = Struct.new(:type, :key)
- ControllerEvent = Struct.new(:which, :type, :axis, :value, :button)
+ ControllerEvent = Struct.new(:which, :type, :axis, :value, :button)
ControllerAxisEvent = Struct.new(:which, :axis, :value)
ControllerButtonEvent = Struct.new(:which, :button)
def initialize(args = {})
- @title = args[:title] || "Ruby 2D"
+
+ # This window instance, stored so it can be called by the class methods
+ @@window = self
+
+ # Title of the window
+ @title = args[:title] || "Ruby 2D"
+
+ # Window background color
@background = Color.new([0.0, 0.0, 0.0, 1.0])
- @width = args[:width] || 640
- @height = args[:height] || 480
- @viewport_width, @viewport_height = nil, nil
- @display_width, @display_height = nil, nil
- @resizable = false
+
+ # Window icon
+ @icon = nil
+
+ # Window size and characteristics
+ @width = args[:width] || 640
+ @height = args[:height] || 480
+ @resizable = false
@borderless = false
@fullscreen = false
- @highdpi = false
- @frames = 0
- @fps_cap = args[:fps] || 60
- @fps = @fps_cap
- @vsync = args[:vsync] || true
+ @highdpi = false
+
+ # Size of the window's viewport (the drawable area)
+ @viewport_width, @viewport_height = nil, nil
+
+ # Size of the computer's display
+ @display_width, @display_height = nil, nil
+
+ # Total number of frames that have been rendered
+ @frames = 0
+
+ # Frames per second upper limit, and the actual FPS
+ @fps_cap = args[:fps_cap] || 60
+ @fps = @fps_cap
+
+ # Vertical synchronization, set to prevent screen tearing (recommended)
+ @vsync = args[:vsync] || true
+
+ # Mouse X and Y position in the window
@mouse_x, @mouse_y = 0, 0
- @objects = []
- @event_key = 0
- @events = {
+
+ # Controller axis and button mappings file
+ @controller_mappings = File.expand_path('~') + "/.ruby2d/controllers.txt"
+
+ # Renderable objects currently in the window, like a linear scene graph
+ @objects = []
+
+ # Unique ID for the input event being registered
+ @event_key = 0
+
+ # Registered input events
+ @events = {
key: {},
key_down: {},
key_held: {},
key_up: {},
mouse: {},
@@ -44,19 +77,84 @@
controller: {},
controller_axis: {},
controller_button_down: {},
controller_button_up: {}
}
+
+ # The window update block
@update_proc = Proc.new {}
+
+ # Whether diagnostic messages should be printed
@diagnostics = false
- @controller_mappings_path = File.join(Dir.home, ".ruby2d", "controllers.txt")
end
- def new_event_key
- @event_key = @event_key.next
+ # Class methods for convenient access to properties
+ class << self
+ def current; get(:window) end
+ def title; get(:title) end
+ def background; get(:background) end
+ def width; get(:width) end
+ def height; get(:height) end
+ def viewport_width; get(:viewport_width) end
+ def viewport_height; get(:viewport_height) end
+ def display_width; get(:display_width) end
+ def display_height; get(:display_height) end
+ def resizable; get(:resizable) end
+ def borderless; get(:borderless) end
+ def fullscreen; get(:fullscreen) end
+ def highdpi; get(:highdpi) end
+ def frames; get(:frames) end
+ def fps; get(:fps) end
+ def fps_cap; get(:fps_cap) end
+ def mouse_x; get(:mouse_x) end
+ def mouse_y; get(:mouse_y) end
+ def diagnostics; get(:diagnostics) end
+
+ def get(sym)
+ @@window.get(sym)
+ end
+
+ def set(opts)
+ @@window.set(opts)
+ end
+
+ def on(event, &proc)
+ @@window.on(event, &proc)
+ end
+
+ def off(event_descriptor)
+ @@window.off(event_descriptor)
+ end
+
+ def add(o)
+ @@window.add(o)
+ end
+
+ def remove(o)
+ @@window.remove(o)
+ end
+
+ def clear
+ @@window.clear
+ end
+
+ def update(&proc)
+ @@window.update(&proc)
+ end
+
+ def show
+ @@window.show
+ end
+
+ def close
+ @@window.close
+ end
end
+ # Public instance methods
+
+ # Retrieve an attribute of the window
def get(sym)
case sym
when :window; self
when :title; @title
when :background; @background
@@ -75,33 +173,38 @@
when :borderless; @borderless
when :fullscreen; @fullscreen
when :highdpi; @highdpi
when :frames; @frames
when :fps; @fps
+ when :fps_cap; @fps_cap
when :mouse_x; @mouse_x
when :mouse_y; @mouse_y
when :diagnostics; @diagnostics
end
end
+ # Set a window attribute
def set(opts)
# Store new window attributes, or ignore if nil
@title = opts[:title] || @title
if Color.is_valid? opts[:background]
@background = Color.new(opts[:background])
end
+ @icon = opts[:icon] || @icon
@width = opts[:width] || @width
@height = opts[:height] || @height
+ @fps_cap = opts[:fps_cap] || @fps_cap
@viewport_width = opts[:viewport_width] || @viewport_width
@viewport_height = opts[:viewport_height] || @viewport_height
@resizable = opts[:resizable] || @resizable
@borderless = opts[:borderless] || @borderless
@fullscreen = opts[:fullscreen] || @fullscreen
@highdpi = opts[:highdpi] || @highdpi
@diagnostics = opts[:diagnostics] || @diagnostics
end
+ # Add an object to the window
def add(o)
case o
when nil
raise Error, "Cannot add '#{o.class}' to window!"
when Array
@@ -109,10 +212,11 @@
else
add_object(o)
end
end
+ # Remove an object from the window
def remove(o)
if o == nil
raise Error, "Cannot remove '#{o.class}' from window!"
end
@@ -122,35 +226,43 @@
else
false
end
end
+ # Clear all objects from the window
def clear
@objects.clear
end
+ # Set an update callback
def update(&proc)
@update_proc = proc
true
end
+ # Generate a new event key (ID)
+ def new_event_key
+ @event_key = @event_key.next
+ end
+
+ # Set an event handler
def on(event, &proc)
unless @events.has_key? event
raise Error, "`#{event}` is not a valid event type"
end
event_id = new_event_key
@events[event][event_id] = proc
EventDescriptor.new(event, event_id)
end
+ # Remove an event handler
def off(event_descriptor)
@events[event_descriptor.type].delete(event_descriptor.id)
end
+ # Key callback method, called by the native and web extentions
def key_callback(type, key)
- # puts "===", "type: #{type}", "key: #{key}"
-
key = key.downcase
# All key events
@events[:key].each do |id, e|
e.call(KeyEvent.new(type, key))
@@ -173,10 +285,11 @@
e.call(KeyEvent.new(type, key))
end
end
end
+ # Mouse callback method, called by the native and web extentions
def mouse_callback(type, button, direction, x, y, delta_x, delta_y)
# All mouse events
@events[:mouse].each do |id, e|
e.call(MouseEvent.new(type, button, direction, x, y, delta_x, delta_y))
end
@@ -203,10 +316,20 @@
e.call(MouseEvent.new(type, nil, nil, x, y, delta_x, delta_y))
end
end
end
+ # Add controller mappings from file
+ def add_controller_mappings
+ unless RUBY_ENGINE == 'opal'
+ if File.exists? @controller_mappings
+ ext_add_controller_mappings(@controller_mappings)
+ end
+ end
+ end
+
+ # Controller callback method, called by the native and web extentions
def controller_callback(which, type, axis, value, button)
# All controller events
@events[:controller].each do |id, e|
e.call(ControllerEvent.new(which, type, axis, value, button))
end
@@ -228,23 +351,29 @@
e.call(ControllerButtonEvent.new(which, button))
end
end
end
+ # Update callback method, called by the native and web extentions
def update_callback
@update_proc.call
end
+ # Show the window
def show
ext_show
end
+ # Close the window
def close
ext_close
end
+ # Private instance methods
+
private
+ # An an object to the window, used by the public `add` method
def add_object(o)
if !@objects.include?(o)
index = @objects.index do |object|
object.z > o.z
end