Class: Smalruby::Character

Inherits:
Sprite
  • Object
show all
Extended by:
Forwardable, Mutex_m
Defined in:
lib/smalruby/character.rb

Overview

キャラクターを表現するクラス

Direct Known Subclasses

Canvas, Console

Instance Attribute Summary collapse

動き collapse

見た目 collapse

調べる collapse

collapse

ペン collapse

ハードウェア collapse

Instance Method Summary collapse

Constructor Details

#initialize(option = {}) ⇒ Character

Returns a new instance of Character.



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/smalruby/character.rb', line 32

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

Instance Attribute Details

#checking_hit_targetsObject

Returns the value of attribute checking_hit_targets.



24
25
26
# File 'lib/smalruby/character.rb', line 24

def checking_hit_targets
  @checking_hit_targets
end

#costume_indexObject

Returns the value of attribute costume_index.



26
27
28
# File 'lib/smalruby/character.rb', line 26

def costume_index
  @costume_index
end

#costumesObject

Returns the value of attribute costumes.



25
26
27
# File 'lib/smalruby/character.rb', line 25

def costumes
  @costumes
end

#enable_penObject (readonly)

Returns the value of attribute enable_pen.



28
29
30
# File 'lib/smalruby/character.rb', line 28

def enable_pen
  @enable_pen
end

#event_handlersObject

Returns the value of attribute event_handlers.



22
23
24
# File 'lib/smalruby/character.rb', line 22

def event_handlers
  @event_handlers
end

#pen_colorObject

Returns the value of attribute pen_color.



29
30
31
# File 'lib/smalruby/character.rb', line 29

def pen_color
  @pen_color
end

#rotation_styleObject

Returns the value of attribute rotation_style.



27
28
29
# File 'lib/smalruby/character.rb', line 27

def rotation_style
  @rotation_style
end

#threadsObject

Returns the value of attribute threads.



23
24
25
# File 'lib/smalruby/character.rb', line 23

def threads
  @threads
end

#volumeObject

Returns the value of attribute volume.



30
31
32
# File 'lib/smalruby/character.rb', line 30

def volume
  @volume
end

Instance Method Details

#alive?Boolean

Returns:

  • (Boolean)


555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
# File 'lib/smalruby/character.rb', line 555

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

#angleObject

角度



193
194
195
196
197
198
199
200
# File 'lib/smalruby/character.rb', line 193

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) ⇒ Object

( )度に向ける



203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
# File 'lib/smalruby/character.rb', line 203

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

#awaitObject

1フレーム待つ



586
587
588
# File 'lib/smalruby/character.rb', line 586

def await
  Smalruby.await
end

#button(pin) ⇒ Object

ボタン



466
467
468
# File 'lib/smalruby/character.rb', line 466

def button(pin)
  Hardware.create_hardware(Hardware::Button, pin)
end

#change_pen_color_by(val) ⇒ Object

change pen color

Parameters:

  • val (Integer)

    color



412
413
414
415
# File 'lib/smalruby/character.rb', line 412

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

#clearObject

Clears all pen marks from the Stage



380
381
382
# File 'lib/smalruby/character.rb', line 380

def clear
  world.current_stage.clear
end

#click(buttons) ⇒ Object



533
534
535
536
537
538
539
540
# File 'lib/smalruby/character.rb', line 533

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

#distance(x, y) ⇒ Object

距離



335
336
337
338
# File 'lib/smalruby/character.rb', line 335

def distance(x, y)
  Math.sqrt((self.x + center_x - x).abs**2 +
            (self.y + center_y - y).abs**2).to_i
end

#down_penObject

ペンを下ろす



385
386
387
# File 'lib/smalruby/character.rb', line 385

def down_pen
  @enable_pen = true
end

#drawObject



487
488
489
490
491
# File 'lib/smalruby/character.rb', line 487

def draw
  draw_balloon if visible

  super
end

#go_to(target) ⇒ Object

