我在测试碰撞检测系统时遇到了一个问题.为了便于可视化,您可以将代码的整体 struct 想象为Main Class=>;Class(船,shell ,敌人),shell 对象在Ship中初始化(获取Ship坐标),敌人对象在属于Main类的更新方法中初始化,碰撞测试在Enemy类(获取敌人对象的坐标)中进行.
我已经确保其他类可以通过attr_accessor访问shell 对象,但出现以下错误:
指向冲突检测方法的nil:nilClass`的undefined method
Shell_Hit_Box‘仍然出现:
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
这应该是所有的方法,彼此之间有有机的联系,并与错误相关,我希望这能得到解决.
如果您认为错误与我所想和所写的不同,以下是Sample的完整代码:
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