Class: Voxelamming::VoxelammingManager

Inherits:
Object
  • Object
show all
Defined in:
lib/voxelamming.rb

Overview

Main process

Constant Summary collapse

@@texture_names =
["grass", "stone", "dirt", "planks", "bricks"]
@@model_names =
["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune", "Pluto", "Sun",
"Moon", "ToyBiplane", "ToyCar", "Drummer", "Robot", "ToyRocket", "RocketToy1", "RocketToy2", "Skull"]

Instance Method Summary collapse

Constructor Details

#initialize(room_name) ⇒ VoxelammingManager

Returns a new instance of VoxelammingManager.



25
26
27
28
29
30
31
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
# File 'lib/voxelamming.rb', line 25

def initialize(room_name)
  @room_name = room_name
  @is_allowed_matrix = 0
  @saved_matrices = []
  @node_transform = [0, 0, 0, 0, 0, 0]
  @matrix_transform = [0, 0, 0, 0, 0, 0]
  @frame_transforms = []
  @global_animation = [0, 0, 0, 0, 0, 0, 1, 0]
  @animation = [0, 0, 0, 0, 0, 0, 1, 0]
  @boxes = []
  @frames = []
  @sentences = []
  @lights = []
  @commands = []
  @models = []
  @model_moves = []
  @sprites = []
  @sprite_moves = []
  @game_score = []
  @game_screen = []  # width, height, angle=90, red=1, green=1, blue=1, alpha=0.5
  @size = 1
  @shape = 'box'
  @is_metallic = 0
  @roughness = 0.5
  @is_allowed_float = 0
  @build_interval = 0.01
  @is_framing = false
  @frame_id = 0
  @websocket = nil
  @last_sent_time = nil
  @timer = nil
end

Instance Method Details

#animate(x, y, z, pitch: 0, yaw: 0, roll: 0, scale: 1, interval: 10) ⇒ Object



197
198
199
200
# File 'lib/voxelamming.rb', line 197

def animate(x, y, z, pitch: 0, yaw: 0, roll: 0, scale: 1, interval: 10)
  x, y, z = round_numbers([x, y, z])
  @animation = [x, y, z, pitch, yaw, roll, scale, interval]
end

#animate_global(x, y, z, pitch: 0, yaw: 0, roll: 0, scale: 1, interval: 10) ⇒ Object



192
193
194
195
# File 'lib/voxelamming.rb', line 192

def animate_global(x, y, z, pitch: 0, yaw: 0, roll: 0, scale: 1, interval: 10)
  x, y, z = round_numbers([x, y, z])
  @global_animation = [x, y, z, pitch, yaw, roll, scale, interval]
end

#change_material(is_metallic: false, roughness: 0.5) ⇒ Object



299
300
301
302
# File 'lib/voxelamming.rb', line 299

def change_material(is_metallic: false, roughness: 0.5)
  @is_metallic = is_metallic ? 1 : 0
  @roughness = roughness
end

#change_shape(shape) ⇒ Object



295
296
297
# File 'lib/voxelamming.rb', line 295

def change_shape(shape)
  @shape = shape
end

#clear_dataObject



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
# File 'lib/voxelamming.rb', line 58

def clear_data
  @is_allowed_matrix = 0
  @saved_matrices = []
  @node_transform = [0, 0, 0, 0, 0, 0]
  @matrix_transform = [0, 0, 0, 0, 0, 0]
  @frame_transforms = []
  @global_animation = [0, 0, 0, 0, 0, 0, 1, 0]
  @animation = [0, 0, 0, 0, 0, 0, 1, 0]
  @boxes = []
  @frames = []
  @sentences = []
  @sprites = []
  @sprite_moves = []
  @game_score = []
  @game_screen = []  # width, height, angle=90, red=1, green=1, blue=1, alpha=0.5
  @lights = []
  @commands = []
  @models = []
  @model_moves = []
  @size = 1
  @shape = 'box'
  @is_metallic = 0
  @roughness = 0.5
  @is_allowed_float = 0
  @build_interval = 0.01
  @is_framing = false
  @frame_id = 0
