网上下载的例子运行以后会出现以下情况:
① 小人移动速度较慢。
② 小人移动动画不准确,即移动时候小人的双脚并不会运动。反而是站着的时候双脚会走。
③ 小人向下或向下移动的时候同时按左键或右键,小人方向不会发生改变,但是会向左或向右移动;小人向左或向右移动的时候按上下键,小人方向会发生改变。这是因为 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有一点致命的地方是并不支持中文文本。中文文本输出会出现乱码。所以想要中文只能用图片的形式输出了。