🔺

Goで三角関数を使った進行方向の処理で詰まったのでまとめてみた

2021/07/03に公開

Goで三角関数を使った進行方向の処理に詰まったのでまとめます。

いわゆるレトロなRPGゲームのキャラ移動のイメージです。

コードはこちら

詰まったポイントは以下の2点でした。

  • sin、cos算定用の関数は90度、180度のようないわゆる角度ではなく、ラジアンを指定する必要があるがGoには角度からラジアンを直接算定する標準パッケージがない。

https://gopherlabs.kubedaily.com/StandardLib/Converting_between_degrees_radians.html

ラジアン(英: radian, 記号: rad)は、国際単位系 (SI) における角度(平面角)の単位である。
円周上でその円の半径と同じ長さの弧を切り取る2本の半径が成す角の値と定義される。

https://ja.wikipedia.org/wiki/ラジアン#:~:text=ラジアン(英%3A radian%2C 記号,を弧度法と呼ぶ。

  • 処理上端数が出てしまうが、切り捨てや切り上げではなく四捨五入を使う必要がありました。
var angle float64
angle = 90
var radian float64

// ラジアン変換
radian = angle * math.Pi / 180

http://www.openspc2.org/reibun/Go/1.1.1/pkg/math/1012/index.html

math.Cos(radian)
math.Sin(radian))

出力結果:
角度90度の場合 Cos: 6.123233995736757e-17 Sin: 1
角度270度の場合 Cos: -1.8369701987210272e-16 Sin: -1

無理数の π を使ってラジアンを算定しているせいか、cos90°、cos270° に端数が生じてしまいました。

math.Floor(math.Cos(radian))
math.Floor(math.Sin(radian))

出力結果:
角度90度の場合 Cos: 0 Sin: 1
角度270度の場合 Cos: -1 Sin: -1

切り捨ての結果、-0.000000..の cos270° が 0 ではなく -1 になってしまいました。

math.Ceil(math.Cos(radian))
math.Ceil(math.Sin(radian)))

出力結果:
角度90度の場合 Cos: 1 Sin: 1
角度270度の場合 Cos: -0 Sin: -1

切り上げの結果、0.0000... の cos90° が 0 ではなく 1 になってしまいました。

math.Round(math.Cos(radian))
math.Round(math.Sin(radian))

出力結果:
角度90度の場合 Cos: 0 Sin: 1
角度270度の場合 Cos: -0 Sin: -1

-0 は気になるものの、ちゃんと cos、sin が計算されています。

進行方向の処理

こんな感じで 角度を変えてやれば x軸方向、y軸方向の移動を処理できます。

for i:=0; i<4; i++{
  radian = angle * math.Pi / 180
  x = x + math.Round(math.Cos(radian))*10
  y = y + math.Round(math.Sin(radian))*10
  angle = angle + 90
}

以上になります、最後までお読みいただきありがとうございました。

コード全体

package main

import (
	"fmt"
	"math"
)

func main() {

	var angle float64
	angle = 90
	var radian float64

	var x, y float64

	for i := 0; i < 8; i++ {
		radian = angle * math.Pi / 180
		fmt.Println("そのまま 角度:", angle, " Cos:", math.Cos(radian), " Sin:", math.Sin(radian))
		fmt.Println("切り捨て 角度:", angle, " Cos:", math.Floor(math.Cos(radian)), " Sin:", math.Floor(math.Sin(radian)))
		fmt.Println("切り上げ 角度:", angle, " Cos:", math.Ceil(math.Cos(radian)), " Sin:", math.Ceil(math.Sin(radian)))
		fmt.Println("四捨五入 角度:", angle, " Cos:", math.Round(math.Cos(radian)), " Sin:", math.Round(math.Sin(radian)))

		x = x + math.Cos(radian)
		y = y + math.Sin(radian)
		angle = angle + 90.0
	}

	fmt.Println("そのまま")
	x, y = 5, -5
	angle = 90
	for i := 0; i < 8; i++ {
		radian = angle * math.Pi / 180
		x = x + math.Cos(radian)*10
		y = y + math.Sin(radian)*10
		fmt.Println("角度:", angle, x, y)
		angle = angle + 90.0
	}

	fmt.Println("切り捨て")
	x, y = 5, -5
	angle = 90
	for i := 0; i < 8; i++ {
		radian = angle * math.Pi / 180
		x = x + math.Floor(math.Cos(radian))*10
		y = y + math.Floor(math.Sin(radian))*10
		fmt.Println("角度:", angle, x, y)
		angle = angle + 90.0
	}

	fmt.Println("切り上げ")
	x, y = 5, -5
	angle = 90
	for i := 0; i < 8; i++ {
		radian = angle * math.Pi / 180
		x = x + math.Ceil(math.Cos(radian))*10
		y = y + math.Ceil(math.Sin(radian))*10
		fmt.Println("角度:", angle, x, y)
		fmt.Println("角度:", angle, x, y)
		angle = angle + 90.0
	}

	fmt.Println("四捨五入")
	x, y = 5, -5
	angle = 90
	for i := 0; i < 8; i++ {
		radian = angle * math.Pi / 180
		x = x + math.Round(math.Cos(radian))*10
		y = y + math.Round(math.Sin(radian))*10
		fmt.Println("角度:", angle, x, y)
		angle = angle + 90.0
	}
}

