2015-09-27 2 views
1

Я полный новичок в Ruby. Сейчас я работаю над уроком 45 Learn Ruby the Hard Way и создаю игру, подобную Zork и Adventure.Доступ к переменной класса с верхнего уровня

Я создал структуру, в которой я создаю «сцены» в разных файлах и требую, чтобы все сцены были в одном файле, где у меня есть движок/карта, которая гарантирует, что текущая сцена не равна «закончена», X 'сцена' введите 'метод.

Однако у меня есть два вопроса: 1) я получаю ошибку говоря «класс Предупреждение доступ к переменным из верхнего уровня» 2) Несмотря на то, что сценарий выполняется я получаю

ex45.rb:30:in `play': undefined method `enter' for nil:NilClass (NoMethodError) from ex45.rb:59:in 

Ниже все моего кода из каждого файла. Приношу свои извинения, если он долго читается, но я хотел бы знать, почему я получаю эти две ошибки и что могу сделать, чтобы исправить их.

Ex45.rb:

require "./scene_one.rb" 
require "./scene_two.rb" 
require "./scene_three.rb" 

@@action = SceneOne.new 
@@action_two = SceneTwo.new 
@@action_three = SceneThree.new 

class Engine 

    def initialize(scene_map) 
     @scene_map = scene_map 
    end 

    def play()  
     current_scene = @scene_map.opening_scene() 
     last_scene = @scene_map.next_scene('finished') 

     while current_scene != last_scene 
      next_scene_name = current_scene.enter() 
      current_scene = @scene_map.next_scene(next_scene_name) 
     end 

     current_scene.enter() 
    end 
end 


class Map 

    @@scenes = { 
     'scene_one' => @@action, 
     'scene_two' => @@action_two, 
     'scene_three' => @@action_three 
    } 

    def initialize(start_scene) 
     @start_scene = start_scene 
    end 

    def next_scene(scene_name) 
     val = @@scenes[scene_name] 
     return val 
    end 

    def opening_scene() 
     return next_scene(@start_scene) 
    end 
end 

a_map = Map.new('scene_one') 
a_game = Engine.new(a_map) 
a_game.play() 

scene_one.rb:

класс SceneOne

def enter 
    puts "What is 1 + 2?" 
    print "> " 

    answer = $stdin.gets.chomp 

    if answer == "3" 
     puts "Good job" 
     return 'scene_two' 
    else 
     puts "try again" 
     test 
    end 
    end 

end 

scene_two.rb

class SceneTwo 

    def enter 
     puts "1 + 3?" 
     print "> " 

     action = $stdin.gets.chomp 

     if action == "4" 
      return 'scene_three' 
     else 
      puts "CANNOT COMPUTE" 
     end 
    end 

end 

scene_three.rb

class SceneThree 

    def enter 
     puts "This is scene three" 
    end 

end 

Заранее благодарен!

ответ

2

Ответ на ваш первый вопрос:

Вам нужно переместить определения переменных класса внутри Map класса, чтобы избавиться от этих предупреждений:

Ex45.rb:5: warning: class variable access from toplevel 
Ex45.rb:6: warning: class variable access from toplevel 
Ex45.rb:7: warning: class variable access from toplevel 

Итак, ваш Map класс будет выглядеть это:

class Map 
    @@action = SceneOne.new 
    @@action_two = SceneTwo.new 
    @@action_three = SceneThree.new 

    @@scenes = { 
     'scene_one' => @@action, 
     'scene_two' => @@action_two, 
     'scene_three' => @@action_three 
    } 

    def initialize(start_scene) 
     @start_scene = start_scene 
    end 

    def next_scene(scene_name) 
     val = @@scenes[scene_name] 
     return val 
    end 

    def opening_scene() 
     return next_scene(@start_scene) 
    end 
end 

Чтобы ответить на ваши вопросы Второй вопрос:

Вы получаете undefined method 'enter' for nil:NilClass (NoMethodError), потому что ваш current_scene становится nil в какой-то момент, а затем вы пытаетесь вызвать: current_scene.enter() т.е. nil.enter и он терпит неудачу с этим сообщением об ошибке.

Для решения этой проблемы вы должны убедиться, что у вас всегда есть какое-то значение в вашем current_scene i.e. Убедитесь, что это не nil.

Я думаю, вы можете просто удалить строку current_scene.enter() с конца вашего метода play в классе Engine. Таким образом, ваш Engine класс будет выглядеть следующим образом:

class Engine 
    def initialize(scene_map) 
     @scene_map = scene_map 
    end 

    def play()  
     current_scene = @scene_map.opening_scene() 
     last_scene = @scene_map.next_scene('finished') 

     while current_scene != last_scene 
      next_scene_name = current_scene.enter() 
      current_scene = @scene_map.next_scene(next_scene_name) 
     end 

     # current_scene.enter() 
    end 
end 

И, вы не получите эту ошибку больше.

+0

Может быть, эта линия? '@ scene_map.opening_scene()' он вызывается из функции воспроизведения в классе Engine, но 'opening_scene()' определяется в классе Map. Но я не так понятен в переменных @ или @@. – HolyMoly

+0

Нет, это не проблема, потому что '@ scene_map' является объектом класса« Карта ». Итак, все в порядке. Проблема заключается в том, что 'current_scene' является' nil' в конце цикла while в методе 'play' класса' Engine', как указано в 2-й части моего ответа. –

+1

Большое спасибо за вашу помощь! Оба решения работали! Я также помнил, что у меня был цикл while, где я заявил, что текущая сцена! = Последняя сцена (т. Е. «Закончена»). Таким образом, этот способ «current_scene» должен был либо равняться в основном scene_map.opening_scene ИЛИ «закончен». Поэтому, как только я добавил свой «готовый» файл, а current_scene не смог = nil, я прекратил получать ошибку. Еще раз спасибо! –

0

Только так вы знаете:

@@y = 20 
p Object.class_variables 

--output:-- 
1.rb:1: warning: class variable access from toplevel 
[:@@y] 

И:

class Object 
    def self.y 
    @@y 
    end 
end 

puts Object.y 

--output:-- 
20 

Но:

class Dog 
    @@y = "hello" 

    def self.y 
    @@y 
    end 
end 

puts Dog.y  #=>hello 
puts Object.y #=>What do you think? 

Выход последней строки является причиной того, что переменные класса не используются в Рубин. Вместо переменных класса, вы должны использовать то, что известно как экземпляра класса переменных:

class Object 
    @y = 10 #class instance variable 

    def self.y 
    @y 
    end 
end 

puts Object.y 


class Dog 
    @y = "hello" 

    def self.y 
    @y 
    end 
end 

puts Dog.y  #=> hello 
puts Object.y #=> 10 

переменная экземпляра класса является просто @variable, что находится внутри класса, но вне любого опр. И вместо того, чтобы быть одним @@ переменной, который разделяется всеми подклассами, каждый подкласс будет иметь свой собственный @variable.

Смежные вопросы