*Removed decceleration for camera.

Improved pathfinding when a unit collides with another unit.
Added generic function to find distances.
Other minor changes.
This commit is contained in:
XaviDCR92 2017-11-05 19:08:38 +01:00
parent 2d04eba931
commit 7b05778e3e
10 changed files with 2065 additions and 1949 deletions

View File

@ -105,31 +105,17 @@ void CameraUpdateSpeed(TYPE_CAMERA* ptrCamera)
}
if ( (PadButtonPressed(PAD_LEFT) == false)
&&
(PadButtonPressed(PAD_RIGHT) == false) )
&&
(PadButtonPressed(PAD_RIGHT) == false) )
{
if (ptrCamera->X_Speed > 0)
{
ptrCamera->X_Speed--;
}
else if (ptrCamera->X_Speed < 0)
{
ptrCamera->X_Speed++;
}
ptrCamera->X_Speed = 0;
}
if ( (PadButtonPressed(PAD_UP) == false)
&&
(PadButtonPressed(PAD_DOWN) == false) )
&&
(PadButtonPressed(PAD_DOWN) == false) )
{
if (ptrCamera->Y_Speed > 0)
{
ptrCamera->Y_Speed--;
}
else if (ptrCamera->Y_Speed < 0)
{
ptrCamera->Y_Speed++;
}
ptrCamera->Y_Speed = 0;
}
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -181,7 +181,7 @@ void Player::ShowResources(void)
GfxPrintTextFont(str, font3x3, 42, 1);
Systemitoa(str, 3, unit_i);
Systemitoa(str, 3, getAliveUnits());
for (i = 0; i < 3; i++)
{
@ -259,6 +259,21 @@ bool Player::checkNewBuildingPosition(TYPE_COLLISION_BLOCK * cb)
return true;
}
uint8_t Player::getAliveUnits(void)
{
uint8_t ret = 0;
for (uint8_t i = 0; i < unit_i; i++)
{
if (units[i].alive != false)
{
ret++;
}
}
return ret;
}
void Player::createUnit(TYPE_UNIT_ID id, TYPE_COLLISION_BLOCK cb)
{
TYPE_RESOURCES res = UnitNeededResourcesFromID(id);
@ -273,20 +288,27 @@ void Player::createUnit(TYPE_UNIT_ID id, TYPE_COLLISION_BLOCK cb)
return;
}
if (unit_i < PLAYER_MAX_UNITS_BUILDINGS)
if (getAliveUnits() < PLAYER_MAX_UNITS_BUILDINGS)
{
TYPE_UNIT* ptrNewUnit = &units[unit_i++];
ptrNewUnit->id = id;
ptrNewUnit->x = cb.x;
ptrNewUnit->y = cb.y;
ptrNewUnit->hp = UnitGetHpFromID(id);
ptrNewUnit->alive = true;
ptrNewUnit->building = (id > MAX_UNIT_ID);
for (uint8_t i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
if (units[i].alive == false)
{
TYPE_UNIT* ptrNewUnit = &units[unit_i++];
ptrNewUnit->id = id;
ptrNewUnit->x = cb.x;
ptrNewUnit->y = cb.y;
ptrNewUnit->hp = UnitGetHpFromID(id);
ptrNewUnit->alive = true;
ptrNewUnit->building = (id > MAX_UNIT_ID);
/* Substract resources from player */
Resources.Wood -= res.Wood;
Resources.Gold -= res.Gold;
Resources.Food -= res.Food;
/* Substract resources from player */
Resources.Wood -= res.Wood;
Resources.Gold -= res.Gold;
Resources.Food -= res.Food;
return;
}
}
}
else
{
@ -296,21 +318,32 @@ void Player::createUnit(TYPE_UNIT_ID id, TYPE_COLLISION_BLOCK cb)
TYPE_COLLISION_BLOCK Player::GetCursorPos(void)
{
enum
{
MOUSE_W = 8,
MOUSE_H = 8
};
TYPE_COLLISION_BLOCK cb;
cb.x = (X_SCREEN_RESOLUTION >> 1) - 4 - Camera.X_Offset;
cb.y = (Y_SCREEN_RESOLUTION >> 1) - 4 - Camera.Y_Offset;
cb.w = 8;
cb.h = 8;
cb.w = MOUSE_W;
cb.h = MOUSE_H;
return cb;
}
void Player::UnitBuildingSelection(void)
{
enum
{
MAX_ALLOWED_DISTANCE = (X_SCREEN_RESOLUTION * X_SCREEN_RESOLUTION) + (Y_SCREEN_RESOLUTION) * (Y_SCREEN_RESOLUTION)
};
uint16_t i;
uint32_t nearest_unit_dist = 0xFFFFFFFF; // Set maximum value
uint32_t dist;
uint32_t dist = nearest_unit_dist;
int8_t nearest_unit = NO_SELECTION;
@ -318,7 +351,7 @@ void Player::UnitBuildingSelection(void)
{
TYPE_UNIT* u = &units[i];
if ( (u->alive == false) || (u->selected != false) )
if ( (u->alive == false) || (u->selected != false) )
{
continue;
}
@ -329,7 +362,7 @@ void Player::UnitBuildingSelection(void)
uint16_t dist_x = (u_cb.x + (u_cb.w >> 1) - cursor_cb.x);
uint16_t dist_y = (u_cb.y + (u_cb.h >> 1) - cursor_cb.y);
dist = (dist_x * dist_x) + (dist_y * dist_y);
dist = SystemGetHyp(dist_x, dist_y);
if (dist < nearest_unit_dist)
{
@ -338,7 +371,7 @@ void Player::UnitBuildingSelection(void)
}
}
selectedUnitCandidate = nearest_unit;
selectedUnitCandidate = dist < (uint32_t)MAX_ALLOWED_DISTANCE? nearest_unit: NO_SELECTION;
}
void Player::ActionsMenu(void)
@ -353,18 +386,21 @@ void Player::ActionsMenu(void)
{
uint8_t availableActions = UnitGetAvailableActions(ptrUnit);
if (!(availableActions & (1 << showActionsMenu_index) ) )
if (availableActions != 0)
{
IncreaseShowActionsMenuIndex();
if (!(availableActions & (1 << showActionsMenu_index) ) )
{
IncreaseShowActionsMenuIndex();
}
UNIT_ACTION action = (UNIT_ACTION)(showActionsMenu_index);
const char* str = UnitGetActionString(action);
GfxPrintTextFont(str, font3x3, 40, Y_SCREEN_RESOLUTION - 4);
break;
}
UNIT_ACTION action = (UNIT_ACTION)(showActionsMenu_index);
const char* str = UnitGetActionString(action);
GfxPrintTextFont(str, font3x3, 40, Y_SCREEN_RESOLUTION - 4);
break;
}
}
@ -428,7 +464,6 @@ void Player::ButtonAPressed(void)
}
}
void Player::ButtonAReleased(void)
{
if (showActionsMenu_counter < ACCEPT_UNIT_BUILDING_OPTIONS_FRAMES)
@ -469,11 +504,11 @@ void Player::ButtonAReleased(void)
break;
case ACTION_BUILD_BARRACKS:
ActionCreateBuilding(ptrUnit, BARRACKS);
ActionCreateBuilding(BARRACKS);
break;
case ACTION_BUILD_TOWER_CENTER:
ActionCreateBuilding(ptrUnit, TOWN_CENTER);
ActionCreateBuilding(TOWN_CENTER);
break;
default:
@ -490,40 +525,51 @@ void Player::ButtonAReleased(void)
void Player::ActionCreateUnit(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID unit)
{
uint8_t w = UnitGetWidthFromID(ptrUnit->id);
uint8_t h = UnitGetHeightFromID(ptrUnit->id);
uint8_t new_pos_x = ptrUnit->x + SystemRand(0, w + (w >> 1));
uint8_t new_pos_y = ptrUnit->y + SystemRand(h, h + (h >> 1));
TYPE_COLLISION_BLOCK cb = {.x = new_pos_x, .y = new_pos_y};
enum
{
MAX_RETRIES = 16
};
createUnit(unit, cb);
uint8_t retries = 0;
do
{
uint8_t w = UnitGetWidthFromID(ptrUnit->id);
uint8_t h = UnitGetHeightFromID(ptrUnit->id);
uint8_t new_pos_x = ptrUnit->x + SystemRand(0, w + (w >> 1));
uint8_t new_pos_y = ptrUnit->y + SystemRand(h, h + (h >> 1));
TYPE_COLLISION_BLOCK cb = { .x = new_pos_x,
.y = new_pos_y,
.w = UnitGetWidthFromID(unit),
.h = UnitGetHeightFromID(unit)};
if (UnitCheckCollisionAgainstOtherUnits(&cb, units, NULL) == false)
{
createUnit(unit, cb);
return;
}
}while (++retries < MAX_RETRIES);
/* Will only get here if we could not create the new unit */
GfxPrintText_Flash(F("Could not create unit"));
}
void Player::ActionCreateBuilding(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID bldg)
void Player::ActionCreateBuilding(TYPE_UNIT_ID bldg)
{
TYPE_COLLISION_BLOCK cb = GetCursorPos();
for (uint8_t i = 0; i < unit_i; i++)
cb.w = UnitGetWidthFromID(bldg);
cb.w = UnitGetHeightFromID(bldg);
if (UnitCheckCollisionAgainstOtherUnits(&cb, units, NULL) == false)
{
TYPE_UNIT* ptrOtherUnit = &units[i];
TYPE_COLLISION_BLOCK ocb = {.x = ptrOtherUnit->x,
.y = ptrOtherUnit->y,
.w = UnitGetWidthFromID(ptrOtherUnit->id),
.h = UnitGetHeightFromID(ptrOtherUnit->id)};
if (ptrOtherUnit->alive == false)
{
continue;
}
if (SystemCollisionCheck(&cb, &ocb) != false)
{
GfxPrintText_Flash(F("Cannot build here"));
return;
}
createUnit(bldg, cb);
}
else
{
GfxPrintText_Flash(F("Cannot build here"));
}
createUnit(bldg, cb);
}
void Player::ButtonBPressed(void)

View File

@ -47,6 +47,7 @@ class Player
void createUnit(TYPE_UNIT_ID id, TYPE_COLLISION_BLOCK cb);
uint8_t getPopulation(void) {return (unit_i + 1);}
void ShowResources(void);
uint8_t getAliveUnits(void);
private:
// Player definition
@ -93,7 +94,10 @@ class Player
// Action callbacks
void ActionCreateUnit(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID unit);
void ActionCreateBuilding(TYPE_UNIT* ptrUnit, TYPE_UNIT_ID bldg);
void ActionCreateBuilding(TYPE_UNIT_ID bldg);
// Collision detection
bool checkCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb);
};
#endif // __cplusplus

