未顯示需要 JavaScript 的文檔選項





Sam Lantinga, 首席程序員, Loki Entertainment Software

1999 年 9 月 01 日

Sam Lantinga 是 Simple DirectMedia Layer (SDL) 庫的作者和 Loki Entertainment 的首席開發人員,他將向您介紹一種將游戲移植到 Linux上的優秀工具。SDL 是一個跨平臺代碼移植的理想工具,它支持許多平臺,如Linux、Solaris、IRIX、FreeBSD 和 MacOS,這對于那些認為可以在 Linux上開發商業軟件的 Linux 開發者來說是一大進步。他向社區的前輩之一討教SDL 如何使 Linux 用戶享受任何平臺上最好的游戲,SDL如何幫助開發者跟上下一代計算機游戲迷的要求。
Sam Lantinga 是 Simple DirectMedia Layer (SDL) 庫的作者和 Loki Entertainment 的首席開發人員,他將向您介紹一種將游戲移植到 Linux 上的優秀工具。SDL 是一個跨平臺代碼移植的理想工具,它支持許多平臺,如 Linux、Solaris、IRIX、FreeBSD 和 MacOS,這對于那些認為可以在 Linux 上開發商業軟件的 Linux 開發者來說是一大進步。他向社區的前輩之一討教 SDL 如何使 Linux 用戶享受任何平臺上最好的游戲,SDL 如何幫助開發者跟上下一代計算機游戲迷的要求。

自從 Linus 首先開發出 Linux 時開始,到現在 Linux 成為所有黑客的夢想并且遍及全世界,Linux 開發最重要的元素之一就是 OS 上游戲的質量和可用性。游戲是我們用來娛樂和休閑的。它們可以提高創造力并拓展思路。游戲還可以用來測量操作系統的性能。由于游戲越來越復雜,它們迫使每 個子系統逼近極限。每當我裝配一個系統時,首先要做的就是裝入一個游戲并試玩,以“測試”每一項的性能。

Linux 上的游戲已經存在了很長時間。從早期的 NetTrek,到受高度贊揚的 DOOM!雷神 (Quake),人們已經可以在 Linux 上玩游戲了。但問題是沒有足夠的游戲。沒有哪家大公司為 Linux 創作能產生轟動效應的游戲。但是,由于該操作系統變得日益流行,這種情況正開始改善。

Linux 上最早期的游戲使用 X11 協議。但是對于游戲來說,X11 實在太慢了,因為它是針對在網絡上透明運行的基于菜單的應用而設計的協議。使用它的游戲通常沒有絢麗的畫面,而且運行得相當慢。 DOOM!是 一個值得注意的例外,雖然它使用 X11,但是它通過使用 MIT 共享內存擴展可以使動畫更流暢,并提供了逼真的三維效果。還有一些游戲使用 SVGA 圖形庫,SVGAlib。我最喜歡的一個老游戲是重力戰爭 (Gravity Wars),它對其模擬的老 Amiga 游戲 Gravity Force 做了重大改動。但使用 SVGAlib 的程序只能適用于少數受支持的顯卡。

早期 X11 游戲, 爭霸 (Craft)的圖片。 神話 2 (Myth 2)的圖片,Loki 出品
單擊以放大圖片 單擊以放大圖片

今天,游戲開發者有了更多的選擇。仍然可以使用 X 工具箱或全屏 API,如 SVGAlib 或 fbcon,來編寫游戲,但他們現在還有許多游戲庫可以使用。Simple DirectMedia Layer 庫是 Linux 上最好的低層游戲開發 API 之一。

