2013-07-13 5 views
2

В моей разработке игр есть класс Point (хранится x, y координаты и другие полезные вещи). Мои игровые объекты имеют свойство @position, которое является экземпляром Point. Когда изменяется @position, игровой объект будет нарисован где-то в другом месте.Могу ли я переопределить поведение оператора присваивания?

Моя проблема заключается в следующем:

@someSprite.position = Point.new(100,100) 
temp = @someSprite.position 
temp.x = 500 

temp становится отнесение @someSprite.position. Изменение его также изменило бы положение спрайта. Этого я не хочу. Я хочу, чтобы temp был другим экземпляром.

Я не могу сделать что-то вроде этого:

temp = @someSprite.position.clone 

из другой детали в рамках: Point является observable. @someSprite наблюдает за собой, @someSprite.position.

Если я использую clone, то temp также клонирует реестр наблюдателей. И когда будет изменено состояние temp, @someSprite будет уведомлено, создавая беспорядок.

Можно сделать это, то:

temp = @someSprite.position.clone 
temp.remove_observer(@someSprite) 

Но что чувствует непрактичным и хак.

Другой подход:

temp = Point.new(@someSprite.position) 

где я сделать конструктор для Point, где он принимает значение от другого Point (без копирования реестра наблюдателя). Это похоже на лучший подход до сих пор, но я хочу достичь этого

temp = @someSprite.position 

Это можно сделать? Могу ли я переопределить поведение оператора присваивания в этом случае?

+1

Оператор присваивания * никогда не переопределяется в Ruby. Сети - сеттеры; даже скрываясь за сахаром, которые заставляют их использовать оператор присваивания (они действительно не так, как вызовы сеттера действительно отправляются сообщениями). – user2246674

+0

@ user2246674: Как насчет предлагать практическое решение вместо того, чтобы быть грубым? – Borodin

+0

@ user2246674: Не могли бы вы расширить свою идею изменчивости в ответ? Мне любопытно, но, честно говоря, мне все еще не хватает предложения. – Voldemort

ответ

1

Я предполагаю, что ваш используете attr_reader на @position определить position метод спрайта. Но вы также можете определить свои собственные геттеры. В этом случае я хотел бы предложить вам создать явный поглотитель для позиции:

class Sprite 
    def position 
     return Point.new(@position.x, @position.y) 
    end 
end 

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

+0

Удивительная идея. Но если я это сделаю, я бы не смог использовать '@someSprite.position.x = 100', чтобы изменить положение' @ someSprite', правильно? Или я чего-то не хватает? – Voldemort

+0

@Omega, да. Почему бы вам не определить вместо этого метод 'move' (или любого другого имени):' @ someSprite.move (10, 20) '? – Shoe

+1

@Omega, когда вы занимаетесь разработкой игр, я обычно всегда создаю «перемещение» (смещение) и метод «move_to» (абсолютная позиция) для спрайтов. – Shoe

1

Вы объяснили, почему вы не можете использовать clone, однако это не означает, что вы не можете переопределить clone или создать новый метод, например duplicate.

Так что на вашем классе Пункта просто определить:

def duplicate 
    Point.new(x,y) 
end 

Тогда вы можете сделать:

temp = @someSprite.position.duplicate 
+0

Так будет ли 'temp = @ someSprite.position' описанным выше способом быть невозможным? – Voldemort

+1

Правильно, поскольку temp - это просто переменная, которую вы назначаете значение, как, например, оригинальный комментатор вашего заявленного вопроса, нечего переопределять. Если вы, например, устанавливали атрибут для другого объекта, например 'someOtherObject.point = @ someSprite.position', тогда вы могли бы определить метод' point = 'на другом объекте, чтобы безопасно клонировать позицию. Но это не то, что вы делаете, поэтому лучше всего поставить метод, который знает, как сделать безопасную копию. –

+0

['dup'] (http://ruby-doc.org/core-2.0/Object.html#method-i-dup) или [' clone'] (http://ruby-doc.org/core- 2.0/Object.html # method-i-clone) могут быть лучшими именами, поскольку 'Object' уже поддерживает их. –

0

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

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