我在测试碰撞检测系统时遇到了一个问题。(船、壳、敌人),壳对象在船中初始化(要取船坐标)、在属于Main类的update方法中初始化敌方对象,在Enemy类中进行碰撞测试(获取敌人对象的坐标)。我已经确保shell对象可以通过attr_accessor被其他类访问,但是错误:指向冲突检测方法的undefined method
shell_hit_box' for nil:NilClass'仍然发生:
def penetration?(shell)
shell.shell_hit_box && [[shell.shell_hit_box, shell.shell_hit_box], [shell.shell_hit_box, shell.shell_hit_box],
[shell.shell_hit_box.x3, shell.shell_hit_box], [shell.shell_hit_box, shell.shell_hit_box]].any? do |coordinates|
@box.contains?(coordinates[0], coordinates[1])
puts"Shikkikan, penetration on enemy confirmed!"
end
end
我的假设是shell对象没有从基本初始化点正确地传递到方法中:
def fire_attilery(shell) #this is where the shell is created and pushed into an array to store
x = @sprite.x + (@sprite.width)*0.5 + @x_velocity
y =@sprite.y + (@sprite.height)*0.5 + @y_velocity
shell=Shell.new(x, y, @sprite.rotate)
@magazine << shell
end
给予炮弹动量的方法:
def move
@sprite.x += @x_velocity
@sprite.y += @y_velocity
@magazine.each do |shell| # shell is push out of array and ordered to fly foward
shell.shell_fired
end
正在检测来自主类的更新方法中的冲突
def update #updating player movement and and spawning enemy
@bismark.move
@bismark.deaccelare
@enemy= Enemy.new
@fleet << @enemy
@enemy.moving_slowly
@fleet.each { |enemy| enemy.move }
if @enemy.penetration?(shell) #calling the colision test method in Enemy Class
print "Working"
end
end
那应该是所有的方法都互相有着有机的联系和相关的错误,我希望这一点能够得到解决。
这是完整的代码示例,如果你认为错误不是从我的想法和写:
require 'ruby2d'
######################################################################################
class Ship
attr_accessor :skin, :x , :y, :shell #making the shell object accessible?
def initialize(skin, x, y)
@skin = skin
@x = x
@y = y
@magazine = []
@fire_rate = 0
@remaning_ammo = 7
@x_velocity= 0
@y_velocity = 0
@sprite = Sprite.new(skin,
width: 78,
height: 99,
clip_width: 220,
time: 150,
rotate: 180,
animations: {
floating: 0..1,
open_fire:2..3 ,
}
)
end
def quarter_speed
@sprite.play(animation: :floating, loop:true )
end
def fire
@sprite.play(animation: :open_fire, loop:false)
end
def rotation(angle)
case angle
when :port
@sprite.rotate -=2
when :starboard
@sprite.rotate +=2
end
end
def acceleration(angle)
case angle
when :forwards
@x_velocity+= Math.sin(@sprite.rotate*Math::PI/180)
@y_velocity -= Math.cos(@sprite.rotate*Math::PI/180)
when :backwards
@x_velocity-= Math.sin(@sprite.rotate*Math::PI/180)
@y_velocity += Math.cos(@sprite.rotate*Math::PI/180)
end
end
def deaccelare
@x_velocity*= 0.99
@y_velocity*= 0.99
end
def move
@sprite.x += @x_velocity
@sprite.y += @y_velocity
@magazine.each do |shell| # shell is push out of array and ordered to fly foward
shell.shell_fired
end
end
def fire_attilery(shell) #this is where the shell in created and push into an array to store
if @fire_rate+40 < Window.frames
x = @sprite.x + (@sprite.width)*0.5 + @x_velocity
y =@sprite.y + (@sprite.height)*0.5 + @y_velocity
shell=Shell.new(x, y, @sprite.rotate)
@magazine << shell
@fire_rate = Window.frames
end
end
end
class Shell
attr_reader :shell_hit_box #making the hit box accessible?
def initialize(x, y, rotation)
@shell = Sprite.new('images/pistol_shell.png',
x: x,
y: y,
width:13,
height:20,
rotate: rotation)
@shell_count = 7
@x_velocity= Math.sin(@shell.rotate*Math::PI/180)
@y_velocity = -Math.cos(@shell.rotate*Math::PI/180)
@shell_hit_box = Square.new(x: x, y: y, size: 10, color:[1,1,1,0.001])
end
def shell_fired
@shell.x += @x_velocity*22
@shell.y += @y_velocity*22
@shell_hit_box.x += @x_velocity*22
@shell_hit_box.y += @y_velocity*22
end
end
class Enemy
attr_accessor
def initialize
@x_velocity= 0
@y_velocity =0
@baseship = Sprite.new('images/enemy.png',
x: rand(Window.width),
y:rand(Window.height),
width: 80,
height: 100,
clip_width: 250,
time: 300,
rotate: rand(360),
animations: {
shipenemy: 0..3,})
@x_velocity+= Math.sin(@baseship.rotate*Math::PI/180)
@y_velocity -= Math.cos(@baseship.rotate*Math::PI/180)
@a = @baseship.x + (@baseship.width)*0.5
@b = @baseship.y + (@baseship.height)*0.5
@box = Square.new(x: @a, y: @b, size:30, color:[1, 0, 1, 0.001] )
end
def moving_slowly
@baseship.play(animation: :shipenemy, loop:true )
end
def move
@box.x += @x_velocity
@box.y += @y_velocity
@baseship.x += @x_velocity
@baseship.y += @y_velocity
end
def penetration?(shell) #this is detecting the collision , source of error i think
shell.shell_hit_box && [[shell.shell_hit_box, shell.shell_hit_box], [shell.shell_hit_box, shell.shell_hit_box],
[shell.shell_hit_box.x3, shell.shell_hit_box], [shell.shell_hit_box, shell.shell_hit_box]].any? do |coordinates|
@box.contains?(coordinates[0], coordinates[1])
puts"Sir, penetration on enemy confirmed!"
end
end
end
class Mainscreen
def initialize
@bismark = Ship.new('images/bismark',230, 230)
@bismark.quarter_speed
@fleet = []
end
def ship_turn(angle)
@bismark.rotation(angle)
end
def bismark_acceleration(angle)
@bismark.acceleration(angle)
end
def update #updating player movement and and spawning enemy
@bismark.move
@bismark.deaccelare
@enemy= Enemy.new
@fleet << @enemy
@enemy.moving_slowly
@fleet.each { |enemy| enemy.move }
if @enemy.penetration?(shell) #calling the colision test method in Enemy Class
print "Working"
end
end
def bismark_fire_shell
@bismark.fire_attilery
@bismark.fire
end
end
mainscreen = Mainscreen.new
update do
mainscreen.update
end
################################The code below doesnt matter much, just user input for movement##########################
on :key_held do |event|
case event.key
when 'up'
mainscreen.bismark_acceleration(:forwards)
when 'down'
mainscreen.bismark_acceleration(:backwards)
when 'left'
mainscreen.ship_turn(:port)
when 'right'
mainscreen.ship_turn(:starboard)
end
end
on :key_down do |event|
if event.key == 'f'
mainscreen.bismark_fire_shell
artilery_sound.play
end
end
show
1条答案
按热度按时间thtygnil1#
我甚至不打算调试你的应用程序,但是如果你想知道 shell 是否是
nil
,只要在发生这种情况时引发一个异常。你甚至不能调用#fire_artillary或#penetration?,除非你为 shell 传递了一个参数,但这个参数仍然可以是
nil
。因为有很多地方你需要评估 shell 是否可以respond_to? :shell_hit_box
,理想的情况是,你应该在存储Shell对象集合的地方修复核心问题。例如,除非您可以用不发射的哑弹填充 *@杂志 *,否则最好将示例变量转换为一个方法,以确保弹匣中没有nil
对象。如果您的目标只是调试它,那么您可以使用Ruby的标准调试gem来跟踪您的 shell 变量,并在
shell == nil
出现时中断,或者明智地使用raise
来探索反向跟踪,找出调用者是谁,以及他们为什么调用以nil
作为 shell 参数的方法。