363 lines
10 KiB
C
363 lines
10 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdbool.h>
|
|
#include <math.h>
|
|
#include "data.h"
|
|
|
|
#define MAX_UNITS 100
|
|
#define MAX_BUILDINGS 50
|
|
|
|
typedef struct Node {
|
|
int x, y;
|
|
int gCost; // Cost from start node
|
|
int hCost; // Heuristic cost to target node
|
|
struct Node* parent;
|
|
} Node;
|
|
|
|
// Function to calculate the distance between two points using Manhattan distance
|
|
int calculateDistance(int x1, int y1, int x2, int y2) {
|
|
return abs(x1 - x2) + abs(y1 - y2);
|
|
}
|
|
|
|
bool isUnitOrBuildingAtPosition(GameData* data, int x, int y) {
|
|
for (int i = 0; i < MAX_UNITS; i++) {
|
|
if (data->units[i].unitID != -1 && data->units[i].x == x && data->units[i].y == y) {
|
|
// Found a unit at the position
|
|
return true;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < MAX_BUILDINGS; i++) {
|
|
if (data->buildings[i].buildingID != -1 && data->buildings[i].x == x && data->buildings[i].y == y) {
|
|
// Found a building at the position
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// No unit or building found at the position
|
|
return false;
|
|
}
|
|
|
|
// A* algorithm implementation
|
|
void aStarPathfinding(GameData* map, int startX, int startY, int targetX, int targetY) {
|
|
// Create start and target nodes
|
|
Node startNode = {startX, startY, 0, 0, NULL};
|
|
Node targetNode = {targetX, targetY, 0, 0, NULL};
|
|
|
|
// Create open and closed lists
|
|
Node* openList = malloc(sizeof(Node) * MAP_SIZE * MAP_SIZE);
|
|
Node* closedList = malloc(sizeof(Node) * MAP_SIZE * MAP_SIZE);
|
|
int openListCount = 0;
|
|
int closedListCount = 0;
|
|
|
|
// Add start node to open list
|
|
openList[openListCount++] = startNode;
|
|
|
|
while (openListCount > 0) {
|
|
// Find the node with the lowest fCost in the open list
|
|
int currentIndex = 0;
|
|
for (int i = 0; i < openListCount; i++) {
|
|
if (openList[i].gCost + openList[i].hCost < openList[currentIndex].gCost + openList[currentIndex].hCost) {
|
|
currentIndex = i;
|
|
}
|
|
}
|
|
|
|
// Move current node to the closed list
|
|
Node currentNode = openList[currentIndex];
|
|
openList[currentIndex] = openList[--openListCount];
|
|
closedList[closedListCount++] = currentNode;
|
|
|
|
// Check if we have reached the target node
|
|
if (currentNode.x == targetNode.x && currentNode.y == targetNode.y) {
|
|
// Path found, reconstruct and print the path
|
|
while (currentNode.parent != NULL) {
|
|
printf("(%d, %d) -> ", currentNode.x, currentNode.y);
|
|
currentNode = *currentNode.parent;
|
|
}
|
|
printf("(%d, %d)\n", startX, startY);
|
|
break;
|
|
}
|
|
|
|
// Generate neighboring nodes
|
|
for (int i = -1; i <= 1; i++) {
|
|
for (int j = -1; j <= 1; j++) {
|
|
if (i == 0 && j == 0) continue;
|
|
|
|
int neighborX = currentNode.x + i;
|
|
int neighborY = currentNode.y + j;
|
|
|
|
// Ignore invalid neighbors or obstacles
|
|
if (neighborX < 0 || neighborX >= MAP_SIZE || neighborY < 0 || neighborY >= MAP_SIZE ||
|
|
map->currentMap.tileData[neighborX][neighborY] == 1 || isUnitOrBuildingAtPosition(map, neighborX, neighborY)) {
|
|
continue;
|
|
}
|
|
|
|
// Calculate neighbor costs
|
|
int gCost = currentNode.gCost + 1; // Assuming uniform movement cost
|
|
int hCost = calculateDistance(neighborX, neighborY, targetNode.x, targetNode.y);
|
|
|
|
// Check if neighbor is in the closed list
|
|
bool inClosedList = false;
|
|
for (int k = 0; k < closedListCount; k++) {
|
|
if (closedList[k].x == neighborX && closedList[k].y == neighborY) {
|
|
inClosedList = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!inClosedList) {
|
|
// Check if neighbor is in the open list
|
|
bool inOpenList = false;
|
|
for (int k = 0; k < openListCount; k++) {
|
|
if (openList[k].x == neighborX && openList[k].y == neighborY) {
|
|
inOpenList = true;
|
|
if (gCost < openList[k].gCost) {
|
|
openList[k].gCost = gCost;
|
|
openList[k].parent = ¤tNode;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!inOpenList) {
|
|
// Add neighbor to open list
|
|
openList[openListCount++] = (Node){neighborX, neighborY, gCost, hCost, ¤tNode};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
free(openList);
|
|
free(closedList);
|
|
}
|
|
|
|
// goap
|
|
|
|
typedef struct {
|
|
int targetX, targetY; // The target position for the unit
|
|
} MoveGoal;
|
|
|
|
typedef struct {
|
|
int unitID; // The ID of the unit to move
|
|
int targetX, targetY; // The target position
|
|
} MoveAction;
|
|
|
|
bool canMove(GameData* gameData, MoveAction* action) {
|
|
// Find the unit in the game data
|
|
for (int i = 0; i < MAX_UNITS; i++) {
|
|
if (gameData->units[i].unitID == action->unitID) {
|
|
// Check if the unit is within range of the target
|
|
int distance = abs(gameData->units[i].x - action->targetX) + abs(gameData->units[i].y - action->targetY);
|
|
return distance <= 5; // Assuming a unit can move up to 5 tiles in one action
|
|
}
|
|
}
|
|
return false; // Unit not found
|
|
}
|
|
|
|
|
|
MoveAction* planMove(GameData* gameData, MoveGoal* goal) {
|
|
// For simplicity, we'll just select the first unit that can move to the goal
|
|
for (int i = 0; i < MAX_UNITS; i++) {
|
|
MoveAction action = {gameData->units[i].unitID, goal->targetX, goal->targetY};
|
|
if (canMove(gameData, &action)) {
|
|
return &action; // Return the action
|
|
}
|
|
}
|
|
return NULL; // No action found
|
|
}
|
|
|
|
|
|
void updateGame(GameData* gameData) {
|
|
// Update game state...
|
|
|
|
// Example: Plan a move for a unit
|
|
MoveGoal goal = {10, 20}; // Move to position (10, 20)
|
|
MoveAction* action = planMove(gameData, &goal);
|
|
if (action != NULL) {
|
|
// Execute the action...
|
|
}
|
|
}
|
|
|
|
void moveUnit(Unit* unit, int targetX, int targetY) {
|
|
// Move the unit to the target position
|
|
unit->x = targetX;
|
|
unit->y = targetY;
|
|
printf("Unit %d moved to (%d, %d).\n", unit->unitID, unit->x, unit->y);
|
|
}
|
|
|
|
// Sample GOAP planning logic for moving a unit to a target position
|
|
void planActions(GameData* gameData) {
|
|
// Assuming we want to move Unit 0 to position (10, 10)
|
|
int targetX = 10;
|
|
int targetY = 10;
|
|
|
|
// Find the Unit with unitID 0
|
|
Unit* unitToMove = NULL;
|
|
for (int i = 0; i < MAX_UNITS; i++) {
|
|
if (gameData->units[i].unitID == 0) {
|
|
unitToMove = &gameData->units[i];
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (unitToMove != NULL) {
|
|
// Implement planning logic here to move the unit to the target position
|
|
printf("Planning to move Unit %d to (%d, %d)...\n", unitToMove->unitID, targetX, targetY);
|
|
|
|
// Execute the action to move the unit
|
|
moveUnit(unitToMove, targetX, targetY);
|
|
} else {
|
|
printf("Unit with ID 0 not found.\n");
|
|
}
|
|
}
|
|
|
|
// behavior tree
|
|
|
|
typedef enum {
|
|
NODE_SELECTOR,
|
|
NODE_SEQUENCE,
|
|
NODE_ACTION,
|
|
NODE_CONDITION
|
|
} NodeType;
|
|
|
|
typedef struct Node {
|
|
NodeType type;
|
|
int (*execute)(struct Node*);
|
|
} Node;
|
|
|
|
|
|
int executeAction(Node* node) {
|
|
// Placeholder for action execution
|
|
return 1; // Assume action is successful
|
|
}
|
|
|
|
int executeCondition(Node* node) {
|
|
// Placeholder for condition checking
|
|
return 1; // Assume condition is true
|
|
}
|
|
|
|
int executeSelector(Node* node) {
|
|
// Selector node executes its children until one succeeds
|
|
for (int i = 0; i < node->numChildren; i++) {
|
|
if (node->children[i]->execute(node->children[i])) {
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int executeSequence(Node* node) {
|
|
// Sequence node executes its children in order until one fails
|
|
for (int i = 0; i < node->numChildren; i++) {
|
|
if (!node->children[i]->execute(node->children[i])) {
|
|
return 0;
|
|
}
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
|
|
Node* createMoveToTargetBehavior() {
|
|
Node* moveToTarget = malloc(sizeof(Node));
|
|
moveToTarget->type = NODE_ACTION;
|
|
moveToTarget->execute = executeAction;
|
|
// Additional setup for the move action...
|
|
return moveToTarget;
|
|
}
|
|
|
|
Node* createAttackEnemyBehavior() {
|
|
Node* attackEnemy = malloc(sizeof(Node));
|
|
attackEnemy->type = NODE_ACTION;
|
|
attackEnemy->execute = executeAction;
|
|
// Additional setup for the attack action...
|
|
return attackEnemy;
|
|
}
|
|
|
|
Node* createPatrolAreaBehavior() {
|
|
Node* patrolArea = malloc(sizeof(Node));
|
|
patrolArea->type = NODE_ACTION;
|
|
patrolArea->execute = executeAction;
|
|
// Additional setup for the patrol action...
|
|
return patrolArea;
|
|
}
|
|
|
|
|
|
Node* createBehaviorTree() {
|
|
Node* root = malloc(sizeof(Node));
|
|
root->type = NODE_SELECTOR;
|
|
root->execute = executeSelector;
|
|
root->numChildren = 3;
|
|
root->children = malloc(sizeof(Node*) * 3);
|
|
|
|
root->children[0] = createMoveToTargetBehavior();
|
|
root->children[1] = createAttackEnemyBehavior();
|
|
root->children[2] = createPatrolAreaBehavior();
|
|
|
|
return root;
|
|
}
|
|
|
|
|
|
void updateUnitBehavior(Node* behaviorTree) {
|
|
behaviorTree->execute(behaviorTree);
|
|
}
|
|
|
|
|
|
// Define the possible return status of a behavior node
|
|
typedef enum {
|
|
SUCCESS,
|
|
FAILURE,
|
|
RUNNING
|
|
} Status;
|
|
|
|
// Define a function pointer type for the behavior node
|
|
typedef Status (*NodeFunction)();
|
|
|
|
// Behavior Tree nodes (functions)
|
|
Status sequence();
|
|
Status selector();
|
|
Status action1();
|
|
Status action2();
|
|
|
|
// Sample action nodes
|
|
Status action1() {
|
|
printf("Executing Action 1\n");
|
|
return SUCCESS;
|
|
}
|
|
|
|
Status action2() {
|
|
printf("Executing Action 2\n");
|
|
return SUCCESS;
|
|
}
|
|
|
|
// Function to save behavior tree to a file
|
|
void saveBehaviorTreeToFile(const char* filename, NodeFunction root) {
|
|
FILE* file = fopen(filename, "wb");
|
|
|
|
if (file == NULL) {
|
|
printf("Error opening file for writing\n");
|
|
return;
|
|
}
|
|
|
|
// Write the address of the root function to the file
|
|
fwrite(&root, sizeof(NodeFunction), 1, file);
|
|
|
|
fclose(file);
|
|
}
|
|
|
|
// Function to load behavior tree from a file
|
|
NodeFunction loadBehaviorTreeFromFile(const char* filename) {
|
|
FILE* file = fopen(filename, "rb");
|
|
|
|
if (file == NULL) {
|
|
printf("Error opening file for reading\n");
|
|
return NULL;
|
|
}
|
|
|
|
NodeFunction root;
|
|
fread(&root, sizeof(NodeFunction), 1, file);
|
|
|
|
fclose(file);
|
|
|
|
return root;
|
|
} |