【APP GAME KIT】能碰到障碍物的移动小人

4 篇文章 0 订阅

网上下载的例子运行以后会出现以下情况:

① 小人移动速度较慢。

② 小人移动动画不准确,即移动时候小人的双脚并不会运动。反而是站着的时候双脚会走。

③ 小人向下或向下移动的时候同时按左键或右键,小人方向不会发生改变,但是会向左或向右移动;小人向左或向右移动的时候按上下键,小人方向会发生改变。这是因为 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有一点致命的地方是并不支持中文文本。中文文本输出会出现乱码。所以想要中文只能用图片的形式输出了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值