end

#close_connectionObject



520
521
522
523
524
525
526
527
# File 'lib/voxelamming.rb', line 520

def close_connection
  if @websocket
    puts 'Closing WebSocket connection.'
    @websocket.close
    @websocket = nil
    EM.stop
  end
end

#create_box(x, y, z, r: 1, g: 1, b: 1, alpha: 1, texture: '') ⇒ Object



147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/voxelamming.rb', line 147

def create_box(x, y, z, r: 1, g: 1, b: 1, alpha: 1, texture: '')
  if @is_allowed_matrix > 0
    # 移動用のマトリックスにより位置を計算する
    matrix = @matrix_transform
    base_position = matrix[0..2]

    if matrix.length == 6
      base_rotation_matrix = get_rotation_matrix(matrix[3], matrix[4], matrix[5])
    else
      base_rotation_matrix = [matrix[3..5], matrix[6..8], matrix[9..11]]
    end

    # Compute the new position after transform
    add_x, add_y, add_z = transform_point_by_rotation_matrix([x, y, z], transpose_3x3(base_rotation_matrix))
    x, y, z = add_vectors(base_position, [add_x, add_y, add_z])
  end

  x, y, z = round_numbers([x, y, z])
  r, g, b, alpha = round_two_decimals([r, g, b, alpha])

  # 重ねておくことを防止
  remove_box(x, y, z)
  if !@@texture_names.include?(texture)
    texture_id = -1
  else
    texture_id = @@texture_names.index(texture)
  end

  if @is_framing
    @frames.append([x, y, z, r, g, b, alpha, texture_id, @frame_id])
  else
    @boxes.append([x, y, z, r, g, b, alpha, texture_id])
  end
end

#create_model(model_name, x: 0, y: 0, z: 0, pitch: 0, yaw: 0, roll: 0, scale: 1, entity_name: '') ⇒ Object



304
305
306
307
308
309
310
311
312
313
# File 'lib/voxelamming.rb', line 304

def create_model(model_name, x: 0, y: 0, z: 0, pitch: 0, yaw: 0, roll: 0, scale: 1, entity_name: '')
  if @@model_names.include?(model_name)
    x, y, z, pitch, yaw, roll, scale = round_two_decimals([x, y, z, pitch, yaw, roll, scale])
    x, y, z, pitch, yaw, roll, scale = [x, y, z, pitch, yaw, roll, scale].map(&:to_s)

    @models << [model_name, x, y, z, pitch, yaw, roll, scale, entity_name]
  else
    puts "No model name: #{model_name}"
  end
end

#create_sprite(sprite_name, color_list, x = 0, y = 0, direction = 0, scale = 1, visible = true) ⇒ Object

通常のスプライトの作成



398
399
400
401
402
403
404
405
406
407
408
# File 'lib/voxelamming.rb', line 398

def create_sprite(sprite_name, color_list, x = 0, y = 0, direction = 0, scale = 1, visible = true)
  # スプライトのテンプレートデータを配列に追加
  create_sprite_template(sprite_name, color_list)

  # スプライトの移動データを配列に追加
  if visible || !(x == 0 && y == 0 && direction == 0 && scale == 1)
    x, y, direction = round_numbers([x, y, direction])
    x, y, direction, scale = [x, y, direction, scale].map(&:to_s)
    @sprite_moves.push([sprite_name, x, y, direction, scale])
  end
end

#create_sprite_template(sprite_name, color_list) ⇒ Object

スプライトのテンプレートを作成(スプライトは配置されない)



354
355
356
# File 'lib/voxelamming.rb', line 354

def create_sprite_template(sprite_name, color_list)
  @sprites << [sprite_name, color_list]
end

#display_dot(x, y, direction = 0, color_id = 10, width = 1, height = 1) ⇒ Object

ドット(弾)を表示する



423
424
425
426
# File 'lib/voxelamming.rb', line 423

