上一篇主題 :: 下一篇主題 |
發表人 |
內容 |
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
發表於: 2008-3-14, PM 8:49 星期五 文章主題: 【基本遊戲技術】2D角色上、下、左、右移動 |
|
|
原始碼及執行檔下載 http://zwshen0603.googlepages.com/Movement.zip
這個範例主要是示範2D角色的上、下、左、右移動,使用HGE 1.8引擎,
有兩個基本技術為:
1. 當玩家按下上、下、左、右鍵,將更新角色座標及移動方向
2. 示範如何利用切割後 sprite 圖檔,來組成角色的移動畫面
這裡大概介紹第2個技術如何做,sprite 是一張已經畫有八個角色的png檔
(參考下圖);每個角色都提供四個方向、每個方向各有三個動作,
所以一個角色共有24張小圖,每張小圖都是高32寬24的大小,按動作上、右、
下、左由上到下排好。在這個程式範例中,只用到左上的一個角色。
要達到四方向的移動動畫,要考慮角色的兩個屬性:方向 及 步伐,
方向決定貼圖來源的 Y 值,以第一個角色為例:
1. UP 方向要從圖檔 Y = 0 開始切
2. RIGHT 方向要從圖檔 Y = 32 開始切
3. DOWN 方向要從圖檔 Y = 32*2 開始切
4. RIGHT 方向要從圖檔 Y = 32*3 開始切
步伐只有0, 1, 2 三步)決定貼圖來源的 X 值,同樣以第一個角色為例:
1. 步伐 0 要從圖檔 X = 0 開始切
2. 步伐 1 要從圖檔 X = 24 開始切
3. 步伐 2 要從圖檔 X = 24*2 開始切
(步伐只有0, 1, 2 三步)
取得 X, Y 值之後,就能從sprite圖檔上切出適當的一小塊圖,並繪製到畫面上。
下列為完整程式碼:
代碼: |
/**
* 2D 角色的東、西、南、北四方向移動
*
* Author: zwshen (zwshen0603@gmail.com)
* Date: 2008/03/14
* Engine: HGE V1.8 2d graphics engine
*/
#include "hge/hge.h"
// 畫面寬度、高度
const int WIDTH = 640, HEIGHT= 480;
// hge 引擎 - 為一個全域變數
HGE *g_hge = 0;
// 移動方向的常數列舉
enum Direction {
UP = 0, RIGHT, DOWN, LEFT
};
// 遊戲角色(char)類別
class Char {
private:
float m_xpos, m_ypos;
int m_width;
int m_height;
int m_step;
float m_speed;
Direction m_dir;
hgeQuad sprite;
private:
void updatePos() {
// 更新角色座標
sprite.v[0].x=m_xpos;
sprite.v[0].y=m_ypos;
sprite.v[1].x=m_xpos+m_width;
sprite.v[1].y=m_ypos;
sprite.v[2].x=m_xpos+m_width;
sprite.v[2].y=m_ypos+m_height;
sprite.v[3].x=m_xpos;
sprite.v[3].y=m_ypos+m_height;
}
void updateSprite() {
// 更新材質來源 - 以方向及步伐來決定
int x = m_step * 24;
int y = m_dir * 32;
sprite.v[0].tx = x/288.0;
sprite.v[0].ty = y/256.0;
sprite.v[1].tx = (x+m_width)/288.0;
sprite.v[1].ty = y/256.0;
sprite.v[2].tx = (x+m_width)/288.0;
sprite.v[2].ty = (y+m_height)/256.0;
sprite.v[3].tx = x/288.0;
sprite.v[3].ty = (y+m_height)/256.0;
}
public:
Char() {
m_dir = RIGHT; // 預設方向為右邊
m_step = 0; // 步伐
m_speed = 100; // 速度
m_xpos = 200; // 角色x座標
m_ypos = 200; // 角色y座標
m_height = 32; // 角色高度
m_width = 24; // 角色寬度
}
void shutdown() {
// 釋放圖片資源
if (sprite.tex)
g_hge->Texture_Free(sprite.tex);
}
void walk(Direction dir) {
float dt = g_hge->Timer_GetDelta();
float dx=0, dy=0;
if (dir==UP)
dy -= m_speed*dt;
if (dir==DOWN)
dy += m_speed*dt;
if (dir==RIGHT)
dx += m_speed*dt;
if (dir==LEFT)
dx -= m_speed*dt;
if (m_dir==dir) {
// 同一個方向,則更新步伐
m_step = (m_step+1)%3;
} else {
// 換新方向,步伐歸零
m_dir = dir;
m_step = 0;
}
m_xpos += dx;
m_ypos += dy;
// 檢查是否超出範圍
if (m_xpos < 0)
m_xpos = 0;
if (m_xpos> WIDTH-m_width)
m_xpos =WIDTH-m_width;
if (m_ypos < 0)
m_ypos = 0;
if (m_ypos> HEIGHT-m_height)
m_ypos =HEIGHT-m_height;
update(); // 更新角色
}
void update() {
updatePos();
updateSprite();
}
bool init() {
sprite.tex = g_hge->Texture_Load("blondeboys.png");
if (!sprite.tex)
return false; // 載入圖檔失敗
sprite.blend=BLEND_ALPHAADD | BLEND_COLORMUL | BLEND_ZWRITE;
for (int i=0; i<4; i++) {
sprite.v[i].z=0.1f;
sprite.v[i].col=0xFFFFFFFF;// no effect
}
update();
return true;
}
void render() {
g_hge->Gfx_RenderQuad(&sprite);
}
};
bool FrameFunc();
bool RenderFunc();
// 遊戲主流程(Game Loop)類別
class GameLoop {
public:
static GameLoop *theGameLoop;
private:
Char m_Player; // 遊戲角色
// 遊戲資源初始化
void init() {
g_hge->System_SetState(HGE_FRAMEFUNC, FrameFunc);
g_hge->System_SetState(HGE_RENDERFUNC, RenderFunc);
g_hge->System_SetState(HGE_TITLE, "2D角色移動範例");
g_hge->System_SetState(HGE_WINDOWED, true);
g_hge->System_SetState(HGE_USESOUND, false);
g_hge->System_SetState(HGE_SCREENWIDTH, WIDTH);
g_hge->System_SetState(HGE_SCREENHEIGHT, HEIGHT);
g_hge->System_SetState(HGE_SCREENBPP, 32);
}
public:
GameLoop() {
g_hge = hgeCreate(HGE_VERSION);
init();
}
~GameLoop() {
// 釋放資源
m_Player.shutdown();
g_hge->System_Shutdown();
g_hge->Release();
}
void start() {
// 進入HGE 遊戲迴圈
if (g_hge->System_Initiate()) {
// 初始player資源
if (m_Player.init() == false) {
// 初始失敗,則就結束遊戲
MessageBox(NULL, "init Player fail.", "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
return;
}
g_hge->System_Start();
} else {
MessageBox(NULL, g_hge->System_GetErrorMessage(), "Error", MB_OK | MB_ICONERROR | MB_APPLMODAL);
}
}
void keydown(Direction key) {
// 通知player做「走路」的動作
m_Player.walk(key);
}
// 繪製每一張frame畫面
void render_frame() {
g_hge->Gfx_BeginScene();
g_hge->Gfx_Clear(0);
m_Player.render(); // 通知player做繪製動作
g_hge->Gfx_EndScene();
}
};
bool FrameFunc() {
if (g_hge->Input_GetKeyState(HGEK_ESCAPE))
return true;
/***
* 判斷是否按上、下、左、右按鍵,並轉交給GameLoop做進一步處理
*/
if (g_hge->Input_GetKeyState(HGEK_LEFT))
GameLoop::theGameLoop->keydown(LEFT);
if (g_hge->Input_GetKeyState(HGEK_RIGHT))
GameLoop::theGameLoop->keydown(RIGHT);
if (g_hge->Input_GetKeyState(HGEK_UP))
GameLoop::theGameLoop->keydown(UP);
if (g_hge->Input_GetKeyState(HGEK_DOWN))
GameLoop::theGameLoop->keydown(DOWN);
return false;
}
bool RenderFunc() {
GameLoop::theGameLoop->render_frame();
return false;
}
GameLoop* GameLoop::theGameLoop = new GameLoop();
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
// 遊戲迴圈 開始運作
GameLoop::theGameLoop->start();
// 釋放遊戲相關資源
delete GameLoop::theGameLoop;
return 0;
}
|
|
|
回頂端 |
|
|
chuangyao 稍嫌羞澀的路人
註冊時間: 2008-03-26 文章: 2
0.00 果凍幣
|
發表於: 2008-3-26, AM 11:22 星期三 文章主題: |
|
|
感謝大大的教導
還在熟悉了解中^^ |
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 6:20 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:48 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
發表於: 2008-4-18, PM 6:42 星期五 文章主題: |
|
|
HPkon 寫到: | 抱歉!!!
就是在下用Dev-C++編譯main.cpp這個檔案時發生很多錯誤
但是在下不知道該怎麼解決
另外想請問一下
樓主大人你是用什麼編譯程式編譯main.cpp這個檔案的 |
我是用 eclipse + CDT 的開發環境,C++ 編譯器是 MinGW32。
這個程式有使用 HGE 2D引擎,不知道你有沒有裝 HGE 呢?
或是你將你的錯誤訊息貼上來,比較好知道問題所在,謝謝。 |
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 8:11 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:49 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 9:02 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:49 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
發表於: 2008-4-18, PM 9:08 星期五 文章主題: |
|
|
HPkon 寫到: | 新的專案開好之後是把main.cpp檔加入在新開的專案理就能執行了嗎???
可是...
在下還是不能執行耶!!! |
不只是這樣子。而是新開的專案,都需要設定hge 的環境,才能正常編譯跟執行。
前一篇回文中有教學文件的link ,你可以參考那文件,再去設定你的專案。
要注意的,是每個人存放 hge 的路徑不一樣,就再依自已的情況設定好吧。 |
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 9:18 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:49 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
發表於: 2008-4-18, PM 9:24 星期五 文章主題: |
|
|
引言回覆: | 在下是下載hge181
可是hge181\lib\gcc裡只有libhge.a這個檔案
並沒有hge.a這個檔案 |
那沒有關係,我是 1.80 版,也只有 libhge.a 一個檔,也就夠了。
教學文件是用 1.5 版,所以情況有點不同,但是不傷大雅。
|
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 9:27 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:49 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
發表於: 2008-4-18, PM 9:32 星期五 文章主題: |
|
|
HPkon 寫到: |
大人抱歉!!!
問一下...
專案開好hge環境也設定好之後
只要把那個main.cpp的檔案加入專案裡就行了嗎??? |
是的,只要這樣就能正常編譯了。不過提醒一下,那張角色圖檔也要放在專案裡,要不然一執行就會當掉。
說話我剛也升級到 1.81 版...XD
另外,如果你想要進一步練習,可以做個 2D 射擊遊戲,不需要有捲動的場景,就像任天堂的小蜜蜂、或是太空侵略者等。雖然我這個範例是用 RPG 的圖檔,但是要練習遊戲,先從飛機射擊 或是 board game (如撲克牌、俄羅斯方塊、小精靈) 做,會比較容易做出成品,也比較有成就感。
zwshen 在 2008-4-18, PM 9:39 星期五 作了第 1 次修改 |
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 9:35 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:49 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
zwshen 對這略感興趣的新人
註冊時間: 2008-03-11 文章: 22 來自: Taiwan 0.00 果凍幣
|
發表於: 2008-4-18, PM 9:41 星期五 文章主題: |
|
|
HPkon 寫到: |
嗚...
在下都有放進去耶!!!
可是還是無法編譯
這到底是為什麼???
heg的環境在下有設好啊!!!
可是編譯時#include "hge/hge.h"發生錯誤!!!
這該怎麼辦呢??? |
可能就是多了 "hge/hge.h" 的 hge 路徑,你可以試試直接用 #include <hge.h>。 |
|
回頂端 |
|
|
Okerofujin 略有貢獻的成員
註冊時間: 2007-10-19 文章: 71
-40.53 果凍幣
|
發表於: 2008-4-18, PM 9:43 星期五 文章主題: |
|
|
問題
Okerofujin 在 2018-7-5, PM 11:49 星期四 作了第 1 次修改 |
|
回頂端 |
|
|
|