( )に行く



240
241
242
243
244
245
246
247
248
249
# File 'lib/smalruby/character.rb', line 240

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

#hitObject



542
543
544
545
546
547
548
549
550
551
552
553
# File 'lib/smalruby/character.rb', line 542

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) ⇒ Boolean

Returns:

  • (Boolean)


355
356
357
# File 'lib/smalruby/character.rb', line 355

def hit?(other)
  check([other]).length > 0
end

#joinObject



573
574
575
576
# File 'lib/smalruby/character.rb', line 573

def join
  @threads.compact!
  @threads.each(&:join)
end

#key_down(keys) ⇒ Object



515
516
517
518
519
520
521
522
# File 'lib/smalruby/character.rb', line 515

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) ⇒ Object



524
525
526
527
528
529
530
531
# File 'lib/smalruby/character.rb', line 524

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) ⇒ Object

LED



431
432
433
# File 'lib/smalruby/character.rb', line 431

def led(pin)
  Hardware.create_hardware(Hardware::Led, pin)
end

#loopObject



578
579
580
581
582
583
# File 'lib/smalruby/character.rb', line 578

def loop
  Kernel.loop do
    yield
    Smalruby.await
  end
end

#motor_driver(pin) ⇒ Object

モータードライバ



461
462
463
# File 'lib/smalruby/character.rb', line 461

def motor_driver(pin)
  Hardware.create_hardware(Hardware::MotorDriver, pin)
end

#move(val = 1) ⇒ Object

( )歩動かす



93
94
95
# File 'lib/smalruby/character.rb', line 93

def move(val = 1)
  self.position = [x + @vector[:x] * val, y + @vector[:y] * val]
end

#move_back(val = 1) ⇒ Object

( )歩後ろに動かす



98
99
100
# File 'lib/smalruby/character.rb', line 98

def move_back(val = 1)
  move(-val)
end

#neo_pixel(pin) ⇒ Object

マイコン内蔵RGB LED



446
447
448
# File 'lib/smalruby/character.rb', line 446

def neo_pixel(pin)
  Hardware.create_hardware(Hardware::NeoPixel, pin)
end

#next_costumeObject

次のコスチュームにする



311
312
313
# File 'lib/smalruby/character.rb', line 311

def next_costume
  self.costume_index = @costume_index + 1
end

#on(event, *options, &block) ⇒ Object



493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
# File 'lib/smalruby/character.rb', line 493

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_shade=(val) ⇒ Object

set pen shade

Parameters:

  • Integer

    val shade



420
421
422
423
424
# File 'lib/smalruby/character.rb', line 420

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 = {}) ⇒ Object

( )の音を鳴らす



364
365
366
367
368
369
370
371
372
373
# File 'lib/smalruby/character.rb', line 364

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) ⇒ Object

( )に向ける



226
227
228
229
230
231
232
233
234
235
236
237
# File 'lib/smalruby/character.rb', line 226

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

#positionObject

X座標、Y座標



150
151
152
# File 'lib/smalruby/character.rb', line 150

def position
  [x, y]
end

#position=(val) ⇒ Object

X座標を( )、Y座標を( )にする



134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/smalruby/character.rb', line 134

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?Boolean

左右の端に着いた?

Returns:

  • (Boolean)


346
347
348
# File 'lib/smalruby/character.rb', line 346

def reach_left_or_right_wall?
  x <= 0 || x >= (Window.width - image.width)
end

#reach_top_or_bottom_wall?Boolean

上下の端に着いた?

Returns:

  • (Boolean)


351
352
353
# File 'lib/smalruby/character.rb', line 351

def reach_top_or_bottom_wall?
  y <= 0 || y >= (Window.height - image.height)
end

#reach_wall?Boolean

端に着いた?

Returns:

  • (Boolean)


341
342
343
# File 'lib/smalruby/character.rb', line 341

def reach_wall?
  reach_left_or_right_wall? || reach_top_or_bottom_wall?
