2

背景:バーズビューJavaScriptゲームのすべてのスプライトに8つの画像があり、プレーヤーの宇宙船の速度に応じて、上、右上、右、右下などを表します。

質問:sprite.speed.xとsprite.speed.yの値(たとえば、4と-2.5、または2と0のようなもの)が与えられた場合、正しい角度を度で取得するにはどうすればよいですか?その角度が与えられると、どの度の値がどのスプライト画像を表すかを検索できます。あるいは、もっと簡単な方法があるかもしれません。(現在、「xがゼロ未満の場合は左の画像を使用する」などを使用しているため、ほとんどの場合、対角線の画像が使用されます。)

探し回って、見つけた...

angle = Math.atan2(speed.y, speed.x);

...しかし、どういうわけか私はまだ何かが欠けています。

PS:ゼロ速度は無視できます。これらのスプライトは、最後の有効な方向画像を使用します。

助けてくれてありがとう!

4

3 に答える 3

10

良い質問!私はtom10の答え(マーク上、+ 1)が好きでしたが、三角法をあまり使わずにそれができるかどうか疑問に思いました。これが簡単な解決策であり、その後に説明が続きます。

// slope is a constant, 0.414...; calculate it just once
var slope = Math.tan(Math.PI/8);

// do this for each x,y point
var s1 = x * slope + y > 0 ? 0 : 1;
var s2 = y * slope + x > 0 ? 0 : 1;
var s3 = y * slope - x < 0 ? 0 : 1;
var s4 = x * slope - y > 0 ? 0 : 1;

var segment = 4 * s4 + 2 * (s2 ^ s4) + (s1 ^ s2 ^ s3 ^ s4);

segmentこれにより、0〜7の値が設定されます。これは2000のランダムポイント(回答の最後にある完全なソースコード)の例です。スプライトの速度のx、y値を使用して、セグメント値を使用して適切なスプライト画像を取得できます。

代替テキスト

タダー!

では、これはどのように機能しますか? 私たちのセグメント式は少し不可解に見えます。

観察1:ポイントの周りの円を等しい角度寸法の8つのセグメントに分割します。360/8=セグメントあたり45度。8つのセグメントのうち4つは、x軸とy軸の2つの側面の1つを中心とし、それぞれ45/2=22.5度でスライスされます。

代替テキスト

観察2:平面上の線の方程式はa*x + b*y + c = 0、不等式に変換されるa*x + b*y + c > 0と、線のどちら側に点が配置されているかをテストするために使用できます。4本の線はすべて原点(x = 0、y = 0)と交差するため、力c=0になります。さらに、それらはすべて、x軸またはy軸のいずれかから22.5度の角度にあります。これにより、4つの一次方程式が得られます。

y = x * tan(22.5); y = -x * tan(22.5); x = y * tan(22.5); x = -y * tan(22.5)

私たちが得る不平等に変わりました:

x * tan(22.5)-y> 0; x * tan(22.5)+ y> 0; y * tan(22.5)-x> 0; y * tan(22.5)+ x> 0

与えられた点の不等式をテストすることで、それが存在する各線の両側で知ることができます。 代替テキスト 代替テキスト

代替テキスト 代替テキスト

観察3:テスト結果を組み合わせて、必要なセグメント番号パターンを取得できます。視覚的な内訳は次のとおりです。

順番に:4 * s42 * (s2 ^ s4)および合計4 * s4 + 2 * (s2 ^ s4) 代替テキスト 代替テキスト 代替テキスト

(^記号はJavascript XOR演算子です。)

そして、ここにs1 ^ s2 ^ s3 ^ s4、最初はそれ自体で、次に追加されます4 * s4 + 2 * (s2 ^ s4) 代替テキスト 代替テキスト

追加のクレジット:整数演算のみを使用するように計算を微調整できますか?はい-xyが整数であることがわかっている場合、不等式の両側に定数を掛けて(そして四捨五入して)、完全に整数の計算を行うことができます。(ただし、これは、数値が常に倍精度浮動小数点であるJavascriptでは失われます。):

var s1 = x * 414 + y * 1000 > 0 ? 0 : 1;
var s2 = y * 414 + x * 1000 > 0 ? 0 : 1;
var s3 = y * 414 - x * 1000 < 0 ? 0 : 1;
var s4 = x * 414 - y * 1000 > 0 ? 0 : 1;

上記のサンプルの完全なソースコード:(新しいhtmlファイルにドロップして任意のブラウザで開くだけです)

(jsbinのライブデモとして参照してください)

<html>
    <head>
        <style type="text/css">
            .dot { position: absolute; font: 10px Arial }
            .d0 { color: #FF0000; }
            .d1 { color: #FFBF00; }
            .d2 { color: #7fcc00; }
            .d3 { color: #00FF7F; }
            .d4 { color: #00FFFF; }
            .d5 { color: #5555FF; }
            .d6 { color: #aF00FF; }
            .d7 { color: #FF00BF; }
        </style>
        <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
        <script type="text/javascript">
            $(function() {
                var $canvas = $("#canvas");
                var canvasSize = 300;
                var count = 2000;
                var slope = Math.tan(Math.PI/8);

                $canvas.css({ width: canvasSize, height: canvasSize });
                for (var i = 0; i < count; ++i) {

                    // generate a random point
                    var x = Math.random() - 0.5;
                    var y = Math.random() - 0.5;

                    // draw our point
                    var $point = $("<div class='dot'></div>")
                        .css({
                            left: Math.floor((x + 0.5) * canvasSize) - 3,
                            top:  Math.floor((y + 0.5) * canvasSize) - 6 })
                        .appendTo($canvas);

                    // figure out in what segment our point lies
                    var s1 = x * slope + y > 0 ? 0 : 1;
                    var s2 = y * slope + x > 0 ? 0 : 1;
                    var s3 = y * slope - x < 0 ? 0 : 1;
                    var s4 = x * slope - y > 0 ? 0 : 1;
                    var segment = 4 * s4 + 2 * (s2 ^ s4) + (s1 ^ s2 ^ s3 ^ s4);

                    // modify the point's html content and color
                    // (via its CSS class) to indicate its segment
                    $point
                        .text(segment)
                        .addClass("d" + segment);
                }
            });
        </script>
    </head>
    <body>
        <div id="canvas" style="position: absolute; border: 1px solid blue">
        </div>
    </body>
</html>
于 2010-09-08T08:31:04.413 に答える
3

あなたが提案することは正確に正しいです!Math.atan2の結果はラジアンであり、おそらく度に精通していることに注意してください。を使用して変換できますangle_degrees = angle*(180./pi)

(RCIXが提案したように正規化する必要はありませんが、必要に応じて正規化することもできます。持っているものは問題なくangle = Math.atan2(speed.y, speed.x);機能するはずです。)

于 2010-09-08T04:44:22.223 に答える
0

あなたは正しい方向に進んでいました。速度ベクトルを正規化し(最初に両方のコンポーネントが0であることを確認します)、それにatan2を呼び出してから、取得したラジアン値を、適切なスプライトを選択するために使用できるある種のわかりやすい方向列挙型に変換します。

于 2010-09-08T02:21:55.627 に答える