Project1
标题: 求改良打砖块的反弹方法 [打印本页]
作者: alexncf125 时间: 2022-5-15 23:13
标题: 求改良打砖块的反弹方法
本帖最后由 alexncf125 于 2022-5-16 12:08 编辑
有大神可以帮忙看看171行跟243行的算法该怎样地改良才能正常么
三张图片放置于Graphics/Breakout_Clone之內
$imported ||= {}
$imported["AI-BreakoutClone"] = true
module BREAKOUT_CLONE
STAGE = {}
STAGE[0] = [
[7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
[6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
[3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
[4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
[5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
[6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
[7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
]
end
module Cache
def self.breakout_clone(filename)
load_bitmap("Graphics/Breakout_Clone/", filename)
end
end
module SceneManager
class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
def self.first_scene_class
if $imported["AI-BreakoutClone"] && !$BTEST
Graphics.resize_screen(544, 480)
return Scene_Breakout_Clone
end
breakout_clone_first_scene_class
end
end
class Game_Temp
attr_accessor :breakout_clone_start
attr_accessor :breakout_clone_gameover
alias breakout_clone_initialize initialize
def initialize
breakout_clone_initialize
@breakout_clone_start = false
@breakout_clone_gameover = false
end
def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
def reset_breakout_clone_start; @breakout_clone_start = false; end
def breakout_clone_start?; @breakout_clone_start == true; end
def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
def breakout_clone_gameover?; @breakout_clone_gameover == true; end
end
class Sprite_Breakout_Clone_Paddle < Sprite
def initialize
super
init_members
create_bitmap
end
def init_members
@slide_speed = 8
end
def create_bitmap
self.bitmap = Cache.breakout_clone("paddle")
self.x = (Graphics.width - paddle_width) / 2
self.y = Graphics.height - paddle_height
end
def slide_speed; @slide_speed; end
def paddle_width; self.bitmap.width; end
def paddle_height; self.bitmap.height; end
def paddle_x; self.x + paddle_width; end
def paddle_y; self.y + paddle_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
end
def update_position
slide_left if Input.press?(:LEFT)
slide_right if Input.press?(:RIGHT)
end
def slide_left
result = self.x - slide_speed
return self.x = 0 if result <= 0
self.x -= slide_speed
end
def slide_right
result = self.x + slide_speed
block = Graphics.width - paddle_width
return self.x = block if result >= block
self.x += slide_speed
end
end
class Sprite_Breakout_Clone_Ball < Sprite
attr_accessor :route_x
attr_accessor :route_y
attr_accessor :ball_last_touch
def initialize(viewport, paddle = nil)
super(viewport)
@paddle = paddle
init_members
create_bitmap
end
def init_members
@move_speed = 4
@route_x = [-(rand(@move_speed) + 1), rand(@move_speed) + 1][rand(2)]
@route_y = -(@move_speed + 1)
@ball_last_touch = :paddle
end
def create_bitmap
self.bitmap = Cache.breakout_clone("ball")
self.x = (Graphics.width - ball_width) / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
end
def move_speed; @move_speed; end
def route_x; @route_x; end
def route_y; @route_y; end
def ball_width; self.bitmap.width; end
def ball_height; self.bitmap.height; end
def ball_x; self.x + ball_width; end
def ball_y; self.y + ball_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
update_ball_touch
end
def update_position
if $game_temp.breakout_clone_start?
self.x = (@paddle.x + @paddle.bitmap.width) / 2 - ball_width / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
else
self.x += route_x
self.y += route_y
end
end
def update_ball_touch
return if $game_temp.breakout_clone_gameover?
update_touch_paddle
update_touch_wall
end
def update_touch_paddle
return if @ball_last_touch == :paddle
if ball_x.between?(@paddle.x, @paddle.x + @paddle.bitmap.width + ball_width) && ball_y.between?(@paddle.y, @paddle.y + @paddle.bitmap.height)
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)
if Input.press?(:RIGHT) && route_x < 0
@route_x = rand(move_speed) + 1
elsif Input.press?(:LEFT) && route_x > 0
@route_x = -(rand(move_speed) + 1)
else
@route_x = -(route_x)
end
else
@route_x = rand(move_speed) + 1 if Input.press?(:RIGHT)
@route_x = -(rand(move_speed) + 1) if Input.press?(:LEFT)
end
@route_y = -(move_speed) unless self.y > @paddle.y
@ball_last_touch = :paddle
end
end
def update_touch_wall
if self.x <= 0 || ball_x >= Graphics.width
@route_x = -(route_x)
@ball_last_touch = :wall
end
if self.y <= 0
@route_y = -(route_y)
@ball_last_touch = :wall
end
end
end
class Sprite_Breakout_Clone_Brick < Sprite
def initialize(viewport, balls = nil, brick = nil)
super(viewport)
@ball = balls
@brick = brick
init_members
create_bitmap
end
def init_members
@brick_life = @brick[0]
end
def create_bitmap
self.bitmap = Cache.breakout_clone("brick")
self.x = @brick[1]
self.y = @brick[2]
end
def dispose
self.bitmap.dispose
super
end
def update
super
update_src_rect
update_brick_touch
update_brick_visible
end
def update_src_rect
return if @brick_life.zero?
index = @brick_life
sy = (index - 1) * 24
self.src_rect.set(0, sy, 68, 24)
end
def update_brick_touch
return if self.visible == false
@ball.each do |b|
return if b.ball_last_touch == self
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)
if (b.x).between?(self.x - b.bitmap.width + 1, self.x + self.bitmap.width - 1)
b.route_y = -(b.route_y)
end
if (b.y).between?(self.y - b.bitmap.height + 1, self.y + self.bitmap.height / 7 - 1)
b.route_x = -(b.route_x)
end
@brick_life -= 1 if @brick_life > 0
b.ball_last_touch = self
end
end
end
def update_brick_visible
self.visible = !@brick_life.zero?
end
end
class Scene_Breakout_Clone < Scene_Base
include BREAKOUT_CLONE
def start
super
create_breakout_clone_paddle
create_breakout_clone_ball
create_breakout_clone_brick
end
def create_breakout_clone_paddle
@breakout_clone_paddle_sprite = Sprite_Breakout_Clone_Paddle.new
end
def create_breakout_clone_ball
@breakout_clone_ball_sprite ||= []
@breakout_clone_ball_sprite.push(Sprite_Breakout_Clone_Ball.new(@viewport1, @breakout_clone_paddle_sprite))
end
def create_breakout_clone_brick
@breakout_clone_brick_sprite ||= []
STAGE[0].each do |brick|
@breakout_clone_brick_sprite.push(Sprite_Breakout_Clone_Brick.new(@viewport1, @breakout_clone_ball_sprite, brick))
end
end
def terminate
super
dispose_breakout_clone_paddle
dispose_breakout_clone_ball
dispose_breakout_clone_brick
end
def dispose_breakout_clone_paddle
@breakout_clone_paddle_sprite.bitmap.dispose
@breakout_clone_paddle_sprite.dispose
end
def dispose_breakout_clone_ball
@breakout_clone_ball_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def dispose_breakout_clone_brick
@breakout_clone_brick_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def update
super
@breakout_clone_paddle_sprite.update
@breakout_clone_ball_sprite.each {|sprite| sprite.update}
@breakout_clone_brick_sprite.each {|sprite| sprite.update}
end
end
$imported ||= {}
$imported["AI-BreakoutClone"] = true
module BREAKOUT_CLONE
STAGE = {}
STAGE[0] = [
[7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
[6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
[3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
[4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
[5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
[6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
[7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
]
end
module Cache
def self.breakout_clone(filename)
load_bitmap("Graphics/Breakout_Clone/", filename)
end
end
module SceneManager
class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
def self.first_scene_class
if $imported["AI-BreakoutClone"] && !$BTEST
Graphics.resize_screen(544, 480)
return Scene_Breakout_Clone
end
breakout_clone_first_scene_class
end
end
class Game_Temp
attr_accessor :breakout_clone_start
attr_accessor :breakout_clone_gameover
alias breakout_clone_initialize initialize
def initialize
breakout_clone_initialize
@breakout_clone_start = false
@breakout_clone_gameover = false
end
def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
def reset_breakout_clone_start; @breakout_clone_start = false; end
def breakout_clone_start?; @breakout_clone_start == true; end
def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
def breakout_clone_gameover?; @breakout_clone_gameover == true; end
end
class Sprite_Breakout_Clone_Paddle < Sprite
def initialize
super
init_members
create_bitmap
end
def init_members
@slide_speed = 8
end
def create_bitmap
self.bitmap = Cache.breakout_clone("paddle")
self.x = (Graphics.width - paddle_width) / 2
self.y = Graphics.height - paddle_height
end
def slide_speed; @slide_speed; end
def paddle_width; self.bitmap.width; end
def paddle_height; self.bitmap.height; end
def paddle_x; self.x + paddle_width; end
def paddle_y; self.y + paddle_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
end
def update_position
slide_left if Input.press?(:LEFT)
slide_right if Input.press?(:RIGHT)
end
def slide_left
result = self.x - slide_speed
return self.x = 0 if result <= 0
self.x -= slide_speed
end
def slide_right
result = self.x + slide_speed
block = Graphics.width - paddle_width
return self.x = block if result >= block
self.x += slide_speed
end
end
class Sprite_Breakout_Clone_Ball < Sprite
attr_accessor :route_x
attr_accessor :route_y
attr_accessor :ball_last_touch
def initialize(viewport, paddle = nil)
super(viewport)
@paddle = paddle
init_members
create_bitmap
end
def init_members
@move_speed = 4
@route_x = [-(rand(@move_speed) + 1), rand(@move_speed) + 1][rand(2)]
@route_y = -(@move_speed + 1)
@ball_last_touch = :paddle
end
def create_bitmap
self.bitmap = Cache.breakout_clone("ball")
self.x = (Graphics.width - ball_width) / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
end
def move_speed; @move_speed; end
def route_x; @route_x; end
def route_y; @route_y; end
def ball_width; self.bitmap.width; end
def ball_height; self.bitmap.height; end
def ball_x; self.x + ball_width; end
def ball_y; self.y + ball_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
update_ball_touch
end
def update_position
if $game_temp.breakout_clone_start?
self.x = (@paddle.x + @paddle.bitmap.width) / 2 - ball_width / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
else
self.x += route_x
self.y += route_y
end
end
def update_ball_touch
return if $game_temp.breakout_clone_gameover?
update_touch_paddle
update_touch_wall
end
def update_touch_paddle
return if @ball_last_touch == :paddle
if ball_x.between?(@paddle.x, @paddle.x + @paddle.bitmap.width + ball_width) && ball_y.between?(@paddle.y, @paddle.y + @paddle.bitmap.height)
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)
if Input.press?(:RIGHT) && route_x < 0
@route_x = rand(move_speed) + 1
elsif Input.press?(:LEFT) && route_x > 0
@route_x = -(rand(move_speed) + 1)
else
@route_x = -(route_x)
end
else
@route_x = rand(move_speed) + 1 if Input.press?(:RIGHT)
@route_x = -(rand(move_speed) + 1) if Input.press?(:LEFT)
end
@route_y = -(move_speed) unless self.y > @paddle.y
@ball_last_touch = :paddle
end
end
def update_touch_wall
if self.x <= 0 || ball_x >= Graphics.width
@route_x = -(route_x)
@ball_last_touch = :wall
end
if self.y <= 0
@route_y = -(route_y)
@ball_last_touch = :wall
end
end
end
class Sprite_Breakout_Clone_Brick < Sprite
def initialize(viewport, balls = nil, brick = nil)
super(viewport)
@ball = balls
@brick = brick
init_members
create_bitmap
end
def init_members
@brick_life = @brick[0]
end
def create_bitmap
self.bitmap = Cache.breakout_clone("brick")
self.x = @brick[1]
self.y = @brick[2]
end
def dispose
self.bitmap.dispose
super
end
def update
super
update_src_rect
update_brick_touch
update_brick_visible
end
def update_src_rect
return if @brick_life.zero?
index = @brick_life
sy = (index - 1) * 24
self.src_rect.set(0, sy, 68, 24)
end
def update_brick_touch
return if self.visible == false
@ball.each do |b|
return if b.ball_last_touch == self
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)
if (b.x).between?(self.x - b.bitmap.width + 1, self.x + self.bitmap.width - 1)
b.route_y = -(b.route_y)
end
if (b.y).between?(self.y - b.bitmap.height + 1, self.y + self.bitmap.height / 7 - 1)
b.route_x = -(b.route_x)
end
@brick_life -= 1 if @brick_life > 0
b.ball_last_touch = self
end
end
end
def update_brick_visible
self.visible = !@brick_life.zero?
end
end
class Scene_Breakout_Clone < Scene_Base
include BREAKOUT_CLONE
def start
super
create_breakout_clone_paddle
create_breakout_clone_ball
create_breakout_clone_brick
end
def create_breakout_clone_paddle
@breakout_clone_paddle_sprite = Sprite_Breakout_Clone_Paddle.new
end
def create_breakout_clone_ball
@breakout_clone_ball_sprite ||= []
@breakout_clone_ball_sprite.push(Sprite_Breakout_Clone_Ball.new(@viewport1, @breakout_clone_paddle_sprite))
end
def create_breakout_clone_brick
@breakout_clone_brick_sprite ||= []
STAGE[0].each do |brick|
@breakout_clone_brick_sprite.push(Sprite_Breakout_Clone_Brick.new(@viewport1, @breakout_clone_ball_sprite, brick))
end
end
def terminate
super
dispose_breakout_clone_paddle
dispose_breakout_clone_ball
dispose_breakout_clone_brick
end
def dispose_breakout_clone_paddle
@breakout_clone_paddle_sprite.bitmap.dispose
@breakout_clone_paddle_sprite.dispose
end
def dispose_breakout_clone_ball
@breakout_clone_ball_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def dispose_breakout_clone_brick
@breakout_clone_brick_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def update
super
@breakout_clone_paddle_sprite.update
@breakout_clone_ball_sprite.each {|sprite| sprite.update}
@breakout_clone_brick_sprite.each {|sprite| sprite.update}
end
end
作者: 仇九 时间: 2022-5-15 23:13
呜~
写了一个RectangleAndRectangle模块来集成矩形的碰撞检测和球的反弹,然后将球与玩家控制的板子,球与砖块的碰撞都集成到了里面。
给精灵对象都加了一个bitmap_width和bitmap_height属性,方便判断,因为砖块的高得除7而移动的球不用会比较麻烦……
让显示球的那个精灵有更多的属性可被外部访问。
其他的都没有改,我想还可以将四周的wall也都设置为一个空的精灵,使用RectangleAndRectangle给的接口来判断应该更好,因为我发现球与最上面的固定墙碰撞时会抽搐~
然后因为球是移动的,所以在球的update里去判断与静态的砖块碰撞会更好一些?
应该……问题大幅减小了,但可能还有。
有时会出现:球看起来会穿透,或者砖块被快速消除这两个问题,这不是bug,只是因为球移速相对较大所以看不清,我用录屏软件录下后一下一下看来着……
$imported ||= {}
$imported["AI-BreakoutClone"] = true
module BREAKOUT_CLONE
STAGE = {}
STAGE[0] = [
[7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
[6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
[3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
[4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
[5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
[6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
[7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
]
end
module Cache
def self.breakout_clone(filename)
load_bitmap("Graphics/Breakout_Clone/", filename)
end
end
module SceneManager
class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
def self.first_scene_class
if $imported["AI-BreakoutClone"] && !$BTEST
Graphics.resize_screen(544, 480)
return Scene_Breakout_Clone
end
breakout_clone_first_scene_class
end
end
class Game_Temp
attr_accessor :breakout_clone_start
attr_accessor :breakout_clone_gameover
alias breakout_clone_initialize initialize
def initialize
breakout_clone_initialize
@breakout_clone_start = false
@breakout_clone_gameover = false
end
def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
def reset_breakout_clone_start; @breakout_clone_start = false; end
def breakout_clone_start?; @breakout_clone_start == true; end
def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
def breakout_clone_gameover?; @breakout_clone_gameover == true; end
end
class Sprite_Breakout_Clone_Paddle < Sprite
attr_accessor :bitmap_width
attr_accessor :bitmap_height
def initialize
super
init_members
create_bitmap
end
def init_members
@slide_speed = 8
end
def create_bitmap
self.bitmap = Cache.breakout_clone("paddle")
self.x = (Graphics.width - paddle_width) / 2
self.y = Graphics.height - paddle_height
@bitmap_width = self.bitmap.width
@bitmap_height = self.bitmap.height
end
def slide_speed; @slide_speed; end
def paddle_width; self.bitmap.width; end
def paddle_height; self.bitmap.height; end
def paddle_x; self.x + paddle_width; end
def paddle_y; self.y + paddle_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
end
def update_position
slide_left if Input.press?(:LEFT)
slide_right if Input.press?(:RIGHT)
end
def slide_left
result = self.x - slide_speed
return self.x = 0 if result <= 0
self.x -= slide_speed
end
def slide_right
result = self.x + slide_speed
block = Graphics.width - paddle_width
return self.x = block if result >= block
self.x += slide_speed
end
end
class Sprite_Breakout_Clone_Ball < Sprite
attr_accessor :route_x
attr_accessor :route_y
attr_accessor :ball_last_touch
attr_accessor :bitmap_width
attr_accessor :bitmap_height
attr_accessor :last_x
attr_accessor :last_y
attr_accessor :move_speed
def initialize(viewport, paddle = nil)
super(viewport)
@paddle = paddle
init_members
create_bitmap
end
def init_members
@move_speed = 4
@route_x = [-(rand(@move_speed) + 1), rand(@move_speed) + 1][rand(2)]
@route_y = -(@move_speed + 1)
@ball_last_touch = :paddle
@last_x = 0
@last_y = 0
end
def create_bitmap
self.bitmap = Cache.breakout_clone("ball")
self.x = (Graphics.width - ball_width) / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
@bitmap_width = self.bitmap.width
@bitmap_height = self.bitmap.height
end
def move_speed; @move_speed; end
def route_x; @route_x; end
def route_y; @route_y; end
def ball_width; self.bitmap.width; end
def ball_height; self.bitmap.height; end
def ball_x; self.x + ball_width; end
def ball_y; self.y + ball_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
update_ball_touch
end
def update_position
@last_x = self.x
@last_y = self.y
if $game_temp.breakout_clone_start?
self.x = (@paddle.x + @paddle.bitmap.width) / 2 - ball_width / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
else
self.x += route_x
self.y += route_y
end
end
def update_ball_touch
return if $game_temp.breakout_clone_gameover?
update_touch_paddle
update_touch_wall
end
def update_touch_paddle
return if @ball_last_touch == @paddle
RectangleAndRectangle.judge(self,@paddle,@paddle,false,true)
end
def update_touch_wall
if self.x <= 0 || ball_x >= Graphics.width
@route_x = -(route_x)
@ball_last_touch = :wall
end
if self.y <= 0
@route_y = -(route_y)
@ball_last_touch = :wall
end
end
end
class Sprite_Breakout_Clone_Brick < Sprite
attr_accessor :bitmap_width
attr_accessor :bitmap_height
attr_accessor :brick_life
def initialize(viewport, balls = nil, brick = nil)
super(viewport)
@ball = balls
@brick = brick
init_members
create_bitmap
end
def init_members
@brick_life = @brick[0]
end
def create_bitmap
self.bitmap = Cache.breakout_clone("brick")
self.x = @brick[1]
self.y = @brick[2]
@bitmap_width = self.bitmap.width
@bitmap_height = self.bitmap.height/7
end
def dispose
self.bitmap.dispose
super
end
def update
super
update_src_rect
update_brick_touch
update_brick_visible
end
def update_src_rect
return if @brick_life.zero?
index = @brick_life
sy = (index - 1) * 24
self.src_rect.set(0, sy, 68, 24)
end
def update_brick_touch
return if self.visible == false
@ball.each do |b|
return if b.ball_last_touch == self
RectangleAndRectangle.judge(b,self,self,true,false)
end
end
def update_brick_visible
self.visible = !@brick_life.zero?
end
end
class Scene_Breakout_Clone < Scene_Base
include BREAKOUT_CLONE
def start
super
create_breakout_clone_paddle
create_breakout_clone_ball
create_breakout_clone_brick
end
def create_breakout_clone_paddle
@breakout_clone_paddle_sprite = Sprite_Breakout_Clone_Paddle.new
end
def create_breakout_clone_ball
@breakout_clone_ball_sprite ||= []
@breakout_clone_ball_sprite.push(Sprite_Breakout_Clone_Ball.new(@viewport1, @breakout_clone_paddle_sprite))
end
def create_breakout_clone_brick
@breakout_clone_brick_sprite ||= []
STAGE[0].each do |brick|
@breakout_clone_brick_sprite.push(Sprite_Breakout_Clone_Brick.new(@viewport1, @breakout_clone_ball_sprite, brick))
end
end
def terminate
super
dispose_breakout_clone_paddle
dispose_breakout_clone_ball
dispose_breakout_clone_brick
end
def dispose_breakout_clone_paddle
@breakout_clone_paddle_sprite.bitmap.dispose
@breakout_clone_paddle_sprite.dispose
end
def dispose_breakout_clone_ball
@breakout_clone_ball_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def dispose_breakout_clone_brick
@breakout_clone_brick_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def update
super
@breakout_clone_paddle_sprite.update
@breakout_clone_ball_sprite.each {|sprite| sprite.update}
@breakout_clone_brick_sprite.each {|sprite| sprite.update}
end
end
#有时方块在两个砖块中间反弹时会快速消除两个砖块,这不是bug,只是速度较快所以肉眼看不清。
#我是想找一个只需简单的加减乘除判断,不需向量的算法,但是不用向量真的好乱……
#即使有更好的算法,也可以在这里面直接修改,不用再去上面改,方便一些。
#其实只要解决一个问题算法就会简单明了许多:找到判断两个线段是否相交的简单办法
#但这个问题不那么复杂的办法需要用到向量和代数几何知识,这应该也是各个碰撞检测算法的核心逻辑。
#写了这么多说明,删掉说明后其实也不多(?)
#我之前将一个js的SAT碰撞检测算法移植到rgss3a里来做我的弹幕插件,等我完善后也可以拿出来做这个。
module RectangleAndRectangle
def self.judge(ball,box,sign,ifHaveLife = false,ifIsPaddle = false)
#==========================================================
#ball: 方块对象
#box: 定碰撞的目标砖块/玩家控制的板
#sign: 记录为ball.ball_last_touch的标志
#ifHaveLife: 是否有生命且需要扣除
#ifIsPaddle: 是否是玩家控制的板子,若是板子则在方块的route_y发生变化时,route_x也发生变动。
#==========================================================
#方块:移动的那个东西,一般应该是个球而不是正方形啊……如果要做成圆的话那最好还是设计一个简易的向量对象,
# 用更正式的数学公式去判定更好。可以学一个碰撞检测算法(例如:分离轴定理)。那样计算量会大一些且需要基础的高数知识。
#砖块:判定碰撞的目标砖块/玩家控制的板
#方法说明:这个方法就是判定方块和砖块四个点(四条边)的关系,从而找到反弹的方式。
#具体来说是分成:
# {1}方块的四个点都不在砖块的内部:完全不碰撞,直接退出
# {2}方块的四个点都在砖块的内部:方块完全陷入砖块内,一般不会出现,但是方块速度较大或者玩家控制的平板快速移动时有可能导致这种情况。
# {3}方块有且只有两个点在砖块内部:向这两个点所形成的线的法线方向反弹即可,因为都是不旋转的矩形,所以只有竖向反弹和横向反弹两种情况。
# {4}方块有且只有一个点在砖块内部:再分各种情况
# (不可能同时有三个点在砖块内部)
#==========================================================
#判断方块的四条边(最小x,最大x,最小y,最大y)是否在砖块内
xs = (ball.x).between?(box.x,box.x+box.bitmap_width)
ys = (ball.y).between?(box.y,box.y+box.bitmap_height)
xe = (ball.ball_x).between?(box.x,box.x+box.bitmap_width)
ye = (ball.ball_y).between?(box.y,box.y+box.bitmap_height)
#==========================================================
#横向完全没有重叠范围 或 纵向完全没有重叠范围,只要有一个完全没有重叠范围,则必不可能接触。(上面的{1})
return if (!xs and !xe) or (!ys and !ye)
#==========================================================
#已经碰撞了,所以执行对应的指令
ball.ball_last_touch = sign
sign.brick_life -= 1 if ifHaveLife and sign.brick_life > 0#必定接触了所以扣掉砖块的一点耐久
#==========================================================
if xs and xe and ys and ye#方块的四个角都在砖块内部,(上面的{2})
ball_x_change(ball,ifIsPaddle)
ball_y_change(ball,ifIsPaddle)
ball.ball_last_touch = nil#假如出了bug,将这个设置成nil则可以在下一帧时重新判定以让系统自动修复部分bug
elsif ((!xs or !xe) and (xs or xe) and ys and ye)#有两个角在砖块内且砖块的纵向边切割方块,则只需横向(X轴)变向(上面的{3})
ball_x_change(ball,ifIsPaddle)
elsif ((!ys or !ye) and (ys or ye) and xs and xe)#有两个角在砖块内且砖块的横向边切割方块,则只需纵向(Y轴)变向(上面的{3})
ball_y_change(ball,ifIsPaddle)
else
#==========================================================
#不可能有三个点在里面所以只剩下一个点在里面的情况,(上面的{4})仅仅知道砖块与方块如何重叠是不够的,还必须知道方块是朝哪个
#角度移动的,然后才能判定【最先与哪条边接触】,然后才能找到【具体是怎么样反弹】
#==========================================================
#cx cy: 方块在上一帧时的中心坐标
cx = ball.last_x+ball.ball_width/2
cy = ball.last_y+ball.ball_height/2
#==========================================================
#tx ty: 方块在此时已经进入砖块内部的那个点在上一帧时的坐标
tx = xs ? (ball.last_x) : (ball.last_x+ball.ball_width)
ty = ys ? (ball.last_y) : (ball.last_y+ball.ball_height)
#==========================================================
#nx ny: 既然方块的一个顶点进入了砖块,那么砖块自然也有一个顶点进入了方块,这个就是那个砖块中进入方块内部的那个顶点的坐标
nx = xs ? (box.x+box.bitmap_width) : (box.x)
ny = ys ? (box.y+box.bitmap_height) : (box.y)
#==========================================================
#差值
disX = (cx-nx).abs
disY = (cy-ny).abs
#==========================================================
#这个有点难解释…………其实就是分了(!xs and tx>=nx) (xs and tx<=nx) (!ys and ty>=ny) (ys and ty<=ny)
#这四种情况。以(!xs and tx>=nx)为例:
#!xs就是说方块的左面的边没有与砖块相交,此时若tx大于等于nx,那就说明方块肯定是碰着砖块的上面的那个边与砖块接触的,所以可以直接纵向反弹
if (!xs and tx>=nx) or (xs and tx<=nx)
ball_y_change(ball,ifIsPaddle)
elsif (!ys and ty>=ny) or (ys and ty<=ny)
ball_x_change(ball,ifIsPaddle)
else
#==========================================================
#实际上,若方块的四个点中只有一个点在砖块内,且知道了nx ny的值,那么他们的碰撞情况就和砖块的长和宽没有关系了。
#这里是直接对比了disX和disY的值,实际上若方块不是一个正方形而是一个长宽不相等的矩形时,这里可以改成对正切值的判定后也可正常判定。
#这里能够直接对比disX和disY的原因就是:方块是正方形,相邻边的比值都是1。
if disX > disY#方块与砖块碰撞,最先碰到的砖块的边是砖块的两个纵向边,所以横向变向
ball_x_change(ball,ifIsPaddle)
elsif disX < disY#方块与砖块碰撞,最先碰到的砖块的边是砖块的两个横向边,所以纵向变向
ball_y_change(ball,ifIsPaddle)
else#直接对角相撞,完全反弹
ball_x_change(ball,ifIsPaddle)
ball_y_change(ball,ifIsPaddle)
end
#==========================================================
end
#==========================================================
end
#==========================================================
end
def self.ball_x_change(ball,ifIsPaddle = false)
return if ifIsPaddle
ball.route_x = -(ball.route_x)
end
def self.ball_y_change(ball,ifIsPaddle = false)
if ifIsPaddle
if Input.press?(:RIGHT) && ball.route_x < 0
@route_x = rand(ball.move_speed) + 1
elsif Input.press?(:LEFT) && ball.route_x > 0
@route_x = -(rand(ball.move_speed) + 1)
end
end
ball.route_y = -(ball.route_y)
end
end
$imported ||= {}
$imported["AI-BreakoutClone"] = true
module BREAKOUT_CLONE
STAGE = {}
STAGE[0] = [
[7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
[6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
[3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
[4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
[5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
[6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
[7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
]
end
module Cache
def self.breakout_clone(filename)
load_bitmap("Graphics/Breakout_Clone/", filename)
end
end
module SceneManager
class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
def self.first_scene_class
if $imported["AI-BreakoutClone"] && !$BTEST
Graphics.resize_screen(544, 480)
return Scene_Breakout_Clone
end
breakout_clone_first_scene_class
end
end
class Game_Temp
attr_accessor :breakout_clone_start
attr_accessor :breakout_clone_gameover
alias breakout_clone_initialize initialize
def initialize
breakout_clone_initialize
@breakout_clone_start = false
@breakout_clone_gameover = false
end
def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
def reset_breakout_clone_start; @breakout_clone_start = false; end
def breakout_clone_start?; @breakout_clone_start == true; end
def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
def breakout_clone_gameover?; @breakout_clone_gameover == true; end
end
class Sprite_Breakout_Clone_Paddle < Sprite
attr_accessor :bitmap_width
attr_accessor :bitmap_height
def initialize
super
init_members
create_bitmap
end
def init_members
@slide_speed = 8
end
def create_bitmap
self.bitmap = Cache.breakout_clone("paddle")
self.x = (Graphics.width - paddle_width) / 2
self.y = Graphics.height - paddle_height
@bitmap_width = self.bitmap.width
@bitmap_height = self.bitmap.height
end
def slide_speed; @slide_speed; end
def paddle_width; self.bitmap.width; end
def paddle_height; self.bitmap.height; end
def paddle_x; self.x + paddle_width; end
def paddle_y; self.y + paddle_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
end
def update_position
slide_left if Input.press?(:LEFT)
slide_right if Input.press?(:RIGHT)
end
def slide_left
result = self.x - slide_speed
return self.x = 0 if result <= 0
self.x -= slide_speed
end
def slide_right
result = self.x + slide_speed
block = Graphics.width - paddle_width
return self.x = block if result >= block
self.x += slide_speed
end
end
class Sprite_Breakout_Clone_Ball < Sprite
attr_accessor :route_x
attr_accessor :route_y
attr_accessor :ball_last_touch
attr_accessor :bitmap_width
attr_accessor :bitmap_height
attr_accessor :last_x
attr_accessor :last_y
attr_accessor :move_speed
def initialize(viewport, paddle = nil)
super(viewport)
@paddle = paddle
init_members
create_bitmap
end
def init_members
@move_speed = 4
@route_x = [-(rand(@move_speed) + 1), rand(@move_speed) + 1][rand(2)]
@route_y = -(@move_speed + 1)
@ball_last_touch = :paddle
@last_x = 0
@last_y = 0
end
def create_bitmap
self.bitmap = Cache.breakout_clone("ball")
self.x = (Graphics.width - ball_width) / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
@bitmap_width = self.bitmap.width
@bitmap_height = self.bitmap.height
end
def move_speed; @move_speed; end
def route_x; @route_x; end
def route_y; @route_y; end
def ball_width; self.bitmap.width; end
def ball_height; self.bitmap.height; end
def ball_x; self.x + ball_width; end
def ball_y; self.y + ball_height; end
def dispose
self.bitmap.dispose
super
end
def update
super
update_position
update_ball_touch
end
def update_position
@last_x = self.x
@last_y = self.y
if $game_temp.breakout_clone_start?
self.x = (@paddle.x + @paddle.bitmap.width) / 2 - ball_width / 2
self.y = Graphics.height - @paddle.bitmap.height - ball_height
else
self.x += route_x
self.y += route_y
end
end
def update_ball_touch
return if $game_temp.breakout_clone_gameover?
update_touch_paddle
update_touch_wall
end
def update_touch_paddle
return if @ball_last_touch == @paddle
RectangleAndRectangle.judge(self,@paddle,@paddle,false,true)
end
def update_touch_wall
if self.x <= 0 || ball_x >= Graphics.width
@route_x = -(route_x)
@ball_last_touch = :wall
end
if self.y <= 0
@route_y = -(route_y)
@ball_last_touch = :wall
end
end
end
class Sprite_Breakout_Clone_Brick < Sprite
attr_accessor :bitmap_width
attr_accessor :bitmap_height
attr_accessor :brick_life
def initialize(viewport, balls = nil, brick = nil)
super(viewport)
@ball = balls
@brick = brick
init_members
create_bitmap
end
def init_members
@brick_life = @brick[0]
end
def create_bitmap
self.bitmap = Cache.breakout_clone("brick")
self.x = @brick[1]
self.y = @brick[2]
@bitmap_width = self.bitmap.width
@bitmap_height = self.bitmap.height/7
end
def dispose
self.bitmap.dispose
super
end
def update
super
update_src_rect
update_brick_touch
update_brick_visible
end
def update_src_rect
return if @brick_life.zero?
index = @brick_life
sy = (index - 1) * 24
self.src_rect.set(0, sy, 68, 24)
end
def update_brick_touch
return if self.visible == false
@ball.each do |b|
return if b.ball_last_touch == self
RectangleAndRectangle.judge(b,self,self,true,false)
end
end
def update_brick_visible
self.visible = !@brick_life.zero?
end
end
class Scene_Breakout_Clone < Scene_Base
include BREAKOUT_CLONE
def start
super
create_breakout_clone_paddle
create_breakout_clone_ball
create_breakout_clone_brick
end
def create_breakout_clone_paddle
@breakout_clone_paddle_sprite = Sprite_Breakout_Clone_Paddle.new
end
def create_breakout_clone_ball
@breakout_clone_ball_sprite ||= []
@breakout_clone_ball_sprite.push(Sprite_Breakout_Clone_Ball.new(@viewport1, @breakout_clone_paddle_sprite))
end
def create_breakout_clone_brick
@breakout_clone_brick_sprite ||= []
STAGE[0].each do |brick|
@breakout_clone_brick_sprite.push(Sprite_Breakout_Clone_Brick.new(@viewport1, @breakout_clone_ball_sprite, brick))
end
end
def terminate
super
dispose_breakout_clone_paddle
dispose_breakout_clone_ball
dispose_breakout_clone_brick
end
def dispose_breakout_clone_paddle
@breakout_clone_paddle_sprite.bitmap.dispose
@breakout_clone_paddle_sprite.dispose
end
def dispose_breakout_clone_ball
@breakout_clone_ball_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def dispose_breakout_clone_brick
@breakout_clone_brick_sprite.each do |sprite|
sprite.bitmap.dispose
sprite.dispose
end
end
def update
super
@breakout_clone_paddle_sprite.update
@breakout_clone_ball_sprite.each {|sprite| sprite.update}
@breakout_clone_brick_sprite.each {|sprite| sprite.update}
end
end
#有时方块在两个砖块中间反弹时会快速消除两个砖块,这不是bug,只是速度较快所以肉眼看不清。
#我是想找一个只需简单的加减乘除判断,不需向量的算法,但是不用向量真的好乱……
#即使有更好的算法,也可以在这里面直接修改,不用再去上面改,方便一些。
#其实只要解决一个问题算法就会简单明了许多:找到判断两个线段是否相交的简单办法
#但这个问题不那么复杂的办法需要用到向量和代数几何知识,这应该也是各个碰撞检测算法的核心逻辑。
#写了这么多说明,删掉说明后其实也不多(?)
#我之前将一个js的SAT碰撞检测算法移植到rgss3a里来做我的弹幕插件,等我完善后也可以拿出来做这个。
module RectangleAndRectangle
def self.judge(ball,box,sign,ifHaveLife = false,ifIsPaddle = false)
#==========================================================
#ball: 方块对象
#box: 定碰撞的目标砖块/玩家控制的板
#sign: 记录为ball.ball_last_touch的标志
#ifHaveLife: 是否有生命且需要扣除
#ifIsPaddle: 是否是玩家控制的板子,若是板子则在方块的route_y发生变化时,route_x也发生变动。
#==========================================================
#方块:移动的那个东西,一般应该是个球而不是正方形啊……如果要做成圆的话那最好还是设计一个简易的向量对象,
# 用更正式的数学公式去判定更好。可以学一个碰撞检测算法(例如:分离轴定理)。那样计算量会大一些且需要基础的高数知识。
#砖块:判定碰撞的目标砖块/玩家控制的板
#方法说明:这个方法就是判定方块和砖块四个点(四条边)的关系,从而找到反弹的方式。
#具体来说是分成:
# {1}方块的四个点都不在砖块的内部:完全不碰撞,直接退出
# {2}方块的四个点都在砖块的内部:方块完全陷入砖块内,一般不会出现,但是方块速度较大或者玩家控制的平板快速移动时有可能导致这种情况。
# {3}方块有且只有两个点在砖块内部:向这两个点所形成的线的法线方向反弹即可,因为都是不旋转的矩形,所以只有竖向反弹和横向反弹两种情况。
# {4}方块有且只有一个点在砖块内部:再分各种情况
# (不可能同时有三个点在砖块内部)
#==========================================================
#判断方块的四条边(最小x,最大x,最小y,最大y)是否在砖块内
xs = (ball.x).between?(box.x,box.x+box.bitmap_width)
ys = (ball.y).between?(box.y,box.y+box.bitmap_height)
xe = (ball.ball_x).between?(box.x,box.x+box.bitmap_width)
ye = (ball.ball_y).between?(box.y,box.y+box.bitmap_height)
#==========================================================
#横向完全没有重叠范围 或 纵向完全没有重叠范围,只要有一个完全没有重叠范围,则必不可能接触。(上面的{1})
return if (!xs and !xe) or (!ys and !ye)
#==========================================================
#已经碰撞了,所以执行对应的指令
ball.ball_last_touch = sign
sign.brick_life -= 1 if ifHaveLife and sign.brick_life > 0#必定接触了所以扣掉砖块的一点耐久
#==========================================================
if xs and xe and ys and ye#方块的四个角都在砖块内部,(上面的{2})
ball_x_change(ball,ifIsPaddle)
ball_y_change(ball,ifIsPaddle)
ball.ball_last_touch = nil#假如出了bug,将这个设置成nil则可以在下一帧时重新判定以让系统自动修复部分bug
elsif ((!xs or !xe) and (xs or xe) and ys and ye)#有两个角在砖块内且砖块的纵向边切割方块,则只需横向(X轴)变向(上面的{3})
ball_x_change(ball,ifIsPaddle)
elsif ((!ys or !ye) and (ys or ye) and xs and xe)#有两个角在砖块内且砖块的横向边切割方块,则只需纵向(Y轴)变向(上面的{3})
ball_y_change(ball,ifIsPaddle)
else
#==========================================================
#不可能有三个点在里面所以只剩下一个点在里面的情况,(上面的{4})仅仅知道砖块与方块如何重叠是不够的,还必须知道方块是朝哪个
#角度移动的,然后才能判定【最先与哪条边接触】,然后才能找到【具体是怎么样反弹】
#==========================================================
#cx cy: 方块在上一帧时的中心坐标
cx = ball.last_x+ball.ball_width/2
cy = ball.last_y+ball.ball_height/2
#==========================================================
#tx ty: 方块在此时已经进入砖块内部的那个点在上一帧时的坐标
tx = xs ? (ball.last_x) : (ball.last_x+ball.ball_width)
ty = ys ? (ball.last_y) : (ball.last_y+ball.ball_height)
#==========================================================
#nx ny: 既然方块的一个顶点进入了砖块,那么砖块自然也有一个顶点进入了方块,这个就是那个砖块中进入方块内部的那个顶点的坐标
nx = xs ? (box.x+box.bitmap_width) : (box.x)
ny = ys ? (box.y+box.bitmap_height) : (box.y)
#==========================================================
#差值
disX = (cx-nx).abs
disY = (cy-ny).abs
#==========================================================
#这个有点难解释…………其实就是分了(!xs and tx>=nx) (xs and tx<=nx) (!ys and ty>=ny) (ys and ty<=ny)
#这四种情况。以(!xs and tx>=nx)为例:
#!xs就是说方块的左面的边没有与砖块相交,此时若tx大于等于nx,那就说明方块肯定是碰着砖块的上面的那个边与砖块接触的,所以可以直接纵向反弹
if (!xs and tx>=nx) or (xs and tx<=nx)
ball_y_change(ball,ifIsPaddle)
elsif (!ys and ty>=ny) or (ys and ty<=ny)
ball_x_change(ball,ifIsPaddle)
else
#==========================================================
#实际上,若方块的四个点中只有一个点在砖块内,且知道了nx ny的值,那么他们的碰撞情况就和砖块的长和宽没有关系了。
#这里是直接对比了disX和disY的值,实际上若方块不是一个正方形而是一个长宽不相等的矩形时,这里可以改成对正切值的判定后也可正常判定。
#这里能够直接对比disX和disY的原因就是:方块是正方形,相邻边的比值都是1。
if disX > disY#方块与砖块碰撞,最先碰到的砖块的边是砖块的两个纵向边,所以横向变向
ball_x_change(ball,ifIsPaddle)
elsif disX < disY#方块与砖块碰撞,最先碰到的砖块的边是砖块的两个横向边,所以纵向变向
ball_y_change(ball,ifIsPaddle)
else#直接对角相撞,完全反弹
ball_x_change(ball,ifIsPaddle)
ball_y_change(ball,ifIsPaddle)
end
#==========================================================
end
#==========================================================
end
#==========================================================
end
def self.ball_x_change(ball,ifIsPaddle = false)
return if ifIsPaddle
ball.route_x = -(ball.route_x)
end
def self.ball_y_change(ball,ifIsPaddle = false)
if ifIsPaddle
if Input.press?(:RIGHT) && ball.route_x < 0
@route_x = rand(ball.move_speed) + 1
elsif Input.press?(:LEFT) && ball.route_x > 0
@route_x = -(rand(ball.move_speed) + 1)
end
end
ball.route_y = -(ball.route_y)
end
end
作者: 喵呜喵5 时间: 2022-5-16 00:40
运行起来又不卡,为什么要优化
作者: 仇九 时间: 2022-5-16 13:12
本帖最后由 仇九 于 2022-5-16 13:31 编辑
研究了一下方块与砖碰撞的情况,也就是243行那里的脚本。
使用录屏软件录了几次穿透的情况,都是在移动的方块碰到砖块的角时发生了穿透。
就是说砖块的角进入了方块里面时会发生穿透。
作者: fux2 时间: 2022-5-16 21:31
老问题了
第一种比较凑合的办法,当计算下一帧应该抵达的球与砖块重合时,强制把X/Y坐标改为贴到目标砖块与向量方向相反的那一面,然后改变力的方向
这种方向简单效果也凑合
第二种其实就是物理引擎里的射线检测,从球的四个角出发,计算4条射线是否与砖块四个边的线段相交,这个其实初中还是高中就学过,两条线求交点
自己研究一下吧
作者: 小怪兽奇奇侠 时间: 2022-5-17 10:57
哇,你们都好厉害呀。
尤其是仇九,年纪那么小,技术那么高,真令人钦佩。
作者: alexncf125 时间: 2022-5-17 11:49
谢谢大神~
球与砖块的碰撞都变得美好了~
不过现在到球与底板的碰撞变得不正常了...
比如, 球向右下走时, 按方向左键, 球不会削回去左上
另外球好像会穿透底板...
要是能改用回之前的就好像完美了~
作者: fux2 时间: 2022-5-17 18:02
做了一点小重构方便自己理解
基本功能看上去是没问题了,细节没考虑,代码也未优化
楼主参考参考就行了
$imported ||= {}
$imported["AI-BreakoutClone"] = true
module BREAKOUT_CLONE
STAGE = {}
STAGE[0] = [
[7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
[6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
[3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
[4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
[5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
[6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
[7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
]
end
module Cache
def self.breakout_clone(filename)
load_bitmap("Graphics/Breakout_Clone/", filename)
end
end
module SceneManager
class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
def self.first_scene_class
if $imported["AI-BreakoutClone"] && !$BTEST
Graphics.resize_screen(544, 480)
return Scene_Breakout_Clone
end
breakout_clone_first_scene_class
end
end
class Game_Temp
attr_accessor :breakout_clone_start
attr_accessor :breakout_clone_gameover
alias breakout_clone_initialize initialize
def initialize
breakout_clone_initialize
@breakout_clone_start = false
@breakout_clone_gameover = false
end
def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
def reset_breakout_clone_start; @breakout_clone_start = false; end
def breakout_clone_start?; @breakout_clone_start == true; end
def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
def breakout_clone_gameover?; @breakout_clone_gameover == true; end
end
class Breakout_Object
include Math
Vector2 = Struct.new(:x, :y) do
include Math
def magnitude
sqrt(x*x+y*y)
end
def normalized
return Vector2.new(0.0,0.0) if y == 0 && x == 0
a = atan2(y,x)
Vector2.new(cos(a),sin(a))
end
def *(rate)
Vector2.new(x*rate,y*rate)
end
end
Segment = Struct.new(:x1,:y1,:x2,:y2,:vertical,:hoster,:offset)
Ray = Struct.new(:x1,:y1,:x2,:y2,:hoster,:offset) do
include Math
def vector
Vector2.new(x2-x1,y2-y1)
end
end
attr_accessor :name
attr_accessor :x
attr_accessor :y
attr_accessor :width
attr_accessor :height
attr_accessor :force
attr_accessor :bounce
attr_accessor :mass
def initialize
init_members_internal
init_members
end
def init_members_internal
@name = ''
@x = 0.0
@y = 0.0
@width = 0.0
@height = 0.0
@force = Vector2.new(0.0,0.0)
@bounce = 1.0
@mass = 0
@alive = true
@static = true
end
def next_x
@x + @force.x
end
def next_y
@y + @force.y
end
def x=(v)
@x = v.to_f
end
def y=(v)
@y = v.to_f
end
def ox
@x + @width / 2
end
def oy
@y + @height / 2
end
def init_members
#
end
def update
#
end
def take_damage(source)
#
end
def is_alive?
@alive
end
def is_static?
@static
end
def bitmap
end
def collide(target, info)
self.force.x *= -1.0 * target.bounce * self.bounce if info.seg.vertical
self.force.y *= -1.0 * target.bounce * self.bounce unless info.seg.vertical
end
def on_collide(source, info)
#
end
def push(target, vertical)
self.force.x = 0.0
self.force.y = 0.0
target.force.x += self.force.x * target.bounce * self.bounce if vertical
target.force.y += self.force.y * target.bounce * self.bounce unless vertical
end
def get_segments
result = Array.new(4)
result[0] = Segment.new(@x,@y+@height,@x,@y,true,self,[0,0])
result[1] = Segment.new(@x,@y,@x+@width,@y,false,self,[-1,0])
result[2] = Segment.new(@x+@width,@y,@x+@width,@y+@height,true,self,[0,-1])
result[3] = Segment.new(@x+@width,@y+@height,@x,@y+@height,false,self,[-1,-1])
result
end
def get_raycastor(power)
af = @force.normalized * power
result = Array.new(4)
result[0] = Ray.new(@x,@y,@x+af.x,@y+af.y,self,[0,0])
result[1] = Ray.new(@x+@width,@y,@x+@width+af.x,@y+af.y,self,[-1,0])
result[2] = Ray.new(@x,@y+@height,@x+af.x,@y+@height+af.y,self,[0,-1])
result[3] = Ray.new(@x+@width,@y+@height,@x+@width+af.x,@y+@height+af.y,self,[-1,-1])
result
end
end
class Breakout_World < Breakout_Object
def init_members
@name = 'world'
@mass = 10
end
end
class Breakout_Paddle < Breakout_Object
def init_members
@name = 'paddle'
@static = false
@mass = 5
end
def collide(target, vertical)
self.force.x = 0 if vertical
self.force.y = 0 unless vertical
end
def on_collide(source, info)
if source.name == 'world'
self.force.x = 0 if info.seg.vertical
self.force.y = 0 unless info.seg.vertical
end
end
def update
if Input.press?(:LEFT)
@force.x = -8
elsif Input.press?(:RIGHT)
@force.x = 8
else
@force.x = 0
end
@force.y = 0
end
def bitmap
Cache.breakout_clone("paddle")
end
end
class Breakout_Ball < Breakout_Object
def init_members
@name = 'ball'
@static = false
@speed = 4
@force.x = ([-(rand(@speed) + 1), rand(@speed) + 1][rand(2)]).to_f
@force.y = -(@speed + 1).to_f
@mass = 1
end
def on_collide(source, info)
if source.name == 'paddle'
dir_force = self.force.magnitude
a = atan2(self.oy - source.oy,self.ox - source.ox)
self.force.x = cos(a) * dir_force
self.force.y = sin(a) * dir_force
elsif source.name == 'world'
if self.y > Graphics.height
die
else
collide(source, info)
end
else
collide(source, info)
end
end
def die
p 'game over'
@static = true
end
def bitmap
Cache.breakout_clone("ball")
end
end
class Breakout_Brick < Breakout_Object
attr_accessor :life
def init_members
@name = 'brick'
@life = 0
@mass = 5
end
def take_damage(source)
if @life > 1
@life-=1
else
@life = 0
@alive = false
end
end
def on_collide(source, info)
take_damage(source) if source.name == 'ball'
end
def bitmap
Cache.breakout_clone("brick")
end
end
class Sprite_Breakout_Single < Sprite
def initialize(object)
super()
@target = object
refresh
end
def refresh
self.bitmap = @target.bitmap
end
def update
return unless is_alive?
self.x = @target.x.to_i
self.y = @target.y.to_i
end
def is_alive?
@target.is_alive?
end
end
class Sprite_Breakout_Block < Sprite_Breakout_Single
def initialize(object)
super
@life = @target.life
end
def update
super
return unless is_alive?
if @life != @target.life
@life = @target.life
refresh
end
end
def refresh
super
sy = (@target.life - 1) * 24
self.src_rect.set(0, sy, 68, 24)
end
end
class Breakout_Manager
include Math
IntersectionInfo = Struct.new(:x,:y,:t,:distance,:ray,:seg)
def initialize(objects)
@objects = objects
end
def get_objects_inrect(x01,x02,y01,y02,hoster)
@objects.find_all do |obj|
if hoster == obj
false
else
x11,x12,y11,y12 = obj.x,obj.x+obj.width,obj.y,obj.y+obj.height
zx = (x01 + x02 -x11 - x12).abs
x = (x01 - x02).abs + (x11 - x12).abs
zy = (y01 + y02 - y11 - y12).abs
y = (y01 - y02).abs + (y11 - y12).abs
zx <= x && zy <= y
end
end
end
def intersection(ox,oy,x,y,ray,segment)
dx = x - ox
dy = y - oy
distance = sqrt(dx*dx+dy*dy)
return IntersectionInfo.new(x,y,0,distance,ray,segment)
end
def get_intersection(ray,segment)
ax,ay,bx,by = ray.x1,ray.y1,ray.x2,ray.y2
cx,cy,dx,dy = segment.x1,segment.y1,segment.x2,segment.y2
area_abc = (ax - cx) * (by - cy) - (ay - cy) * (bx - cx)
area_abd = (ax - dx) * (by - dy) - (ay - dy) * (bx - dx)
return nil if area_abc*area_abd >= 0
area_cda = (cx - ax) * (dy - ay) - (cy - ay) * (dx - ax)
area_cdb = area_cda + area_abc - area_abd
return nil if area_cda*area_cdb >= 0
t = area_cda / (area_abd-area_abc)
fdx= t*(bx - ax)
fdy= t*(by - ay)
x = ax+fdx
y = ay+fdy
distance = sqrt(fdx*fdx+fdy*fdy)
return IntersectionInfo.new(x,y,t,distance,ray,segment)
end
def get_collide(obj,targets,power)
segments = Array.new(targets.size * 4)
targets.each_with_index do |target,i|
target.get_segments.each_with_index do |seg,j|
segments[i*4+j] = seg
end
end
all_point = []
castor_list = obj.get_raycastor(power)
castor_list.each do |castor|
segments.each do |seg|
info = get_intersection(castor,seg)
all_point << info if info
end
end
return [nil,0] if all_point.size == 0
all_point.sort!{|a,b| a.distance - b.distance}
result = all_point.first
[result,power - result.distance]
end
def get_fix_x(speed,seg)
return 0.0 if speed.x == 0 || !seg.vertical
speed.x > 0 ? -0.5 : 0.5
end
def get_fix_y(speed,seg)
return 0.0 if speed.y == 0 || seg.vertical
speed.y > 0 ? -0.5 : 0.5
end
def update
@objects = @objects.find_all do |obj|
obj.update
unless obj.is_static?
nx = obj.next_x
ny = obj.next_y
xlist = [obj.x,obj.x+obj.width,nx,nx+obj.width]
ylist = [obj.y,obj.y+obj.height,ny,ny+obj.height]
targets = get_objects_inrect(xlist.min,xlist.max,ylist.min,ylist.max,obj)
power = obj.force.magnitude
base_power = power
count = 0
while(power > 0)
collide_info = get_collide(obj,targets,power)
if collide_info[0]
info = collide_info[0]
seg = info.seg
ray = info.ray
speed = ray.vector
obj.x = info.x + ray.offset[0]*obj.width + get_fix_x(speed,seg)
obj.y = info.y + ray.offset[1]*obj.height + get_fix_y(speed,seg)
obj.on_collide(seg.hoster, info)
seg.hoster.on_collide(obj, info)
else
obj.x += obj.force.x * power / base_power
obj.y += obj.force.y * power / base_power
end
count+=1
power = collide_info[1]
power = 0 if count > 2
end
end
obj.is_alive?
end
end
end
class Scene_Breakout_Clone < Scene_Base
include BREAKOUT_CLONE
def start
super
init_members
create_breakout_clone_paddle
create_breakout_clone_ball
create_breakout_clone_brick
create_breakout_clone_worldbox
create_manager
end
def init_members
@objects = []
@sprites = []
@cache_bitmaps = {
'paddle'=>Cache.breakout_clone("paddle"),
'ball'=>Cache.breakout_clone("ball"),
'brick'=>Cache.breakout_clone("brick")
}
end
def create_breakout_clone_paddle
bitmap = @cache_bitmaps['paddle']
@paddle = Breakout_Paddle.new
@paddle.width = bitmap.width
@paddle.height = bitmap.height
@paddle.x = Graphics.width / 2 - @paddle.width / 2
@paddle.y = Graphics.height - @paddle.height
@objects << @paddle
@sprites << Sprite_Breakout_Single.new(@paddle)
end
def create_breakout_clone_ball
bitmap = @cache_bitmaps['ball']
ball = Breakout_Ball.new
$tests = ball
ball.width = bitmap.width
ball.height = bitmap.height
ball.x = Graphics.width / 2 - ball.width / 2
ball.y = @paddle.y - (@paddle.height + ball.height) / 2
@objects << ball
@sprites << Sprite_Breakout_Single.new(ball)
end
def create_breakout_clone_brick
STAGE[0].each do |brick|
brick_obj = Breakout_Brick.new
brick_obj.width = 68
brick_obj.height = 24
brick_obj.life = brick[0]
brick_obj.x = brick[1]
brick_obj.y = brick[2]
@objects << brick_obj
@sprites << Sprite_Breakout_Block.new(brick_obj)
end
end
def create_breakout_clone_worldbox
worldbox = Breakout_World.new
worldbox.width = Graphics.width
worldbox.height = Graphics.height + 32
@objects << worldbox
end
def create_manager
@manager = Breakout_Manager.new(@objects)
end
def terminate
super
dispose_all
end
def dispose_all
@sprites.each{|spr| spr.dispose}
end
def update
super
@manager.update
@sprites = @sprites.find_all do |spr|
spr.update
ret = spr.is_alive?
spr.dispose unless ret
ret
end
end
end
$imported ||= {}
$imported["AI-BreakoutClone"] = true
module BREAKOUT_CLONE
STAGE = {}
STAGE[0] = [
[7, 15, 0], [7, 91, 0], [7, 167, 0], [7, 242, 0], [7, 317, 0], [7, 393, 0], [7, 469, 0],
[6, 15, 40], [6, 91, 40], [6, 167, 40], [6, 242, 40], [6, 317, 40], [6, 393, 40], [6, 469, 40],
[3, 15, 80], [1, 91, 80], [1, 167, 80], [1, 242, 80], [1, 317, 80], [1, 393, 80], [1, 469, 80],
[4, 15, 120], [2, 91, 120], [1, 167, 120], [1, 242, 120], [1, 317, 120], [2, 393, 120], [4, 469, 120],
[5, 15, 160], [3, 91, 160], [1, 167, 160], [1, 242, 160], [1, 317, 160], [3, 393, 160], [5, 469, 160],
[6, 15, 200], [4, 91, 200], [2, 167, 200], [1, 242, 200], [2, 317, 200], [4, 393, 200], [6, 469, 200],
[7, 15, 240], [6, 91, 240], [4, 167, 240], [1, 242, 240], [4, 317, 240], [6, 393, 240], [7, 469, 240]
]
end
module Cache
def self.breakout_clone(filename)
load_bitmap("Graphics/Breakout_Clone/", filename)
end
end
module SceneManager
class << self; alias :breakout_clone_first_scene_class :first_scene_class; end
def self.first_scene_class
if $imported["AI-BreakoutClone"] && !$BTEST
Graphics.resize_screen(544, 480)
return Scene_Breakout_Clone
end
breakout_clone_first_scene_class
end
end
class Game_Temp
attr_accessor :breakout_clone_start
attr_accessor :breakout_clone_gameover
alias breakout_clone_initialize initialize
def initialize
breakout_clone_initialize
@breakout_clone_start = false
@breakout_clone_gameover = false
end
def set_breakout_clone_start(flag); @breakout_clone_start = flag; end
def reset_breakout_clone_start; @breakout_clone_start = false; end
def breakout_clone_start?; @breakout_clone_start == true; end
def set_breakout_clone_gameover(flag); @breakout_clone_gameover = flag; end
def reset_breakout_clone_gameover; @breakout_clone_gameover = false; end
def breakout_clone_gameover?; @breakout_clone_gameover == true; end
end
class Breakout_Object
include Math
Vector2 = Struct.new(:x, :y) do
include Math
def magnitude
sqrt(x*x+y*y)
end
def normalized
return Vector2.new(0.0,0.0) if y == 0 && x == 0
a = atan2(y,x)
Vector2.new(cos(a),sin(a))
end
def *(rate)
Vector2.new(x*rate,y*rate)
end
end
Segment = Struct.new(:x1,:y1,:x2,:y2,:vertical,:hoster,:offset)
Ray = Struct.new(:x1,:y1,:x2,:y2,:hoster,:offset) do
include Math
def vector
Vector2.new(x2-x1,y2-y1)
end
end
attr_accessor :name
attr_accessor :x
attr_accessor :y
attr_accessor :width
attr_accessor :height
attr_accessor :force
attr_accessor :bounce
attr_accessor :mass
def initialize
init_members_internal
init_members
end
def init_members_internal
@name = ''
@x = 0.0
@y = 0.0
@width = 0.0
@height = 0.0
@force = Vector2.new(0.0,0.0)
@bounce = 1.0
@mass = 0
@alive = true
@static = true
end
def next_x
@x + @force.x
end
def next_y
@y + @force.y
end
def x=(v)
@x = v.to_f
end
def y=(v)
@y = v.to_f
end
def ox
@x + @width / 2
end
def oy
@y + @height / 2
end
def init_members
#
end
def update
#
end
def take_damage(source)
#
end
def is_alive?
@alive
end
def is_static?
@static
end
def bitmap
end
def collide(target, info)
self.force.x *= -1.0 * target.bounce * self.bounce if info.seg.vertical
self.force.y *= -1.0 * target.bounce * self.bounce unless info.seg.vertical
end
def on_collide(source, info)
#
end
def push(target, vertical)
self.force.x = 0.0
self.force.y = 0.0
target.force.x += self.force.x * target.bounce * self.bounce if vertical
target.force.y += self.force.y * target.bounce * self.bounce unless vertical
end
def get_segments
result = Array.new(4)
result[0] = Segment.new(@x,@y+@height,@x,@y,true,self,[0,0])
result[1] = Segment.new(@x,@y,@x+@width,@y,false,self,[-1,0])
result[2] = Segment.new(@x+@width,@y,@x+@width,@y+@height,true,self,[0,-1])
result[3] = Segment.new(@x+@width,@y+@height,@x,@y+@height,false,self,[-1,-1])
result
end
def get_raycastor(power)
af = @force.normalized * power
result = Array.new(4)
result[0] = Ray.new(@x,@y,@x+af.x,@y+af.y,self,[0,0])
result[1] = Ray.new(@x+@width,@y,@x+@width+af.x,@y+af.y,self,[-1,0])
result[2] = Ray.new(@x,@y+@height,@x+af.x,@y+@height+af.y,self,[0,-1])
result[3] = Ray.new(@x+@width,@y+@height,@x+@width+af.x,@y+@height+af.y,self,[-1,-1])
result
end
end
class Breakout_World < Breakout_Object
def init_members
@name = 'world'
@mass = 10
end
end
class Breakout_Paddle < Breakout_Object
def init_members
@name = 'paddle'
@static = false
@mass = 5
end
def collide(target, vertical)
self.force.x = 0 if vertical
self.force.y = 0 unless vertical
end
def on_collide(source, info)
if source.name == 'world'
self.force.x = 0 if info.seg.vertical
self.force.y = 0 unless info.seg.vertical
end
end
def update
if Input.press?(:LEFT)
@force.x = -8
elsif Input.press?(:RIGHT)
@force.x = 8
else
@force.x = 0
end
@force.y = 0
end
def bitmap
Cache.breakout_clone("paddle")
end
end
class Breakout_Ball < Breakout_Object
def init_members
@name = 'ball'
@static = false
@speed = 4
@force.x = ([-(rand(@speed) + 1), rand(@speed) + 1][rand(2)]).to_f
@force.y = -(@speed + 1).to_f
@mass = 1
end
def on_collide(source, info)
if source.name == 'paddle'
dir_force = self.force.magnitude
a = atan2(self.oy - source.oy,self.ox - source.ox)
self.force.x = cos(a) * dir_force
self.force.y = sin(a) * dir_force
elsif source.name == 'world'
if self.y > Graphics.height
die
else
collide(source, info)
end
else
collide(source, info)
end
end
def die
p 'game over'
@static = true
end
def bitmap
Cache.breakout_clone("ball")
end
end
class Breakout_Brick < Breakout_Object
attr_accessor :life
def init_members
@name = 'brick'
@life = 0
@mass = 5
end
def take_damage(source)
if @life > 1
@life-=1
else
@life = 0
@alive = false
end
end
def on_collide(source, info)
take_damage(source) if source.name == 'ball'
end
def bitmap
Cache.breakout_clone("brick")
end
end
class Sprite_Breakout_Single < Sprite
def initialize(object)
super()
@target = object
refresh
end
def refresh
self.bitmap = @target.bitmap
end
def update
return unless is_alive?
self.x = @target.x.to_i
self.y = @target.y.to_i
end
def is_alive?
@target.is_alive?
end
end
class Sprite_Breakout_Block < Sprite_Breakout_Single
def initialize(object)
super
@life = @target.life
end
def update
super
return unless is_alive?
if @life != @target.life
@life = @target.life
refresh
end
end
def refresh
super
sy = (@target.life - 1) * 24
self.src_rect.set(0, sy, 68, 24)
end
end
class Breakout_Manager
include Math
IntersectionInfo = Struct.new(:x,:y,:t,:distance,:ray,:seg)
def initialize(objects)
@objects = objects
end
def get_objects_inrect(x01,x02,y01,y02,hoster)
@objects.find_all do |obj|
if hoster == obj
false
else
x11,x12,y11,y12 = obj.x,obj.x+obj.width,obj.y,obj.y+obj.height
zx = (x01 + x02 -x11 - x12).abs
x = (x01 - x02).abs + (x11 - x12).abs
zy = (y01 + y02 - y11 - y12).abs
y = (y01 - y02).abs + (y11 - y12).abs
zx <= x && zy <= y
end
end
end
def intersection(ox,oy,x,y,ray,segment)
dx = x - ox
dy = y - oy
distance = sqrt(dx*dx+dy*dy)
return IntersectionInfo.new(x,y,0,distance,ray,segment)
end
def get_intersection(ray,segment)
ax,ay,bx,by = ray.x1,ray.y1,ray.x2,ray.y2
cx,cy,dx,dy = segment.x1,segment.y1,segment.x2,segment.y2
area_abc = (ax - cx) * (by - cy) - (ay - cy) * (bx - cx)
area_abd = (ax - dx) * (by - dy) - (ay - dy) * (bx - dx)
return nil if area_abc*area_abd >= 0
area_cda = (cx - ax) * (dy - ay) - (cy - ay) * (dx - ax)
area_cdb = area_cda + area_abc - area_abd
return nil if area_cda*area_cdb >= 0
t = area_cda / (area_abd-area_abc)
fdx= t*(bx - ax)
fdy= t*(by - ay)
x = ax+fdx
y = ay+fdy
distance = sqrt(fdx*fdx+fdy*fdy)
return IntersectionInfo.new(x,y,t,distance,ray,segment)
end
def get_collide(obj,targets,power)
segments = Array.new(targets.size * 4)
targets.each_with_index do |target,i|
target.get_segments.each_with_index do |seg,j|
segments[i*4+j] = seg
end
end
all_point = []
castor_list = obj.get_raycastor(power)
castor_list.each do |castor|
segments.each do |seg|
info = get_intersection(castor,seg)
all_point << info if info
end
end
return [nil,0] if all_point.size == 0
all_point.sort!{|a,b| a.distance - b.distance}
result = all_point.first
[result,power - result.distance]
end
def get_fix_x(speed,seg)
return 0.0 if speed.x == 0 || !seg.vertical
speed.x > 0 ? -0.5 : 0.5
end
def get_fix_y(speed,seg)
return 0.0 if speed.y == 0 || seg.vertical
speed.y > 0 ? -0.5 : 0.5
end
def update
@objects = @objects.find_all do |obj|
obj.update
unless obj.is_static?
nx = obj.next_x
ny = obj.next_y
xlist = [obj.x,obj.x+obj.width,nx,nx+obj.width]
ylist = [obj.y,obj.y+obj.height,ny,ny+obj.height]
targets = get_objects_inrect(xlist.min,xlist.max,ylist.min,ylist.max,obj)
power = obj.force.magnitude
base_power = power
count = 0
while(power > 0)
collide_info = get_collide(obj,targets,power)
if collide_info[0]
info = collide_info[0]
seg = info.seg
ray = info.ray
speed = ray.vector
obj.x = info.x + ray.offset[0]*obj.width + get_fix_x(speed,seg)
obj.y = info.y + ray.offset[1]*obj.height + get_fix_y(speed,seg)
obj.on_collide(seg.hoster, info)
seg.hoster.on_collide(obj, info)
else
obj.x += obj.force.x * power / base_power
obj.y += obj.force.y * power / base_power
end
count+=1
power = collide_info[1]
power = 0 if count > 2
end
end
obj.is_alive?
end
end
end
class Scene_Breakout_Clone < Scene_Base
include BREAKOUT_CLONE
def start
super
init_members
create_breakout_clone_paddle
create_breakout_clone_ball
create_breakout_clone_brick
create_breakout_clone_worldbox
create_manager
end
def init_members
@objects = []
@sprites = []
@cache_bitmaps = {
'paddle'=>Cache.breakout_clone("paddle"),
'ball'=>Cache.breakout_clone("ball"),
'brick'=>Cache.breakout_clone("brick")
}
end
def create_breakout_clone_paddle
bitmap = @cache_bitmaps['paddle']
@paddle = Breakout_Paddle.new
@paddle.width = bitmap.width
@paddle.height = bitmap.height
@paddle.x = Graphics.width / 2 - @paddle.width / 2
@paddle.y = Graphics.height - @paddle.height
@objects << @paddle
@sprites << Sprite_Breakout_Single.new(@paddle)
end
def create_breakout_clone_ball
bitmap = @cache_bitmaps['ball']
ball = Breakout_Ball.new
$tests = ball
ball.width = bitmap.width
ball.height = bitmap.height
ball.x = Graphics.width / 2 - ball.width / 2
ball.y = @paddle.y - (@paddle.height + ball.height) / 2
@objects << ball
@sprites << Sprite_Breakout_Single.new(ball)
end
def create_breakout_clone_brick
STAGE[0].each do |brick|
brick_obj = Breakout_Brick.new
brick_obj.width = 68
brick_obj.height = 24
brick_obj.life = brick[0]
brick_obj.x = brick[1]
brick_obj.y = brick[2]
@objects << brick_obj
@sprites << Sprite_Breakout_Block.new(brick_obj)
end
end
def create_breakout_clone_worldbox
worldbox = Breakout_World.new
worldbox.width = Graphics.width
worldbox.height = Graphics.height + 32
@objects << worldbox
end
def create_manager
@manager = Breakout_Manager.new(@objects)
end
def terminate
super
dispose_all
end
def dispose_all
@sprites.each{|spr| spr.dispose}
end
def update
super
@manager.update
@sprites = @sprites.find_all do |spr|
spr.update
ret = spr.is_alive?
spr.dispose unless ret
ret
end
end
end
欢迎光临 Project1 (https://rpg.blue/) |
Powered by Discuz! X3.1 |