def display_dot(x, y, direction = 0, color_id = 10, width = 1, height = 1)
  template_name = "dot_#{color_id}_#{width}_#{height}"
  display_sprite_template(template_name, x, y, direction, 1)
end

#display_sprite_template(sprite_name, x, y, direction = 0, scale = 1) ⇒ Object

スプライトのテンプレートを使って、複数のスプライトを表示する



359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/voxelamming.rb', line 359

def display_sprite_template(sprite_name, x, y, direction = 0, scale = 1)
  # x, y, directionを丸める
  x, y, direction = round_numbers([x, y, direction])
  x, y, direction, scale = [x, y, direction, scale].map(&:to_s)

  # rotation_styleを取得
  if @rotation_styles[sprite_name]
    rotation_style = @rotation_styles[sprite_name]

    # rotation_styleが変更された場合、新しいスプライトデータを配列に追加
    if rotation_style == 'left-right'
      direction_mod = direction.to_i % 360  # 常に0から359の範囲で処理(常に正の数になる)
      if direction_mod > 90 && direction_mod < 270
        direction = "-180"  # -180は左右反転するようにボクセラミング側で実装されている
      else
        direction = "0"
      end
    elsif rotation_style == "don't rotate"
      direction = "0"
    else
      direction = direction.to_s
    end
  else
    direction = direction.to_s
  end

  # sprite_moves 配列から指定されたスプライト名の情報を検索
  matching_sprites = @sprite_moves.select { |info| info[0] == sprite_name }

  # スプライトの移動データを保存または更新
  if matching_sprites.empty?
    @sprite_moves.push([sprite_name, x, y, direction, scale])
  else
    index = @sprite_moves.index(matching_sprites[0])
    @sprite_moves[index] += [x, y, direction, scale]
  end
end

#display_text(text, x, y, direction = 0, scale = 1, color_id = 7, is_vertical = false, align = '') ⇒ Object

テキストを表示する



429
430
431
432
433
434
435
436
437
438
439
440
441
442
# File 'lib/voxelamming.rb', line 429

def display_text(text, x, y, direction = 0, scale = 1, color_id = 7, is_vertical = false, align = '')
  text_format = ''
  align = align.downcase  # 破壊的メソッドの代わりに非破壊的メソッドを使用

  text_format += 't' if align.include?('top')
  text_format += 'b' if align.include?('bottom')
  text_format += 'l' if align.include?('left')
  text_format += 'r' if align.include?('right')

  text_format += is_vertical ? 'v' : 'h'

  template_name = "text_#{text}_#{color_id}_#{text_format}"
  display_sprite_template(template_name, x, y, direction, scale)
end

#draw_line(x1, y1, z1, x2, y2, z2, r: 1, g: 1, b: 1, alpha: 1) ⇒ Object



241
242
243
244
245
246
247
248
249
250
251
252
253
254
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
# File 'lib/voxelamming.rb', line 241

def draw_line(x1, y1, z1, x2, y2, z2, r: 1, g: 1, b: 1, alpha: 1)
  x1, y1, z1, x2, y2, z2 = [x1, y1, z1, x2, y2, z2].map(&:floor)
  diff_x = x2 - x1
  diff_y = y2 - y1
  diff_z = z2 - z1
  max_length = [diff_x.abs, diff_y.abs, diff_z.abs].max

  return false if diff_x == 0 && diff_y == 0 && diff_z == 0

  if diff_x.abs == max_length
    if x2 > x1
      (x1..x2).each do |x|
        y = y1 + (x - x1) * diff_y.to_f / diff_x
        z = z1 + (x - x1) * diff_z.to_f / diff_x
        create_box(x, y, z, r: r, g: g, b: b, alpha: alpha)
      end
    else
      x1.downto(x2 + 1) do |x|
        y = y1 + (x - x1) * diff_y.to_f / diff_x
        z = z1 + (x - x1) * diff_z.to_f / diff_x
        create_box(x, y, z, r: r, g: g, b: b, alpha: alpha)
      end
    end
  elsif diff_y.abs == max_length
    if y2 > y1
      (y1..y2).each do |y|
        x = x1 + (y - y1) * diff_x.to_f / diff_y
        z = z1 + (y - y1) * diff_z.to_f / diff_y
        create_box(x, y, z, r: r, g: g, b: b, alpha: alpha)
      end
    else
      y1.downto(y2 + 1) do |y|
        x = x1 + (y - y1) * diff_x.to_f / diff_y
        z = z1 + (y - y1) * diff_z.to_f / diff_y
        create_box(x, y, z, r: r, g: g, b: b, alpha: alpha)
      end
    end
  elsif diff_z.abs == max_length
    if z2 > z1
      (z1..z2).each do |z|
        x = x1 + (z - z1) * diff_x.to_f / diff_z
        y = y1 + (z - z1) * diff_y.to_f / diff_z
        create_box(x, y, z, r: r, g: g, b: b, alpha: alpha)
      end
    else
      z1.downto(z2 + 1) do |z|
        x = x1 + (z - z1) * diff_x.to_f / diff_z
        y = y1 + (z - z1) * diff_y.to_f / diff_z
        create_box(x, y, z, r: r, g: g, b: b, alpha: alpha)
      end
    end
  end
end

#frame_inObject



95
96
97
# File 'lib/voxelamming.rb', line 95

def frame_in
  @is_framing = true
end

#frame_outObject



99
100
101
102
# File 'lib/voxelamming.rb', line 99

def frame_out
  @is_framing = false
  @frame_id += 1
end

#move_model(entity_name, x: 0, y: 0, z: 0, pitch: 0, yaw: 0, roll: 0, scale: 1) ⇒ Object



315
316
317
318
319
320
# File 'lib/voxelamming.rb', line 315

def move_model(entity_name, x: 0, y: 0, z: 0, pitch: 0, yaw: 0, roll: 0, scale: 1)
  x, y, z, pitch, yaw, roll, scale = round_two_decimals([x, y, z, pitch, yaw, roll, scale])
  x, y, z, pitch, yaw, roll, scale = [x, y, z, pitch, yaw, roll, scale].map(&:to_s)

  @model_moves << [entity_name, x, y, z, pitch, yaw, roll, scale]
end

#move_sprite(sprite_name, x, y, direction = 0, scale = 1, visible = true) ⇒ Object

通常のスプライトの移動



411
412
413
414
415
# File 'lib/voxelamming.rb', line 411

def move_sprite(sprite_name, x, y, direction = 0, scale = 1, visible = true)
  if visible
    display_sprite_template(sprite_name, x, y, direction, scale)
  end
end

#move_sprite_clone(sprite_name, x, y, direction = 0, scale = 1) ⇒ Object

スプライトクローンの移動



418
419
420
# File 'lib/voxelamming.rb', line 418

def move_sprite_clone(sprite_name, x, y, direction = 0, scale = 1)
  display_sprite_template(sprite_name, x, y, direction, scale)
end

#pop_matrixObject



109
110
111
112
# File 'lib/voxelamming.rb', line 109

def pop_matrix
  @is_allowed_matrix -= 1
  @matrix_transform = @saved_matrices.pop
end

#push_matrixObject



104
105
106
107
# File 'lib/voxelamming.rb', line 104

def push_matrix
  @is_allowed_matrix += 1
  @saved_matrices.push(@matrix_transform)
end

#remove_box(x, y, z) ⇒ Object



182
183
184
185
186
187
188
189
190
# File 'lib/voxelamming.rb', line 182

def remove_box(x, y, z)
  x, y, z = round_numbers([x, y, z])

  if @is_framing
    @frames.reject! { |frame| frame[0] == x && frame[1] == y && frame[2] == z && frame[8] == @frame_id }
  else
    @boxes.reject! { |box| box[0] == x && box[1] == y && box[2] == z }
  end
end

#reset_close_timerObject



510
511
512
513
514
515
516
517
518
# File 'lib/voxelamming.rb', line 510

