【APP GAME KIT】能碰到障礙物的移動小人
阿新 • • 發佈:2019-01-01
網上下載的例子執行以後會出現以下情況:
① 小人移動速度較慢。
② 小人移動動畫不準確,即移動時候小人的雙腳並不會運動。反而是站著的時候雙腳會走。
③ 小人向下或向下移動的時候同時按左鍵或右鍵,小人方向不會發生改變,但是會向左或向右移動;小人向左或向右移動的時候按上下鍵,小人方向會發生改變。這是因為 if 和 else if 導致的按鍵事故。
原版程式碼:
// Includes, namespace and prototypes #include "template.h" using namespace AGK; app App; // Function prototypes void loadTiles(); void displayTiles(); void updateAlecX(float); void updateAlecY(float); // Constants for the screen resolution const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; // Constants for the image numbers const int GRASS = 1; const int PATH = 2; const int PATHNE = 3; const int PATHNW = 4; const int PATHSE = 5; const int PATHSW = 6; const int TREENW = 7; const int TREENE = 8; const int TREESW = 9; const int TREESE = 10; const int ROCK = 11; // Constants for the tile image sizes const int TILE_WIDTH = 64; const int TILE_HEIGHT = 48; // Constants for the tile map size declarators const int TILE_ROWS = 10; const int TILE_COLS = 10; // Constants for the Alec sprite sheet const int ALEC_IMAGE = 12; // Texture atlas image index const int ALEC_SPRITE = 100; // Alec's sprite index const int ALEC_FRAME_WIDTH = 40; // Alec's frame width const int ALEC_FRAME_HEIGHT = 75; // Alec's frame height const int ALEC_FRAME_COUNT = 16; // Alec's frame count const int EAST_START = 1; // First frame for going east const int EAST_END = 4; // Last frame for going east const int NORTH_START = 5; // First frame for going north const int NORTH_END = 8; // Last frame for going north const int SOUTH_START = 9; // First frame for going south const int SOUTH_END = 12; // Last frame for going south const int WEST_START = 13; // First frame for going west const int WEST_END = 16; // Last frame for going west const int ALEC_FPS = 5; // Alec's frames per second const int ANIMATION_LOOP = 1; // To make Alec loop const float ALEC_STARTING_X = 0; // Alec's starting X coordinate const float ALEC_STARTING_Y = 150; // Alec's starting Y coordinate // Constants for Alec's direction const int NORTH = 1; const int SOUTH = 2; const int EAST = 3; const int WEST = 4; // The tile map int g_tileMap[TILE_ROWS][TILE_COLS] = { {GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS}, {GRASS, GRASS, GRASS, ROCK, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS}, {GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, PATHNW, PATH, PATH }, {GRASS, GRASS, GRASS, GRASS, GRASS, TREENW, TREENE, PATH, GRASS, GRASS}, {PATH, PATH, PATH, PATH, PATHNE, TREESW, TREESE, PATH, ROCK, GRASS}, {GRASS, GRASS, GRASS, GRASS, PATH, GRASS, GRASS, PATH, GRASS, GRASS}, {GRASS, GRASS, GRASS, GRASS, PATHSW, PATH, PATH, PATHSE, GRASS, GRASS}, {GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS}, {GRASS, ROCK, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS}, {GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS, GRASS} }; // Variable for Alec's direction int g_alecDirection = EAST; // Begin app, called once at the start void app::Begin( void ) { // Set the window title. agk::SetWindowTitle("Walking Alec"); // Set the virtual resolution. agk::SetVirtualResolution(SCREEN_WIDTH, SCREEN_HEIGHT); // Load the texture atlas. agk::LoadImage(ALEC_IMAGE, "Alec/Alec.png"); // Create the sprite using the texture atlas as the image. agk::CreateSprite(ALEC_SPRITE, ALEC_IMAGE); // Make sure Alec is displayed on top of the tile sprites. agk::SetSpriteDepth(ALEC_SPRITE, 0); // Set Alec's starting position. agk::SetSpritePosition(ALEC_SPRITE, ALEC_STARTING_X, ALEC_STARTING_Y); // Set the sprite animation. agk::SetSpriteAnimation(ALEC_SPRITE, ALEC_FRAME_WIDTH, ALEC_FRAME_HEIGHT, ALEC_FRAME_COUNT); // Load the tile images. loadTiles(); // Create the tile sprites and display them. displayTiles(); } // Main loop, called every frame void app::Loop ( void ) { // Get the state of the direction keys. float directionX = agk::GetDirectionX(); float directionY = agk::GetDirectionY(); // If the right or left arrow keys are pressed, // update Alec's X coordinate. if (directionX != 0) { updateAlecX(directionX); } // If the up or down arrow keys are pressed, // update Alec's Y coordinate. if (directionY != 0) { updateAlecY(directionY); } // Refresh the screen. agk::Sync(); } // Called when the app ends void app::End ( void ) { } // The loadTiles function loads the images that will be // used for tiles. void loadTiles() { agk::LoadImage(GRASS, "Alec/Grass.png"); agk::LoadImage(PATH, "Alec/Path.png"); agk::LoadImage(PATHNE, "Alec/PathNE.png"); agk::LoadImage(PATHNW, "Alec/PathNW.png"); agk::LoadImage(PATHSE, "Alec/PathSE.png"); agk::LoadImage(PATHSW, "Alec/PathSW.png"); agk::LoadImage(TREENE, "Alec/TreeNE.png"); agk::LoadImage(TREENW, "Alec/TreeNW.png"); agk::LoadImage(TREESE, "Alec/TreeSE.png"); agk::LoadImage(TREESW, "Alec/TreeSW.png"); agk::LoadImage(ROCK, "Alec/Rock.png"); } // The displayTiles function displays the tiles, as // specified by the tile map. void displayTiles() { // Variables for the tile coordinates float x = 0, y = 0; // Variable to temporarily hold a sprite index int spriteIndex; // Display all the tiles specified in the map. for (int r = 0; r < TILE_ROWS; r++) { // Set x to 0. x = 0; // Display all the tiles in this row. for (int c = 0; c < TILE_COLS; c++) { // Create a sprite for this tile. spriteIndex = agk::CreateSprite(g_tileMap[r][c]); // Set the tile's position. agk::SetSpritePosition(spriteIndex, x, y); // Update the X coordinate for the next tile. x += TILE_WIDTH; } // Increase y for the next row. y += TILE_HEIGHT; } } // The updateAlecX function turns Alec either east or west, // depending on which arrow key is being pressed, and moves // him to his new X coordinate. void updateAlecX(float directionX) { float alecX, // Alec's current X position newX; // Alec's new X coordinate // Get Alec's X coordinate alecX = agk::GetSpriteX(ALEC_SPRITE); // Which key was pressed? Right or left? if (directionX > 0) { // Turn Alec east agk::PlaySprite(ALEC_SPRITE, ALEC_FPS, ANIMATION_LOOP, EAST_START, EAST_END); // Save Alec's current direction. g_alecDirection = EAST; // Calculate Alec's new X coordinate. newX = alecX + 1; } else if (directionX < 0) { // Turn Alec west agk::PlaySprite(ALEC_SPRITE, ALEC_FPS, ANIMATION_LOOP, WEST_START, WEST_END); // Save Alec's current direction. g_alecDirection = WEST; // Calculate Alec's new X coordinate newX = alecX - 1; } // Move Alec agk::SetSpriteX(ALEC_SPRITE, newX); } // The updateAlecY function turns Alec either north or south, // depending on which arrow key is being pressed, and moves // him to his new Y coordinate. void updateAlecY(float directionY) { float alecY, // Alec's current Y position newY; // Alec's new Y coordinate // Get Alec's Y coordinate alecY = agk::GetSpriteY(ALEC_SPRITE); // Which key was pressed? Up or down? if (directionY < 0) { // Turn Alec north agk::PlaySprite(ALEC_SPRITE, ALEC_FPS, ANIMATION_LOOP, NORTH_START, NORTH_END); // Save Alec's current direction. g_alecDirection = NORTH; // Calculate Alec's new Y coordinate. newY = alecY - 1; } else if (directionY > 0) { // Turn Alec south agk::PlaySprite(ALEC_SPRITE, ALEC_FPS, ANIMATION_LOOP, SOUTH_START, SOUTH_END); // Save Alec's current direction. g_alecDirection = SOUTH; // Calculate Alec's new Y coordinate. newY = alecY + 1; } // Move Alec agk::SetSpriteY(ALEC_SPRITE, newY); }
自己嘗試獨立打了一次程式碼:
#include "template.h" using namespace AGK; app App; //tile圖片編號 const int GRASS = 1;//草坪圖片 const int PATH = 2;//石徑滿 const int PATHNE = 3;//石徑左拐下 const int PATHNW = 4;//石徑右拐下 const int PATHSE = 5;//石徑左拐上 const int PATHSW = 6;//石徑上拐右 const int TREENW = 7;//樹左上部分 const int TREENE = 8;//樹右上部分 const int TREESW = 9;//樹坐下部分 const int TREESE = 10;//樹右下部分 const int ROCK = 11;//石頭 //每張矩圖的大小 const int TILE_WIDTH = 64; const int TILE_HEIGHT = 48; //地圖矩陣n x n const int TILE_ROWS = 10; const int TILE_COLS = 10; //螢幕大小 const int SCREEN_WIDTH = 640; const int SCREEN_HEIGHT = 480; int g_tileMap[TILE_ROWS][TILE_COLS] = { GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS, GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS, GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,PATHNW,PATH,PATH, GRASS,GRASS,GRASS,GRASS,GRASS,TREENW,TREENE,PATH,GRASS,GRASS, PATH ,PATH ,PATH ,PATH ,PATHNE,TREESW,TREESE,PATH,ROCK,GRASS, GRASS,GRASS,GRASS,GRASS,PATH,GRASS,GRASS,PATH,GRASS,GRASS, GRASS,GRASS,GRASS,GRASS,PATHSW,PATH,PATH,PATHSE,GRASS,GRASS, GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS, GRASS,ROCK,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS, GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS,GRASS, }; //四個方向 const int NORTH = 1; const int SOUTH = 2; const int EAST = 3; const int WEST = 4; //人物引數 const int ALEC_IMAGE = 12;//ALEC圖片 const int ALEC_SPRITE = 100;//ALEC精靈 const int ALEC_FRAME_WIDTH = 40;//alec人物圖片寬度 const int ALEC_FRAME_HEIGHT = 75;//alec人物圖片高度 const int ALEC_FRAME_COUNT = 16;//總共16幅圖片 const int EAST_START = 1;//向東開始 const int EAST_END = 4;//向東結束 const int NORTH_START = 5;//向北開始 const int NORTH_END = 8;//向北結束 const int SOUTH_START = 9;//向南開始 const int SOUTH_END = 12;//向南結束 const int WEST_START = 13;//向西開始 const int WEST_END = 16;//向西結束 const int ALEC_FPS = 5;//幀率 const int ANIMATION_LOOP = 1;//迴圈 const int WALK_DISTANCE = 4; const int STANDING = 0;//站立 const int WALKING = 1;//行走 const float ALEC_STARTING_X = 0;//X座標 const float ALEC_STARTING_Y = 150;//Y座標 int g_alecDirection = EAST;//人物朝向 int g_state = STANDING;//人物當前狀態 //測試資料 const int X = 1; const int Y = 2; //Function void loadTiles();//載入tile圖片 void displayTiles();//輸出地圖 void updateAlecX(float); void updateAlecY(float); int direction(float,float); bool checkCollision(float x,float y); void app::Begin(void) { agk::SetVirtualResolution (SCREEN_WIDTH, SCREEN_HEIGHT); agk::SetWindowTitle("Walking Alec"); agk::LoadImage(ALEC_IMAGE,"Alec/Alec.png"); agk::CreateSprite(ALEC_SPRITE,ALEC_IMAGE); agk::SetSpriteDepth(ALEC_SPRITE,0); agk::SetSpritePosition(ALEC_SPRITE,ALEC_STARTING_X,ALEC_STARTING_Y); agk::SetSpriteAnimation(ALEC_SPRITE,ALEC_FRAME_WIDTH,ALEC_FRAME_HEIGHT,ALEC_FRAME_COUNT); agk::CreateText(X,agk::Str(ALEC_STARTING_X)); agk::SetTextSize(X,24); agk::SetTextPosition(X,SCREEN_WIDTH - agk::GetTextTotalWidth(X),0); agk::CreateText(Y,agk::Str(ALEC_STARTING_Y)); agk::SetTextSize(Y,24); agk::SetTextPosition(Y,SCREEN_WIDTH - agk::GetTextTotalWidth(Y),agk::GetTextTotalHeight(X)+5); agk::CreateText(200,"10"); agk::SetTextSize(200,24); agk::SetTextPosition(200,SCREEN_WIDTH - agk::GetTextTotalWidth(200),agk::GetTextTotalHeight(X)+5+agk::GetTextTotalHeight(Y)+5); agk::CreateText(201,"10"); agk::SetTextSize(201,24); agk::SetTextPosition(201,SCREEN_WIDTH - agk::GetTextTotalWidth(201),agk::GetTextTotalHeight(X)+5+agk::GetTextTotalHeight(Y)+5+agk::GetTextTotalHeight(200)+5); agk::CreateText(202,"1"); agk::SetTextSize(202,24); agk::SetTextPosition(202,0,400 ); loadTiles(); displayTiles(); } void app::Loop (void) { float directionX = agk::GetDirectionX(); float directionY = agk::GetDirectionY(); agk::SetTextString(X,agk::Str(agk::GetSpriteX(ALEC_SPRITE))); agk::SetTextString(Y,agk::Str(agk::GetSpriteY(ALEC_SPRITE))); int isLEFTRIGHT = direction(directionX,directionY); switch(isLEFTRIGHT){ case 0: if(g_state==WALKING){ g_state = STANDING; switch(g_alecDirection){ case NORTH: agk::PlaySprite(ALEC_SPRITE,1,ANIMATION_LOOP,6,6); break; case SOUTH: agk::PlaySprite(ALEC_SPRITE,1,ANIMATION_LOOP,10,10); break; case WEST: agk::PlaySprite(ALEC_SPRITE,1,ANIMATION_LOOP,14,14); break; case EAST: agk::PlaySprite(ALEC_SPRITE,1,ANIMATION_LOOP,2,2); break; } } break; case 1: updateAlecX(directionX); break; case 2: updateAlecY(directionY); break; } agk::Sync(); } void app::End (void) { } void loadTiles(){//載入tile圖片 agk::LoadImage(GRASS,"Alec/Grass.png"); agk::LoadImage(PATH,"Alec/Path.png"); agk::LoadImage(PATHNE,"Alec/PathNE.png"); agk::LoadImage(PATHNW,"Alec/PathNW.png"); agk::LoadImage(PATHSE,"Alec/PathSE.png"); agk::LoadImage(PATHSW,"Alec/PathSW.png"); agk::LoadImage(TREENW,"Alec/TreeNW.png"); agk::LoadImage(TREENE,"Alec/TreeNE.png"); agk::LoadImage(TREESW,"Alec/TreeSW.png"); agk::LoadImage(TREESE,"Alec/TreeSE.png"); agk::LoadImage(ROCK,"Alec/Rock.png"); } void displayTiles(){ float x = 0, y = 0; int spriteIndex; for(int r = 0;r<TILE_ROWS;r++){ x = 0; for(int c = 0 ; c < TILE_COLS; c++){ spriteIndex = agk::CreateSprite(g_tileMap[r][c]); agk::SetSpritePosition(spriteIndex,x,y); x+=TILE_WIDTH; } y+=TILE_HEIGHT; } } void updateAlecX(float directionX){ float alecX,newX; alecX = agk::GetSpriteX(ALEC_SPRITE); if(directionX>0){ if(g_alecDirection !=EAST || g_state==STANDING){ agk::PlaySprite(ALEC_SPRITE,ALEC_FPS,ANIMATION_LOOP,EAST_START,EAST_END); g_alecDirection = EAST; g_state = WALKING; } if(alecX+ALEC_FRAME_WIDTH <= SCREEN_WIDTH-WALK_DISTANCE && checkCollision(alecX+WALK_DISTANCE,agk::GetSpriteY(ALEC_SPRITE))){ newX = alecX + WALK_DISTANCE; agk::SetSpriteX(ALEC_SPRITE,newX); } } else if(directionX < 0){ if(g_alecDirection !=WEST || g_state==STANDING){ agk::PlaySprite(ALEC_SPRITE,ALEC_FPS,ANIMATION_LOOP,WEST_START,WEST_END); g_alecDirection = WEST; g_state = WALKING; } if(alecX>=WALK_DISTANCE && checkCollision(alecX-WALK_DISTANCE,agk::GetSpriteY(ALEC_SPRITE))){ newX = alecX - WALK_DISTANCE; agk::SetSpriteX(ALEC_SPRITE,newX); } } } void updateAlecY(float directionY){ float alecY,newY; alecY = agk::GetSpriteY(ALEC_SPRITE); if(directionY > 0){ if(g_alecDirection != SOUTH || g_state==STANDING){ agk::PlaySprite(ALEC_SPRITE,ALEC_FPS,ANIMATION_LOOP,SOUTH_START,SOUTH_END); g_alecDirection = SOUTH; g_state = WALKING; } if(alecY+ALEC_FRAME_HEIGHT <= SCREEN_HEIGHT-WALK_DISTANCE && checkCollision(agk::GetSpriteX(ALEC_SPRITE),alecY+WALK_DISTANCE)){ newY = alecY + WALK_DISTANCE; agk::SetSpriteY(ALEC_SPRITE,newY); } } else if(directionY < 0){ if(g_alecDirection != NORTH || g_state==STANDING){ agk::PlaySprite(ALEC_SPRITE,ALEC_FPS,ANIMATION_LOOP,NORTH_START,NORTH_END); g_alecDirection = NORTH; g_state = WALKING; } if(alecY>=WALK_DISTANCE && checkCollision(agk::GetSpriteX(ALEC_SPRITE),alecY-WALK_DISTANCE)){ newY = alecY - WALK_DISTANCE; agk::SetSpriteY(ALEC_SPRITE,newY); } } } int direction(float x,float y){ int c=0,isx = -1; if(x!=0){ c++; isx = 1; } if(y!=0){ c++; isx = 0; } switch(c){ case 0: return 0; break; case 1: if(isx == 1){ return 1; } else if(isx == 0){ return 2; } break; case 2: switch(g_alecDirection){ case NORTH: case SOUTH: return 1; break; case WEST: case EAST: return 2; break; } break; } return 0; } bool checkCollision(float a,float b){ int y = (int)((a + ALEC_FRAME_WIDTH/2)/TILE_WIDTH); int x = (int)((b + ALEC_FRAME_HEIGHT)/TILE_HEIGHT); agk::SetTextString(200,agk::Str(x)); agk::SetTextString(201,agk::Str(y)); agk::SetTextString(202,agk::Str(g_tileMap[x][y])); if(g_tileMap[x][y]>=7){ return false; } return true; }
做出的修改如下:
① 小人速度加快。
② 增加了阻礙移動的物體。
③ 按下左右鍵時候按下上下鍵的時候互相切換,反之亦然。這樣雖然避免了if和else if導致有一個鍵先行判斷而另一個鍵後判斷的情況。但是人物移動的時候兩個方向快速切換也是影響視覺效果。最好還是繪製四個斜方向的移動小人動畫。
④ 小人移動的時候雙腳擺動,站立時停止擺動。
實際上的速度要比gif圖片要快的多。中間的圖上右上右動的極快。
agk有一點致命的地方是並不支援中文文字。中文文字輸出會出現亂碼。所以想要中文只能用圖片的形式輸出了。