電子書籍の厳選無料作品が豊富!

Rubyにてゲームプログラミングをしているのですが、
Angleとして使用する数値を (0..360) の範囲内に常に収める為、Angleクラスで管理しようと思っています。


そこで作成方法の質問なのですが、記号などによる適切な作成方法が分かりません。
適切な記述を教えて頂けたら幸いです。
angle = Angle[30]     # Vectorを参考にしたのですが、配列では無い為、微妙な記述・・・
angle = Angle.new(30)  # かと言って、普通に作成するのもどうかと・・・


また、attr_readerで参照するのも微妙な記述だと思います。
angle = Angle.new(30)
angle.angle  # => 30

できればクラス参照で値を取得したいのですが、方法が分かりません。
angle = Angle.new(30)
angle  # => 30


ご教授の程、お願い致します。

A 回答 (4件)

No3です。



>Numeric並に手軽に呼び出せた方が良いと思ったからです。

それは無理です。せいぜい、組み込みクラスのRationalのように、
def Angle(x)
Angle.new(x)
end
と、クラス名と同名の関数(Kernelのメソッド)を定義するくらいですね。

>クラスのみ参照で、戻り値(Numeric)を取得したいです。
>angle  # => 30(Numeric)のオブジェクト

いやだから、それはわかっていて、それを文字通りにするのは無理なので、それに対しての回答が、

>数値演算関係がすべて定義されているなら、あとは to_int to_i to_f to_s inspect 等を適切に定義すれば良いです。

です。
p angle で 30 を表示するためには、inspect を定義すれば良いし、puts angle なら to_s を定義すれば良いと言うことです。

ただ、
>30 + Angle.new(30)
>Numeric側の演算子定義を直すのも手なのですが、
ということは、上記回答の前提の、「数値演算関係がすべて定義されているなら」もまだと言うことですね。

30 + Angle.new(30) の結果は、Angleオブジェクトじゃ無くてNumericオブジェクトということでいいですか?であれば、Numericクラスを修正するので無くAngle#coerceを定義してください。
class Angle
def coerce(other)
[other, @angle]
end
end

ただ、そもそも 30 + Angle.new(30) などという計算をするのはおかしくないですか?
Angle.new(30) + Angle.new(30) とするべきでは?
    • good
    • 0
この回答へのお礼

引き続き何度もご回答して頂きありがとうございます。

Kernelのメソッドを定義する方法は、正に思っていたような記述です!!
作成はそれでやってみます。

>いやだから、それはわかっていて、それを文字通りにするのは無理なので
やはりクラス参照のみでは、Numericオブジェクトは取得できませんでしたか・・・。
上記の方法でやってみます。

>ということは、上記回答の前提の、「数値演算関係がすべて定義されているなら」もまだと言うことですね。
これについては、Angleクラス内の演算子関係を全て定義していることだと思っていました。

coerceメソッド、ヘルプで見ました。かなり使えるメソッドだと思います。
(ヘルプくらい、もっと前にしっかりと読みこんでおくべきでした・・・)
是非、これを使いたいと思います。

>Angle.new(30) + Angle.new(30) とするべきでは?
もちろんそのつもりです。ただ、そういう使い方をする可能性も視野に入れておきたかったのです。


お蔭様で、思っていたような処理を組むことが出来そうです。
とても参考になりました。ありがとうございます。
これで、また一歩先に進めそうです。

お礼日時:2013/03/26 09:56

>newを使わずに作成した方がAngleらしい記述だと思うのですが、



そんなことはないです。なぜそう思ったのですか?なんとなくですか?

>また、参照もメソッドを呼び出さず、クラスのインスタンスを参照するやり方を教えて頂きたいのです。

数値演算関係がすべて定義されているなら、あとは to_int to_i to_f to_s inspect 等を適切に定義すれば良いです。

この回答への補足

ご回答ありがとうございます。

newが、Angleらしくない記述だと思った訳は、Angleは頻繁に使う物であり、
Numeric並に手軽に呼び出せた方が良いと思ったからです。
また、Vector[]は配列らしさを取り込んだ上手い記述だと思ったので、そのような分かり易い記述にしようと思いました。


それと、お聞きしたいことが上手く伝わらなかったようなので、質問をもう少し補足したいと思います。
またまた分かりづらい質問になってしまい申し訳ありません。

class Angle
 attr_reader :angle
 def initialize(angle)
  @angle = angle
 end
end

angle = Angle.new(30)
angle.angle  # => 30(Numeric)のオブジェクト