def reset_close_timer
  EM.cancel_timer(@timer) if @timer

  @timer = EM.add_timer(2) do
    if Time.now - @last_sent_time >= 2
      close_connection
    end
  end
end

#round_numbers(num_list) ⇒ Object



529
530
531
532
533
534
535
# File 'lib/voxelamming.rb', line 529

def round_numbers(num_list)
  if @is_allowed_float == 1
    round_two_decimals(num_list)
  else
    num_list.map { |val| val.round(1).floor }
  end
end

#round_two_decimals(num_list) ⇒ Object



537
538
539
# File 'lib/voxelamming.rb', line 537

def round_two_decimals(num_list)
  num_list.map { |val| val.round(2) }
end

#send_data(name: '') ⇒ Object



444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
# File 'lib/voxelamming.rb', line 444

def send_data(name: '')
  puts 'send_data'
  now = DateTime.now
  data_to_send = {
    "nodeTransform": @node_transform,
    "frameTransforms": @frame_transforms,
    "globalAnimation": @global_animation,
    "animation": @animation,
    "boxes": @boxes,
    "frames": @frames,
    "sentences": @sentences,
    "lights": @lights,
    "commands": @commands,
    "models": @models,
    "modelMoves": @model_moves,
    "sprites": @sprites,
    "spriteMoves": @sprite_moves,
    "gameScore": @game_score,
    "gameScreen": @game_screen,
    "size": @size,
    "shape": @shape,
    "interval": @build_interval,
    "isMetallic": @is_metallic,
    "roughness": @roughness,
    "isAllowedFloat": @is_allowed_float,
    "name": name,
    "date": now.to_s
  }.to_json

  EM.run do
    if @websocket.nil?
      @websocket = Faye::WebSocket::Client.new('wss://websocket.voxelamming.com')

      @websocket.on :open do |_event|
        p [:open]
        puts 'WebSocket connection open'
        @websocket.send(@room_name)
        puts "Joined room: #{@room_name}"
        send_data_to_server(data_to_send)
      end

      @websocket.on :error do |event|
        puts "WebSocket error: #{event.message}"
        EM.stop
      end

      @websocket.on :close do |_event|
        puts 'WebSocket connection closed'
        EM.stop
      end
    else
      send_data_to_server(data_to_send)
    end
  end
end

#send_data_to_server(data) ⇒ Object



500
501
502
503
504
505
506
507
508
# File 'lib/voxelamming.rb', line 500

def send_data_to_server(data)
  if @websocket && @websocket.ready_state == Faye::WebSocket::API::OPEN
    @websocket.send(data)
    puts 'Sent data to server'
    @last_sent_time = Time.now

    reset_close_timer
  end
end

#send_game_clearObject



337
338
339
# File 'lib/voxelamming.rb', line 337

def send_game_clear
  @commands << 'gameClear'
end

#send_game_overObject



333
334
335
# File 'lib/voxelamming.rb', line 333

def send_game_over
  @commands << 'gameOver'
end

#set_box_size(box_size) ⇒ Object



202
203
204
# File 'lib/voxelamming.rb', line 202

def set_box_size(box_size)
  @size = box_size
end

#set_build_interval(interval) ⇒ Object



206
207
208
# File 'lib/voxelamming.rb', line 206

def set_build_interval(interval)
  @build_interval = interval
end

#set_command(command) ⇒ Object



233
234
235
236
237
238
239
# File 'lib/voxelamming.rb', line 233

def set_command(command)
  @commands << command

  if command == 'float'
    @is_allowed_float = 1
  end
end

#set_frame_fps(fps = 2) ⇒ Object



87
88
89
# File 'lib/voxelamming.rb', line 87

def set_frame_fps(fps = 2)
  @commands << "fps #{fps}"
end

#set_frame_repeats(repeats = 10) ⇒ Object



91
92
93
# File 'lib/voxelamming.rb', line 91

def set_frame_repeats(repeats = 10)
  @commands << "repeats #{repeats}"
