Will
Will

Reputation: 23

undefined method `-' for nil:NilClass (NoMethodError)

I can't work out how to fix it so it takes ten away from the health class variable, as it says that it is an error.

/home/will/Code/Rubygame/objects.rb:61:in `attacked': undefined method `-' for nil:NilClass (NoMethodError)
    from ./main.rb:140:in `update'
    from /var/lib/gems/2.3.0/gems/gosu-0.10.8/lib/gosu/patches.rb:140:in `tick'
    from /var/lib/gems/2.3.0/gems/gosu-0.10.8/lib/gosu/patches.rb:140:in `tick'
    from ./main.rb:197:in `<main>'

Here is the code in main:

def update
    @player.left if Gosu::button_down? Gosu::KbA
    @player.right if Gosu::button_down? Gosu::KbD
    @player.up if Gosu::button_down? Gosu::KbW
    @player.down if Gosu::button_down? Gosu::KbS
    if Gosu::button_down? Gosu::KbK 
        @player.shot if @player_type == "Archer" or @player_type == "Mage"
        if @object.collision(@xshot, @yshot) == true
            x, y, health = YAML.load_file("Storage/info.yml")
            @object.attacked #LINE 140
        end
    end

end

And here is where the @object.attacked leads to:

 def attacked
    puts "attacked"
    @health -= 10 #LINE 61
    @xy.insert(@health)
    File.open("Storage/info.yml", "w") {|f| f.write(@xy.to_yaml) }
    @xy.delete_at(2)
    if @health == 0
        @dead = true
    end
end 

And the yaml file if needed:

   ---
   - 219.0
   - 45.0
   - 100.0

I tried to put .to_i after the @health like this:

   @health.to_i -= 10

But it just brings up another error saying:

   undefined method `to_i=' for nil:NilClass (NoMethodError)

Upvotes: 2

Views: 5299

Answers (2)

Maxim Fedotov
Maxim Fedotov

Reputation: 1357

As mentioned by @omnikron, your @health is uninitialized, hence -= throws an exception when trying to subtract from nil. If we go with initialize method instead, I imagine your object class looking like:

Class Object
  attr_accessor :health

  def initialize
    @health = 100
  end
end

def attacked
  puts "attacked"
  @object.health -= 10 #LINE 61
  @xy.insert(@object.health)
  File.open("Storage/info.yml", "w") {|f| f.write(@xy.to_yaml) }
  @xy.delete_at(2)
  if @health == 0
    @dead = true
  end
end

Upvotes: 2

omnikron
omnikron

Reputation: 2321

The error message is telling you that @health == nil in your attacked method. You need to initialize this value somewhere! Usually this would be in the aptly-named initialize method of your class. Alternatively going on the code that you have provided so far, if when somebody is attacked for the first time you want to set the @health instance variable to a default value you could change it to:

def attacked
  @health ||= 100 # or whatever
  puts "attacked"
  @health -= 10 #LINE 61
  @xy.insert(@health)
  File.open("Storage/info.yml", "w") {|f| f.write(@xy.to_yaml) }
  @xy.delete_at(2)
  if @health == 0
    @dead = true
  end
end 

Note: the ||= syntax is ruby's conditional assignment operator – it means 'set @health to 100 unless @health is already defined.

Upvotes: 2

Related Questions