end

#rgb_led_anode(pin) ⇒ Object

RGB LED(アノード)



436
437
438
# File 'lib/smalruby/character.rb', line 436

def rgb_led_anode(pin)
  Hardware.create_hardware(Hardware::RgbLedAnode, pin)
end

#rgb_led_cathode(pin) ⇒ Object

RGB LED(カソード)



441
442
443
# File 'lib/smalruby/character.rb', line 441

def rgb_led_cathode(pin)
  Hardware.create_hardware(Hardware::RgbLedCathode, pin)
end

#rotate(angle) ⇒ Object

( )度回転する



183
184
185
# File 'lib/smalruby/character.rb', line 183

def rotate(angle)
  self.angle += angle
end

#say(options = {}) ⇒ Object



255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/smalruby/character.rb', line 255

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) ⇒ Object

汎用的なセンサー



471
472
473
# File 'lib/smalruby/character.rb', line 471

def sensor(pin)
  Hardware.create_hardware(Hardware::Sensor, pin)
end

#servo(pin) ⇒ Object

サーボモーター



451
452
453
# File 'lib/smalruby/character.rb', line 451

def servo(pin)
  Hardware.create_hardware(Hardware::Servo, pin)
end

#smalrubot_s1Object

create or get Hardware::SmalrubotS1 instance



481
482
483
# File 'lib/smalruby/character.rb', line 481

def smalrubot_s1
  Hardware.create_hardware(Hardware::SmalrubotS1)
end

#smalrubot_v3Object

create or get Hardware::SmalrubotV3 instance



476
477
478
# File 'lib/smalruby/character.rb', line 476

def smalrubot_v3
  Hardware.create_hardware(Hardware::SmalrubotV3)
end

#startObject



509
510
511
512
513
# File 'lib/smalruby/character.rb', line 509

def start
  @event_handlers[:start].try(:each) do |h|
    @threads << h.call
  end
end

#switch_costume(name) ⇒ Object

コスチュームを( )にする



316
317
318
319
320
321
322
323
# File 'lib/smalruby/character.rb', line 316

def switch_costume(name)
  if @costume_name__index.key?(name)
    index = @costume_name__index[name]
  else
    index = 0
  end
  self.costume_index = index
end

#turnObject

くるっと振り返る



155
156
157
# File 'lib/smalruby/character.rb', line 155

def turn
  sync_angle(@vector[:x] * -1, @vector[:y] * -1)
end

#turn_if_reach_wallObject

もし端に着いたら、跳ね返る



170
171
172
173
174
175
176
177
178
179
180
# File 'lib/smalruby/character.rb', line 170

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_xObject

横に振り返る



160
161
162
# File 'lib/smalruby/character.rb', line 160

def turn_x
  sync_angle(@vector[:x] * -1, @vector[:y])
end

#turn_yObject

縦に振り返る



165
166
167
# File 'lib/smalruby/character.rb', line 165

def turn_y
  sync_angle(@vector[:x], @vector[:y] * -1)
end

#two_wheel_drive_car(pin) ⇒ Object

2WD車



456
457
458
# File 'lib/smalruby/character.rb', line 456

def two_wheel_drive_car(pin)
  Hardware.create_hardware(Hardware::TwoWheelDriveCar, pin)
end

#up_penObject

ペンを上げる



390
391
392
# File 'lib/smalruby/character.rb', line 390

def up_pen
  @enable_pen = false
end

#visible=(val) ⇒ Object

表示する/隠す



301
302
303
304
305
306
307
308
# File 'lib/smalruby/character.rb', line 301

def visible=(val)
  if val
    self.collision_enable = true
  else
    self.collision_enable = false
  end
  super
end

#x=(val) ⇒ Object

X座標を( )にする



103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/smalruby/character.rb', line 103

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) ⇒ Object

Y座標を( )にする



119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/smalruby/character.rb', line 119

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