end

#set_game_score(score, x = 0, y = 0) ⇒ Object



328
329
330
331
# File 'lib/voxelamming.rb', line 328

def set_game_score(score, x = 0, y = 0)
  score, x, y = [score, x, y].map(&:to_f)
  @game_score = [score, x, y]
end

#set_game_screen(width, height, angle = 90, r = 1, g = 1, b = 0, alpha = 0.5) ⇒ Object

Game API



324
325
326
# File 'lib/voxelamming.rb', line 324

def set_game_screen(width, height, angle = 90, r = 1, g = 1, b = 0, alpha = 0.5)
  @game_screen = [width, height, angle, r, g, b, alpha]
end

#set_light(x, y, z, r: 1, g: 1, b: 1, alpha: 1, intensity: 1000, interval: 1, light_type: 'point') ⇒ Object



217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/voxelamming.rb', line 217

def set_light(x, y, z, r: 1, g: 1, b: 1, alpha: 1, intensity: 1000, interval: 1, light_type: 'point')
  x, y, z = round_numbers([x, y, z])
  r, g, b, alpha = round_two_decimals([r, g, b, alpha])

  if light_type == 'point'
    light_type = 1
  elsif light_type == 'spot'
    light_type = 2
  elsif light_type == 'directional'
    light_type = 3
  else
    light_type = 1
  end
  @lights << [x, y, z, r, g, b, alpha, intensity, interval, light_type]
end

#set_rotation_style(sprite_name, rotation_style = 'all around') ⇒ Object



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

def set_rotation_style(sprite_name, rotation_style = 'all around')
  @rotation_styles[sprite_name] = rotation_style
end

#transform(x, y, z, pitch: 0, yaw: 0, roll: 0) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/voxelamming.rb', line 114

def transform(x, y, z, pitch: 0, yaw: 0, roll: 0)
  if @is_allowed_matrix > 0
    # 移動用のマトリックスを計算する
    matrix = @saved_matrices.last
    puts "before matrix: #{matrix}"
    base_position = matrix[0..2]

    if matrix.length == 6
      base_rotation_matrix = get_rotation_matrix(matrix[3], matrix[4], matrix[5])
    else
      base_rotation_matrix = [matrix[3..5], matrix[6..8], matrix[9..11]]
    end

    # Compute the new position after transform
    add_x, add_y, add_z = transform_point_by_rotation_matrix([x, y, z], transpose_3x3(base_rotation_matrix))
    x, y, z = add_vectors(base_position, [add_x, add_y, add_z])
    x, y, z = round_numbers([x, y, z])

    # Compute the rotation after transform
    transform_rotation_matrix = get_rotation_matrix(-pitch, -yaw, -roll)
    rotate_matrix = matrix_multiply(transform_rotation_matrix, base_rotation_matrix)
    @matrix_transform = [x, y, z, *rotate_matrix[0], *rotate_matrix[1], *rotate_matrix[2]]
  else
    x, y, z = round_numbers([x, y, z])

    if @is_framing
      @frame_transforms.append([x, y, z, pitch, yaw, roll, @frame_id])
    else
      @node_transform = [x, y, z, pitch, yaw, roll]
    end
  end
end

#write_sentence(sentence, x, y, z, r: 1, g: 1, b: 1, alpha: 1, font_size: 8, is_fixed_width: false) ⇒ Object



210
211
212
213
214
215
# File 'lib/voxelamming.rb', line 210

def write_sentence(sentence, x, y, z, r: 1, g: 1, b: 1, alpha: 1, font_size: 8, is_fixed_width: false)
  x, y, z = round_numbers([x, y, z]).map(&:to_s)
  r, g, b, alpha = round_two_decimals([r, g, b, alpha])
  r, g, b, alpha, font_size =  [r, g, b, alpha, font_size].map(&:floor).map(&:to_s)
  @sentences << [sentence, x, y, z, r, g, b, alpha, font_size, is_fixed_width ? "1" : "0"]
end