首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >碰撞检测测试中对象的Nil类

碰撞检测测试中对象的Nil类
EN

Stack Overflow用户
提问于 2022-11-26 07:51:47
回答 1查看 39关注 0票数 2

我在测试碰撞检测系统时遇到了一个问题。为了可视化起见,可以将代码的总体结构看作是主类=>Class( ship,shell,敌),在船上初始化shell对象(获取船舶坐标),在属于主类的更新方法中初始化敌人对象,在敌人类(获取敌人对象的坐标)中进行碰撞测试。我已经确保其他类可以通过attr_accessor访问shell对象,但是指向碰撞检测方法的错误:undefined method shell_hit_box‘for nil:NilClass’仍然发生:

代码语言:javascript
复制
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对象没有从基本初始化点正确地传递到方法中:

代码语言:javascript
复制
 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

方法给出壳的动量:

代码语言:javascript
复制
  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

主类更新方法中的碰撞检测

代码语言:javascript
复制
 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

这应该是所有的方法,相互之间有一个有机的关系,并与错误有关,我希望这能得到解决。

这是示例的完整代码,如果您认为错误不是我所想和写的:

代码语言:javascript
复制
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 
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-11-27 04:37:06

我甚至不会尝试调试您的应用程序,但是如果您想知道shell是否为nil,则在发生这种情况时只需引发异常即可。仅举一个用于调试的示例:

代码语言:javascript
复制
def penetration? shell
  raise if shell.nil?
  # ... whatever
end

你甚至不能打电话给#fire_artillery或#渗透?除非您传递shell的参数,但该参数仍然可以是nil。由于有很多地方需要评估shell是否可以respond_to? :shell_hit_box,所以理想情况下,您应该在存储Shell对象集合的地方修复核心问题。例如,除非您可以用不触发的duds填充@杂志,否则最好将实例变量转换为确保杂志中没有nil对象的方法。

如果您的目标仅仅是调试这一点,那么您可以使用Ruby的标准调试gem来跟踪您的shell变量并在任何时候中断shell == nil,或者明智地使用raise来探索回溯跟踪,找出调用者是谁,以及为什么他们用nil作为shell的参数来调用方法。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/74580562

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档