上記のように定義するとそうなるのですが、下記のようにしたいのです。
クラスのみ参照で、戻り値(Numeric)を取得したいです。
angle  # => 30(Numeric)のオブジェクト

しかし、やり方が分かりません。
google先生や、リファレンスもある程度見たのですが、見つかりませんでした・・・。
試行錯誤としては、下記のようにメソッドを組んでみたのですが、当然呼び出せません。
def self
 @angle
end

このやり方で呼び出したい理由としては、下記のような計算があった時に、Numericとして渡したいからです。
30 + Angle.new(30)
Numeric側の演算子定義を直すのも手なのですが、AngleはNumeric以外の様々な場所で使われているので、
そのまま使えるのが効率的だと思っています。
演算子を直すことになると、Numeric以下の様々なクラスを修正する必要も出てきます・・・。

例としては、下記のようなケースも考えられます。
angle = Angle.new(30)
sprite = Sprite.new
sprite.angle = angle.angle  # 現状、このように呼び出すしかない。
# sprite.angle = angle     # 本当はこのように呼び出したい。

尚、Spriteクラスはブラックボックス化されており、ソースを弄る事ができません・・・。
(つまり、angleに渡す値はNumericでないといけないということです。)
angle.angleと、二重にangleを記述しないと呼び出せないのでは、優れた記述とは言えないと思います。


to_int、to_i、to_f、to_sは、今のところ使うつもりはないので定義していません。
inspectについてなのですが、思っていたことに非常に近いことが出来ました。ご教授ありがとうございます。
しかし、p で参照した値が計算の際にそのまま渡されると思っていたので、やはり思っていたようにはできませんでした・・・。


何度も補足してしまい、申し訳ありません・・・。
ご回答の程、宜しくお願い致します。

補足日時:2013/03/25 12:08
    • good
    • 0

補足欄の意味が分かりにくいのですが、



angle = Angle[30]
を使えるようにしたいのでしたら
def self.[](ang)
@angle=ang
end
で可能ですが、多分聞きたいことと違うような気がします。

p angle
で角度が表示されるようにするには、
def inspect
@angle.to_s
end
で可能なのですが、あくまでも表示だけを変更しているだけです。

この回答への補足

引き続きご回答ありがとうございます。
回答内容がこちらから閲覧できなかった為、返信が遅くなってしまいました。
分かりづらい補足で申し訳ありません。
詳しい補足は、回答NO3のnotnot様の補足に書いたのでそちらの閲覧をお願いいたします。
何度も補足をしてしまい申し訳ありません。


作成方法については、Angle[30]の変わりに、良い記述方法のアドバイスが欲しいのです。
Angle{30}とか、何か記号を使った良い記述を教えて頂きたいのです。
(できれば、Numeric並に楽に作成できるのが望ましいです。)

また、inspectが表示だけしか変更できないということに、先程気がつきました。
angle = Angle.new(30)
angle  # 30(Numeric)のオブジェクト
表示だけでなく、上記のように見なされるように変更したいです。
そのような方法は、不可能でしょうか・・・?


ご回答お願い致します。

補足日時:2013/03/25 12:32
    • good
    • 0

こんな感じでしょうか



class Angle
attr_accessor :angle
def initialize(ang)
@angle=ang
end

def to_s()
@angle.to_s
end

def +(other)
self.class.new(case other
when Angle then @angle+other.angle
else @angle+other
end)
end
end

p ang1=Angle.new(30)
p ang1.angle
ang1.angle=45
p ang1
puts ang1 #=>45
p ang1+12
puts ang1+12 #=>57
puts ang1+Angle.new(12) #=>57

ang1はNumeric classではありませんので、演算は定義してやる必要があります。
演算した結果がNumericで良いのなら、forwardableを使って委譲する手もあります。
参考
http://jp.rubyist.net/magazine/?0012-BundledLibr …

この回答への補足

お早い回答ありがとうございます。
質問が分かりづらくて申し訳ありません。

演算子定義などは、Vectorクラスを参考に作成できるのですが、
作成の際の記述方法が分からなくて困っています。
newを使わずに作成した方がAngleらしい記述だと思うのですが、
配列ではないので、Angle[30]などのように作成するのもどうかと思い、適切な作成方法を知りたいのです。

また、参照もメソッドを呼び出さず、クラスのインスタンスを参照するやり方を教えて頂きたいのです。
angle = Angle[30]
p angle   # => 30 (angle.angleと二重に書かなくても参照可能)

ということでお願い致します。

補足日時:2013/03/24 20:12
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!