我正在开发一款独立视频游戏,并且一直在这样的假设下进行操作:因为我的控制器上的拇指杆具有圆形运动范围,所以它返回“圆形”坐标;也就是说,笛卡尔坐标被限制在一个圆形区域(半径为 1)。事实上,坐标是“正方形”;例如,右上角的拇指杆位置注册为 x=1,y=1。当我将坐标从笛卡尔坐标转换为极坐标时,幅度可能会超过 1 - 这会导致玩家沿对角线移动的速度比垂直或水平移动的速度更快。
所以,为了澄清,我想用方向和幅度来记录模拟摇杆的位置,其中幅度在 0 和 1 之间。摇杆返回方形平面上的坐标,因此只需将坐标从笛卡尔坐标转换为极性还不够。我想我需要转换坐标空间,但这已经突破了我猴脑的极限。
请参阅将正方形映射到圆形。映射还有一个很好的可视化效果。你得到:
xCircle = xSquare * sqrt(1 - 0.5*ySquare^2)
yCircle = ySquare * sqrt(1 - 0.5*xSquare^2)
映射不是唯一的。这个问题还有很多其他的解决方案。
例如,这个映射也可以工作
u = x √(x² + y² - x²y²) / √(x² + y²)
v = y √(x² + y² - x²y²) / √(x² + y²)
其中 (u,v) 是圆盘坐标,(x,y) 是方坐标。
一张图片胜过一千个单词,所以这里有一些图像来说明映射及其逆的非唯一性。
For a C++ implementation
,请转至 另请参阅“使圆盘平方的分析方法”,了解讨论不同映射方程及其证明和推导的论文。
将每个值除以幅度,将所有值标准化为单位向量,例如
magn = sqrt(x * x + y * y);
newx = magn > 1.0 ? x / magn : x;
newy = magn > 1.0 ? y / magn : y;
但是,这可能会产生裁剪幅度的效果,而不是对内部值进行标准化。也就是说,对于“完全”推入左上角的控制器和“几乎”推入的控制器,您将获得相同的值完全朝着同一个方向。
我最近不得不在 JavaScript 中做类似的事情,并创建了一种将单位正方形的
X
和
Y
标准化(或映射?)到四分之一单位圆的方法,将速度导出为 V
,将方向导出为d
。这用于生成具有随机值的流场网格点。我使用 (n * 2) - 1
来获取
X
和 Y
值,其中 n
是 0
和 1
之间的随机数。 X 和 Y 的值在 -1
和 1
之间。首先,我们得到 h
的斜边或
X,Y
。
h = √(X² + Y²)
然后我们得到
∆
和
X
之间的角度,即 h
,作为绝对值 |•|
。我们得到绝对值,所以我们不会得到负值 V
∆ = |arcsin(X/h)|
现在我们有了角度,我们可以沿着该角度延伸斜边。我们通过将
X
最大化到 1 来实现这一点。我们称之为
h'
h' = 1/cos(∆)
因为我们使用了绝对值,所以这会改变沿原点的方向。我们这样解释。
q = 45(π/180)
if (∆ ≥ q) h' = 1/cos(q - (∆ mod q))
这样,现在我们可以用
h
标准化
h'
。
V = h/h'
为了获得真正的
∆
或
d
,我们必须用一些案例逻辑来纠正它的方向。我们将使用度数转换为弧度,然后使用之前计算的 ∆
。
逻辑如下: (X ≥ 0)?(Y ≥ 0)?toRad(90) mod ∆: ∆ + toRad(270):(Y ≤ 0)? ∆ + toRad(180): ∆ + toRad(90)
澄清一下,每种情况都对应于网格/圆的一个象限。
如果
X ≥ 0
Y ≥ 0
,则 toRad(90) mod ∆
如果 X ≥ 0
Y < 0
,则 ∆ + toRad(270)
如果 X < 0
Y ≤ 0
,则 ∆ + toRad(180)
如果 X < 0
Y > 0
,则 ∆ + toRad(90)
这基本上就是我想出的。在某种程度上,它对值进行插值,使其保持在 0 和 1 之间,因此像
1,0
和
1,1
这样的值都等于 1。其中 1,0
是 100% 向右,1,1
是 100% 向上/向右前进。 X
和 Y
的负值只会沿各自的轴翻转方向。如果 X,Y
等于 0,则 V
和 d
也为 0。我希望这可以帮助人们避免将来头痛。