出力結果

のまま 角度: 90  Cos: 6.123233995736757e-17  Sin: 1
切り捨て 角度: 90  Cos: 0  Sin: 1
切り上げ 角度: 90  Cos: 1  Sin: 1
四捨五入 角度: 90  Cos: 0  Sin: 1
そのまま 角度: 180  Cos: -1  Sin: 1.2246467991473515e-16
切り捨て 角度: 180  Cos: -1  Sin: 0
切り上げ 角度: 180  Cos: -1  Sin: 1
四捨五入 角度: 180  Cos: -1  Sin: 0
そのまま 角度: 270  Cos: -1.8369701987210272e-16  Sin: -1
切り捨て 角度: 270  Cos: -1  Sin: -1
切り上げ 角度: 270  Cos: -0  Sin: -1
四捨五入 角度: 270  Cos: -0  Sin: -1
そのまま 角度: 360  Cos: 1  Sin: -2.449293598294703e-16
切り捨て 角度: 360  Cos: 1  Sin: -1
切り上げ 角度: 360  Cos: 1  Sin: -0
四捨五入 角度: 360  Cos: 1  Sin: -0
そのまま 角度: 450  Cos: 3.0616169978683787e-16  Sin: 1
切り捨て 角度: 450  Cos: 0  Sin: 1
切り上げ 角度: 450  Cos: 1  Sin: 1
四捨五入 角度: 450  Cos: 0  Sin: 1
そのまま 角度: 540  Cos: -1  Sin: 3.6739403974420544e-16
切り捨て 角度: 540  Cos: -1  Sin: 0
切り上げ 角度: 540  Cos: -1  Sin: 1
四捨五入 角度: 540  Cos: -1  Sin: 0
そのまま 角度: 630  Cos: -4.28626379701573e-16  Sin: -1
切り捨て 角度: 630  Cos: -1  Sin: -1
切り上げ 角度: 630  Cos: -0  Sin: -1
四捨五入 角度: 630  Cos: -0  Sin: -1
そのまま 角度: 720  Cos: 1  Sin: -4.898587196589406e-16
切り捨て 角度: 720  Cos: 1  Sin: -1
切り上げ 角度: 720  Cos: 1  Sin: -0
四捨五入 角度: 720  Cos: 1  Sin: -0
そのまま
角度: 90 5.000000000000001 5
角度: 180 -4.999999999999999 5.000000000000001
角度: 270 -5.000000000000001 -4.999999999999999
角度: 360 4.999999999999999 -5.000000000000002
角度: 450 5.000000000000002 4.999999999999998
角度: 540 -4.999999999999998 5.000000000000002
角度: 630 -5.000000000000003 -4.999999999999998
角度: 720 4.999999999999997 -5.0000000000000036
切り捨て
角度: 90 5 5
角度: 180 -5 5
角度: 270 -15 -5
角度: 360 -5 -15
角度: 450 -5 -5
角度: 540 -15 -5
角度: 630 -25 -15
角度: 720 -15 -25
切り上げ
角度: 90 15 5
角度: 90 15 5
角度: 180 5 15
角度: 180 5 15
角度: 270 5 5
角度: 270 5 5
角度: 360 15 5
角度: 360 15 5
角度: 450 25 15
角度: 450 25 15
角度: 540 15 25
角度: 540 15 25
角度: 630 15 15
角度: 630 15 15
角度: 720 25 15
角度: 720 25 15
四捨五入
角度: 90 5 5
角度: 180 -5 5
角度: 270 -5 -5
角度: 360 5 -5
角度: 450 5 5
角度: 540 -5 5
角度: 630 -5 -5
角度: 720 5 -5

Discussion