早期功能機僅支援整數運算。若需實現旋轉、軌跡、波形等遊戲邏輯,**查表法**是唯一可行方案:預計算 sin/cos 值存入陣列,運行時直接索引或線性插值。
// 角度單位:度/10(0~36 對應 0~360°)
// 數值縮放:×256(8.8 定點數,即 1.0 = 256)
private static final int[] SINES = {
0, 44, 88, 128, 165, 196, 222, 241, 252, 256, // 0°~90°
// 實際項目需擴展至 36 個條目(每 10° 一個)
};
// 正弦查詢:返回 sin(angle) * 256
private static int sineTimes256(int angle) {
angle %= 36; // 歸一化 0~35
if (angle < 0) angle += 36; // 處理負角度
if (angle <= 9) { // 0°~90°
return SINES[angle];
} else if (angle <= 18) { // 90°~180°
return SINES[18 - angle];
} else if (angle <= 27) { // 180°~270°
return -SINES[angle - 18];
} else { // 270°~360°
return -SINES[36 - angle];
}
}
// 餘弦 = 正弦相位偏移 90°(即 +9 步)
private static int cosineTimes256(int angle) {
return sineTimes256(angle + 9);
}
// 離線生成 360 條目(1° 步長)×256 定點數表
public class SinTableGen {
public static void main(String[] args) {
int[] table = new int[360];
for (int i = 0; i < 360; i++) {
double rad = Math.toRadians(i);
table[i] = (int) Math.round(Math.sin(rad) * 256);
}
// 輸出 Java 陣列初始化代碼
System.out.print("private static final int[] SIN_TABLE = {");
for (int i = 0; i < 360; i++) {
if (i % 12 == 0) System.out.print("\n ");
System.out.print(table[i] + (i < 359 ? ", " : " };\n"));
}
}
}
若步長 1° 仍不夠(如慢速旋轉),可做**定點數線性插值**:
// angle 為 0~3599(百分一度),返回 sin*256
public static int sin100(int angle) {
angle %= 36000;
if (angle < 0) angle += 36000;
int idx = angle / 100; // 整度索引
int frac = angle % 100; // 小數部分 0~99
int v1 = SIN_TABLE[idx];
int v2 = SIN_TABLE[(idx + 1) % 360];
// 定點數插值:v1 + (v2-v1)*frac/100
return v1 + ((v2 - v1) * frac) / 100;
}
| 運算 | 公式(Q8.8 格式,縮放 256) | 範例 |
|---|---|---|
| 加/減 | 直接加減 | a + b |
| 乘法 | (a * b) >> 8 | (sin * amplitude) >> 8 |
| 除法 | (a << 8) / b | (x << 8) / cos |
| 轉浮點 | val / 256.0 | 僅調試用 |
// 向量 (x, y) 繞原點旋轉 angle 度(angle 為 0~359)
// 定點數版本,輸入輸出均為 ×256
public static void rotate256(int[] vec, int angle) {
int sin = sineTimes256(angle);
int cos = cosineTimes256(angle);
int x = vec[0], y = vec[1];
// x' = x*cos - y*sin
// y' = x*sin + y*cos
vec[0] = ((x * cos - y * sin) >> 8);
vec[1] = ((x * sin + y * cos) >> 8);
}
| 方案 | 表大小 | 最大誤差 | 適用場景 |
|---|---|---|---|
| 10° 步長 + 無插值 | 36 × 2B = 72B | ~1.5% | 極度受限設備、粗略動畫 |
| 1° 步長 + 無插值 | 360 × 2B = 720B | ~0.15% | 大多數遊戲足夠 |
| 0.1° 步長 + 線性插值 | 3600 × 2B = 7.2KB | < 0.001% | 高精度物理/軌跡 |
| CORDIC 算法 | 0B(純計算) | 可控 | 無表空間、CPU 允許 10-20 迭代 |
查表法是 J2ME 時代**解決無浮點三角函數的標準解法**。關鍵在於:選對步長與定點數格式、善用對稱性減半存儲、乘除遵循定點數移位規則。現代項目若維護舊代碼,可直接沿用;新項目建議要求 CLDC 1.1+ 直接用 Math.sin(硬體/軟浮點均可)。