Thanks, Mireben. That looks alot easier than I thought it was going to be. Unfortunately, I've got another bug with the damn raycasting. It seems as if the enemy is only pointing towards the player when the player is colliding with something, rather than when there is a clear line of sight. This error has left me utterly baffled. I have absolutely no idea what could be causing it to do this.
Here is the relevant section of the code (not much different from before):
// Set AI Task
//-------------------------------------------------------------------------
// Raycast from enemy to player
if (SC_RayCast (Player_Character_Mesh, dbObjectPositionX(Local_Character.Mesh), dbObjectPositionY(Local_Character.Mesh), dbObjectPositionZ(Local_Character.Mesh),
dbObjectPositionX(Player_Character_Mesh), Player_Height, dbObjectPositionZ(Player_Character_Mesh),
Local_Character.Mesh) == 1)
{
Local_Character.AI_Task = 2;
}
else
{
Local_Character.AI_Task = 0;
}
// Behavior based on AI Task
//-------------------------------------------------------------------------
// Oblivious
if (Local_Character.AI_Task == 0)
{
// Temporary
}
// Alerted
if (Local_Character.AI_Task == 2)
{
dbPointObject (Local_Character.Mesh, dbObjectPositionX(Player_Character_Mesh), dbObjectPositionY(Local_Character.Mesh), dbObjectPositionZ(Player_Character_Mesh));
}
Here is the entire code, just in case.
#include "DarkGDK.h"
#include "SC_Collision.h"
//-------------------------------------------------------------------------
// Global variables
//-------------------------------------------------------------------------
int ObjID = 1;
int TexID = 1;
int SndID = 1;
int Game_Mode = 0; // 0 = main menu, 1 = loading, 2 = gameplay, 3 = cutscene, 4 = pause menu
//-------------------------------------------------------------------------
// Structures
//-------------------------------------------------------------------------
// Structure for characters
struct Char_Struct
{
int Mesh; // .X mesh file for the character
int AI; // 0 = Player, 1 = Ally, 2 = Neutral, 3 = Enemy
int AI_Task; // Current action/task that the character is performing, irrelevant for player character
float Position[3]; // XYZ coordinate of the character's initial position in the level
float Rotation; // The character's initial rotation in the level
float Health_Max; // If max <= 0 the character is dead right from the start and therefore
float Health_Current; // only exists as a corpse, otherwise he/she will die when current <= 0
float Energy;
int Alert_Mode; // 0 = undetected, 1 = alert, 2 = searching, 3 = detected
};
// Structure for cover objects
struct Cover_Struct
{
int Mesh; // .X mesh file for the cover object
float Position[3]; // XYZ coordinate for the cover object's position
float Rotation; // Rotation of the cover object
float Health_Max; // If max < 0 the cover object is indestructible,
float Health_Current; // otherwise it will be destroyed when current <= 0
};
// Structure for hazards
struct Hazard_Struct
{
int Mesh; // .X mesh file for the hazard
float Position[3]; // XYZ coordinate for the hazard's position
float Rotation; // Rotation of the hazard
float Damage; // Damage that the hazard deals to a character who is inside it
};
// Structure for each item in a terminal's list
struct Terminal_Item_Struct
{
char Text[50]; // The text for the item that appears in the terminal screen
int Type; // The type of effect that is triggered when the item is selected in the terminal screen, 0 for non selectable (a.k.a. just a label)
int Target; // The target of the effect triggered by selecting the item, 0 for none if the effect type doesn't need one
};
// Structure for terminals
struct Terminal_Struct
{
int Mesh; // .X mesh file for the terminal
float Position[3]; // XYZ coordinate for the terminal's position
float Rotation; // Rotation of the terminal
struct Terminal_Item_Struct List[10]; // The list of items that appear in the terminal screen
};
// Structure for levels
struct Level
{
int Mesh; // .X mesh file for the level
float End_Position[3]; // A cube that ends the level when
float End_Scale[3]; // entered by the player
struct Char_Struct Character[200]; // Array of all the human characters in the level
struct Cover_Struct Cover[200]; // Array of all the cover objects in the level
struct Hazard_Struct Hazard[200]; // Array of all the hazards in the level
struct Terminal_Struct Terminal[200]; // Array of all the terminals in the level
int Waypoint[200][3]; // Array of all the XYZ coordinates for the waypoints used in the enemy patrol AI
};
//-------------------------------------------------------------------------
// Loading functions
//-------------------------------------------------------------------------
// Function to load 3D objects
int Load_3D (char Local_Filepath[], char Tex_Filepath[], int Local_Collision_Group)
{
int Local_ID;
// Generate an ID number for the mesh
Local_ID = ObjID;
++ObjID;
// Load the mesh
dbLoadObject (Local_Filepath, Local_ID);
// Load and apply the texture
dbLoadImage (Tex_Filepath, TexID);
dbTextureObject (Local_ID, TexID);
++TexID;
dbSetObjectTransparency (Local_ID, 1);
// Setup collision
if (Local_Collision_Group > 0)
{
SC_SetupObject (Local_ID, Local_Collision_Group, 0);
}
return Local_ID;
}
//-------------------------------------------------------------------------
// Structure Functions
//-------------------------------------------------------------------------
// Function to create a character
struct Char_Struct Create_Character (char Local_Mesh[], char Local_Tex[], int Local_AI, float Local_X, float Local_Y, float Local_Z, float Local_Rot, float Local_Health)
{
struct Char_Struct Local_Character;
// Load character mesh
Local_Character.Mesh = Load_3D (Local_Mesh, Local_Tex, 1);
// Set AI type
Local_Character.AI = Local_AI;
// Set starting position and rotation
Local_Character.Position[0] = Local_X;
Local_Character.Position[1] = Local_Y;
Local_Character.Position[2] = Local_Z;
Local_Character.Rotation = Local_Rot;
// Set health
Local_Character.Health_Max = Local_Health;
Local_Character.Health_Current = Local_Character.Health_Max;
// Position and rotate character
dbPositionObject (Local_Character.Mesh, Local_Character.Position[0], Local_Character.Position[1], Local_Character.Position[2]);
dbRotateObject (Local_Character.Mesh, 0, Local_Character.Rotation, 0);
// Update collision info
SC_UpdateObject (Local_Character.Mesh);
return Local_Character;
}
// Function to create a cover object
struct Cover_Struct Create_Cover (char Local_Mesh[], char Local_Tex[], float Local_X, float Local_Y, float Local_Z, float Local_Rot, float Local_Health)
{
struct Cover_Struct Local_Cover;
// Load cover mesh
Local_Cover.Mesh = Load_3D (Local_Mesh, Local_Tex, 1);
// Set position and rotation
Local_Cover.Position[0] = Local_X;
Local_Cover.Position[1] = Local_Y;
Local_Cover.Position[2] = Local_Z;
Local_Cover.Rotation = Local_Rot;
// Set health
Local_Cover.Health_Max = Local_Health;
Local_Cover.Health_Current = Local_Cover.Health_Max;
// Position and rotate cover object
dbPositionObject (Local_Cover.Mesh, Local_Cover.Position[0], Local_Cover.Position[1], Local_Cover.Position[2]);
dbRotateObject (Local_Cover.Mesh, 0, Local_Cover.Rotation, 0);
// Update collision info
SC_UpdateObject (Local_Cover.Mesh);
return Local_Cover;
}
// Function to create a hazard
struct Hazard_Struct Create_Hazard (char Local_Mesh[], char Local_Tex[], float Local_X, float Local_Y, float Local_Z, float Local_Rot, float Local_Damage)
{
struct Hazard_Struct Local_Hazard;
// Load hazard mesh
Local_Hazard.Mesh = Load_3D (Local_Mesh, Local_Tex, 2);
// Set position and rotation
Local_Hazard.Position[0] = Local_X;
Local_Hazard.Position[1] = Local_Y;
Local_Hazard.Position[2] = Local_Z;
Local_Hazard.Rotation = Local_Rot;
// Set Damage
Local_Hazard.Damage = Local_Damage;
// Position and rotate cover object
dbPositionObject (Local_Hazard.Mesh, Local_Hazard.Position[0], Local_Hazard.Position[1], Local_Hazard.Position[2]);
dbRotateObject (Local_Hazard.Mesh, 0, Local_Hazard.Rotation, 0);
// Update collision info
SC_UpdateObject (Local_Hazard.Mesh);
return Local_Hazard;
}
// Function to create a terminal
struct Terminal_Struct Create_Terminal (char Local_Mesh[], char Local_Tex[], float Local_X, float Local_Y, float Local_Z, float Local_Rot)
{
struct Terminal_Struct Local_Terminal;
// Load cover mesh
Local_Terminal.Mesh = Load_3D (Local_Mesh, Local_Tex, 0);
// Set position and rotation
Local_Terminal.Position[0] = Local_X;
Local_Terminal.Position[1] = Local_Y;
Local_Terminal.Position[2] = Local_Z;
Local_Terminal.Rotation = Local_Rot;
// Position and rotate cover object
dbPositionObject (Local_Terminal.Mesh, Local_Terminal.Position[0], Local_Terminal.Position[1], Local_Terminal.Position[2]);
dbRotateObject (Local_Terminal.Mesh, 0, Local_Terminal.Rotation, 0);
return Local_Terminal;
}
// Function to load the current level
struct Level Load_Level (char Local_Mesh[], char Local_Tex[])
{
struct Level Local_Level;
// Load world mesh
Local_Level.Mesh = Load_3D (Local_Mesh, Local_Tex, 1);
// Create characters
Local_Level.Character[0] = Create_Character ("Data/3D/Characters/TestPlayer/mesh.x", "Data/3D/Characters/TestPlayer/texture.dds", 0, -85.00, 2.00, -64.00, 90.00, 100);
Local_Level.Character[1] = Create_Character ("Data/3D/Characters/TestEnemy/mesh.x", "Data/3D/Characters/TestEnemy/texture.dds", 3, -55.836, 2.00, -22.187, -45, 20);
Local_Level.Character[2] = Create_Character ("Data/3D/Characters/TestEnemy/mesh.x", "Data/3D/Characters/TestEnemy/texture.dds", 3, -24.899, 2.00, -24.423, 45, 20);
Local_Level.Character[3] = Create_Character ("Data/3D/Characters/TestEnemy/mesh.x", "Data/3D/Characters/TestEnemy/texture.dds", 3, 37.500, 2.00, -6.000, 0, 20);
Local_Level.Character[4] = Create_Character ("Data/3D/Characters/TestEnemy/mesh.x", "Data/3D/Characters/TestEnemy/texture.dds", 3, 44.548, 2.00, -11.314, 120, 20);
// Create cover objects
Local_Level.Cover[0] = Create_Cover ("Data/3D/Objects/cover1/mesh.x", "Data/3D/Objects/cover1/texture.dds", -57.436, 2.5, -19.288, 0, -1);
Local_Level.Cover[1] = Create_Cover ("Data/3D/Objects/cover2/mesh.x", "Data/3D/Objects/cover2/texture.dds", -23.245, 2.5, -19.998, 0, -1);
Local_Level.Cover[2] = Create_Cover ("Data/3D/Objects/cover3/mesh.x", "Data/3D/Objects/cover3/texture.dds", 26.500, 2.582, 23.103, 0, -1);
// Create hazards
Local_Level.Hazard[0] = Create_Hazard ("Data/3D/Objects/testhazard/mesh.x", "Data/3D/Objects/testhazard/texture.dds", 10.00, 0, -64.00, 0, 1);
// Create terminals
Local_Level.Terminal[0] = Create_Terminal ("Data/3D/Objects/WallTerminal/mesh.x", "Data/3D/Objects/WallTerminal/texture.dds", -70.056, 2.5, -46.164, -30.963);
Local_Level.Terminal[1] = Create_Terminal ("Data/3D/Objects/WallTerminal/mesh.x", "Data/3D/Objects/WallTerminal/texture.dds", -44.631, 2.5, -26.811, -67.381);
Local_Level.Terminal[2] = Create_Terminal ("Data/3D/Objects/WallTerminal/mesh.x", "Data/3D/Objects/WallTerminal/texture.dds", -28.692, 2.5, -34.654, 30.964);
Local_Level.Terminal[3] = Create_Terminal ("Data/3D/Objects/WallTerminal/mesh.x", "Data/3D/Objects/WallTerminal/texture.dds", 25.505, 2.5, 46.114, 0);
Local_Level.Terminal[4] = Create_Terminal ("Data/3D/Objects/WallTerminal/mesh.x", "Data/3D/Objects/WallTerminal/texture.dds", 24.916, 2.5, -52.505, -67.375);
Local_Level.Terminal[5] = Create_Terminal ("Data/3D/Objects/WallTerminal/mesh.x", "Data/3D/Objects/WallTerminal/texture.dds", 33.446, 2.5, -38.944, 90);
return Local_Level;
}
// End_Level
//-------------------------------------------------------------------------
// Main function
//-------------------------------------------------------------------------
void DarkGDK (void)
{
// Initialization
//-------------------------------------------------------------------------
dbSyncOn ();
dbSetDisplayMode (dbDesktopWidth (), dbDesktopHeight(), 32);
dbSetWindowOff ();
dbAutoCamOff ();
dbHideMouse ();
dbColorBackdrop (dbRGB(0, 0, 0));
dbSetCameraRange (.001, 3000);
SC_Start();
// Variables
//-------------------------------------------------------------------------
struct Level Current_Level;
int Player_State;
float Speed_Mult;
float Camera_Initial_X;
float Camera_Initial_Y;
float Camera_Initial_Z;
// Main Loop
//-------------------------------------------------------------------------
for (int Main_Loop = 1; Main_Loop > 0;)
{
switch (Game_Mode)
{
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Main Menu
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
case 0:
Game_Mode = 1; // TEMPORARY
break;
//-------------------------------------------------------------------------
// Load Level
//-------------------------------------------------------------------------
case 1:
// Determine which level to load
// Create the level
Current_Level = Load_Level ("Data/3D/World/TestLevel/mesh.x", "Data/3D/World/TestLevel/texture.dds");
// Proceed to gameplay
Game_Mode = 2;
break;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Gameplay
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
case 2:
// If escape is pressed, go to pause menu
if (dbKeyState(1) == 1)
{
Game_Mode = 4;
}
// If the player is in the end area, execute Level_End
// Character Loop
int Player_Character_Mesh;
for (int Local_Loops = 0; dbObjectExist(Current_Level.Character[Local_Loops].Mesh) == 1; ++Local_Loops)
{
struct Char_Struct Local_Character = Current_Level.Character[Local_Loops];
float Initial_X = dbObjectPositionX(Local_Character.Mesh);
float Initial_Y = dbObjectPositionY(Local_Character.Mesh);
float Initial_Z = dbObjectPositionZ(Local_Character.Mesh);
switch (Local_Character.AI)
{
// Player
//--------------------------------------------------------------------------------------------------------------------------------------------------------
case 0:
Player_Character_Mesh = Local_Character.Mesh;
// Rotation
//-------------------------------------------------------------------------
dbRotateObject (Local_Character.Mesh, 0, dbObjectAngleY(Local_Character.Mesh) + (dbMouseMoveX() * .25), 0);
// Player State
//-------------------------------------------------------------------------
if (dbKeyState(29) == 1) // Crouch
{
Player_State = 3;
}
else if (dbKeyState(42) == 1) // Sprint
{
Player_State = 2;
}
else // Standing
{
Player_State = 1;
}
switch (Player_State)
{
// Crouch
//-------------------------------------------------------------------------
case 3:
dbSetObjectFrame (Local_Character.Mesh, dbTotalObjectFrames(Local_Character.Mesh));
Speed_Mult = .4;
break;
// Sprint
//-------------------------------------------------------------------------
case 2:
dbSetObjectFrame (Local_Character.Mesh, 0);
Speed_Mult = 3;
break;
// Standing
//-------------------------------------------------------------------------
case 1:
dbSetObjectFrame (Local_Character.Mesh, 0);
Speed_Mult = 1;
break;
}
// Movement
//-------------------------------------------------------------------------
if (dbKeyState(17) == 1) // Forward
{
dbMoveObject (Local_Character.Mesh, .10 * Speed_Mult);
}
if (Speed_Mult <= 1)
{
if (dbKeyState(31) == 1) // Backward
{
dbMoveObject (Local_Character.Mesh, -.10 * Speed_Mult);
}
if (dbKeyState(30) == 1) // Left
{
dbRotateObject (Local_Character.Mesh, 0, dbObjectAngleY(Local_Character.Mesh) - 90, 0);
dbMoveObject (Local_Character.Mesh, .10 * Speed_Mult);
dbRotateObject (Local_Character.Mesh, 0, dbObjectAngleY(Local_Character.Mesh) + 90, 0);
}
if (dbKeyState(32) == 1) // Right
{
dbRotateObject (Local_Character.Mesh, 0, dbObjectAngleY(Local_Character.Mesh) + 90, 0);
dbMoveObject (Local_Character.Mesh, .10 * Speed_Mult);
dbRotateObject (Local_Character.Mesh, 0, dbObjectAngleY(Local_Character.Mesh) - 90, 0);
}
}
// Camera position and rotation
dbPositionCamera ( dbObjectPositionX(Local_Character.Mesh),
dbObjectPositionY(Local_Character.Mesh) + .75,
dbObjectPositionZ(Local_Character.Mesh));
dbRotateCamera (dbCameraAngleX() + (dbMouseMoveY() * .25), dbObjectAngleY(Local_Character.Mesh), 0);
Camera_Initial_X = dbCameraPositionX();
Camera_Initial_Y = dbCameraPositionY();
Camera_Initial_Z = dbCameraPositionZ();
dbMoveCamera (-5);
dbRotateCamera (dbCameraAngleX(), dbCameraAngleY() + 90, 0);
dbMoveCamera (1.5);
dbRotateCamera (dbCameraAngleX(), dbObjectAngleY(Local_Character.Mesh), 0);
// Camera Collision
if (SC_SphereCastGroup(1, Camera_Initial_X, Camera_Initial_Y, Camera_Initial_Z, dbCameraPositionX(), dbCameraPositionY(), dbCameraPositionZ(), .5,
Local_Character.Mesh) > 0)
{
dbPositionCamera (SC_GetStaticCollisionX(), SC_GetStaticCollisionY(), SC_GetStaticCollisionZ());
}
break;
// Ally
//--------------------------------------------------------------------------------------------------------------------------------------------------------
case 1:
// Temporary
break;
// Neutral
//--------------------------------------------------------------------------------------------------------------------------------------------------------
case 2:
// Temporary
break;
// Enemy
//--------------------------------------------------------------------------------------------------------------------------------------------------------
case 3:
// Determine whether the player is crouching
float Player_Height;
if (Player_State >= 3)
{
Player_Height = dbObjectPositionY(Player_Character_Mesh) / 2;
}
else
{
Player_Height = dbObjectPositionY(Player_Character_Mesh);
}
// Set AI Task
//-------------------------------------------------------------------------
// Raycast from enemy to player
if (SC_RayCast (Player_Character_Mesh, dbObjectPositionX(Local_Character.Mesh), dbObjectPositionY(Local_Character.Mesh), dbObjectPositionZ(Local_Character.Mesh),
dbObjectPositionX(Player_Character_Mesh), Player_Height, dbObjectPositionZ(Player_Character_Mesh),
Local_Character.Mesh) == 1)
{
Local_Character.AI_Task = 2;
}
else
{
Local_Character.AI_Task = 0;
}
// Behavior based on AI Task
//-------------------------------------------------------------------------
// Oblivious
if (Local_Character.AI_Task == 0)
{
// Temporary
}
// Alerted
if (Local_Character.AI_Task == 2)
{
dbPointObject (Local_Character.Mesh, dbObjectPositionX(Player_Character_Mesh), dbObjectPositionY(Local_Character.Mesh), dbObjectPositionZ(Player_Character_Mesh));
}
break;
}
// Character Collision
//--------------------------------------------------------------------------------------------------------------------------------------------------------
if (SC_SphereSlideGroup (1, Initial_X, Initial_Y, Initial_Z, dbObjectPositionX(Local_Character.Mesh),
dbObjectPositionY(Local_Character.Mesh), dbObjectPositionZ(Local_Character.Mesh),
1.6, Local_Character.Mesh) > 0)
{
dbPositionObject (Local_Character.Mesh, SC_GetCollisionSlideX(), dbObjectPositionY(Local_Character.Mesh), SC_GetCollisionSlideZ());
SC_UpdateObject (Local_Character.Mesh);
}
}
break;
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
// Pause Menu
//------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
case 4:
Main_Loop = 0; // TEMPORARY
}
//-------------------------------------------------------------------------
// Update Screen
//-------------------------------------------------------------------------
dbSync ();
}
return;
}
And just for good measure, I have attached the entire project folder to this post. Just use the shortcut to run the EXE, it's never worked by hitting F5 in Visual Studio for some reason that I still haven't figured out.
I apologize if I'm being a nuisance, but I really need help.
Hail to the king baby
I love Evil Dead.