SDL 是什么?
Simple DirectMedia Layer 庫,簡稱 SDL,是為數不多的商業游戲開發公司使用的免費軟件庫之一。它提供跨平臺的二維幀緩沖區圖形和音頻服務,它支持 Linux、Win32 和 BeOS。也不同程度地支持其它平臺,包括 Solaris、IRIX、FreeBSD 和 MacOS。除了大量的服務,包括線程、獨立于字節存儲次序的宏和 CD 音頻,SDL 還提供了一個簡單的 API,它允許您盡可能接近本機硬件。使用 SDL 有三重優點:穩定、簡單和靈活。

  • 穩定。如果 SDL 不向 API 提供可靠的支持,那么那些愛好者和商業公司就不能使用它。因為使用了 SDL,就添加了錯誤修正并增強了性能,也就加強了 API 的強健性。就像內核開發是分步進行的,SDL 的開發也是分步進行的,其中一部分是可靠穩定的 API,其它部分是新功能和構思的沙箱。
  • 簡單。SDL 被設計成一個簡單的 API,以最少的代碼實現您的構思。比如,我最近從 Linux 演示組 Optimum中移植了一些演示程序,我將它們的 X11 代碼替換成 SDL 代碼(請參見下面的列表)。您可以看到,SDL 代碼非常易于編寫和理解。

    X11 代碼

    int init_x (int X, int Y,
    int W, int H, int bpp,
    const char *Name) {
    XPixmapFormatValues *formatList;
    int formatCount;
    int i;
    int formatOk;
    int scanlineLength;
    XGCValues gcVal;
    unsigned long gcMask;
    dis = XOpenDisplay ( NULL );
    if ( dis == NULL) {
    fprintf ( stderr , "Error :\n" );
    fprintf ( stderr , " Cannot connect to Display.\n");
    exit (1);
    }
    screen = DefaultScreen ( dis );
    depth = DefaultDepth ( dis , screen );
    width = DisplayWidth ( dis , screen );
    height = DisplayHeight ( dis , screen );

    winRoot = DefaultRootWindow ( dis );
    winAttr.border_pixel = BlackPixel ( dis , screen );
    winAttr.background_pixel = BlackPixel ( dis , screen );
    winMask = CWBackPixel | CWBorderPixel;

    formatList = XListPixmapFormats( dis, &formatCount);
    if (formatList == NULL){
    fprintf ( stderr , " Cannot get pixmap list\n");
    exit (1);
    }
    formatOk=-1;
    for (i=0; ibytes_per_line*xim->height,
    IPC_CREAT|0777);
    xim->data = SHMInfo.shmaddr = (char *)shmat(SHMInfo.shmid, 0, 0);
    SHMInfo.readOnly = False;
    XShmAttach(dis, &SHMInfo);
    XSync(dis, False);
    buffer=(unsigned char *)xim->data;
    #else
    buffer = (unsigned char *)calloc(W*H, pixmapFormat.bits_per_pixel/8);
    xim = XCreateImage ( dis , CopyFromParent , depth , ZPixmap , 0 ,
    (char *) buffer , W , H ,
    pixmapFormat.scanline_pad, scanlineLength);
    if (xim == NULL){
    fprintf(stderr, " Couldnt create Ximage..\n");
    exit(-1);
    }
    #endif
    gcVal.foreground = 0;
    gcVal.background = 0;
    gcMask = GCForeground | GCBackground;
    gc = XCreateGC ( dis , win , gcMask , &gcVal );
    if (depth==24)
    depth = pixmapFormat.bits_per_pixel;
    return (depth);
    }

    SDL 代碼

    int init_x (int X, int Y,
    int W, int H, int bpp,
    const char *Name) {
    int i;
    if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
    {
    fprintf ( stderr , "Erreur :\n" );
    fprintf ( stderr , " Impossible de se connecter au Display\n");
    exit (1);
    }
    screen = SDL_SetVideoMode(W, H, bpp, SDL_SWSURFACE|SDL_HWPALETTE);
    if ( screen == NULL )
    {
    fprintf ( stderr , "Erreur :\n" );
    fprintf ( stderr , " Impossible de se connecter au Display\n");
    exit (1);
    }
    SDL_WM_SetCaption ( Name, Name );
    for ( i=SDL_NOEVENT; iformat->BitsPerPixel;
    width = screen->w;
    height = screen->h;
    buffer = (unsigned char *)screen->pixels;
    return (depth);
    }

  • 靈活。 返回到上面的 Optimum 演示代碼示例,只要移植到 SDL,并確定一些數據假設,那么根本不必改動代碼,演示就可以在 Win32、BeOS 和 Linux 控制臺上運行了。靈活性的另一方面體現在盡管代碼完全是跨平臺的,但不會把您和底層實現隔開。SDL 提供了函數 SDL_GetWMInfo(),該函數可以讓您訪問底層驅動程序的專用窗口信息。Loki Entertainment Software 廣泛使用這一技術為它們的游戲智能窗口管理器交互。

    Optimum 演示版的屏幕快照

這種堅如磐石般的穩定、簡單和強大功能的組合已經給 Linux 帶來了一些極其引人入勝的游戲,包括 Hopkins F.B.I.文明:力量的呼喚 (Civilization: Call To Power)神話 2:Soulblighter (MythII: Soulblighter)鐵路大亨 2 (Railroad Tycoon II)等等。編程愛好者和商業公司使用這個庫的事實表示它正在日益提高其功能和穩定性。這符合實際游戲的實際需要。

文明:力量的呼喚 (Civilization: Call To Power)的圖片 天旋地轉 2 (Descent 2)的圖片
單擊以放大圖片 單擊以放大圖片