ゲーム 450x800 公開中

まじたいスリーマッチパズル

投稿者:rmake 投稿日時: 2013/09/27 11:51:54
スリーマッチパズルを作ってみました。
ソースが読みにくいかもしれませんが
Code on Rmake のポテンシャルを確認できるかと思います。
閲覧: 362 評価: 30
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
  • Starwhite
あなたはまだ評価していません。
# デバッグ用情報表示の設定 game.draw_collision_mode false game.draw_fps_mode true IS_VIEW_FPS = true # 画像のローディング game.loading do |loader| loader.add :window, :system => "window" loader.add :gui_item, :system => "gui_item" loader.add :circle_white, 205 loader.add :bomb, 17 loader.add :majitai, 206 loader.add :bg, 204 end # ゲームの初期化 game.on_init do set_window_image :window set_gui_image :gui_item # オープニングのシーンへ scene_change :start_scene end # scene :start_scene do |scene| scene.loading do |loader| end scene.on_init do speak "3 match pazzle" speak "円をドラッグして、3つ以上そろえると円が消えます。" speak "このゲームに終わりはありません。やめる時は自分の意志の力でやめてください。" scene_change :stage_scene end end scene :stage_scene do |scene| scene.loading do |loader| end scene.on_init do start_stage scene end end # ベクトルの長さを求めます。 def vector_len a Math.sqrt a[0] * a[0] + a[1] * a[1] end # ベクトルの足し算 # ここではベクトルを、長さ2の配列で扱っています。 def vector_add a, b [a[0] + b[0], a[1] + b[1]] end # ベクトルの引き算 def vector_sub a, b [a[0] - b[0], a[1] - b[1]] end # ベクトルとスカラーの掛け算 def vector_mul a, b [a[0] * b, a[1] * b] end # ベクトルの正規化、つまりベクトルの長さを1にする。 def vector_normal v l = vector_len v if l > 0 vector_mul v, 1.0 / l else [0, 1] end end # class Lazy_call def initialize @funcs = [] end def add fiber @funcs.push fiber end def poll i = 0 while i < @funcs.length fiber = @funcs[i] if fiber.resume #game.logger.debug "delete fiber" @funcs.delete_at i else #game.logger.debug "next fiber" i += 1 end end end end class Drop attr_accessor :game_stage, :cell_x, :cell_y, :sprite, :index, :color_code, :need_delete def initialize game_stage, color_code self.game_stage = game_stage self.color_code = color_code if color_code != 6 self.sprite = game_stage.scene.sprite :template => :sprite_template_drop, :texture => :circle_white else self.sprite = game_stage.scene.sprite :template => :sprite_template_majitai, :texture => :majitai self.sprite.change_animation :animate end self.sprite.set_data :drop, self self.need_delete = false end def delete self.game_stage.scene.sprite :template => :sprite_template_bomb, :center_position => self.sprite.get_center_position self.game_stage.remove_drop self self.game_stage.set_active_count self.game_stage.active_count - 1 self.sprite.delete end # 爆発用のスプライトテンプレート sprite_template :sprite_template_bomb do |sprite_template| sprite_template.texture :bomb # テクスチャーの設定 sprite_template.scale 2.0, 2.0 # 拡大量 sprite_template.src_size 96, 96 # アニメーション時のコピー元の矩形の大きさ sprite_template.dest_size 96, 96 # アニメーション時のコピー先の矩形の設定 sprite_template.copy_rect 0, 0 # src_sizeのグリッドで区切られたテクスチャーの # どの位置の画像を表示するかの設定 sprite_template.center_offset 48, 48 # スプライトの中心位置の設定 sprite_template.layer_order 40 # 描画順の設定 sprite_template.collision :rect, :position => [0, 0], :width => [0, 0], :group_id => 0 # 当たり判定はいらないが、デフォルトだとデバッグ時に見づらいため適当な値を設定している sprite_template.render_way_type :add # 爆発のアニメーションの設定(コマンドリスト) sprite_template.animation :bomb do |commands| (0...16).each do |i| # 1行に8パターンならんでいるのでこのような書き方 # 1フレームアニメーションを表示します。 commands.copy_rect :frame => 1, :src => [i % 8, (i / 8).floor] # アニメーションの待ち commands.wait_animation end # アニメーションが終わったら消します。 commands.proc_call do |s| s.delete end end # スプライトが生成された時の処理 sprite_template.event :on_add do |event| # 起動時のアニメーションを設定します event.target.change_animation :bomb end end def self.sprite_tamplate_drop_init sprite_template, type sprite_template.position 230, 600 sprite_template.rotation 0.0 sprite_template.scale 1.0, 1.0 sprite_template.texture :circle_white sprite_template.src_size 64, 64 sprite_template.dest_size 64, 64 sprite_template.copy_rect 0, 0 sprite_template.center_offset 32, 32 sprite_template.collision :circle, :mode => :center, :position => [0, 0], :radius => 31.5, :group_id => 1 sprite_template.layer_order 10 sprite_template.motion :fall do |commands| commands.loop false (0...80).each do |i| commands.velocity 0, i / 4 commands.wait_frame 1 end commands.velocity 0, 20 commands.wait_frame 1024 end sprite_template.motion :up do |commands| commands.loop true commands.velocity(0, lambda do |s| drop = s.get_data :drop cp = s.get_center_position pt = drop.game_stage.snaped_cell_world_pos *cp d = vector_sub pt, cp #if drop.index == 0 # game.logger.debug "pt #{pt}, cp #{cp}, vector_len(d) #{vector_len(d)}" #end if vector_len(d) < 2 s.change_motion :stay drop.game_stage.insert_drop drop d[1] else d[1] / 2 end end) commands.wait_frame 1 end sprite_template.motion :stay do |commands| commands.loop false commands.velocity 0, 0 commands.wait_frame 1 end sprite_template.motion :swap do |commands| commands.loop false commands.proc_call do |s| drop = s.get_data :drop drop.game_stage.remove_drop drop s.set_data :moving, true end commands.move_to(lambda do |s| s.get_data :next_x end, lambda do |s| s.get_data :next_y end, 15) commands.wait_motion commands.proc_call do |s| drop = s.get_data :drop s.set_data :moving, false drop.game_stage.insert_drop drop end commands.wait_frame 1 commands.proc_call do |s| drop = s.get_data :drop if drop.game_stage.need_revert s.change_motion :swap_back else drop.game_stage.moving = false end end end sprite_template.motion :swap_back do |commands| commands.loop false commands.proc_call do |s| drop = s.get_data :drop drop.game_stage.remove_drop drop s.set_data :moving, true end commands.move_to(lambda do |s| s.get_data :back_x end, lambda do |s| s.get_data :back_y end, 15) commands.wait_motion commands.proc_call do |s| drop = s.get_data :drop drop.game_stage.insert_drop drop s.set_data :moving, false drop.game_stage.moving = false end end sprite_template.event :on_add do |event| event.target.change_motion :fall end sprite_template.event :on_collision do |event| source = event.pair[0] another = event.pair[1] next unless another next unless source next if source.get_data :moving drop = source.get_data :drop #game.logger.debug "source #{source}" #game.logger.debug "another #{another}" #game.logger.debug "source.destroyed #{source.destroyed}" #game.logger.debug "another.destroyed #{another.destroyed}" #game.logger.debug "source.get_center_position #{source.get_center_position}" #game.logger.debug "another.get_center_position #{another.get_center_position}" if source.get_center_position[1] < another.get_center_position[1] drop.game_stage.remove_drop drop drop.sprite.change_motion :up end end #sprite_template.event :on_step do |event| # #end if type == :majitai sprite_template.texture :majitai sprite_template.layer_order 20 sprite_template.animation :animate do |commands| commands.loop true (0...59).each do |i| # 1行に8パターンならんでいるのでこのような書き方 # 1フレームアニメーションを表示します。 commands.copy_rect :frame => 1, :src => [i % 8, (i / 8).floor] # アニメーションの待ち commands.wait_animation end end end end sprite_template :sprite_template_drop do |sprite_template| self.sprite_tamplate_drop_init sprite_template, :drop end sprite_template :sprite_template_majitai do |sprite_template| self.sprite_tamplate_drop_init sprite_template, :majitai end end class GameStage attr_accessor :touch_down, :scene, :sprite, :floor_y, :cells, :floor, :left_top_x, :left_top_y, :cell_w, :cell_h, :cell_sw, :cell_sh, :lazy_call, :index_count, :need_revert, :need_decide, :next_position, :back_position, :moving, :score, :majitai_count, :score_label, :score_text, :majitai_count_label, :majitai_count_text def initialize scene self.touch_down = false self.scene = scene self.sprite = scene.sprite :template => :sprite_template_screen self.sprite.set_data :game_stage, self GameStage.instance = self self.floor = scene.collision :template => :sprite_template_floor self.lazy_call = Lazy_call.new self.index_count = 0 self.need_revert = false self.need_decide = true self.moving = false self.score = 0 self.majitai_count = 0 text = scene.text :position => [self.screen_width - 200, self.screen_height - 24], :layer_order => 200 text.set_text_area_size 200, 24 text.set_font_point_size 18 text.set_text "スタートメニュー" text.event :on_click do |event| # スタートメニューに戻る game.change_project "start_menu" end if IS_VIEW_FPS fps_sp = scene.text :position => [10, self.screen_height - 24] fps_sp.set_text_area_size 200, 24 fps_sp.set_font_point_size 18 tm = Time.now.to_f count = 0 fps_sp.event :on_step do now = Time.now.to_f count += 1 if now - tm > 1 fps_sp.set_text "fps = #{count}" count = 0 tm = now end end end # self.score_label = scene.text :position => [10, self.screen_height - 64 - 32], :layer_order => 200 self.score_label.set_text_area_size 200, 32 self.score_label.set_font_point_size 20 self.score_label.set_text "Score" self.score_text = scene.text :position => [self.screen_width - 200, self.screen_height - 64 - 32], :layer_order => 200 self.score_text.set_text_area_size 200, 32 self.score_text.set_font_point_size 20 self.score_text.set_text self.score.to_s # self.majitai_count_label = scene.text :position => [10, self.screen_height - 64], :layer_order => 200 self.majitai_count_label.set_text_area_size 200, 32 self.majitai_count_label.set_font_point_size 12 self.majitai_count_label.set_text "生き残っている\nmajitai" self.majitai_count_text = scene.text :position => [self.screen_width - 200, self.screen_height - 64], :layer_order => 200 self.majitai_count_text.set_text_area_size 200, 32 self.majitai_count_text.set_font_point_size 20 self.majitai_count_text.set_text self.majitai_count.to_s # @active_count = 0 @on_disactive = nil end def self.instance @instance end def self.instance= o @instance = o end def screen_width game.get_screen_size[0] end def screen_height game.get_screen_size[1] end def active_count @active_count end def active_count= v @active_count = v #game.logger.debug "@active_count #{@active_count}" if @active_count == 0 @on_disactive.call end end def set_active_count v @active_count = v end def on_disactive &f @on_disactive = f end def can_move !self.moving && self.active_count <= 0 end def new_drop i, j w = self.cell_w h = self.cell_h sw = self.cell_sw sh = self.cell_sh r = rand(2) g = rand(2) b = rand(2) #if j == 2 # r = 1 # g = 0 # b = 0 #end if r == 1 && g == 1 && b == 1 r, g, b = [1, 0, 0] elsif r == 0 && g == 0 && b == 0 r, g, b = [0, 0, 1] end color_code = r + g * 2 + b * 4 drop = Drop.new self, color_code drop.sprite.set_center_position j * sw + (screen_width - sw * w) / 2 + sw / 2, (h - i - 1) * sh - sh * h drop.index = self.index_count r *= 255 g *= 255 b *= 255 if color_code != 6 drop.sprite.set_color r, g, b, 255 end self.active_count += 1 self.index_count += 1 end def make_drops w = 7 h = 7 sw = 64 sh = 64 self.cell_w = w self.cell_h = h self.cell_sw = sw self.cell_sh = sh self.left_top_x = (screen_width - sw * w) / 2 - sw / 2 self.left_top_y = (screen_height - sh * h) / 2 - sh / 2 self.floor_y = (screen_height - sh * h) / 2 + sh * h + 2 self.cells = Array.new h, [] self.floor.set_center_position screen_width / 2, self.floor_y # bg = scene.sprite :texture => :bg, :position => [self.left_top_x, self.left_top_y], :layer_order => 0 dest_rects = [] colors = [] src_rects = [] (-5...h).each do |i| (-5...w).each do |j| dest_rects.concat [j * sw - sw * 1.5, i * sh - sh * 1.5, sw, sh] colors.concat [63, 63, 63, 255] src_rects.concat [0, 0, sw, sh] end end (0...w).each do |j| dest_rects.concat [j * sw - sw * 1.5, h * sh - sh * 1.5, sw, sh] colors.concat [63, 63, 63, 255] src_rects.concat [sw, 0, sw, sh] end bg.set_rects dest_rects, colors, src_rects # (0...h).each do |i| self.cells[i] = Array.new w, nil end fiber = Fiber.new do (0...h).each do |i| (0...w).each do |j| self.new_drop i, j Fiber.yield false end end true end self.lazy_call.add fiber self.on_disactive do self.decision end end def snaped_cell_pos x, y [((x - self.left_top_x) / self.cell_sw).floor - 1, ((y - self.left_top_y) / self.cell_sh).floor - 1] end def snaped_cell_world_pos x, y ix, iy = snaped_cell_pos x, y [(ix + 1) * self.cell_sw + self.left_top_x, (iy + 1) * self.cell_sh + self.left_top_y] end def decision w = self.cell_w h = self.cell_h self.need_revert = true #game.logger.debug "decision #{w} #{h}" #pt_info = "pt_info\n" cluster_array = [] #table = Array h, [] # crush? table = [] (0...h).each do |i| table.push [] (0...w).each do |j| table[i].push({ :cluster_id => nil, :counts => [], :parent => nil, :evaled => false, :color_code => 0 }) current_cell = self.cells[i][j] table[i][j][:color_code] = current_cell.color_code table[i][j][:parent] = table[i][j] end end cluster_count = 0 (0...h).each do |i| j = 0 while j < w jst = j start_cell = self.cells[i][j] c = start_cell.color_code cell_connect_count = 0 #game.logger.debug "check #{i} #{j} #{cell_connect_count} #{c}" cell_connect_count = 1 jed = j j += 1 while j < w + 1 if j < w current_cell = self.cells[i][j] else current_cell = nil end #game.logger.debug "check #{i} #{j} #{cell_connect_count} #{current_cell ? current_cell.color_code : "_"}" if cell_connect_count >= 3 && (current_cell == nil || current_cell.color_code != c) #game.logger.debug "cell_connect_count #{cell_connect_count}" cluster = table[i][jst][:parent] (jst..jed).each do |k| table[i][k][:parent] = cluster self.cells[i][k].need_delete = true end cluster[:counts].push cell_connect_count cluster_count += 1 break elsif current_cell && current_cell.color_code == c jed = j cell_connect_count += 1 j += 1 else break end end end end (0...w).each do |i| j = 0 while j < h jst = j start_cell = self.cells[j][i] c = start_cell.color_code cell_connect_count = 0 #game.logger.debug "check #{j} #{i} #{cell_connect_count} #{c}" cell_connect_count = 1 jed = j j += 1 while j < h + 1 if j < h current_cell = self.cells[j][i] else current_cell = nil end #game.logger.debug "check #{i} #{j} #{cell_connect_count} #{current_cell ? current_cell.color_code : "_"}" if cell_connect_count >= 3 && (current_cell == nil || current_cell.color_code != c) #game.logger.debug "cell_connect_count #{cell_connect_count}" cluster = table[i][jst][:parent] (jst..jed).each do |k| table[k][i][:parent] = cluster self.cells[k][i].need_delete = true end cluster[:counts].push cell_connect_count cluster_count += 1 break elsif current_cell && current_cell.color_code == c jed = j cell_connect_count += 1 j += 1 else break end end end end if false (0...h).each do |i| (0...w).each do |j| down_cells = [] right_cells = [] current_cell = self.cells[i][j] #game.logger.debug "current_cell #{current_cell}" unless current_cell #pt_info += "null, " next end c = self.cells[i][j].color_code #game.logger.debug "c #{c}" #pt_info += "#{current_cell.index} (#{current_cell.cell_x}, #{current_cell.cell_y}), " (0...2).each do |k| #game.logger.debug "self.cells[i + k + 1][j].color_code #{self.cells[i + k + 1][j].color_code}" if i + k + 1 < h && c == self.cells[i + k + 1][j].color_code down_cells.push self.cells[i + k + 1][j] #game.logger.debug "down_cells.push" end #game.logger.debug "self.cells[i][j + k + 1].color_code #{self.cells[i][j + k + 1].color_code}" if j + k + 1 < w && c == self.cells[i][j + k + 1].color_code right_cells.push self.cells[i][j + k + 1] #game.logger.debug "right_cells.push" end end if down_cells.length >= 2 || right_cells.length >= 2 current_cell.need_delete = true #game.logger.debug "current_cell.need_delete = true" end if down_cells.length >= 2 down_cells.each do |cell| cell.need_delete = true end end if right_cells.length >= 2 right_cells.each do |cell| cell.need_delete = true end end end #pt_info += "\n" end end #game.logger.debug pt_info a = Array.new w, 0 deleted = false (0...h).each do |i| (0...w).each do |j| cell = self.cells[i][j] next unless cell if cell.need_delete a[cell.cell_x] += 1 #game.logger.debug "cell.delete" cell.delete deleted = true end end end fiber = Fiber.new do l = true ct = 0 while l l = false (0...w).each do |i| if a[i] > 0 self.new_drop ct, i l = true a[i] -= 1 Fiber.yield false end end ct += 1 end true end self.lazy_call.add fiber # (0...h).each do |i| (0...w).each do |j| cluster = table[i][j][:parent] next if cluster[:evaled] if cluster[:counts].length > 0 s = 1 cluster[:counts].each do |k| s = ((k - 2) ** 2) * 10 * s end self.score += s end cluster[:evaled] = true end end self.majitai_count = 0 (0...h).each do |i| (0...w).each do |j| cluster = table[i][j][:parent] next if cluster[:counts].length > 0 cluster = table[i][j] c = cluster[:color_code] self.majitai_count += 1 if c == 6 end end self.score_text.set_text self.score.to_s self.majitai_count_text.set_text self.majitai_count.to_s # if deleted fall_fiber = Fiber.new do (0...h).each do |i| (0...w).each do |j| #game.logger.debug "start fall!" cell = self.cells[h - i - 1][j] if cell self.remove_drop cell cell.sprite.change_motion :fall end end Fiber.yield false end true end self.lazy_call.add fall_fiber self.need_revert = false end self.need_decide = false end def insert_drop drop cp = drop.sprite.get_center_position cell = snaped_cell_pos *cp drop.cell_x = cell[0] drop.cell_y = cell[1] #game.logger.debug "insert_drop drop.index #{drop.index}, drop.cell_x #{drop.cell_x}, drop.cell_y #{drop.cell_y}" self.cells[drop.cell_y][drop.cell_x] = drop #game.logger.debug "insert_drop #{drop.index}" self.active_count -= 1 end def remove_drop drop return unless drop.cell_y #game.logger.debug "remove_drop drop.cell_x #{drop.cell_x}, drop.cell_y #{drop.cell_y}" self.cells[drop.cell_y][drop.cell_x] = nil drop.cell_x = nil drop.cell_y = nil self.active_count += 1 end sprite_template :sprite_template_floor do |sprite_template| sprite_template.collision :rect, :position => [-1024, 0], :width => [2048, 32], :group_id => 1 sprite_template.layer_order 0 end sprite_template :sprite_template_screen do |sprite_template| sprite_template.layer_order 100 sprite_template.align :fullscreen # 画面全体に広げます sprite_template.no_image true sprite_template.event :on_add do |event| end # タッチダウン時の処理 sprite_template.event :on_touch_down do |event| gs = event.target.get_data :game_stage if gs.can_move gs.back_position = gs.snaped_cell_pos event.screen_x + gs.cell_sw / 2, event.screen_y + gs.cell_sh / 2 end end # タッチムーブ時の処理 sprite_template.event :on_touch_move do |event| gs = event.target.get_data :game_stage gs.next_position = gs.snaped_cell_pos event.screen_x + gs.cell_sw / 2, event.screen_y + gs.cell_sh / 2 if gs.back_position && ((gs.next_position[0] == gs.back_position[0] && (gs.next_position[1] - gs.back_position[1]).abs == 1) || (gs.next_position[1] == gs.back_position[1] && (gs.next_position[0] - gs.back_position[0]).abs == 1)) next if gs.next_position[0] < 0 next if gs.next_position[1] < 0 next if gs.next_position[0] >= gs.cell_w next if gs.next_position[1] >= gs.cell_h next if gs.back_position[0] < 0 next if gs.back_position[1] < 0 next if gs.back_position[0] >= gs.cell_w next if gs.back_position[1] >= gs.cell_h #game.logger.debug "gs.snaped_cell_pos on_touch_move" #game.logger.debug "gs.back_position #{gs.back_position}, gs.next_position #{gs.next_position}" cell0 = gs.cells[gs.back_position[1]][gs.back_position[0]] cell1 = gs.cells[gs.next_position[1]][gs.next_position[0]] next unless cell0 next unless cell1 #game.logger.debug "cell0 #{cell0}, cell1 #{cell1}" cp0 = cell0.sprite.get_position cp1 = cell1.sprite.get_position #game.logger.debug "cp0 #{cp0}, cp1 #{cp1}" cell0.sprite.set_data :back_x, cp0[0] cell0.sprite.set_data :back_y, cp0[1] cell0.sprite.set_data :next_x, cp1[0] cell0.sprite.set_data :next_y, cp1[1] cell1.sprite.set_data :back_x, cp1[0] cell1.sprite.set_data :back_y, cp1[1] cell1.sprite.set_data :next_x, cp0[0] cell1.sprite.set_data :next_y, cp0[1] #game.logger.debug "pre chamge_motion" cell0.sprite.change_motion :swap cell1.sprite.change_motion :swap #game.logger.debug "post chamge_motion" gs.back_position = nil #game.logger.debug "gs.snaped_cell_pos on_touch_move end" end end # タッチアップ時の処理 sprite_template.event :on_touch_up do |event| end sprite_template.event :on_step do |event| gs = event.target.get_data :game_stage gs.lazy_call.poll end end end def start_stage scene, options = {} game.collision_group_pair 1, 1, true gs = GameStage.new scene gs.make_drops end
コード一覧
  • start.rb

コメントするには、ログインする必要があります。

コメント一覧
お知らせ

2014/03/04 ver. 0.1.39 を公開しました!
・0.1.36でWindowsで起動しない問題を修正しました
(Android版はバージョン番号のみの変更です。)

2014/03/04 ver. 0.1.36 を公開しました!
・アプリケーションアイコンを変更しました
・セーブ・ロードを繰り返すとアプリが強制終了する問題を修正しました
・他、重大なバグを修正しました

ダウンロードはこちらから。

2013/07/17 Code on Rmakeをα公開しました!