View File

@ -326,3 +326,8 @@ bool Systemitoa(char* str, size_t sz, int16_t value)
return false;
}
uint32_t SystemGetHyp(uint16_t x, uint16_t y)
{
return (uint32_t)((uint32_t)(x * x) + (uint32_t)(y * y));
}

View File

@ -87,6 +87,8 @@ bool SystemArrayCompare(unsigned short * arr1, unsigned short * arr2, size_t sz)
bool SystemCollisionCheck(TYPE_COLLISION_BLOCK* c1, TYPE_COLLISION_BLOCK* c2);
// Transforms integer to string. Use this instead of sprintf() as much as possible.
bool Systemitoa(char* str, size_t sz, int16_t value);
// Return hypothenuse of two points
uint32_t SystemGetHyp(uint16_t x, uint16_t y);
/* **************************************
* Global Variables *

119
Unit.c
View File

@ -36,30 +36,29 @@ struct t_coordinates
/* Tables */
static uint8_t const UnitHPTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = 25,
[SOLDIER] = 80,
[BARRACKS] = 100,
[TOWN_CENTER] = 200 };
[SOLDIER] = 80,
[BARRACKS] = 100,
[TOWN_CENTER] = 200 };
static TYPE_RESOURCES const UnitResourcesTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = {.Wood = 0, .Gold = 0, .Food = 50},
[SOLDIER] = {.Wood = 25, .Gold = 10, .Food = 50},
[BARRACKS] = {.Wood = 100, .Gold = 0, .Food = 0},
[TOWN_CENTER] = {.Wood = 200, .Gold = 0, .Food = 0} };
[SOLDIER] = {.Wood = 25, .Gold = 10, .Food = 50},
[BARRACKS] = {.Wood = 100, .Gold = 0, .Food = 0},
[TOWN_CENTER] = {.Wood = 200, .Gold = 0, .Food = 0} };
static uint8_t const UnitSpeedTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = 1,
[SOLDIER] = 1,
[BARRACKS] = 0,
[TOWN_CENTER] = 0 };
[SOLDIER] = 1,
[BARRACKS] = 0,
[TOWN_CENTER] = 0 };
static const char* const UnitActionsTable_Level[MAX_ACTIONS] = { [ACTION_BUILD_BARRACKS] = "B.BARR",
[ACTION_ATTACK] = "ATTACK",
[ACTION_CREATE_PEASANT] = "C.PEAS.",
[ACTION_CREATE_SOLDIER] = "C.SLDR.",
[ACTION_BUILD_TOWER_CENTER] = "C.TWNC."};
[ACTION_CREATE_PEASANT] = "C.PEAS.",
[ACTION_CREATE_SOLDIER] = "C.SLDR.",
[ACTION_BUILD_TOWER_CENTER] = "C.TWNC."};
static uint8_t const UnitActionsTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = ((1 << ACTION_BUILD_BARRACKS) | (1 << ACTION_BUILD_TOWER_CENTER) | (1 << ACTION_ATTACK)),
[SOLDIER] = (1 << ACTION_ATTACK),
[BARRACKS] = (1 << ACTION_CREATE_SOLDIER),
[TOWN_CENTER] = (1 << ACTION_CREATE_PEASANT) };
static uint8_t const UnitActionsTable[MAX_UNITS_BUILDINGS] = { [PEASANT] = ((1 << ACTION_BUILD_BARRACKS) | (1 << ACTION_BUILD_TOWER_CENTER)),
[SOLDIER] = 0,
[BARRACKS] = (1 << ACTION_CREATE_SOLDIER),
[TOWN_CENTER] = (1 << ACTION_CREATE_PEASANT) };
// **************
// Sprite tables
@ -282,6 +281,36 @@ void UnitAttackAccepted(TYPE_UNIT* ptrUnit)
ptrUnit->selecting_attack = true;
}
bool UnitCheckCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb, TYPE_UNIT* ptrUnitArray, TYPE_UNIT* ptrCurrentUnit)
{
for (uint8_t i = 0; i < PLAYER_MAX_UNITS_BUILDINGS; i++)
{
TYPE_UNIT* ptrOtherUnit = &ptrUnitArray[i];
TYPE_COLLISION_BLOCK ocb = {.x = ptrOtherUnit->x,
.y = ptrOtherUnit->y,
.w = UnitGetWidthFromID(ptrOtherUnit->id),
.h = UnitGetHeightFromID(ptrOtherUnit->id)};
if (ptrOtherUnit->alive == false)
{
continue;
}
if (ptrOtherUnit == ptrCurrentUnit)
{
/* We are referring to the same TYPE_UNIT instance. Discard. */
continue;
}
if (SystemCollisionCheck(cb, &ocb) != false)
{
return true;
}
}
return false;
}
void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
{
size_t i;
@ -330,41 +359,41 @@ void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
if (ptrUnit->walking != false)
{
// If player is still walking, check collisions
// against all other active units.
size_t j;
TYPE_COLLISION_BLOCK cu = { .x = ptrUnit->x + x_d,
.y = ptrUnit->y + y_d,
.w = UnitGetWidthFromID(ptrUnit->id),
.h = UnitGetHeightFromID(ptrUnit->id) };
for (j = 0; j < sz; j++)
if (UnitCheckCollisionAgainstOtherUnits(&cu, unitArray, ptrUnit) == true)
{
TYPE_UNIT* ptrOtherUnit = &unitArray[j];
uint32_t dist = 0;
uint32_t dist2 = 0;
TYPE_COLLISION_BLOCK cu = { .x = ptrUnit->x + x_d,
.y = ptrUnit->y + y_d,
.w = UnitGetWidthFromID(ptrUnit->id),
.h = UnitGetHeightFromID(ptrUnit->id) };
TYPE_COLLISION_BLOCK ou;
if (ptrOtherUnit->alive == false)
switch (ptrUnit->dir)
{
continue;
}
case DIRECTION_LEFT:
// Fall through
case DIRECTION_RIGHT:
dist = SystemGetHyp(abs(ptrUnit->x - ptrUnit->target_x), abs((ptrUnit->y + y_d) - ptrUnit->target_y));
dist2 = SystemGetHyp(abs(ptrUnit->x - ptrUnit->target_x), abs((ptrUnit->y - y_d) - ptrUnit->target_y));
if (j == i)
{
// Do not compare against itself!
continue;
}
y_d = dist < dist2? x_d: -x_d;
ptrUnit->dir = y_d? DIRECTION_DOWN: DIRECTION_UP;
ou.x = ptrOtherUnit->x;
ou.y = ptrOtherUnit->y;
ou.w = UnitGetWidthFromID(ptrOtherUnit->id);
ou.h = UnitGetHeightFromID(ptrOtherUnit->id);
x_d = 0;
break;
if (SystemCollisionCheck(&cu, &ou) != false)
{
//bMoving = false;
return;
case DIRECTION_UP:
// Fall through
case DIRECTION_DOWN:
dist = SystemGetHyp(abs((ptrUnit->x - x_d) - ptrUnit->target_x), abs(ptrUnit->y - ptrUnit->target_y));
dist2 = SystemGetHyp(abs((ptrUnit->x + x_d) - ptrUnit->target_x), abs(ptrUnit->y - ptrUnit->target_y));
x_d = dist < dist2? -y_d: -x_d;
ptrUnit->dir = x_d? DIRECTION_RIGHT: DIRECTION_LEFT;
y_d = 0;
break;
}
}
}
@ -373,7 +402,7 @@ void UnitHandler(TYPE_UNIT* unitArray, size_t sz)
if (ptrUnit->walking != false)
{
// If no collision is detected, keep moving to the new position
/* If no collision is detected, keep moving to the new position */
ptrUnit->x += x_d;
ptrUnit->y += y_d;
}

5
Unit.h
View File

@ -79,7 +79,6 @@ typedef struct
typedef enum t_availableactions
{
ACTION_BUILD_BARRACKS,
ACTION_ATTACK,
ACTION_CREATE_PEASANT,
ACTION_CREATE_SOLDIER,
ACTION_BUILD_TOWER_CENTER,
@ -107,8 +106,12 @@ TYPE_RESOURCES UnitNeededResourcesFromID(TYPE_UNIT_ID id);
// Rendering
void UnitDraw(TYPE_UNIT* ptrUnit, TYPE_CAMERA* ptrCamera, bool bHighlighted);
// Movement
void UnitMoveTo(TYPE_UNIT* ptrUnit, uint16_t x, uint16_t y);
// Collision cheking
bool UnitCheckCollisionAgainstOtherUnits(TYPE_COLLISION_BLOCK* cb, TYPE_UNIT* ptrUnitArray, TYPE_UNIT* ptrCurrentUnit);
// Selection index
const char* UnitGetActionString(UNIT_ACTION action);