(請保留-> 作者: 羅冰 https://blog.csdn.net/luobing4365)
UEFI下的彈跳小游戲
- 1 Bounce游戲
- 1.1 游戲架構
- 1.2 移植和撰寫代碼
- 1)撰寫檔案讀取到記憶體的函式
- 2)撰寫影像顯示函式
- 3)實作彈跳函式Bounce
- 4)實作主功能
- 2 測驗彈跳小游戲
昨天閑暇的時候,把Tim Lewis的迷宮游戲編譯了一下,自娛自樂在UEFI下玩了一把,
奇怪的是,CSDN竟然給我發了“入選《游戲領域內容榜》第27名”,如下圖:

圖1 CSDN奇怪的評選
嗯,雖然從理論上來說,這篇博客也算寫了個游戲,可我主要寫的是UEFI程式啊,除了這篇博客的名字外,在關鍵字里我也沒有設定“游戲”字樣,
實在搞不懂CSDN的評判演算法,
不管了,昨天看Tim Lewis的代碼中,還有一些游戲,今天想再編譯試試,
1 Bounce游戲
在早期的Windows XP中,有一個讓人印象深刻的屏保,桌面上一個小球,在螢屏上來回撞,運行的程序中畫出各種軌跡,
Bounce就是用來實作類似功能的UEFI程式,
不過,直接編譯后,發現無法運行,看了下代碼,影像是通過類似HII的方式來組織的,
不大習慣這種方式,我還是決定自己把程式修改一下,
1.1 游戲架構
從功能上來說,要實作的比較簡單:
1) 影像顯示(包括指定位置的影像顯示);
2) 遇到障礙物的動作處理(主要是螢屏四周),
這是個粗糙的架構,在此基礎上,可以擴展多個影像碰撞后的處理,實作類似以前的屏保的效果,
實際上,UEFI開發探索系列博客中所開發的影像處理函式,完全可以直接使用,
為了方便,我也是在之前的代碼基礎上進行移植的,基礎工程是以前的MyGuiFrame,修改了其中與影像處理相關Picture.c,以及添加了一個檔案處理函式,位于FileRW.c中,
1.2 移植和撰寫代碼
主要的撰寫步驟如下,
1)撰寫檔案讀取到記憶體的函式
修改原來通過GUID獲取檔案的方法,直接讀取bmp影像到記憶體,檔案處理的函式,放在了FileRW.c中,如下所示:
//robin 增加一個處理影像檔案的加載函式
EFI_STATUS
LoadFile(
IN CONST CHAR8 *FilePath,
OUT VOID **File,
OUT UINT32 *FileSize
)
{
FILE *f = fopen(FilePath, "rb");
if (f == NULL) {
return EFI_NOT_FOUND;
}
fseek(f, 0, SEEK_END);
*FileSize = ftell(f);
fseek(f, 0, SEEK_SET); //same as rewind(f);
*File = malloc(*FileSize);
if (*File == NULL) {
return EFI_OUT_OF_RESOURCES;
}
if (fread(*File, *FileSize, 1, f) < 1) {
return EFI_DEVICE_ERROR;
}
fclose(f);
return EFI_SUCCESS;
}
2)撰寫影像顯示函式
影像顯示的函式包括DisplayImage()和DisplayImageAt(),內容如下:
EFI_GRAPHICS_OUTPUT_BLT_PIXEL *mBlt;
UINTN mHeight;
UINTN mWidth;
int DisplayImageAt (UINTN X, UINTN Y)
{
gGraphicsOutput->Blt (
gGraphicsOutput,
mBlt,
EfiBltBufferToVideo,
0,
0,
X,
Y,
mWidth,
mHeight,
mWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
);
return 0;
}
EFI_STATUS
DisplayImage (
IN CONST CHAR8 *BmpFilePath
)
{
EFI_STATUS Status;
UINT8 *ImageData;
UINTN ImageSize;
UINTN BltSize;
UINTN CoordinateX;
UINTN CoordinateY;
//robin 修改原有代碼,將影像檔案加載
Status = LoadFile(BmpFilePath, (VOID **)&ImageData, &ImageSize);
if (EFI_ERROR(Status)) { //print error messages
return FALSE;
}
BltSize = 0;
Status = ConvertBmpToGopBlt (
ImageData,
ImageSize,
(VOID **) &mBlt,
&BltSize,
&mHeight,
&mWidth
);
if (EFI_ERROR (Status)) {
free (ImageData);
}
CoordinateX = (gGraphicsOutput->Mode->Info->HorizontalResolution / 2) - (mWidth / 2);
CoordinateY = (gGraphicsOutput->Mode->Info->VerticalResolution / 2) - (mHeight / 2);
DisplayImageAt ((UINTN) CoordinateX, (UINTN) CoordinateY);
return EFI_SUCCESS;
}
DisplayImageAt()在指定位置處,將記憶體mBlt中存盤的影像,直接顯示到螢屏上;而DisplayImage()則完成了將BMP影像加載到記憶體mBlt,以及呼叫DisplayImageAt()顯示影像的功能,
3)實作彈跳函式Bounce
彈跳函式通過UEFI定時器,按一定的頻率移動影像,如果影像撞到螢屏四周,則反彈回來繼續移動,
邏輯結構還是比較簡單的,內容如下:
EFI_GRAPHICS_OUTPUT_BLT_PIXEL mBoundBg = {201, 174, 255, 0};
EFI_EVENT mEvent;
EFI_STATUS bounce (VOID)
{
EFI_EVENT events[2];
UINTN index;
EFI_INPUT_KEY Key;
INTN DeltaX;
INTN DeltaY;
INTN CurrentX;
INTN CurrentY;
INTN NewX;
INTN NewY;
gBS->CreateEvent (
EVT_TIMER,
0,
NULL,
NULL,
&mEvent
);
gBS->SetTimer (
mEvent,
TimerPeriodic,
// 10*1000*1000 //fix time? 1s
10*1000*80 //80ms
);
Key.ScanCode = SCAN_NULL;
DeltaX = 3;
DeltaY = 3;
events[0] = gST->ConIn->WaitForKey;
events[1] = mEvent;
CurrentX = (gGraphicsOutput->Mode->Info->HorizontalResolution / 2) - (mWidth / 2);
CurrentY = (gGraphicsOutput->Mode->Info->VerticalResolution / 2) - (mHeight / 2);
do {
gBS->WaitForEvent (2, events, &index);
if (index == 0) {
gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
continue;
} else {
NewX = CurrentX + DeltaX;
NewY = CurrentY + DeltaY;
if (NewX + mWidth > gGraphicsOutput->Mode->Info->HorizontalResolution) {
//bounce X
NewX = gGraphicsOutput->Mode->Info->HorizontalResolution - mWidth;
DeltaX = -DeltaX;
} else if (NewX < 0) {
//bounce X
NewX = 0;
DeltaX = -DeltaX;
}
if (NewY + mHeight > gGraphicsOutput->Mode->Info->VerticalResolution) {
//bounce Y
NewY = gGraphicsOutput->Mode->Info->VerticalResolution - mHeight;
DeltaY = -DeltaY;
} else if (NewY < 0) {
//bounce Y
NewY = 0;
DeltaY = -DeltaY;
}
gGraphicsOutput->Blt(
gGraphicsOutput,
&mBoundBg,
EfiBltVideoFill,
0,
0,
CurrentX,
CurrentY,
mWidth,
mHeight,
0
);
DisplayImageAt (NewX, NewY);
CurrentX = NewX;
CurrentY = NewY;
}
} while (Key.ScanCode != SCAN_END);
gST->ConOut->Reset (gST->ConOut, FALSE);
return EFI_SUCCESS;
}
4)實作主功能
在主程式中,添加對bmp影像的加載顯示,并實作彈跳效果:
if (EFI_ERROR (DisplayImage("bounce.bmp"))) {
return 1;
}
bounce();
為了方便演示,我把螢屏解析度改為了800x600,
經過以上步驟,就完成了彈跳小游戲的編程了,
2 測驗彈跳小游戲
使用如下命令編譯:
C:\vUDK2018\edk2>build -p RobinPkg\RobinPkg.dsc -m RobinPkg\Applications\BounceGame\BounceGame.inf -a IA32
把編譯好的程式BounceGame.efi以及專案檔案夾下的bounce.bmp拷貝到模擬器所在檔案夾,運行BounceGame.efi即可看到效果,
在Tianocore模擬器中,運行效果如圖2所示,

圖2 彈跳小游戲
Gitee地址:https://gitee.com/luobing4365/uefi-exolorer
專案代碼位于:/ FF RobinPkg/RobinPkg/Applications/BounceGame下
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/295271.html
標籤:其他
上一篇:Python單人貪吃蛇
