TO Vo_Dich:
Một nhân vật (player hoặc monster) có một biến xác nhận event. Bachi đặt là behavior. Sẽ có 2 function điều khiển hoạt động nhân vật.
behavior gồm : BE_STAND, BE_MOVE (left, right, ...), BE_ATTACK, BE_DIE
Function thứ nhất là Control_Character. Function này sẽ phân làm 2 phần đối với player và monster, và sẽ phân nữa trong trường hợp điều khiển NPC hoặc follower. Function này sẽ chuyển đổi giá trị behavior cho các nhân vật.
Function thứ hai là Animate_Character. Function này chỉ có 1 phần. Nó sẽ kiểm tra giá trị của các trường hợp behavior để điều khiển nhân vật.
Source của Control_Character: (Tất nhiên đố ai mà hiểu hết trong cái đám loạn xạ này, nhưng nắm ý chính của nó là được rồi).
//test input to control player character
void CCharacterManager::ControlPlayer() {
if ((player->bDie) | (player->bAnimBehavior == ANI_DIE)) return;
d = 0;
if (iInput::GetKeyState(HGEK_UP)) d += 1;
if (iInput::GetKeyState(HGEK_DOWN)) d += 18;
if (iInput::GetKeyState(HGEK_RIGHT)) d += 9;
if (iInput::GetKeyState(HGEK_LEFT)) d += 36;
switch (d) {
case 1:
d = DIR_N;
break;
case 9:
d = DIR_E;
break;
case 18:
d = DIR_S;
break;
case 36:
d = DIR_W;
break;
case 10:
d = DIR_NE;
break;
case 27:
d = DIR_SE;
break;
case 54:
d = DIR_SW;
break;
case 37:
d = DIR_NW;
break;
default:
d = 255;
break;
}
bool temp = true;
if (iInput::GetKeyState(HGEK_CTRL)) {
if ((d < 8) && (player->bAnimBehavior != ANI_ATTACK)) player->bCurrentDir = d;
if ((player->bAnimBehavior == ANI_STAND) | ((player->bAnimBehavior == ANI_WALK) && (player->fDimX == player->fDestX) && (player->fDimY == player->fDestY))) {
temp = false;
player->SetBehavior(ANI_ATTACK);
}
}
if (player->bAnimBehavior == ANI_ATTACK) temp = false;
if (temp) {
if (d < 8) {
MovePlayer(d);
}
else {
if ((player->bAnimBehavior != ANI_STAND) && (player->fDimX == player->fDestX) && (player->fDimY == player->fDestY)) {
player->SetBehavior(ANI_STAND);
}
}
}
}
//AI control monsters
void CCharacterManager::ControlMonsters() {
int i;
BYTE b1, b2;
FindWaypoint(monster[queue]);
queue++;
if (queue == iMonsterCount) queue = 0;
for (i = 0; i < iMonsterCount; i++) {
if ((!monster->bDie) && (monster->bAnimBehavior != ANI_DIE)) {
b1 = b2 = 2;
if (monster->iCellX < player->iCellX) b1 = 1;
if (monster->iCellX > player->iCellX) b1 = 0;
if (monster->iCellY < player->iCellY) b2 = 1;
if (monster->iCellY > player->iCellY) b2 = 0;
d = bDirConv[b1][b2];
if (d < 255) {
x1 = monster->iCellX + iDirDX[d];
y1 = monster->iCellY + iDirDY[d];
if ((x1 >= 0) && (x1 < pTileMap->iMapWidth) && (y1 >= 0) && (y1 < pTileMap->iMapHeight)) {
if ((!player->bDie) && (bOccupacy[x1][y1] == 1)) { //player in attack range
if ((d < 8) && (monster->bAnimBehavior != ANI_ATTACK)) monster->bCurrentDir = d;
if ((monster->bAnimBehavior == ANI_STAND) | ((monster->bAnimBehavior == ANI_WALK) && (monster->fDimX == monster->fDestX) && (monster->fDimY == monster->fDestY))) {
monster->SetBehavior(ANI_ATTACK);
return;
}
}
}
if (monster->pWaypoint->size) {
b1 = b2 = 2;
if (monster->iCellX < monster->pWaypoint->head->data->x) b1 = 1;
if (monster->iCellX > monster->pWaypoint->head->data->x) b1 = 0;
if (monster->iCellY < monster->pWaypoint->head->data->y) b2 = 1;
if (monster->iCellY > monster->pWaypoint->head->data->y) b2 = 0;
d = bDirConv[b1][b2];
monster->pWaypoint->Delete();
MoveCharacter(monster, d, i + 2);
}
}
}
}
}
Source của animate:
//Animate a character c
void CCharacterManager::AnimateCharacter(CCharacter *c) {
if (!c->bDie) {
if (c->bAnimBehavior == ANI_WALK) {
c->NextFrame();
if (c->fDimX < c->fDestX) {
c->fDimX += c->fMoveRate;
if (c->fDimX > c->fDestX) c->fDimX = c->fDestX;
}
else if (c->fDimX > c->fDestX) {
c->fDimX -= c->fMoveRate;
if (c->fDimX < c->fDestX) c->fDimX = c->fDestX;
}
if (c->fDimY < c->fDestY) {
c->fDimY += c->fMoveRate;
if (c->fDimY > c->fDestY) c->fDimY = c->fDestY;
}
else if (c->fDimY > c->fDestY) {
c->fDimY -= c->fMoveRate;
if (c->fDimY < c->fDestY) c->fDimY = c->fDestY;
}
}
else if (c->bAnimBehavior == ANI_ATTACK) {
if (!(c->iAnimFrame | c->iAnimCounter)) {
iEffect::Play(c->cType->sound);
}
c->NextFrame();
if (!(c->iAnimFrame | c->iAnimCounter)) {
c->SetBehavior(ANI_STAND);
x1 = c->iCellX + iDirDX[c->bCurrentDir];
y1 = c->iCellY + iDirDY[c->bCurrentDir];
if ((x1 >= 0) && (x1 < pTileMap->iMapWidth) && (y1 >= 0) && (y1 < pTileMap->iMapHeight)) {
if (c == player) {
if (bOccupacy[x1][y1] > 1) { //hit a monster
i = bOccupacy[x1][y1] - 2;
if ((!monster->bDie) && (monster->bAnimBehavior != ANI_DIE)) {
//test "real" position of the monster (because
//when moving, the position of the monster is
//set to an "unactual" one.
x1 = (int) (monster->fDimX / HALF_TILE_WIDTH) >> 1;
y1 = (int) (monster->fDimY / HALF_TILE_HEIGHT) >> 1;
if ((x1 == monster->iCellX) && (y1 == monster->iCellY)) {
monster->iHitPoint -= player->cType->iDamage; //damage the monster
if (monster->iHitPoint <= 0) monster->SetBehavior(ANI_DIE);
}
}
}
}
else {
if (bOccupacy[x1][y1] == 1) { //hit the player
if ((!player->bDie) && (player->bAnimBehavior != ANI_DIE)) {
//test "real" position of the player (because
//when moving, the position of the player is
//set to an "unactual" one.
x1 = (int) (player->fDimX / HALF_TILE_WIDTH) >> 1;
y1 = (int) (player->fDimY / HALF_TILE_HEIGHT) >> 1;
if ((x1 == player->iCellX) && (y1 == player->iCellY)) {
player->iHitPoint -= monster->cType->iDamage; //damage the player
if (player->iHitPoint <= 0) player->SetBehavior(ANI_DIE);
}
}
}
}
}
}
}
else if (c->bAnimBehavior == ANI_STAND) {
c->NextFrame();
}
else if (c->bAnimBehavior == ANI_DIE) {
if (!(c->iAnimFrame | c->iAnimCounter)) iEffect::Play(c->cType->sound2);
c->NextFrame();
if (c->iAnimFrame == c->cType->iFrameCount[ANI_DIE] - 1) {
bOccupacy[c->iCellX][c->iCellY] = 0;
c->bRenderPriority = RENDER_LOW;
c->bDie = true;
c->fDimX += iUtils::Rnd(-4, 4);
c->fDimY += iUtils::Rnd(-4, 4);
}
}
}
}