class Smalruby::Character
キャラクターを表現するクラス
Attributes
checking_hit_targets[RW]
costume_index[RW]
costumes[RW]
enable_pen[R]
event_handlers[RW]
pen_color[RW]
rotation_style[R]
threads[RW]
volume[RW]
Public Class Methods
new(option = {})
click to toggle source
Calls superclass method
# File lib/smalruby/character.rb, line 31 def initialize(option = {}) defaults = { x: 0, y: 0, costume: nil, costume_index: 0, angle: 0, visible: true, rotation_style: :free } opt = process_optional_arguments(option, defaults) @costume_name__index = {} @costumes = Array.wrap(opt[:costume]).compact.map.with_index { |costume, i| if costume.is_a?(String) md = /^(?:([^:]+):)?(.*)$/.match(costume) name = md[1] path = md[2] costume = Image.load(asset_path(path)) end name ||= "costume#{i + 1}" @costume_name__index[name] = i costume } @costume_index = opt[:costume_index] super(opt[:x], opt[:y], @costumes[@costume_index]) @event_handlers = {} @threads = [] @checking_hit_targets = [] @angle = 0 unless Util.windows? @enable_pen = false @pen_color = 'black' @volume = 100 self.scale_x = 1.0 self.scale_y = 1.0 @vector = { x: 1, y: 0 } [:visible].each do |k| if opt.key?(k) send("#{k}=", opt[k]) end end self.rotation_style = opt[:rotation_style] self.angle = opt[:angle] if opt[:angle] != 0 # HACK: Windows XP SP3の環境でワーカースレッドで音声を読み込めな # い不具合が発生した。このためメインスレッドでプリロードしておく。 %w(do re mi fa so ra si do_2).each do |n| new_sound("piano_#{n}.wav") end World.instance.objects << self end
Public Instance Methods
alive?()
click to toggle source
# File lib/smalruby/character.rb, line 554 def alive? @threads.compact! @threads.delete_if { |t| if t.alive? false else begin t.join rescue => e Util.print_exception(e) exit(1) end true end } @threads.length > 0 end
angle()
click to toggle source
角度
Calls superclass method
# File lib/smalruby/character.rb, line 192 def angle return super if @rotation_style == :free x, y = @vector[:x], @vector[:y] a = Math.acos(x / Math.sqrt(x**2 + y**2)) * 180 / Math::PI a = 360 - a if y < 0 a end
angle=(val)
click to toggle source
( )度に向ける
Calls superclass method
# File lib/smalruby/character.rb, line 202 def angle=(val) val %= 360 radian = val * Math::PI / 180 @vector[:x] = Math.cos(radian) @vector[:y] = Math.sin(radian) if @rotation_style == :free self.scale_x = scale_x.abs super(val) elsif @rotation_style == :left_right if @vector[:x] >= 0 self.scale_x = scale_x.abs else self.scale_x = scale_x.abs * -1 end super(0) else self.scale_x = scale_x.abs super(0) end end
await()
click to toggle source
1フレーム待つ
# File lib/smalruby/character.rb, line 585 def await Smalruby.await end
change_pen_color_by(val)
click to toggle source
change pen color
@param [Integer] val color
# File lib/smalruby/character.rb, line 411 def change_pen_color_by(val) h, s, l = Color.rgb_to_hsl(*pen_color) @pen_color = Color.hsl_to_rgb(h + val, s, l) end
clear()
click to toggle source
Clears all pen marks from the Stage
# File lib/smalruby/character.rb, line 379 def clear world.current_stage.clear end
click(buttons)
click to toggle source
# File lib/smalruby/character.rb, line 532 def click(buttons) @event_handlers[:click].try(:each) do |h| if h.options.length > 0 && !h.options.any? { |b| buttons.include?(b) } next end @threads << h.call(Input.mouse_pos_x, Input.mouse_pos_y) end end
costume_index=(val)
click to toggle source
# File lib/smalruby/character.rb, line 324 def costume_index=(val) @costume_index = val % @costumes.length self.image = @costumes[@costume_index] end
distance(x, y)
click to toggle source
距離
# File lib/smalruby/character.rb, line 334 def distance(x, y) Math.sqrt((self.x + center_x - x).abs**2 + (self.y + center_y - y).abs**2).to_i end
down_pen()
click to toggle source
ペンを下ろす
# File lib/smalruby/character.rb, line 384 def down_pen @enable_pen = true end
draw()
click to toggle source
@!endgroup
Calls superclass method
# File lib/smalruby/character.rb, line 486 def draw draw_balloon if visible super end
go_to(target)
click to toggle source
( )に行く
# File lib/smalruby/character.rb, line 239 def go_to(target) if target == :mouse x = Input.mouse_pos_x - center_x y = Input.mouse_pos_y - center_y else x = target.x y = target.y end self.position = [x, y] end
hit()
click to toggle source
# File lib/smalruby/character.rb, line 541 def hit # TODO: なんでもいいからキャラクターに当たった場合に対応する @checking_hit_targets &= World.instance.objects objects = check(@checking_hit_targets) return if objects.empty? @event_handlers[:hit].try(:each) do |h| if h.options.length > 0 && !h.options.any? { |o| objects.include?(o) } next end @threads << h.call(h.options & objects) end end
hit?(other)
click to toggle source
# File lib/smalruby/character.rb, line 354 def hit?(other) check([other]).length > 0 end
join()
click to toggle source
# File lib/smalruby/character.rb, line 572 def join @threads.compact! @threads.each(&:join) end
key_down(keys)
click to toggle source
# File lib/smalruby/character.rb, line 514 def key_down(keys) @event_handlers[:key_down].try(:each) do |h| if h.options.length > 0 && !h.options.any? { |k| keys.include?(k) } next end @threads << h.call end end
key_push(keys)
click to toggle source
# File lib/smalruby/character.rb, line 523 def key_push(keys) @event_handlers[:key_push].try(:each) do |h| if h.options.length > 0 && !h.options.any? { |k| keys.include?(k) } next end @threads << h.call end end
led(pin)
click to toggle source
LED
# File lib/smalruby/character.rb, line 430 def led(pin) Hardware.create_hardware(Hardware::Led, pin) end
loop() { || ... }
click to toggle source
# File lib/smalruby/character.rb, line 577 def loop Kernel.loop do yield Smalruby.await end end
motor_driver(pin)
click to toggle source
モータードライバ
# File lib/smalruby/character.rb, line 460 def motor_driver(pin) Hardware.create_hardware(Hardware::MotorDriver, pin) end
move(val = 1)
click to toggle source
( )歩動かす
# File lib/smalruby/character.rb, line 92 def move(val = 1) self.position = [x + @vector[:x] * val, y + @vector[:y] * val] end
move_back(val = 1)
click to toggle source
( )歩後ろに動かす
# File lib/smalruby/character.rb, line 97 def move_back(val = 1) move(-val) end
neo_pixel(pin)
click to toggle source
マイコン内蔵RGB LED
# File lib/smalruby/character.rb, line 445 def neo_pixel(pin) Hardware.create_hardware(Hardware::NeoPixel, pin) end
next_costume()
click to toggle source
次のコスチュームにする
# File lib/smalruby/character.rb, line 310 def next_costume self.costume_index = @costume_index + 1 end
on(event, *options, &block)
click to toggle source
# File lib/smalruby/character.rb, line 492 def on(event, *options, &block) event = event.to_sym @event_handlers[event] ||= [] h = EventHandler.new(self, options, &block) @event_handlers[event] << h case event when :start @threads << h.call if Smalruby.started? when :hit @checking_hit_targets << options @checking_hit_targets.flatten! @checking_hit_targets.uniq! end end
pen_color=(val)
click to toggle source
set pen color
@param [Array<Integer>|Symbol|Integer] val color
When color is Array<Integer>, it means [R, G, B]. When color is Symbol, it means the color code; like :white, :black, etc... When color is Integer, it means hue.
# File lib/smalruby/character.rb, line 399 def pen_color=(val) if val.is_a?(Numeric) val %= 201 _, s, l = Color.rgb_to_hsl(*pen_color) val = Color.hsl_to_rgb(val, s, l) end @pen_color = val end
pen_shade=(val)
click to toggle source
set pen shade
@param Integer val shade
# File lib/smalruby/character.rb, line 419 def pen_shade=(val) val %= 101 h, s, = *Color.rgb_to_hsl(*pen_color) @pen_color = Color.hsl_to_rgb(h, s, val) end
play(option = {})
click to toggle source
( )の音を鳴らす
# File lib/smalruby/character.rb, line 363 def play(option = {}) defaults = { name: 'piano_do.wav' } opt = process_optional_arguments(option, defaults) sound = new_sound(opt[:name]) sound.set_volume(calc_volume) sound.play end
point_towards(target)
click to toggle source
( )に向ける
# File lib/smalruby/character.rb, line 225 def point_towards(target) if target == :mouse tx = Input.mouse_pos_x ty = Input.mouse_pos_y else tx = target.x ty = target.y end dx = tx - x dy = ty - y self.angle = Math.atan2(dy, dx) * 180 / Math::PI end
position()
click to toggle source
X座標、Y座標
# File lib/smalruby/character.rb, line 149 def position [x, y] end
position=(val)
click to toggle source
X座標を( )、Y座標を( )にする
# File lib/smalruby/character.rb, line 133 def position=(val) if @enable_pen @enable_pen = false left = x + center_x top = y + center_y self.x = val[0] self.y = val[1] draw_pen(left, top, x + center_x, y + center_y) @enable_pen = true else self.x = val[0] self.y = val[1] end end
reach_left_or_right_wall?()
click to toggle source
左右の端に着いた?
# File lib/smalruby/character.rb, line 345 def reach_left_or_right_wall? x <= 0 || x >= (Window.width - image.width) end
reach_top_or_bottom_wall?()
click to toggle source
上下の端に着いた?
# File lib/smalruby/character.rb, line 350 def reach_top_or_bottom_wall? y <= 0 || y >= (Window.height - image.height) end
reach_wall?()
click to toggle source
端に着いた?
# File lib/smalruby/character.rb, line 340 def reach_wall? reach_left_or_right_wall? || reach_top_or_bottom_wall? end
rgb_led_anode(pin)
click to toggle source
RGB LED(アノード)
# File lib/smalruby/character.rb, line 435 def rgb_led_anode(pin) Hardware.create_hardware(Hardware::RgbLedAnode, pin) end
rgb_led_cathode(pin)
click to toggle source
RGB LED(カソード)
# File lib/smalruby/character.rb, line 440 def rgb_led_cathode(pin) Hardware.create_hardware(Hardware::RgbLedCathode, pin) end
rotate(angle)
click to toggle source
( )度回転する
# File lib/smalruby/character.rb, line 182 def rotate(angle) self.angle += angle end
rotation_style=(val)
click to toggle source
# File lib/smalruby/character.rb, line 186 def rotation_style=(val) @rotation_style = val sync_angle(@vector[:x], @vector[:y]) end
say(options = {})
click to toggle source
@!group 見た目
# File lib/smalruby/character.rb, line 254 def say(options = {}) defaults = { message: '', second: 0, } opts = process_optional_arguments(options, defaults) message = opts[:message].to_s return if message == @current_message @current_message = message if @balloon @balloon.vanish @balloon = nil end return if message.empty? lines = message.to_s.lines.map { |l| l.scan(/.{1,10}/) }.flatten font = new_font(16) width = lines.map { |l| font.get_width(l) }.max height = lines.length * (font.size + 1) frame_size = 3 margin_size = 3 image = Image.new(width + (frame_size + margin_size) * 2, height + (frame_size + margin_size) * 2) image.box_fill(0, 0, width + (frame_size + margin_size) * 2 - 1, height + (frame_size + margin_size) * 2 - 1, [125, 125, 125]) image.box_fill(frame_size, frame_size, width + (frame_size + margin_size) + margin_size - 1, height + (frame_size + margin_size) + margin_size - 1, [255, 255, 255]) lines.each.with_index do |line, row| image.draw_font(frame_size + margin_size, frame_size + margin_size + (font.size + 1) * row, line, font, [0, 0, 0]) end @balloon = Sprite.new(x, y, image) end
sensor(pin)
click to toggle source
汎用的なセンサー
# File lib/smalruby/character.rb, line 470 def sensor(pin) Hardware.create_hardware(Hardware::Sensor, pin) end
servo(pin)
click to toggle source
サーボモーター
# File lib/smalruby/character.rb, line 450 def servo(pin) Hardware.create_hardware(Hardware::Servo, pin) end
smalrubot_s1()
click to toggle source
create or get Hardware::SmalrubotS1
instance
# File lib/smalruby/character.rb, line 480 def smalrubot_s1 Hardware.create_hardware(Hardware::SmalrubotS1) end
smalrubot_v3()
click to toggle source
create or get Hardware::SmalrubotV3
instance
# File lib/smalruby/character.rb, line 475 def smalrubot_v3 Hardware.create_hardware(Hardware::SmalrubotV3) end
start()
click to toggle source
# File lib/smalruby/character.rb, line 508 def start @event_handlers[:start].try(:each) do |h| @threads << h.call end end
switch_costume(name)
click to toggle source
コスチュームを( )にする
# File lib/smalruby/character.rb, line 315 def switch_costume(name) if @costume_name__index.key?(name) index = @costume_name__index[name] else index = 0 end self.costume_index = index end
turn()
click to toggle source
くるっと振り返る
# File lib/smalruby/character.rb, line 154 def turn sync_angle(@vector[:x] * -1, @vector[:y] * -1) end
turn_if_reach_wall()
click to toggle source
もし端に着いたら、跳ね返る
# File lib/smalruby/character.rb, line 169 def turn_if_reach_wall lr = reach_left_or_right_wall? tb = reach_top_or_bottom_wall? if lr && tb turn elsif lr turn_x elsif tb turn_y end end
turn_x()
click to toggle source
横に振り返る
# File lib/smalruby/character.rb, line 159 def turn_x sync_angle(@vector[:x] * -1, @vector[:y]) end
turn_y()
click to toggle source
縦に振り返る
# File lib/smalruby/character.rb, line 164 def turn_y sync_angle(@vector[:x], @vector[:y] * -1) end
two_wheel_drive_car(pin)
click to toggle source
2WD車
# File lib/smalruby/character.rb, line 455 def two_wheel_drive_car(pin) Hardware.create_hardware(Hardware::TwoWheelDriveCar, pin) end
up_pen()
click to toggle source
ペンを上げる
# File lib/smalruby/character.rb, line 389 def up_pen @enable_pen = false end
visible=(val)
click to toggle source
表示する/隠す
Calls superclass method
# File lib/smalruby/character.rb, line 300 def visible=(val) if val self.collision_enable = true else self.collision_enable = false end super end
x=(val)
click to toggle source
X座標を( )にする
Calls superclass method
# File lib/smalruby/character.rb, line 102 def x=(val) left = x + center_x top = y + center_y if val < 0 val = 0 elsif val + image.width >= Window.width val = Window.width - image.width end super(val) draw_pen(left, top, x + center_x, y + center_y) if @enable_pen end
y=(val)
click to toggle source
Y座標を( )にする
Calls superclass method
# File lib/smalruby/character.rb, line 118 def y=(val) left = x + center_x top = y + center_y if val < 0 val = 0 elsif val + image.height >= Window.height val = Window.height - image.height end super(val) draw_pen(left, top, x + center_x, y + center_y) if @enable_pen end
Private Instance Methods
asset_path(name)
click to toggle source
# File lib/smalruby/character.rb, line 604 def asset_path(name) program_path = Pathname($PROGRAM_NAME).expand_path(Dir.pwd) paths = [Pathname("../#{name}").expand_path(program_path), Pathname("../__assets__/#{name}").expand_path(program_path), Pathname("../../../assets/#{name}").expand_path(__FILE__)] paths.find { |path| path.file? }.to_s end
calc_volume()
click to toggle source
# File lib/smalruby/character.rb, line 660 def calc_volume (255 * @volume / 100.0).to_i end
draw_balloon()
click to toggle source
# File lib/smalruby/character.rb, line 626 def draw_balloon if @balloon @balloon.x = x + image.width / 2 if @balloon.x < 0 @balloon.x = 0 elsif @balloon.x + @balloon.image.width >= Window.width @balloon.x = Window.width - @balloon.image.width end @balloon.y = y - @balloon.image.height if @balloon.y < 0 @balloon.y = 0 elsif @balloon.y + @balloon.image.height >= Window.height @balloon.y = Window.height - @balloon.image.height end @balloon.draw end end
draw_pen(left, top, right, bottom)
click to toggle source
# File lib/smalruby/character.rb, line 591 def draw_pen(left, top, right, bottom) return if Util.raspberrypi? || !visible || vanished? world.current_stage.line(left: left, top: top, right: right, bottom: bottom, color: @pen_color) end
new_font(size)
click to toggle source
# File lib/smalruby/character.rb, line 612 def new_font(size) self.class.font_cache.synchronize do self.class.font_cache[size] ||= Font.new(size) end self.class.font_cache[size] end
new_sound(name)
click to toggle source
# File lib/smalruby/character.rb, line 619 def new_sound(name) self.class.sound_cache.synchronize do self.class.sound_cache[name] ||= Sound.new(asset_path(name)) end self.class.sound_cache[name] end
print_exception(exception)
click to toggle source
# File lib/smalruby/character.rb, line 653 def print_exception(exception) $stderr.puts("#{exception.class}: #{exception.message}") $stderr.puts(" #{exception.backtrace.join("\n ")}") end
process_optional_arguments(options, defaults)
click to toggle source
# File lib/smalruby/character.rb, line 644 def process_optional_arguments(options, defaults) unknown_keys = options.keys - defaults.keys if unknown_keys.length > 0 s = unknown_keys.map { |k| "#{k}: #{options[k].inspect}" }.join(', ') fail ArgumentError, "Unknown options: #{s}" end defaults.merge(options) end
sync_angle(x, y)
click to toggle source
# File lib/smalruby/character.rb, line 598 def sync_angle(x, y) a = Math.acos(x / Math.sqrt(x**2 + y**2)) * 180 / Math::PI a = 360 - a if y < 0 self.angle = a end