首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> J2ME

手機遊戲任意角度旋轉演算法實作(全機型相容)

     編輯:J2ME

前言

早期 J2ME 無硬體加速,精靈旋轉需純軟體實作。本文提供一個基於查表法正弦/餘弦 + 雙線性插值的通用 Sprite.rotate(count) 實作,可離線預生成 360 度內 count 幀旋轉圖,執行時直接播放,效能穩定。

核心資料結構

public class Sprite {
    public short[][] pixels;      // 每幀像素陣列 (ARGB 4444 打包於 short)
    public short width, height;   // 單幀尺寸
    public byte numOfFrame;       // 總幀數
    public int curFrame;          // 當前幀

    // 正弦表:0~359 度 × 256 定點數 (sin × 256)
    public final static int[] SIN_TABLE = {
        0, 4, 8, 13, 17, 22, 26, 31, 35, 39, 44, 48, 53, 57, 61, 65, 70, 74, 78, 83,
        87, 91, 95, 99, 103, 107, 111, 115, 119, 123, 127, 131, 135, 138, 142, 146,
        149, 153, 156, 160, 163, 167, 170, 173, 177, 180, 183, 186, 189, 192, 195,
        198, 200, 203, 206, 208, 211, 213, 216, 218, 220, 223, 225, 227, 229, 231,
        232, 234, 236, 238, 239, 241, 242, 243, 245, 246, 247, 248, 249, 250, 251,
        251, 252, 253, 253, 254, 254, 254, 254, 254, 255, 254, 254, 254, 254, 254,
        253, 253, 252, 251, 251, 250, 249, 248, 247, 246, 245, 243, 242, 241, 239,
        238, 236, 234, 232, 231, 229, 227, 225, 223, 220, 218, 216, 213, 211, 208,
        206, 203, 200, 198, 195, 192, 189, 186, 183, 180, 177, 173, 170, 167, 163,
        160, 156, 153, 149, 146, 142, 138, 135, 131, 127, 123, 119, 115, 111, 107,
        103, 99, 95, 91, 87, 83, 78, 74, 70, 65, 61, 57, 53, 48, 44, 39, 35, 31,
        26, 22, 17, 13, 8, 4, 0, -4, -8, -13, -17, -22, -26, -31, -35, -39, -44,
        -48, -53, -57, -61, -65, -70, -74, -78, -83, -87, -91, -95, -99, -103, -107,
        -111, -115, -119, -123, -127, -131, -135, -138, -142, -146, -149, -153, -156,
        -160, -163, -167, -170, -173, -177, -180, -183, -186, -189, -192, -195, -198,
        -200, -203, -206, -208, -211, -213, -216, -218, -220, -223, -225, -227, -229,
        -231, -232, -234, -236, -238, -239, -241, -242, -243, -245, -246, -247, -248,
        -249, -250, -251, -251, -252, -253, -253, -254, -254, -254, -254, -255, -254,
        -254, -254, -254, -254, -253, -253, -252, -251, -251, -250, -249, -248, -247,
        -246, -245, -243, -242, -241, -239, -238, -236, -234, -232, -231, -229, -227,
        -225, -223, -220, -218, -216, -213, -211, -208, -206, -203, -200, -198, -195,
        -192, -189, -186, -183, -180, -177, -173, -170, -167, -163, -160, -156, -153,
        -149, -146, -142, -138, -135, -131, -127, -123, -119, -115, -111, -107, -103,
        -99, -95, -91, -87, -83, -78, -74, -70, -65, -61, -57, -53, -48, -44, -39,
        -35, -31, -26, -22, -17, -13, -8, -4
    };
    // ... 建構子、常數略
}

旋轉核心:rotate(int count)

輸入:欲預生成的幀數 count(如 16、32)。輸出:新 Sprite,包含 count 幀旋轉後圖像。

演算法步驟

  1. 根據原圖尺寸查表決定旋轉半徑(外接圓半徑),確保旋轉無裁切。
  2. 目標畫布尺寸 = radius × 2(正方形)。
  3. 對每一幀 frame = 0 ~ count-1:
    • 角度 angle = frame * (360 / count)。
    • 查表取 sin = SIN_TABLE[angle] << 8、cos = SIN_TABLE[(angle+90)%360] << 8(定點數 8.8 格式)。
    • 以目標畫布中心為原點,反向映射每個像素至原圖座標(雙線性插值)。
    • 超出原圖邊界 → 填透明色。

關鍵輔助函式:雙線性插值 project()

private final short project(short[] src, int srcW, int srcH,
                            int u, int v) {
    // u, v: 定點數 16.16 (整數部 16 bits, 小數部 16 bits)
    int uInt = (u >> 16) % srcW; if (uInt < 0) uInt += srcW;
    int vInt = (v >> 16) % srcH; if (vInt < 0) vInt += srcH;
    int uFrac = (u >> 8) & 0xFF; // 0~255
    int vFrac = (v >> 8) & 0xFF;

    // 取四鄰域像素 (ARGB 4444)
    int p00 = src[vInt * srcW + uInt];
    int p10 = src[vInt * srcW + (uInt+1)%srcW];
    int p01 = src[((vInt+1)%srcH) * srcW + uInt];
    int p11 = src[((vInt+1)%srcH) * srcW + (uInt+1)%srcW];

    // 各通道獨立插值
    int a = lerp4(p00>>12, p10>>12, p01>>12, p11>>12, uFrac, vFrac);
    int r = lerp4(p00>>8&0xF, p10>>8&0xF, p01>>8&0xF, p11>>8&0xF, uFrac, vFrac);
    int g = lerp4(p00>>4&0xF, p10>>4&0xF, p01>>4&0xF, p11>>4&0xF, uFrac, vFrac);
    int b = lerp4(p00&0xF, p10&0xF, p01&0xF, p11&0xF, uFrac, vFrac);
    return (short)((a<<12)|(r<<8)|(g<<4)|b);
}

// 簡化雙線性插值權重計算
private int lerp4(int v00, int v10, int v01, int v11, int fx, int fy) {
    int wx1 = 256 - fx, wy1 = 256 - fy;
    return (v00*wx1*wy1 + v10*fx*wy1 + v01*wx1*fy + v11*fx*fy) >> 16;
}

原始碼中以展開式計算四通道,此處封裝為 lerp4 便於理解。

繪製與 Nokia UI API 相容

draw(Graphics, x, y, manipulate) 內部呼叫 drawPixels,支援 Nokia 專有 manipulate 參數(翻轉、旋轉 90/180/270),並以 drawLine 掃描線繪製加速(連續相同像素合併)。

使用建議

  • 離線預生成:遊戲啟動或載入關卡時呼叫 rotate(16/32),將結果快取;執行時僅播放幀,零運算負擔。
  • 尺寸限制:原始碼針對常見尺寸(6×12、8×8、10×16、11×15、24×24、26×26、40×40)硬編碼半徑。通用版應改為 radius = (short)Math.sqrt(w*w + h*h)/2 + 1。
  • 記憶體權衡:32 幀 × 40×40 ≈ 100 KB。視 Heap 酌減幀數或尺寸。

總結

以查表法避開 Math.sin/cos 浮點運算,配合定點數雙線性插值,實現無浮點、全機型相容的精靈旋轉。此技術在早期 J2ME 射擊、競速遊戲中廣泛應用。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved