diff options
| -rw-r--r-- | .travis.yml | 6 | ||||
| m--------- | assets | 0 | ||||
| -rw-r--r-- | ext/ruby2d/ruby2d-opal.rb | 68 | ||||
| -rw-r--r-- | ext/ruby2d/ruby2d.c | 109 | ||||
| -rw-r--r-- | lib/ruby2d/application.rb | 4 | ||||
| -rw-r--r-- | lib/ruby2d/dsl.rb | 4 | ||||
| -rw-r--r-- | lib/ruby2d/window.rb | 248 | ||||
| -rw-r--r-- | test/input.rb | 35 | ||||
| -rw-r--r-- | test/key.rb | 30 | ||||
| -rw-r--r-- | test/mouse.rb | 53 | ||||
| -rw-r--r-- | test/testcard.rb | 7 |
11 files changed, 369 insertions, 195 deletions
diff --git a/.travis.yml b/.travis.yml index 2d4190a..efbcf69 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,12 +1,12 @@ os: osx -osx_image: xcode8 +osx_image: xcode8.3 language: ruby rvm: - - 2.2.5 + - 2.4.0 before_install: - sw_vers - brew update - brew tap simple2d/tap - - brew install simple2d + - brew install --HEAD simple2d script: - rake diff --git a/assets b/assets -Subproject da267e388d8865490276d8819f3113a9f8660af +Subproject 265922df6da40531c322cde9f1a9a3ab15385c8 diff --git a/ext/ruby2d/ruby2d-opal.rb b/ext/ruby2d/ruby2d-opal.rb index ff372dc..d4bea68 100644 --- a/ext/ruby2d/ruby2d-opal.rb +++ b/ext/ruby2d/ruby2d-opal.rb @@ -17,25 +17,69 @@ const $R2D_SPRITE = 4; const $R2D_TEXT = 5; -function on_key(e, key) { - switch (e) { - case S2D.KEYDOWN: - #{$R2D_WINDOW.key_down_callback(`key`)}; +function on_key(e) { + + switch (e.type) { + case S2D.KEY_DOWN: + #{type = :down}; break; - - case S2D.KEY: - #{$R2D_WINDOW.key_callback(`key`)}; + case S2D.KEY_HELD: + #{type = :held}; break; - - case S2D.KEYUP: - #{$R2D_WINDOW.key_up_callback(`key`)}; + case S2D.KEY_UP: + #{type = :up}; break; } + + #{$R2D_WINDOW.key_callback(type, `e.key`)}; } -function on_mouse(x, y) { - #{$R2D_WINDOW.mouse_callback("any", `x`, `y`)}; +function on_mouse(e) { + + #{direction = nil} + #{button = nil} + + switch (e.type) { + case S2D.MOUSE_DOWN: + #{type = :down}; + break; + case S2D.MOUSE_UP: + #{type = :up}; + break; + case S2D.MOUSE_SCROLL: + #{type = :scroll}; + #{direction} = e.direction == S2D.MOUSE_SCROLL_NORMAL ? #{:normal} : #{:inverted}; + break; + case S2D.MOUSE_MOVE: + #{type = :move}; + break; + } + + if (e.type == S2D.MOUSE_DOWN || e.type == S2D.MOUSE_UP) { + switch (e.button) { + case S2D.MOUSE_LEFT: + #{button = :left}; + break; + case S2D.MOUSE_MIDDLE: + #{button = :middle}; + break; + case S2D.MOUSE_RIGHT: + #{button = :right}; + break; + case S2D.MOUSE_X1: + #{button = :x1}; + break; + case S2D.MOUSE_X2: + #{button = :x2}; + break; + } + } + + #{$R2D_WINDOW.mouse_callback( + type, button, direction, + `e.x`, `e.y`, `e.delta_x`, `e.delta_y` + )}; } diff --git a/ext/ruby2d/ruby2d.c b/ext/ruby2d/ruby2d.c index f25587d..6c3dc4e 100644 --- a/ext/ruby2d/ruby2d.c +++ b/ext/ruby2d/ruby2d.c @@ -59,10 +59,12 @@ #define r_data_wrap_struct(name, data) mrb_obj_value(Data_Wrap_Struct(mrb, mrb->object_class, &name##_data_type, data)) #define r_data_get_struct(self, var, mrb_type, rb_type, data) Data_Get_Struct(mrb, r_iv_get(self, var), mrb_type, data) #define r_define_module(name) mrb_module_get(mrb, name) - #define r_define_class(module, name) mrb_class_get_under(mrb, module, name); + #define r_define_class(module, name) mrb_class_get_under(mrb, module, name) #define r_define_method(class, name, function, args) mrb_define_method(mrb, class, name, function, args) #define r_args_none (MRB_ARGS_NONE()) #define r_args_req(n) MRB_ARGS_REQ(n) + // Helpers + #define r_char_to_sym(str) mrb_check_intern_cstr(mrb, str) #else // Ruby #define R_VAL VALUE @@ -79,10 +81,12 @@ #define r_data_wrap_struct(name, data) Data_Wrap_Struct(rb_cObject, NULL, (free_##name), data) #define r_data_get_struct(self, var, mrb_type, rb_type, data) Data_Get_Struct(r_iv_get(self, var), rb_type, data) #define r_define_module(name) rb_define_module(name) - #define r_define_class(module, name) rb_define_class_under(module, name, rb_cObject); + #define r_define_class(module, name) rb_define_class_under(module, name, rb_cObject) #define r_define_method(class, name, function, args) rb_define_method(class, name, function, args) #define r_args_none 0 #define r_args_req(n) n + // Helpers + #define r_char_to_sym(str) ID2SYM(rb_intern(str)) #endif // @type_id values for rendering @@ -429,39 +433,106 @@ static void free_music(S2D_Music *mus) { /* * Simple 2D `on_key` input callback function */ -static void on_key(S2D_Event e, const char *key) { - switch (e) { - case S2D_KEYDOWN: - r_funcall(ruby2d_window, "key_down_callback", 1, r_str_new(key)); +static void on_key(S2D_Event e) { + + R_VAL type; + + switch (e.type) { + case S2D_KEY_DOWN: + type = r_char_to_sym("down"); break; - - case S2D_KEY: - r_funcall(ruby2d_window, "key_callback", 1, r_str_new(key)); + case S2D_KEY_HELD: + type = r_char_to_sym("held"); break; - - case S2D_KEYUP: - r_funcall(ruby2d_window, "key_up_callback", 1, r_str_new(key)); + case S2D_KEY_UP: + type = r_char_to_sym("up"); break; } + + r_funcall(ruby2d_window, "key_callback", 2, type, r_str_new(e.key)); } /* * Simple 2D `on_mouse` input callback function */ -void on_mouse(int x, int y) { - r_funcall(ruby2d_window, "mouse_callback", 3, r_str_new("any"), INT2NUM(x), INT2NUM(y)); +void on_mouse(S2D_Event e) { + + R_VAL type = R_NIL; R_VAL button = R_NIL; R_VAL direction = R_NIL; + + switch (e.type) { + case S2D_MOUSE_DOWN: + // type, button, x, y + type = r_char_to_sym("down"); + break; + case S2D_MOUSE_UP: + // type, button, x, y + type = r_char_to_sym("up"); + break; + case S2D_MOUSE_SCROLL: + // type, direction, delta_x, delta_y + type = r_char_to_sym("scroll"); + direction = e.direction == S2D_MOUSE_SCROLL_NORMAL ? + r_str_new("normal") : r_str_new("inverted"); + break; + case S2D_MOUSE_MOVE: + // type, x, y, delta_x, delta_y + type = r_char_to_sym("move"); + break; + } + + if (e.type == S2D_MOUSE_DOWN || e.type == S2D_MOUSE_UP) { + switch (e.button) { + case S2D_MOUSE_LEFT: + button = r_str_new("left"); + break; + case S2D_MOUSE_MIDDLE: + button = r_str_new("middle"); + break; + case S2D_MOUSE_RIGHT: + button = r_str_new("right"); + break; + case S2D_MOUSE_X1: + button = r_str_new("x1"); + break; + case S2D_MOUSE_X2: + button = r_str_new("x2"); + break; + } + } + + // Bug in MRuby: If `button` or `direction` are symbols (created with + // r_char_to_sym), they will always both be `nil`. Use `r_str_new` for now. + + r_funcall( + ruby2d_window, "mouse_callback", 7, type, button, direction, + INT2NUM(e.x), INT2NUM(e.y), INT2NUM(e.delta_x), INT2NUM(e.delta_y) + ); } /* * Simple 2D `on_controller` input callback function */ -static void on_controller(int which, bool is_axis, int axis, int val, bool is_btn, int btn, bool pressed) { - r_funcall(ruby2d_window, "controller_callback", 7, - INT2NUM(which), - is_axis ? R_TRUE : R_FALSE, INT2NUM(axis), INT2NUM(val), - is_btn ? R_TRUE : R_FALSE, INT2NUM(btn), pressed ? R_TRUE : R_FALSE +static void on_controller(S2D_Event e) { + + R_VAL type = R_NIL; + + switch (e.type) { + case S2D_AXIS: + type = r_char_to_sym("axis"); + break; + case S2D_BUTTON_DOWN: + type = r_char_to_sym("button_down"); + break; + case S2D_BUTTON_UP: + type = r_char_to_sym("button_up"); + break; + } + + r_funcall( + ruby2d_window, "controller_callback", 5, INT2NUM(e.which), type, + INT2NUM(e.axis), INT2NUM(e.value), INT2NUM(e.button) ); } diff --git a/lib/ruby2d/application.rb b/lib/ruby2d/application.rb index 8de526d..a63b00d 100644 --- a/lib/ruby2d/application.rb +++ b/lib/ruby2d/application.rb @@ -12,8 +12,8 @@ module Ruby2D::Application @@window.set(opts) end - def on(args = {}, &proc) - @@window.on(args, &proc) + def on(event, &proc) + @@window.on(event, &proc) end def on_key(&proc) diff --git a/lib/ruby2d/dsl.rb b/lib/ruby2d/dsl.rb index 910c100..99b44af 100644 --- a/lib/ruby2d/dsl.rb +++ b/lib/ruby2d/dsl.rb @@ -9,8 +9,8 @@ module Ruby2D::DSL Application.set(opts) end - def on(args = {}, &proc) - Application.on(args, &proc) + def on(event, &proc) + Application.on(event, &proc) end def on_key(&proc) diff --git a/lib/ruby2d/window.rb b/lib/ruby2d/window.rb index 5bc68b1..4ae1d6e 100644 --- a/lib/ruby2d/window.rb +++ b/lib/ruby2d/window.rb @@ -6,27 +6,32 @@ module Ruby2D attr_reader :objects attr_accessor :mouse_x, :mouse_y, :frames, :fps + 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) + def initialize(args = {}) - @title = args[:title] || "Ruby 2D" - @background = Color.new([0.0, 0.0, 0.0, 1.0]) - @width = args[:width] || 640 - @height = args[:height] || 480 + @title = args[:title] || "Ruby 2D" + @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 - @resizable = false - @borderless = false - @fullscreen = false - @highdpi = false - @frames = 0 - @fps_cap = args[:fps] || 60 - @fps = @fps_cap - @vsync = args[:vsync] || true - @mouse_x = 0; @mouse_y = 0 - @objects = [] - @keys_down, @keys, @keys_up, @mouse, @controller = {}, {}, {}, {}, {} - @on_key_proc = Proc.new {} - @on_controller_proc = Proc.new {} - @update_proc = Proc.new {} - @diagnostics = false + @resizable = false + @borderless = false + @fullscreen = false + @highdpi = false + @frames = 0 + @fps_cap = args[:fps] || 60 + @fps = @fps_cap + @vsync = args[:vsync] || true + @mouse_x, @mouse_y = 0, 0 + @objects = [] + @key, @key_down, @key_held, @key_up = [], [], [], [] + @mouse, @mouse_down, @mouse_up, @mouse_scroll, @mouse_move = [], [], [], [], [] + @controller, @controller_axis = [], [] + @controller_button_down, @controller_button_up = [], [] + @update_proc = Proc.new {} + @diagnostics = false end def get(sym) @@ -100,86 +105,123 @@ module Ruby2D true end - # def on(mouse: nil, key: nil, key_up: nil, key_down: nil, controller: nil, &proc) - def on(args = {}, &proc) - mouse = args[:mouse] - key = args[:key] - key_up = args[:key_up] - key_down = args[:key_down] - controller = args[:controller] + def on(event, &proc) + case event + when :key + @key.push(proc) + when :key_down + @key_down.push(proc) + when :key_held + @key_held.push(proc) + when :key_up + @key_up.push(proc) + when :mouse + @mouse.push(proc) + when :mouse_up + @mouse_up.push(proc) + when :mouse_down + @mouse_down.push(proc) + when :mouse_scroll + @mouse_scroll.push(proc) + when :mouse_move + @mouse_move.push(proc) + when :controller + @controller.push(proc) + when :controller_axis + @controller_axis.push(proc) + when :controller_button + @controller_button.push(proc) + end + end + + def key_callback(type, key) + # puts "===", "type: #{type}", "key: #{key}" - unless mouse.nil? - reg_mouse(mouse, &proc) - end + key = key.downcase - unless key_down.nil? - reg_key_down(key_down, &proc) + # All key events + @key.each do |e| + e.call(KeyEvent.new(type, key)) end - unless key.nil? - reg_key(key, &proc) - end + case type + # When key is pressed, fired once + when :down + @key_down.each do |e| + e.call(KeyEvent.new(type, key)) + end + # When key is being held down, fired every frame + when :held + @key_held.each do |e| + e.call(KeyEvent.new(type, key)) + end + # When key released, fired once + when :up + @key_up.each do |e| + e.call(KeyEvent.new(type, key)) + end + end + end + + def mouse_callback(type, button, direction, x, y, delta_x, delta_y) + # Convert to symbols (see MRuby bug in native extension) + button = button.to_sym unless button == nil + direction = direction.to_sym unless direction == nil - unless key_up.nil? - reg_key_up(key_up, &proc) + # All mouse events + @mouse.each do |e| + e.call(MouseEvent.new(type, button, direction, x, y, delta_x, delta_y)) end - unless controller.nil? - reg_controller(controller, &proc) - end - end - - def mouse_callback(btn, x, y) - if @mouse.has_key? 'any' - @mouse[btn].call(x, y) + case type + # When mouse button pressed + when :down + @mouse_down.each do |e| + e.call(MouseEvent.new(type, button, nil, x, y, nil, nil)) + end + # When mouse button released + when :up + @mouse_up.each do |e| + e.call(MouseEvent.new(type, button, nil, x, y, nil, nil)) + end + # When mouse motion / movement + when :scroll + @mouse_scroll.each do |e| + e.call(MouseEvent.new(type, nil, direction, nil, nil, delta_x, delta_y)) + end + # When mouse scrolling, wheel or trackpad + when :move + @mouse_move.each do |e| + e.call(MouseEvent.new(type, nil, nil, x, y, delta_x, delta_y)) + end + end + end + + def controller_callback(which, type, axis, value, button) + # All controller events + @controller.each do |e| + e.call(ControllerEvent.new(which, type, axis, value, button)) end - end - - def on_key(&proc) - @on_key_proc = proc - true - end - - def key_down_callback(key) - key = key.downcase - if @keys_down.has_key? 'any' - @keys_down['any'].call - end - if @keys_down.has_key? key - @keys_down[key].call - end - end - - def key_callback(key) - key = key.downcase - @on_key_proc.call(key) - if @keys.has_key? 'any' - @keys['any'].call - end - if @keys.has_key? key - @keys[key].call - end - end - - def key_up_callback(key) - key = key.downcase - if @keys_up.has_key? 'any' - @keys_up['any'].call - end - if @keys_up.has_key? key - @keys_up[key].call + + case type + # When controller axis motion, like analog sticks + when :axis + @controller_axis.each do |e| + e.call(ControllerEvent.new(which, type, axis, value, nil)) + end + # When controller button is pressed + when :button_down + @controller_button_down.each do |e| + e.call(ControllerEvent.new(which, type, nil, nil, button)) + end + # When controller button is released + when :button_up + @controller_button_up.each do |e| + e.call(ControllerEvent.new(which, type, nil, nil, button)) + end end end - def on_controller(&proc) - @on_controller_proc = proc - true - end - - def controller_callback(which, is_axis, axis, val, is_btn, btn, pressed) - @on_controller_proc.call(which, is_axis, axis, val, is_btn, btn, pressed) - end - def update_callback @update_proc.call end @@ -195,35 +237,5 @@ module Ruby2D end end - # Register key string with proc - def reg_key_down(key, &proc) - @keys_down[key] = proc - true - end - - # Register key string with proc - def reg_key(key, &proc) - @keys[key] = proc - true - end - - # Register key string with proc - def reg_key_up(key, &proc) - @keys_up[key] = proc - true - end - - # Register mouse button string with proc - def reg_mouse(btn, &proc) - @mouse[btn] = proc - true - end - - # Register controller string with proc - def reg_controller(event, &proc) - @controller[event] = proc - true - end - end end diff --git a/test/input.rb b/test/input.rb deleted file mode 100644 index 82bce4a..0000000 --- a/test/input.rb +++ /dev/null @@ -1,35 +0,0 @@ -require 'ruby2d' - -set width: 200, height: 100, title: "Ruby 2D — Input" - -on key_down: 'a' do - puts "Key 'a' down" -end - -on key: 'b' do - puts "Key 'b' held down" -end - -on key_up: 'c' do - puts "Key 'c' up" -end - -on key_down: 'any' do - puts "A key was pressed" -end - -on_key do |key| - if key == 'd' - puts "on_key: #{key}" - end -end - -on mouse: 'any' do |x, y| - puts "Mouse clicked at: #{x}, #{y}" -end - -on key: 'escape' do - close -end - -show diff --git a/test/key.rb b/test/key.rb new file mode 100644 index 0000000..3c2c8e6 --- /dev/null +++ b/test/key.rb @@ -0,0 +1,30 @@ +require 'ruby2d' + +set title: "Ruby 2D — Key", width: 300, height: 200 + +s1 = Square.new(5, 5, 50, [1, 1, 1, 1]) +s2 = Square.new(60, 5, 50, [1, 1, 1, 1]) + +on :key do |event| + puts event +end + +on :key_down do |event| + s1.color = [1, 0, 0, 1] +end + +on :key_held do |event| + s2.color = [0, 1, 0, 1] +end + +on :key_up do |event| + s1.color = [1, 1, 1, 1] + s2.color = [1, 1, 1, 1] +end + + +on :key_down do |event| + close if event.key == 'escape' +end + +show diff --git a/test/mouse.rb b/test/mouse.rb new file mode 100644 index 0000000..7daa738 --- /dev/null +++ b/test/mouse.rb @@ -0,0 +1,53 @@ +require 'ruby2d' + +set title: "Ruby 2D — Mouse", width: 400, height: 300 + +on :mouse do |event| + puts event +end + +s1 = Square.new(5, 5, 25, [1, 1, 0, 1]) # mouse down square +s2 = Square.new(188, 10, 25) # mouse scroll square +s3 = Square.new(188, 137, 25, [1, 1, 1, 1]) # mouse move delta square +s4 = Square.new(35, 5, 10) # mouse move position square + +on :mouse_down do |event| + case event.button + when :left + s1.color = [1, 0, 0, 1] + when :middle + s1.color = [0, 0, 1, 1] + when :right + s1.color = [0, 1, 0, 1] + end + s1.x = event.x + s1.y = event.y +end + +on :mouse_up do |event| + s1.color = [1, 1, 0, 1] + s1.x = event.x + s1.y = event.y +end + +on :mouse_scroll do |event| + s2.x = s2.x + event.delta_x + s2.y = s2.y + event.delta_y +end + +on :mouse_move do |event| + s3.x = 188 + event.delta_x + s3.y = 137 + event.delta_y + s4.x = event.x - 5 + s4.y = event.y - 5 +end + +# Crosshairs +Rectangle.new(199, 0, 2, 300, [1, 0, 0, 1]) +Rectangle.new(0, 149, 400, 2, [1, 0, 0, 1]) + +on :key_down do |event| + close if event.key == 'escape' +end + +show diff --git a/test/testcard.rb b/test/testcard.rb index 1951390..a7dc308 100644 --- a/test/testcard.rb +++ b/test/testcard.rb @@ -203,12 +203,11 @@ updated_text.remove updated_text.add UPDATED_TEXT_OPTIONS = "of various size".split(" ") -on key: 'escape' do - close +on :key_down do |event| + close if event.key == 'escape' end -on mouse: 'any' do |x, y| - puts "Mouse down at: #{x}, #{y}" +on :mouse_down do pointer_outline.x = (get :mouse_x) - 9 pointer_outline.y = (get :mouse_y) - 11 flash = 2 |
