设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 1882|回复: 12
打印 上一主题 下一主题

[已经解决] 求改良打砖块的反弹方法

[复制链接]

Lv5.捕梦者

梦石
0
星屑
26513
在线时间
5385 小时
注册时间
2016-3-8
帖子
1658
跳转到指定楼层
1
发表于 2022-5-15 23:13:54 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
1000星屑
本帖最后由 alexncf125 于 2022-5-16 12:08 编辑

有大神可以帮忙看看171行跟243行的算法该怎样地改良才能正常么

三张图片放置于Graphics/Breakout_Clone之內
RUBY 代码复制
  1. $imported ||= {}
  2. $imported["AI-BreakoutClone"] = true
  3.  
  4. module BREAKOUT_CLONE
  5.   STAGE = {}
  6.   STAGE[0] = [
  7.   [7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
  8.   [6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
  9.   [3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
  10.   [4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
  11.   [5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
  12.   [6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
  13.   [7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
  14.   ]
  15. end
  16.  
  17. module Cache
  18.   def self.breakout_clone(filename)
  19.     load_bitmap("Graphics/Breakout_Clone/", filename)
  20.   end
  21. end
  22.  
  23. module SceneManager
  24.   class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
  25.   def self.first_scene_class
  26.     if $imported["AI-BreakoutClone"] && !$BTEST
  27.       Graphics.resize_screen(544, 480)
  28.       return Scene_Breakout_Clone
  29.     end
  30.     breakout_clone_first_scene_class
  31.   end
  32. end
  33.  
  34. class Game_Temp
  35.  
  36.   attr_accessor :breakout_clone_start
  37.   attr_accessor :breakout_clone_gameover
  38.  
  39.   alias breakout_clone_initialize initialize
  40.   def initialize
  41.     breakout_clone_initialize
  42.     @breakout_clone_start = false
  43.     @breakout_clone_gameover = false
  44.   end
  45.  
  46.   def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
  47.   def reset_breakout_clone_start; @breakout_clone_start = false; end
  48.   def breakout_clone_start?; @breakout_clone_start == true; end
  49.  
  50.   def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
  51.   def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
  52.   def breakout_clone_gameover?; @breakout_clone_gameover == true; end
  53.  
  54. end
  55.  
  56. class Sprite_Breakout_Clone_Paddle < Sprite
  57.  
  58.   def initialize
  59.     super
  60.     init_members
  61.     create_bitmap
  62.   end
  63.  
  64.   def init_members
  65.     @slide_speed = 8
  66.   end
  67.  
  68.   def create_bitmap
  69.     self.bitmap = Cache.breakout_clone("paddle")
  70.     self.x = (Graphics.width - paddle_width) / 2
  71.     self.y = Graphics.height - paddle_height
  72.   end
  73.  
  74.   def slide_speed; @slide_speed; end
  75.   def paddle_width; self.bitmap.width; end
  76.   def paddle_height; self.bitmap.height; end
  77.   def paddle_x; self.x + paddle_width; end
  78.   def paddle_y; self.y + paddle_height; end
  79.  
  80.   def dispose
  81.     self.bitmap.dispose
  82.     super
  83.   end
  84.  
  85.   def update
  86.     super
  87.     update_position
  88.   end
  89.  
  90.   def update_position
  91.     slide_left if Input.press?(:LEFT)
  92.     slide_right if Input.press?(:RIGHT)
  93.   end
  94.  
  95.   def slide_left
  96.     result = self.x - slide_speed
  97.     return self.x = 0 if result <= 0
  98.     self.x -= slide_speed
  99.   end
  100.  
  101.   def slide_right
  102.     result = self.x + slide_speed
  103.     block = Graphics.width - paddle_width
  104.     return self.x = block if result >= block
  105.     self.x += slide_speed
  106.   end
  107.  
  108. end
  109.  
  110. class Sprite_Breakout_Clone_Ball < Sprite
  111.  
  112.   attr_accessor :route_x
  113.   attr_accessor :route_y
  114.   attr_accessor :ball_last_touch
  115.  
  116.   def initialize(viewport, paddle = nil)
  117.     super(viewport)
  118.     @paddle = paddle
  119.     init_members
  120.     create_bitmap
  121.   end
  122.  
  123.   def init_members
  124.     @move_speed = 4
  125.     @route_x = [-(rand(@move_speed) + 1), rand(@move_speed) + 1][rand(2)]
  126.     @route_y = -(@move_speed + 1)
  127.     @ball_last_touch = :paddle
  128.   end
  129.  
  130.   def create_bitmap
  131.     self.bitmap = Cache.breakout_clone("ball")
  132.     self.x = (Graphics.width - ball_width) / 2
  133.     self.y = Graphics.height - @paddle.bitmap.height - ball_height
  134.   end
  135.  
  136.   def move_speed; @move_speed; end
  137.   def route_x; @route_x; end
  138.   def route_y; @route_y; end
  139.   def ball_width; self.bitmap.width; end
  140.   def ball_height; self.bitmap.height; end
  141.   def ball_x; self.x + ball_width; end
  142.   def ball_y; self.y + ball_height; end
  143.  
  144.   def dispose
  145.     self.bitmap.dispose
  146.     super
  147.   end
  148.  
  149.   def update
  150.     super
  151.     update_position
  152.     update_ball_touch
  153.   end
  154.  
  155.   def update_position
  156.     if $game_temp.breakout_clone_start?
  157.       self.x = (@paddle.x + @paddle.bitmap.width) / 2  - ball_width / 2
  158.       self.y = Graphics.height - @paddle.bitmap.height - ball_height
  159.     else
  160.       self.x += route_x
  161.       self.y += route_y
  162.     end
  163.   end
  164.  
  165.   def update_ball_touch
  166.     return if $game_temp.breakout_clone_gameover?
  167.     update_touch_paddle
  168.     update_touch_wall
  169.   end
  170.  
  171.   def update_touch_paddle
  172.     return if @ball_last_touch == :paddle
  173.     if ball_x.between?(@paddle.x, @paddle.x + @paddle.bitmap.width + ball_width) && ball_y.between?(@paddle.y, @paddle.y + @paddle.bitmap.height)
  174.       if (ball_x.between?(@paddle.x, @paddle.x + (ball_width / 2)) && route_x > 0) || (self.x.between?(@paddle.x + @paddle.bitmap.width - (ball_width / 2), @paddle.x + @paddle.bitmap.width) && route_x < 0)
  175.         if Input.press?(:RIGHT) && route_x < 0
  176.           @route_x =  rand(move_speed) + 1
  177.         elsif Input.press?(:LEFT) && route_x > 0
  178.           @route_x = -(rand(move_speed) + 1)
  179.         else
  180.           @route_x = -(route_x)
  181.         end
  182.       else
  183.         @route_x =  rand(move_speed) + 1 if Input.press?(:RIGHT)
  184.         @route_x = -(rand(move_speed) + 1) if Input.press?(:LEFT)
  185.       end
  186.       @route_y = -(move_speed) unless self.y > @paddle.y
  187.       @ball_last_touch = :paddle
  188.     end
  189.   end
  190.  
  191.         def update_touch_wall
  192.     if self.x <= 0 || ball_x >= Graphics.width
  193.       @route_x = -(route_x)
  194.       @ball_last_touch = :wall
  195.     end
  196.     if self.y <= 0
  197.       @route_y = -(route_y)
  198.       @ball_last_touch = :wall
  199.     end
  200.   end
  201.  
  202. end
  203.  
  204. class Sprite_Breakout_Clone_Brick < Sprite
  205.  
  206.   def initialize(viewport, balls = nil, brick = nil)
  207.     super(viewport)
  208.     @ball = balls
  209.     @brick = brick
  210.     init_members
  211.     create_bitmap
  212.   end
  213.  
  214.   def init_members
  215.     @brick_life = @brick[0]
  216.   end
  217.  
  218.   def create_bitmap
  219.     self.bitmap = Cache.breakout_clone("brick")
  220.     self.x = @brick[1]
  221.     self.y = @brick[2]
  222.   end
  223.  
  224.   def dispose
  225.     self.bitmap.dispose
  226.     super
  227.   end
  228.  
  229.   def update
  230.     super
  231.     update_src_rect
  232.     update_brick_touch
  233.     update_brick_visible
  234.   end
  235.  
  236.   def update_src_rect
  237.     return if @brick_life.zero?
  238.     index = @brick_life
  239.     sy = (index - 1) * 24
  240.     self.src_rect.set(0, sy, 68, 24)
  241.   end
  242.  
  243.   def update_brick_touch
  244.     return if self.visible == false
  245.     @ball.each do |b|
  246.       return if b.ball_last_touch == self
  247.       if b.ball_x.between?(self.x, self.x + self.bitmap.width + b.ball_width) && b.ball_y.between?(self.y, self.y + self.bitmap.height / 7 + b.ball_height)
  248.         if (b.x).between?(self.x - b.bitmap.width + 1, self.x + self.bitmap.width - 1)
  249.           b.route_y = -(b.route_y)
  250.         end
  251.         if (b.y).between?(self.y - b.bitmap.height + 1, self.y + self.bitmap.height / 7 - 1)
  252.           b.route_x = -(b.route_x)
  253.         end
  254.         @brick_life -= 1 if @brick_life > 0
  255.         b.ball_last_touch = self
  256.       end
  257.     end
  258.   end
  259.  
  260.   def update_brick_visible
  261.     self.visible = !@brick_life.zero?
  262.   end
  263.  
  264. end
  265.  
  266. class Scene_Breakout_Clone < Scene_Base
  267.  
  268.   include BREAKOUT_CLONE
  269.  
  270.   def start
  271.     super
  272.     create_breakout_clone_paddle
  273.     create_breakout_clone_ball
  274.     create_breakout_clone_brick
  275.   end
  276.  
  277.   def create_breakout_clone_paddle
  278.     @breakout_clone_paddle_sprite = Sprite_Breakout_Clone_Paddle.new
  279.   end
  280.  
  281.   def create_breakout_clone_ball
  282.     @breakout_clone_ball_sprite ||= []
  283.     @breakout_clone_ball_sprite.push(Sprite_Breakout_Clone_Ball.new(@viewport1, @breakout_clone_paddle_sprite))
  284.   end
  285.  
  286.   def create_breakout_clone_brick
  287.     @breakout_clone_brick_sprite ||= []
  288.     STAGE[0].each do |brick|
  289.       @breakout_clone_brick_sprite.push(Sprite_Breakout_Clone_Brick.new(@viewport1, @breakout_clone_ball_sprite, brick))
  290.     end
  291.   end
  292.  
  293.   def terminate
  294.     super
  295.     dispose_breakout_clone_paddle
  296.     dispose_breakout_clone_ball
  297.     dispose_breakout_clone_brick
  298.   end
  299.  
  300.   def dispose_breakout_clone_paddle
  301.     @breakout_clone_paddle_sprite.bitmap.dispose
  302.     @breakout_clone_paddle_sprite.dispose
  303.   end
  304.  
  305.   def dispose_breakout_clone_ball
  306.     @breakout_clone_ball_sprite.each do |sprite|
  307.       sprite.bitmap.dispose
  308.       sprite.dispose
  309.     end
  310.   end
  311.  
  312.   def dispose_breakout_clone_brick
  313.     @breakout_clone_brick_sprite.each do |sprite|
  314.       sprite.bitmap.dispose
  315.       sprite.dispose
  316.     end
  317.   end
  318.  
  319.   def update
  320.     super
  321.     @breakout_clone_paddle_sprite.update
  322.     @breakout_clone_ball_sprite.each {|sprite| sprite.update}
  323.     @breakout_clone_brick_sprite.each {|sprite| sprite.update}
  324.   end
  325.  
  326. end


最佳答案

查看完整内容

呜~ 写了一个RectangleAndRectangle模块来集成矩形的碰撞检测和球的反弹,然后将球与玩家控制的板子,球与砖块的碰撞都集成到了里面。 给精灵对象都加了一个bitmap_width和bitmap_height属性,方便判断,因为砖块的高得除7而移动的球不用会比较麻烦…… 让显示球的那个精灵有更多的属性可被外部访问。 其他的都没有改,我想还可以将四周的wall也都设置为一个空的精灵,使用RectangleAndRectangle给的接口来判断应该更好,因为我 ...

Lv5.捕梦者

梦石
16
星屑
12217
在线时间
1428 小时
注册时间
2020-3-21
帖子
366

极短23获奖

2
发表于 2022-5-15 23:13:55 | 只看该作者
呜~

写了一个RectangleAndRectangle模块来集成矩形的碰撞检测和球的反弹,然后将球与玩家控制的板子,球与砖块的碰撞都集成到了里面。
给精灵对象都加了一个bitmap_width和bitmap_height属性,方便判断,因为砖块的高得除7而移动的球不用会比较麻烦……
让显示球的那个精灵有更多的属性可被外部访问。

其他的都没有改,我想还可以将四周的wall也都设置为一个空的精灵,使用RectangleAndRectangle给的接口来判断应该更好,因为我发现球与最上面的固定墙碰撞时会抽搐~
然后因为球是移动的,所以在球的update里去判断与静态的砖块碰撞会更好一些?
应该……问题大幅减小了,但可能还有。
有时会出现:球看起来会穿透,或者砖块被快速消除这两个问题,这不是bug,只是因为球移速相对较大所以看不清,我用录屏软件录下后一下一下看来着……

RUBY 代码复制
  1. $imported ||= {}
  2. $imported["AI-BreakoutClone"] = true
  3.  
  4. module BREAKOUT_CLONE
  5.   STAGE = {}
  6.   STAGE[0] = [
  7.   [7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
  8.   [6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
  9.   [3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
  10.   [4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
  11.   [5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
  12.   [6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
  13.   [7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
  14.   ]
  15. end
  16.  
  17. module Cache
  18.   def self.breakout_clone(filename)
  19.     load_bitmap("Graphics/Breakout_Clone/", filename)
  20.   end
  21. end
  22.  
  23. module SceneManager
  24.   class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
  25.   def self.first_scene_class
  26.     if $imported["AI-BreakoutClone"] && !$BTEST
  27.       Graphics.resize_screen(544, 480)
  28.       return Scene_Breakout_Clone
  29.     end
  30.     breakout_clone_first_scene_class
  31.   end
  32. end
  33.  
  34. class Game_Temp
  35.  
  36.   attr_accessor :breakout_clone_start
  37.   attr_accessor :breakout_clone_gameover
  38.  
  39.   alias breakout_clone_initialize initialize
  40.   def initialize
  41.     breakout_clone_initialize
  42.     @breakout_clone_start = false
  43.     @breakout_clone_gameover = false
  44.   end
  45.  
  46.   def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
  47.   def reset_breakout_clone_start; @breakout_clone_start = false; end
  48.   def breakout_clone_start?; @breakout_clone_start == true; end
  49.  
  50.   def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
  51.   def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
  52.   def breakout_clone_gameover?; @breakout_clone_gameover == true; end
  53.  
  54. end
  55.  
  56. class Sprite_Breakout_Clone_Paddle < Sprite
  57.  
  58.   attr_accessor :bitmap_width
  59.   attr_accessor :bitmap_height
  60.  
  61.   def initialize
  62.     super
  63.     init_members
  64.     create_bitmap
  65.   end
  66.  
  67.   def init_members
  68.     @slide_speed = 8
  69.   end
  70.  
  71.   def create_bitmap
  72.     self.bitmap = Cache.breakout_clone("paddle")
  73.     self.x = (Graphics.width - paddle_width) / 2
  74.     self.y = Graphics.height - paddle_height
  75.     @bitmap_width = self.bitmap.width
  76.     @bitmap_height = self.bitmap.height
  77.   end
  78.  
  79.   def slide_speed; @slide_speed; end
  80.   def paddle_width; self.bitmap.width; end
  81.   def paddle_height; self.bitmap.height; end
  82.   def paddle_x; self.x + paddle_width; end
  83.   def paddle_y; self.y + paddle_height; end
  84.  
  85.   def dispose
  86.     self.bitmap.dispose
  87.     super
  88.   end
  89.  
  90.   def update
  91.     super
  92.     update_position
  93.   end
  94.  
  95.   def update_position
  96.     slide_left if Input.press?(:LEFT)
  97.     slide_right if Input.press?(:RIGHT)
  98.   end
  99.  
  100.   def slide_left
  101.     result = self.x - slide_speed
  102.     return self.x = 0 if result <= 0
  103.     self.x -= slide_speed
  104.   end
  105.  
  106.   def slide_right
  107.     result = self.x + slide_speed
  108.     block = Graphics.width - paddle_width
  109.     return self.x = block if result >= block
  110.     self.x += slide_speed
  111.   end
  112.  
  113. end
  114.  
  115. class Sprite_Breakout_Clone_Ball < Sprite
  116.  
  117.   attr_accessor :route_x
  118.   attr_accessor :route_y
  119.   attr_accessor :ball_last_touch
  120.   attr_accessor :bitmap_width
  121.   attr_accessor :bitmap_height
  122.   attr_accessor :last_x
  123.   attr_accessor :last_y
  124.   attr_accessor :move_speed
  125.  
  126.   def initialize(viewport, paddle = nil)
  127.     super(viewport)
  128.     @paddle = paddle
  129.     init_members
  130.     create_bitmap
  131.   end
  132.  
  133.   def init_members
  134.     @move_speed = 4
  135.     @route_x = [-(rand(@move_speed) + 1), rand(@move_speed) + 1][rand(2)]
  136.     @route_y = -(@move_speed + 1)
  137.     @ball_last_touch = :paddle
  138.     @last_x = 0
  139.     @last_y = 0
  140.   end
  141.  
  142.   def create_bitmap
  143.     self.bitmap = Cache.breakout_clone("ball")
  144.     self.x = (Graphics.width - ball_width) / 2
  145.     self.y = Graphics.height - @paddle.bitmap.height - ball_height
  146.     @bitmap_width = self.bitmap.width
  147.     @bitmap_height = self.bitmap.height
  148.   end
  149.  
  150.   def move_speed; @move_speed; end
  151.   def route_x; @route_x; end
  152.   def route_y; @route_y; end
  153.   def ball_width; self.bitmap.width; end
  154.   def ball_height; self.bitmap.height; end
  155.   def ball_x; self.x + ball_width; end
  156.   def ball_y; self.y + ball_height; end
  157.  
  158.   def dispose
  159.     self.bitmap.dispose
  160.     super
  161.   end
  162.  
  163.   def update
  164.     super
  165.     update_position
  166.     update_ball_touch
  167.   end
  168.  
  169.   def update_position
  170.     @last_x = self.x
  171.     @last_y = self.y
  172.     if $game_temp.breakout_clone_start?
  173.       self.x = (@paddle.x + @paddle.bitmap.width) / 2  - ball_width / 2
  174.       self.y = Graphics.height - @paddle.bitmap.height - ball_height
  175.     else
  176.       self.x += route_x
  177.       self.y += route_y
  178.     end
  179.   end
  180.  
  181.   def update_ball_touch
  182.     return if $game_temp.breakout_clone_gameover?
  183.     update_touch_paddle
  184.     update_touch_wall
  185.   end
  186.  
  187.   def update_touch_paddle
  188.     return if @ball_last_touch == @paddle
  189.     RectangleAndRectangle.judge(self,@paddle,@paddle,false,true)
  190.   end
  191.   def update_touch_wall
  192.     if self.x <= 0 || ball_x >= Graphics.width
  193.       @route_x = -(route_x)
  194.       @ball_last_touch = :wall
  195.     end
  196.     if self.y <= 0
  197.       @route_y = -(route_y)
  198.       @ball_last_touch = :wall
  199.     end
  200.   end
  201.  
  202. end
  203.  
  204. class Sprite_Breakout_Clone_Brick < Sprite
  205.  
  206.   attr_accessor :bitmap_width
  207.   attr_accessor :bitmap_height
  208.   attr_accessor :brick_life
  209.  
  210.   def initialize(viewport, balls = nil, brick = nil)
  211.     super(viewport)
  212.     @ball = balls
  213.     @brick = brick
  214.     init_members
  215.     create_bitmap
  216.   end
  217.  
  218.   def init_members
  219.     @brick_life = @brick[0]
  220.   end
  221.  
  222.   def create_bitmap
  223.     self.bitmap = Cache.breakout_clone("brick")
  224.     self.x = @brick[1]
  225.     self.y = @brick[2]
  226.     @bitmap_width = self.bitmap.width
  227.     @bitmap_height = self.bitmap.height/7
  228.   end
  229.  
  230.   def dispose
  231.     self.bitmap.dispose
  232.     super
  233.   end
  234.  
  235.   def update
  236.     super
  237.     update_src_rect
  238.     update_brick_touch
  239.     update_brick_visible
  240.   end
  241.  
  242.   def update_src_rect
  243.     return if @brick_life.zero?
  244.     index = @brick_life
  245.     sy = (index - 1) * 24
  246.     self.src_rect.set(0, sy, 68, 24)
  247.   end
  248.  
  249.   def update_brick_touch
  250.     return if self.visible == false
  251.     @ball.each do |b|
  252.       return if b.ball_last_touch == self
  253.       RectangleAndRectangle.judge(b,self,self,true,false)
  254.     end
  255.   end
  256.  
  257.   def update_brick_visible
  258.     self.visible = !@brick_life.zero?
  259.   end
  260.  
  261. end
  262.  
  263. class Scene_Breakout_Clone < Scene_Base
  264.  
  265.   include BREAKOUT_CLONE
  266.  
  267.   def start
  268.     super
  269.     create_breakout_clone_paddle
  270.     create_breakout_clone_ball
  271.     create_breakout_clone_brick
  272.   end
  273.  
  274.   def create_breakout_clone_paddle
  275.     @breakout_clone_paddle_sprite = Sprite_Breakout_Clone_Paddle.new
  276.   end
  277.  
  278.   def create_breakout_clone_ball
  279.     @breakout_clone_ball_sprite ||= []
  280.     @breakout_clone_ball_sprite.push(Sprite_Breakout_Clone_Ball.new(@viewport1, @breakout_clone_paddle_sprite))
  281.   end
  282.  
  283.   def create_breakout_clone_brick
  284.     @breakout_clone_brick_sprite ||= []
  285.     STAGE[0].each do |brick|
  286.       @breakout_clone_brick_sprite.push(Sprite_Breakout_Clone_Brick.new(@viewport1, @breakout_clone_ball_sprite, brick))
  287.     end
  288.   end
  289.  
  290.   def terminate
  291.     super
  292.     dispose_breakout_clone_paddle
  293.     dispose_breakout_clone_ball
  294.     dispose_breakout_clone_brick
  295.   end
  296.  
  297.   def dispose_breakout_clone_paddle
  298.     @breakout_clone_paddle_sprite.bitmap.dispose
  299.     @breakout_clone_paddle_sprite.dispose
  300.   end
  301.  
  302.   def dispose_breakout_clone_ball
  303.     @breakout_clone_ball_sprite.each do |sprite|
  304.       sprite.bitmap.dispose
  305.       sprite.dispose
  306.     end
  307.   end
  308.  
  309.   def dispose_breakout_clone_brick
  310.     @breakout_clone_brick_sprite.each do |sprite|
  311.       sprite.bitmap.dispose
  312.       sprite.dispose
  313.     end
  314.   end
  315.  
  316.   def update
  317.     super
  318.     @breakout_clone_paddle_sprite.update
  319.     @breakout_clone_ball_sprite.each {|sprite| sprite.update}
  320.     @breakout_clone_brick_sprite.each {|sprite| sprite.update}
  321.   end
  322.  
  323. end
  324.  
  325.  
  326.  
  327.  
  328. #有时方块在两个砖块中间反弹时会快速消除两个砖块,这不是bug,只是速度较快所以肉眼看不清。
  329. #我是想找一个只需简单的加减乘除判断,不需向量的算法,但是不用向量真的好乱……
  330. #即使有更好的算法,也可以在这里面直接修改,不用再去上面改,方便一些。
  331. #其实只要解决一个问题算法就会简单明了许多:找到判断两个线段是否相交的简单办法
  332. #但这个问题不那么复杂的办法需要用到向量和代数几何知识,这应该也是各个碰撞检测算法的核心逻辑。
  333. #写了这么多说明,删掉说明后其实也不多(?)
  334. #我之前将一个js的SAT碰撞检测算法移植到rgss3a里来做我的弹幕插件,等我完善后也可以拿出来做这个。
  335. module RectangleAndRectangle
  336.   def self.judge(ball,box,sign,ifHaveLife = false,ifIsPaddle = false)
  337.     #==========================================================
  338.     #ball: 方块对象
  339.     #box: 定碰撞的目标砖块/玩家控制的板
  340.     #sign: 记录为ball.ball_last_touch的标志
  341.     #ifHaveLife: 是否有生命且需要扣除
  342.     #ifIsPaddle: 是否是玩家控制的板子,若是板子则在方块的route_y发生变化时,route_x也发生变动。
  343.     #==========================================================
  344.     #方块:移动的那个东西,一般应该是个球而不是正方形啊……如果要做成圆的话那最好还是设计一个简易的向量对象,
  345.     #      用更正式的数学公式去判定更好。可以学一个碰撞检测算法(例如:分离轴定理)。那样计算量会大一些且需要基础的高数知识。
  346.     #砖块:判定碰撞的目标砖块/玩家控制的板
  347.     #方法说明:这个方法就是判定方块和砖块四个点(四条边)的关系,从而找到反弹的方式。
  348.     #具体来说是分成:
  349.     #    {1}方块的四个点都不在砖块的内部:完全不碰撞,直接退出
  350.     #    {2}方块的四个点都在砖块的内部:方块完全陷入砖块内,一般不会出现,但是方块速度较大或者玩家控制的平板快速移动时有可能导致这种情况。
  351.     #    {3}方块有且只有两个点在砖块内部:向这两个点所形成的线的法线方向反弹即可,因为都是不旋转的矩形,所以只有竖向反弹和横向反弹两种情况。
  352.     #    {4}方块有且只有一个点在砖块内部:再分各种情况
  353.     # (不可能同时有三个点在砖块内部)
  354.     #==========================================================
  355.     #判断方块的四条边(最小x,最大x,最小y,最大y)是否在砖块内
  356.     xs = (ball.x).between?(box.x,box.x+box.bitmap_width)
  357.     ys = (ball.y).between?(box.y,box.y+box.bitmap_height)
  358.     xe = (ball.ball_x).between?(box.x,box.x+box.bitmap_width)
  359.     ye = (ball.ball_y).between?(box.y,box.y+box.bitmap_height)
  360.     #==========================================================
  361.     #横向完全没有重叠范围 或 纵向完全没有重叠范围,只要有一个完全没有重叠范围,则必不可能接触。(上面的{1})
  362.     return if (!xs and !xe) or (!ys and !ye)
  363.     #==========================================================
  364.     #已经碰撞了,所以执行对应的指令
  365.     ball.ball_last_touch = sign
  366.     sign.brick_life -= 1 if ifHaveLife and sign.brick_life > 0#必定接触了所以扣掉砖块的一点耐久
  367.     #==========================================================
  368.     if xs and xe and ys and ye#方块的四个角都在砖块内部,(上面的{2})
  369.       ball_x_change(ball,ifIsPaddle)
  370.       ball_y_change(ball,ifIsPaddle)
  371.       ball.ball_last_touch = nil#假如出了bug,将这个设置成nil则可以在下一帧时重新判定以让系统自动修复部分bug
  372.     elsif ((!xs or !xe) and (xs or xe) and ys and ye)#有两个角在砖块内且砖块的纵向边切割方块,则只需横向(X轴)变向(上面的{3})
  373.       ball_x_change(ball,ifIsPaddle)
  374.     elsif ((!ys or !ye) and (ys or ye) and xs and xe)#有两个角在砖块内且砖块的横向边切割方块,则只需纵向(Y轴)变向(上面的{3})
  375.       ball_y_change(ball,ifIsPaddle)
  376.     else
  377.       #==========================================================
  378.       #不可能有三个点在里面所以只剩下一个点在里面的情况,(上面的{4})仅仅知道砖块与方块如何重叠是不够的,还必须知道方块是朝哪个
  379.       #角度移动的,然后才能判定【最先与哪条边接触】,然后才能找到【具体是怎么样反弹】
  380.       #==========================================================
  381.       #cx cy: 方块在上一帧时的中心坐标
  382.       cx = ball.last_x+ball.ball_width/2
  383.       cy = ball.last_y+ball.ball_height/2
  384.       #==========================================================
  385.       #tx ty: 方块在此时已经进入砖块内部的那个点在上一帧时的坐标
  386.       tx = xs ? (ball.last_x) : (ball.last_x+ball.ball_width)
  387.       ty = ys ? (ball.last_y) : (ball.last_y+ball.ball_height)
  388.       #==========================================================
  389.       #nx ny: 既然方块的一个顶点进入了砖块,那么砖块自然也有一个顶点进入了方块,这个就是那个砖块中进入方块内部的那个顶点的坐标
  390.       nx = xs ? (box.x+box.bitmap_width) : (box.x)
  391.       ny = ys ? (box.y+box.bitmap_height) : (box.y)
  392.       #==========================================================
  393.       #差值
  394.       disX = (cx-nx).abs
  395.       disY = (cy-ny).abs
  396.       #==========================================================
  397.       #这个有点难解释…………其实就是分了(!xs and tx>=nx) (xs and tx<=nx) (!ys and ty>=ny) (ys and ty<=ny)
  398.       #这四种情况。以(!xs and tx>=nx)为例:
  399.       #!xs就是说方块的左面的边没有与砖块相交,此时若tx大于等于nx,那就说明方块肯定是碰着砖块的上面的那个边与砖块接触的,所以可以直接纵向反弹
  400.       if (!xs and tx>=nx) or (xs and tx<=nx)
  401.         ball_y_change(ball,ifIsPaddle)
  402.       elsif (!ys and ty>=ny) or (ys and ty<=ny)
  403.         ball_x_change(ball,ifIsPaddle)
  404.       else
  405.         #==========================================================
  406.         #实际上,若方块的四个点中只有一个点在砖块内,且知道了nx ny的值,那么他们的碰撞情况就和砖块的长和宽没有关系了。
  407.         #这里是直接对比了disX和disY的值,实际上若方块不是一个正方形而是一个长宽不相等的矩形时,这里可以改成对正切值的判定后也可正常判定。
  408.         #这里能够直接对比disX和disY的原因就是:方块是正方形,相邻边的比值都是1。
  409.         if disX > disY#方块与砖块碰撞,最先碰到的砖块的边是砖块的两个纵向边,所以横向变向
  410.           ball_x_change(ball,ifIsPaddle)
  411.         elsif disX < disY#方块与砖块碰撞,最先碰到的砖块的边是砖块的两个横向边,所以纵向变向
  412.           ball_y_change(ball,ifIsPaddle)
  413.         else#直接对角相撞,完全反弹
  414.           ball_x_change(ball,ifIsPaddle)
  415.           ball_y_change(ball,ifIsPaddle)
  416.         end
  417.         #==========================================================
  418.       end
  419.       #==========================================================
  420.     end
  421.     #==========================================================
  422.   end
  423.  
  424.   def self.ball_x_change(ball,ifIsPaddle = false)
  425.     return if ifIsPaddle
  426.     ball.route_x = -(ball.route_x)
  427.   end
  428.  
  429.   def self.ball_y_change(ball,ifIsPaddle = false)
  430.     if ifIsPaddle
  431.       if Input.press?(:RIGHT) && ball.route_x < 0
  432.         @route_x =  rand(ball.move_speed) + 1
  433.       elsif Input.press?(:LEFT) && ball.route_x > 0
  434.         @route_x = -(rand(ball.move_speed) + 1)
  435.       end
  436.     end
  437.     ball.route_y = -(ball.route_y)
  438.   end
  439. end
回复

使用道具 举报

Lv5.捕梦者 (暗夜天使)

只有笨蛋才会看到

梦石
1
星屑
21820
在线时间
9436 小时
注册时间
2012-6-19
帖子
7120

开拓者短篇九导演组冠军

3
发表于 2022-5-16 00:40:18 | 只看该作者
运行起来又不卡,为什么要优化

点评

说来惭愧,我直接试着游戏里跑了一下挺正常的,没看出啥bug……(X  发表于 2022-5-16 01:29
大大应该能看出那反射路线有很多bug吧...我测试时好像会连续打穿几块砖块...  发表于 2022-5-16 01:12
回复

使用道具 举报

Lv5.捕梦者

梦石
16
星屑
12217
在线时间
1428 小时
注册时间
2020-3-21
帖子
366

极短23获奖

4
发表于 2022-5-16 13:12:22 | 只看该作者
本帖最后由 仇九 于 2022-5-16 13:31 编辑

研究了一下方块与砖碰撞的情况,也就是243行那里的脚本。

使用录屏软件录了几次穿透的情况,都是在移动的方块碰到砖块的时发生了穿透。
就是说砖块的角进入了方块里面时会发生穿透。


点评

是的是的, 求教大佬有木有正确的方法能提供一下, 谢谢.  发表于 2022-5-16 16:28
回复

使用道具 举报

Lv5.捕梦者 (管理员)

老黄鸡

梦石
0
星屑
42662
在线时间
7616 小时
注册时间
2009-7-6
帖子
13506

开拓者贵宾

5
发表于 2022-5-16 21:31:19 | 只看该作者
老问题了
第一种比较凑合的办法,当计算下一帧应该抵达的球与砖块重合时,强制把X/Y坐标改为贴到目标砖块与向量方向相反的那一面,然后改变力的方向
这种方向简单效果也凑合

第二种其实就是物理引擎里的射线检测,从球的四个角出发,计算4条射线是否与砖块四个边的线段相交,这个其实初中还是高中就学过,两条线求交点
自己研究一下吧
RGDirect - DirectX驱动的RGSS,点我了解.
RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复

使用道具 举报

Lv4.逐梦者

梦石
0
星屑
11205
在线时间
2068 小时
注册时间
2013-6-10
帖子
1516
6
发表于 2022-5-17 10:57:41 | 只看该作者
哇,你们都好厉害呀。
尤其是仇九,年纪那么小,技术那么高,真令人钦佩。
回复

使用道具 举报

Lv5.捕梦者

梦石
0
星屑
26513
在线时间
5385 小时
注册时间
2016-3-8
帖子
1658
7
 楼主| 发表于 2022-5-17 11:49:11 | 只看该作者
仇九 发表于 2022-5-16 21:52
呜~

写了一个RectangleAndRectangle模块来集成矩形的碰撞检测和球的反弹,然后将球与玩家控制的板子,球与 ...

谢谢大神~
球与砖块的碰撞都变得美好了~

不过现在到球与底板的碰撞变得不正常了...
比如, 球向右下走时, 按方向左键, 球不会削回去左上
另外球好像会穿透底板...
要是能改用回之前的就好像完美了~

点评

啊……错了错了,应该是需要在373行后再加一句ball_y_change(ball,false) if ifIsPaddle,这样就能在球碰到板的左右侧壁时在y方向上也反弹。  发表于 2022-5-17 23:32
唔,要改的话在RectangleAndRectangle模块下的ball_x_change方法中添加东西就行。  发表于 2022-5-17 23:27
回复

使用道具 举报

Lv5.捕梦者 (管理员)

老黄鸡

梦石
0
星屑
42662
在线时间
7616 小时
注册时间
2009-7-6
帖子
13506

开拓者贵宾

8
发表于 2022-5-17 18:02:20 | 只看该作者
做了一点小重构方便自己理解
基本功能看上去是没问题了,细节没考虑,代码也未优化
楼主参考参考就行了

RUBY 代码复制
  1. $imported ||= {}
  2. $imported["AI-BreakoutClone"] = true
  3.  
  4. module BREAKOUT_CLONE
  5.   STAGE = {}
  6.   STAGE[0] = [
  7.   [7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
  8.   [6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
  9.   [3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
  10.   [4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
  11.   [5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
  12.   [6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
  13.   [7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
  14.   ]
  15. end
  16.  
  17. module Cache
  18.   def self.breakout_clone(filename)
  19.     load_bitmap("Graphics/Breakout_Clone/", filename)
  20.   end
  21. end
  22.  
  23. module SceneManager
  24.   class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
  25.   def self.first_scene_class
  26.     if $imported["AI-BreakoutClone"] && !$BTEST
  27.       Graphics.resize_screen(544, 480)
  28.       return Scene_Breakout_Clone
  29.     end
  30.     breakout_clone_first_scene_class
  31.   end
  32. end
  33.  
  34. class Game_Temp
  35.  
  36.   attr_accessor :breakout_clone_start
  37.   attr_accessor :breakout_clone_gameover
  38.  
  39.   alias breakout_clone_initialize initialize
  40.   def initialize
  41.     breakout_clone_initialize
  42.     @breakout_clone_start = false
  43.     @breakout_clone_gameover = false
  44.   end
  45.  
  46.   def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
  47.   def reset_breakout_clone_start; @breakout_clone_start = false; end
  48.   def breakout_clone_start?; @breakout_clone_start == true; end
  49.  
  50.   def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
  51.   def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
  52.   def breakout_clone_gameover?; @breakout_clone_gameover == true; end
  53.  
  54. end
  55.  
  56. class Breakout_Object
  57.  
  58.   include Math
  59.  
  60.   Vector2 = Struct.new(:x, :y) do
  61.     include Math
  62.     def magnitude
  63.       sqrt(x*x+y*y)
  64.     end
  65.     def normalized
  66.       return Vector2.new(0.0,0.0) if y == 0 && x == 0
  67.       a = atan2(y,x)
  68.       Vector2.new(cos(a),sin(a))
  69.     end
  70.     def *(rate)
  71.       Vector2.new(x*rate,y*rate)
  72.     end
  73.   end
  74.  
  75.   Segment = Struct.new(:x1,:y1,:x2,:y2,:vertical,:hoster,:offset)
  76.   Ray = Struct.new(:x1,:y1,:x2,:y2,:hoster,:offset) do
  77.     include Math
  78.     def vector
  79.       Vector2.new(x2-x1,y2-y1)
  80.     end
  81.   end
  82.  
  83.   attr_accessor :name
  84.   attr_accessor :x
  85.   attr_accessor :y
  86.   attr_accessor :width
  87.   attr_accessor :height
  88.   attr_accessor :force
  89.   attr_accessor :bounce
  90.   attr_accessor :mass
  91.  
  92.   def initialize
  93.     init_members_internal
  94.     init_members
  95.   end
  96.  
  97.   def init_members_internal
  98.     @name = ''
  99.     @x = 0.0
  100.     @y = 0.0
  101.     @width = 0.0
  102.     @height = 0.0
  103.     @force = Vector2.new(0.0,0.0)
  104.     @bounce = 1.0
  105.     @mass = 0
  106.     @alive = true
  107.     @static = true
  108.   end
  109.  
  110.   def next_x
  111.     @x + @force.x
  112.   end
  113.  
  114.   def next_y
  115.     @y + @force.y
  116.   end
  117.  
  118.   def x=(v)
  119.     @x = v.to_f
  120.   end
  121.  
  122.   def y=(v)
  123.     @y = v.to_f
  124.   end
  125.  
  126.   def ox
  127.     @x + @width / 2
  128.   end
  129.  
  130.   def oy
  131.     @y + @height / 2
  132.   end
  133.  
  134.   def init_members
  135.     #
  136.   end
  137.  
  138.   def update
  139.     #
  140.   end
  141.  
  142.   def take_damage(source)
  143.     #
  144.   end
  145.  
  146.   def is_alive?
  147.     @alive
  148.   end
  149.  
  150.   def is_static?
  151.     @static
  152.   end
  153.  
  154.   def bitmap
  155.   end
  156.  
  157.   def collide(target, info)
  158.     self.force.x *= -1.0 * target.bounce * self.bounce if info.seg.vertical
  159.     self.force.y *= -1.0 * target.bounce * self.bounce unless info.seg.vertical
  160.   end
  161.  
  162.   def on_collide(source, info)
  163.     #
  164.   end
  165.  
  166.   def push(target, vertical)
  167.     self.force.x = 0.0
  168.     self.force.y = 0.0
  169.     target.force.x += self.force.x * target.bounce * self.bounce if vertical
  170.     target.force.y += self.force.y * target.bounce * self.bounce unless vertical
  171.   end
  172.  
  173.   def get_segments
  174.     result = Array.new(4)
  175.     result[0] = Segment.new(@x,@y+@height,@x,@y,true,self,[0,0])
  176.     result[1] = Segment.new(@x,@y,@x+@width,@y,false,self,[-1,0])
  177.     result[2] = Segment.new(@x+@width,@y,@x+@width,@y+@height,true,self,[0,-1])
  178.     result[3] = Segment.new(@x+@width,@y+@height,@x,@y+@height,false,self,[-1,-1])
  179.     result
  180.   end
  181.  
  182.   def get_raycastor(power)
  183.     af = @force.normalized * power
  184.     result = Array.new(4)
  185.     result[0] = Ray.new(@x,@y,@x+af.x,@y+af.y,self,[0,0])
  186.     result[1] = Ray.new(@x+@width,@y,@x+@width+af.x,@y+af.y,self,[-1,0])
  187.     result[2] = Ray.new(@x,@y+@height,@x+af.x,@y+@height+af.y,self,[0,-1])
  188.     result[3] = Ray.new(@x+@width,@y+@height,@x+@width+af.x,@y+@height+af.y,self,[-1,-1])
  189.     result
  190.   end
  191.  
  192. end
  193.  
  194. class Breakout_World < Breakout_Object
  195.  
  196.   def init_members
  197.     @name = 'world'
  198.     @mass = 10
  199.   end
  200.  
  201. end
  202.  
  203. class Breakout_Paddle < Breakout_Object
  204.  
  205.   def init_members
  206.     @name = 'paddle'
  207.     @static = false
  208.     @mass = 5
  209.   end
  210.  
  211.   def collide(target, vertical)
  212.     self.force.x = 0 if vertical
  213.     self.force.y = 0 unless vertical
  214.   end
  215.  
  216.   def on_collide(source, info)
  217.     if source.name == 'world'
  218.       self.force.x = 0 if info.seg.vertical
  219.       self.force.y = 0 unless info.seg.vertical
  220.     end
  221.   end
  222.  
  223.   def update
  224.     if Input.press?(:LEFT)
  225.       @force.x = -8
  226.     elsif Input.press?(:RIGHT)
  227.       @force.x = 8
  228.     else
  229.       @force.x = 0
  230.     end
  231.     @force.y = 0
  232.   end
  233.  
  234.   def bitmap
  235.     Cache.breakout_clone("paddle")
  236.   end
  237.  
  238. end
  239.  
  240. class Breakout_Ball < Breakout_Object
  241.  
  242.   def init_members
  243.     @name = 'ball'
  244.     @static = false
  245.     @speed = 4
  246.     @force.x = ([-(rand(@speed) + 1), rand(@speed) + 1][rand(2)]).to_f
  247.     @force.y = -(@speed + 1).to_f
  248.     @mass = 1
  249.   end
  250.  
  251.   def on_collide(source, info)
  252.     if source.name == 'paddle'
  253.       dir_force = self.force.magnitude
  254.       a = atan2(self.oy - source.oy,self.ox - source.ox)
  255.       self.force.x = cos(a) * dir_force
  256.       self.force.y = sin(a) * dir_force
  257.     elsif source.name == 'world'
  258.       if self.y > Graphics.height
  259.         die
  260.       else
  261.         collide(source, info)
  262.       end
  263.     else
  264.       collide(source, info)
  265.     end
  266.   end
  267.  
  268.   def die
  269.     p 'game over'
  270.     @static = true
  271.   end
  272.  
  273.   def bitmap
  274.     Cache.breakout_clone("ball")
  275.   end
  276.  
  277. end
  278.  
  279. class Breakout_Brick < Breakout_Object
  280.  
  281.   attr_accessor :life
  282.  
  283.   def init_members
  284.     @name = 'brick'
  285.     @life = 0
  286.     @mass = 5
  287.   end
  288.  
  289.   def take_damage(source)
  290.     if @life > 1
  291.       @life-=1
  292.     else
  293.       @life = 0
  294.       @alive = false
  295.     end
  296.   end
  297.  
  298.   def on_collide(source, info)
  299.     take_damage(source) if source.name == 'ball'
  300.   end
  301.  
  302.   def bitmap
  303.     Cache.breakout_clone("brick")
  304.   end
  305.  
  306. end
  307.  
  308. class Sprite_Breakout_Single < Sprite
  309.  
  310.   def initialize(object)
  311.     super()
  312.     @target = object
  313.     refresh
  314.   end
  315.  
  316.   def refresh
  317.     self.bitmap = @target.bitmap
  318.   end
  319.  
  320.   def update
  321.     return unless is_alive?
  322.     self.x = @target.x.to_i
  323.     self.y = @target.y.to_i
  324.   end
  325.  
  326.   def is_alive?
  327.     @target.is_alive?
  328.   end
  329.  
  330. end
  331.  
  332. class Sprite_Breakout_Block < Sprite_Breakout_Single
  333.  
  334.   def initialize(object)
  335.     super
  336.     @life = @target.life
  337.   end
  338.  
  339.   def update
  340.     super
  341.     return unless is_alive?
  342.     if @life != @target.life
  343.       @life = @target.life
  344.       refresh
  345.     end
  346.   end
  347.  
  348.   def refresh
  349.     super
  350.     sy = (@target.life - 1) * 24
  351.     self.src_rect.set(0, sy, 68, 24)
  352.   end
  353.  
  354. end
  355.  
  356. class Breakout_Manager
  357.  
  358.   include Math
  359.  
  360.   IntersectionInfo = Struct.new(:x,:y,:t,:distance,:ray,:seg)
  361.  
  362.   def initialize(objects)
  363.     @objects = objects
  364.   end
  365.  
  366.   def get_objects_inrect(x01,x02,y01,y02,hoster)
  367.     @objects.find_all do |obj|
  368.       if hoster == obj
  369.         false
  370.       else
  371.         x11,x12,y11,y12 = obj.x,obj.x+obj.width,obj.y,obj.y+obj.height
  372.         zx = (x01 + x02 -x11 - x12).abs
  373.         x  = (x01 - x02).abs + (x11 - x12).abs
  374.         zy = (y01 + y02 - y11 - y12).abs
  375.         y  = (y01 - y02).abs + (y11 - y12).abs
  376.         zx <= x && zy <= y
  377.       end
  378.     end
  379.   end
  380.  
  381.   def intersection(ox,oy,x,y,ray,segment)
  382.     dx = x - ox
  383.     dy = y - oy
  384.     distance = sqrt(dx*dx+dy*dy)
  385.     return IntersectionInfo.new(x,y,0,distance,ray,segment)
  386.   end
  387.  
  388.   def get_intersection(ray,segment)
  389.     ax,ay,bx,by = ray.x1,ray.y1,ray.x2,ray.y2
  390.     cx,cy,dx,dy = segment.x1,segment.y1,segment.x2,segment.y2
  391.     area_abc = (ax - cx) * (by - cy) - (ay - cy) * (bx - cx)
  392.     area_abd = (ax - dx) * (by - dy) - (ay - dy) * (bx - dx)
  393.     return nil if area_abc*area_abd >= 0
  394.     area_cda = (cx - ax) * (dy - ay) - (cy - ay) * (dx - ax)
  395.     area_cdb = area_cda + area_abc - area_abd
  396.     return nil if area_cda*area_cdb >= 0
  397.     t = area_cda / (area_abd-area_abc)
  398.     fdx= t*(bx - ax)
  399.     fdy= t*(by - ay)
  400.     x = ax+fdx
  401.     y = ay+fdy
  402.     distance = sqrt(fdx*fdx+fdy*fdy)
  403.     return IntersectionInfo.new(x,y,t,distance,ray,segment)
  404.   end
  405.  
  406.   def get_collide(obj,targets,power)
  407.     segments = Array.new(targets.size * 4)
  408.     targets.each_with_index do |target,i|
  409.       target.get_segments.each_with_index do |seg,j|
  410.         segments[i*4+j] = seg
  411.       end
  412.     end
  413.     all_point = []
  414.     castor_list = obj.get_raycastor(power)
  415.     castor_list.each do |castor|
  416.       segments.each do |seg|
  417.         info = get_intersection(castor,seg)
  418.         all_point << info if info
  419.       end
  420.     end
  421.     return [nil,0] if all_point.size == 0
  422.     all_point.sort!{|a,b| a.distance - b.distance}
  423.     result = all_point.first
  424.     [result,power - result.distance]
  425.   end
  426.  
  427.   def get_fix_x(speed,seg)
  428.     return 0.0 if speed.x == 0 || !seg.vertical
  429.     speed.x > 0 ? -0.5 : 0.5
  430.   end
  431.  
  432.   def get_fix_y(speed,seg)
  433.     return 0.0 if speed.y == 0 || seg.vertical
  434.     speed.y > 0 ? -0.5 : 0.5
  435.   end
  436.  
  437.   def update
  438.     @objects = @objects.find_all do |obj|
  439.       obj.update
  440.       unless obj.is_static?
  441.         nx = obj.next_x
  442.         ny = obj.next_y
  443.         xlist = [obj.x,obj.x+obj.width,nx,nx+obj.width]
  444.         ylist = [obj.y,obj.y+obj.height,ny,ny+obj.height]
  445.         targets = get_objects_inrect(xlist.min,xlist.max,ylist.min,ylist.max,obj)
  446.         power = obj.force.magnitude
  447.         base_power = power
  448.         count = 0
  449.         while(power > 0)
  450.           collide_info = get_collide(obj,targets,power)
  451.           if collide_info[0]
  452.             info = collide_info[0]
  453.             seg = info.seg
  454.             ray = info.ray
  455.             speed = ray.vector
  456.             obj.x = info.x + ray.offset[0]*obj.width + get_fix_x(speed,seg)
  457.             obj.y = info.y + ray.offset[1]*obj.height + get_fix_y(speed,seg)
  458.             obj.on_collide(seg.hoster, info)
  459.             seg.hoster.on_collide(obj, info)
  460.           else
  461.             obj.x += obj.force.x * power / base_power
  462.             obj.y += obj.force.y * power / base_power
  463.           end
  464.           count+=1
  465.           power = collide_info[1]
  466.           power = 0 if count > 2
  467.         end
  468.       end
  469.       obj.is_alive?
  470.     end
  471.   end
  472.  
  473. end
  474.  
  475. class Scene_Breakout_Clone < Scene_Base
  476.  
  477.   include BREAKOUT_CLONE
  478.  
  479.   def start
  480.     super
  481.     init_members
  482.     create_breakout_clone_paddle
  483.     create_breakout_clone_ball
  484.     create_breakout_clone_brick
  485.     create_breakout_clone_worldbox
  486.     create_manager
  487.   end
  488.  
  489.   def init_members
  490.     @objects = []
  491.     @sprites = []
  492.     @cache_bitmaps = {
  493.     'paddle'=>Cache.breakout_clone("paddle"),
  494.     'ball'=>Cache.breakout_clone("ball"),
  495.     'brick'=>Cache.breakout_clone("brick")
  496.     }
  497.   end
  498.  
  499.   def create_breakout_clone_paddle
  500.     bitmap = @cache_bitmaps['paddle']
  501.     @paddle = Breakout_Paddle.new
  502.     @paddle.width = bitmap.width
  503.     @paddle.height = bitmap.height
  504.     @paddle.x = Graphics.width / 2 - @paddle.width / 2
  505.     @paddle.y = Graphics.height - @paddle.height
  506.     @objects << @paddle
  507.     @sprites << Sprite_Breakout_Single.new(@paddle)
  508.   end
  509.  
  510.   def create_breakout_clone_ball
  511.     bitmap = @cache_bitmaps['ball']
  512.     ball = Breakout_Ball.new
  513.     $tests = ball
  514.     ball.width = bitmap.width
  515.     ball.height = bitmap.height
  516.     ball.x = Graphics.width / 2 - ball.width / 2
  517.     ball.y = @paddle.y - (@paddle.height + ball.height) / 2
  518.     @objects << ball
  519.     @sprites << Sprite_Breakout_Single.new(ball)
  520.   end
  521.  
  522.   def create_breakout_clone_brick
  523.     STAGE[0].each do |brick|
  524.       brick_obj = Breakout_Brick.new
  525.       brick_obj.width = 68
  526.       brick_obj.height = 24
  527.       brick_obj.life = brick[0]
  528.       brick_obj.x = brick[1]
  529.       brick_obj.y = brick[2]
  530.       @objects << brick_obj
  531.       @sprites << Sprite_Breakout_Block.new(brick_obj)
  532.     end
  533.   end
  534.  
  535.   def create_breakout_clone_worldbox
  536.     worldbox = Breakout_World.new
  537.     worldbox.width = Graphics.width
  538.     worldbox.height = Graphics.height + 32
  539.     @objects << worldbox
  540.   end
  541.  
  542.   def create_manager
  543.     @manager = Breakout_Manager.new(@objects)
  544.   end
  545.  
  546.   def terminate
  547.     super
  548.     dispose_all
  549.   end
  550.  
  551.   def dispose_all
  552.     @sprites.each{|spr| spr.dispose}
  553.   end
  554.  
  555.   def update
  556.     super
  557.     @manager.update
  558.     @sprites = @sprites.find_all do |spr|
  559.       spr.update
  560.       ret = spr.is_alive?
  561.       spr.dispose unless ret
  562.       ret
  563.     end
  564.   end
  565.  
  566. end
RGDirect - DirectX驱动的RGSS,点我了解.
RM全系列成套系统定制请联系QQ1213237796
不接受对其他插件维护的委托
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2024-12-23 02:40

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表