[Add] More basic AI functions.

[Change] Split AI into it's own unit.
[Note] Space battles are fun!
This commit is contained in:
Rtch90 2018-04-14 21:47:30 +01:00
parent 03fe164ce1
commit 235b1c6c5b
8 changed files with 163 additions and 70 deletions

View File

@ -20,7 +20,7 @@ Lephisto3D_SOURCES = main.cpp glfreetype.cpp body.cpp space.cpp ship.cpp player.
star.cpp frame.cpp ship_cpanel.cpp sector_view.cpp mtrand.cpp world_view.cpp system_view.cpp \
star_system.cpp sector.cpp system_info_view.cpp generic_system_view.cpp date.cpp space_station.cpp \
space_station_view.cpp model_body.cpp ship_type.cpp info_view.cpp model_coll_mesh_data.cpp \
object_viewer_view.cpp custom_starsystems.cpp serializer.cpp sfx.cpp
object_viewer_view.cpp custom_starsystems.cpp serializer.cpp sfx.cpp ship_ai.cpp
Lephisto3D_LDADD = sbre/libsbre.a collider/libcollider.a libgui.a
ModelViewer_SOURCES = sbre_viewer.cpp glfreetype.cpp

View File

@ -19,7 +19,7 @@ public:
virtual void SetPosition(vector3d p) = 0;
virtual vector3d GetPosition(void) const = 0; /* Within frame. */
virtual void SetVelocity(vector3d v) { assert(0); }
virtual vector3d GetVelocity(void) { assert(0); return vector3d(0.0); }
virtual vector3d GetVelocity(void) const { assert(0); return vector3d(0.0); }
virtual double GetRadius(void) const = 0 ;
virtual double GetMass(void) const { assert(0); return 0; }
virtual void SetRotMatrix(const matrix4x4d& r) {};

View File

@ -148,7 +148,7 @@ void DynamicBody::SetRotMatrix(const matrix4x4d& r) {
SetPosition(pos);
}
void DynamicBody::GetRotMatrix(matrix4x4d& m) {
void DynamicBody::GetRotMatrix(matrix4x4d& m) const{
m = m_orient;
m[12] = 0;
m[13] = 0;
@ -175,7 +175,7 @@ void DynamicBody::SetMassDistributionFromCollMesh(const CollMesh* m) {
SetMass(m_mass);
}
vector3d DynamicBody::GetAngularMomentum(void) {
vector3d DynamicBody::GetAngularMomentum(void) const {
return m_angInertia * m_angVel;
}
@ -183,11 +183,11 @@ DynamicBody::~DynamicBody(void) {
}
vector3d DynamicBody::GetAngVelocity(void) {
vector3d DynamicBody::GetAngVelocity(void) const {
return m_angVel;
}
vector3d DynamicBody::GetVelocity(void) {
vector3d DynamicBody::GetVelocity(void) const {
return m_vel;
}

View File

@ -10,20 +10,20 @@ public:
DynamicBody(void);
virtual ~DynamicBody(void);
virtual void SetRotMatrix(const matrix4x4d& r);
virtual void GetRotMatrix(matrix4x4d& m);
virtual void GetRotMatrix(matrix4x4d& m) const;
virtual void SetVelocity(vector3d v);
virtual void SetPosition(vector3d p);
virtual vector3d GetPosition(void) const;
virtual vector3d GetVelocity(void);
vector3d GetAngVelocity(void);
virtual vector3d GetVelocity(void) const;
vector3d GetAngVelocity(void) const;
void SetAngVelocity(vector3d v);
void SetMesh(ObjMesh* m);
virtual bool OnCollision(Body* b, Uint32 flags) { return true; }
vector3d GetAngularMomentum(void);
vector3d GetAngularMomentum(void) const;
double GetAngularInertia(void) const { return m_angInertia; }
void SetMassDistributionFromCollMesh(const CollMesh* m);
void DisableBodyOnly(void) { m_enabled = false; }
bool IsEnabled(void) { return m_enabled; }
bool IsEnabled(void) const { return m_enabled; }
virtual void Disable(void);
virtual void Enable(void);
virtual double GetMass(void) const { return m_mass; }

View File

@ -192,7 +192,7 @@ vector3d Ship::CalcRotDamping(void) {
}
void Ship::SetThrusterState(enum ShipType::Thruster t, float level) {
m_thrusters[t] = level;
m_thrusters[t] = CLAMP(level, 0.0, 1.0);
}
void Ship::ClearThrusterState(void) {
@ -325,7 +325,7 @@ void Ship::TimeStepUpdate(const float timeStep) {
const ShipType& stype = GetShipType();
for(int i = 0; i < ShipType::THRUSTER_MAX; i++) {
float force = timeStep * stype.linThrust[i] * m_thrusters[i];
float force = stype.linThrust[i]*m_thrusters[i];
switch(i) {
case ShipType::THRUSTER_REAR:
case ShipType::THRUSTER_FRONT:
@ -373,38 +373,6 @@ void Ship::TimeStepUpdate(const float timeStep) {
if(m_testLanded) TestLanded();
}
void Ship::AITimeStep(const float timeStep) {
bool done = false;
if(m_todo.size() != 0) {
AIInstruction& inst = m_todo.front();
switch(inst.cmd) {
case DO_KILL:
done = AICmdKill(static_cast<const Ship*>(inst.arg));
break;
case DO_NOTHING: done = true; break;
}
}
if(done) {
printf("AI '%s' succesfully executed %d:'%s'\n", GetLabel().c_str(), m_todo.front().cmd,
static_cast<Ship*>(m_todo.front().arg)->GetLabel().c_str());
m_todo.pop_front();
}
}
bool Ship::AICmdKill(const Ship* enemy) {
/* Needs to deal with frames, large distances, and success. */
if(GetFrame() == enemy->GetFrame()) {
vector3d dir = vector3d::Normalize(enemy->GetPosition() - GetPosition());
AIFaceDirection(dir);
}
return false;
}
void Ship::AIInstruct(enum AICommand cmd, void* arg) {
m_todo.push_back(AIInstruction(cmd, arg));
}
void Ship::NotifyDeath(const Body* const dyingBody) {
if(GetNavTarget() == dyingBody)
SetNavTarget(0);
@ -455,28 +423,6 @@ void Ship::SetCombatTarget(Body* const target) {
L3D::worldView->UpdateCommsOptions();
}
/* Orient so our -ve z axis == dir. ie.. So that direction points forwards. */
void Ship::AIFaceDirection(const vector3d& dir) {
matrix4x4d rot;
GetRotMatrix(rot);
rot = rot.InverseOf();
const vector3d zaxis = vector3d(-rot[2], -rot[6], -rot[10]);
vector3d rotaxis = vector3d::Cross(zaxis, dir);
const float dot = vector3d::Dot(dir, zaxis);
/* If facing > 90 degrees away then max turn rate.. */
if(dot < 0) rotaxis.Normalize();
rotaxis = rot*rotaxis;
ClearThrusterState();
/* We still must apply rotation damping. */
rotaxis -= CalcRotDamping();
SetAngThrusterState(0, rotaxis.x);
SetAngThrusterState(1, rotaxis.y);
SetAngThrusterState(2, rotaxis.z);
if(dot > 0) SetThrusterState(ShipType::THRUSTER_REAR, 1.0);
if(dot > 0.95f) SetGunState(0,1);
else SetGunState(0,0);
}
bool Ship::IsFiringLasers(void) {
for(int i = 0; i < ShipType::GUNMOUNT_MAX; i++) {
if(m_gunState[i]) return true;

View File

@ -48,6 +48,8 @@ public:
FlightState GetFlightState(void) const { return m_flightState; }
float GetWheelState(void) const { return m_wheelState; }
void AIFaceDirection(const vector3d& dir);
void AIAccelToModelRelativeVelocity(const vector3d v);
void AIModelCoordsMatchSpeedRelTo(const vector3d v, const Ship*);
EquipSet m_equipment;

145
src/ship_ai.cpp Normal file
View File

@ -0,0 +1,145 @@
#include "libs.h"
#include "ship.h"
#include "l3d.h"
void Ship::AITimeStep(const float timeStep) {
bool done = false;
if(m_todo.size() != 0) {
AIInstruction& inst = m_todo.front();
switch(inst.cmd) {
case DO_KILL:
done = AICmdKill(static_cast<const Ship*>(inst.arg));
break;
case DO_NOTHING: done = true; break;
}
}
if(done) {
printf("AI '%s' successfullyexecuted %d:'%s'\n", GetLabel().c_str(), m_todo.front().cmd,
static_cast<Ship*>(m_todo.front().arg)->GetLabel().c_str());
m_todo.pop_front();
}
}
bool Ship::AICmdKill(const Ship* enemy) {
SetGunState(0,0);
/* Needs to deal with frames, large distances and success. */
if(GetFrame() == enemy->GetFrame()) {
const float dist = (enemy->GetPosition() - GetPosition()).Length();
vector3d dir = vector3d::Normalize(enemy->GetPosition() - GetPosition());
if(dist > 500.0) {
AIFaceDirection(dir);
/* Thunder at player at 400m/sec. */
AIModelCoordsMatchSpeedRelTo(vector3d(0,0,-400), enemy);
/* Fire guns if aiming good enough. */
matrix4x4d rot;
GetRotMatrix(rot);
const vector3d zaxis = vector3d(-rot[8], -rot[9], -rot[10]);
const float dot = vector3d::Dot(dir, vector3d(-rot[8], -rot[9], -rot[10]));
if(dot > 0.95f) SetGunState(0,1);
} else {
/* If we are too close, turn away! */
AIFaceDirection(-dir);
AIModelCoordsMatchSpeedRelTo(vector3d(0,0,-1000), enemy);
}
}
return false;
}
void Ship::AIInstruct(enum AICommand cmd, void* arg) {
m_todo.push_back(AIInstruction(cmd, arg));
}
/* Orient so our -ve z axis == dir. ie.. So that direction points forwards. */
void Ship::AIFaceDirection(const vector3d& dir) {
matrix4x4d rot;
GetRotMatrix(rot);
rot = rot.InverseOf();
const vector3d zaxis = vector3d(-rot[2], -rot[6], -rot[10]);
vector3d rotaxis = vector3d::Cross(zaxis, dir);
vector3d angVel = rot*GetAngVelocity();
const float dot = vector3d::Dot(dir, zaxis);
/* If facing > 90 degrees away then max turn rate. */
if(dot < 0) rotaxis.Normalize();
rotaxis = rot*rotaxis;
vector3d desiredAngVelChange = 4*(rotaxis - angVel);
ClearThrusterState();
/* We still must apply rotation damping. */
rotaxis -= CalcRotDamping();
SetAngThrusterState(0, desiredAngVelChange.x);
SetAngThrusterState(1, desiredAngVelChange.y);
SetAngThrusterState(2, desiredAngVelChange.z);
}
void Ship::AIModelCoordsMatchSpeedRelTo(const vector3d v, const Ship* other) {
matrix4x4d m; GetRotMatrix(m);
vector3d relToVel = m.InverseOf() * other->GetVelocity() + v;
AIAccelToModelRelativeVelocity(relToVel);
}
/*
* Try to reach this model-relative velocity.
* (0,0,-100) would mean going 100m/s forward.
*/
void Ship::AIAccelToModelRelativeVelocity(const vector3d v) {
const ShipType& stype = GetShipType();
vector3d relVel = GetVelocity(); // - enemy->GetVelocity();
matrix4x4d m; GetRotMatrix(m);
relVel = m.InverseOf() * relVel;
vector3d difVel = v - relVel;
/* We want to change velocity by difVel.. */
//SetVelocty(m*(relVel+difVel));
const float invMass = 1.0 / GetMass();
if(difVel.x > 0) {
/* Figure out biggest accel can get, and then what we need this timestep. */
float velChange = L3D::GetTimeStep() * stype.linThrust[ShipType::THRUSTER_RIGHT] * invMass;
float thrust;
if(velChange < difVel.x) thrust = 1.0;
else thrust = difVel.x / velChange;
thrust *= thrust; /* This is just to hide control jiggle. */
SetThrusterState(ShipType::THRUSTER_RIGHT, thrust);
} else {
float velChange = L3D::GetTimeStep() * stype.linThrust[ShipType::THRUSTER_LEFT] * invMass;
float thrust;
if(velChange > difVel.x) thrust = 1.0;
else thrust = difVel.x / velChange;
thrust *= thrust;
SetThrusterState(ShipType::THRUSTER_LEFT, thrust);
}
if(difVel.y > 0) {
float velChange = L3D::GetTimeStep() * stype.linThrust[ShipType::THRUSTER_TOP] * invMass;
float thrust;
if(velChange < difVel.y) thrust = 1.0;
else thrust = difVel.y / velChange;
thrust *= thrust;
SetThrusterState(ShipType::THRUSTER_TOP, thrust);
} else {
float velChange = L3D::GetTimeStep() * stype.linThrust[ShipType::THRUSTER_BOTTOM] * invMass;
float thrust;
if(velChange > difVel.y) thrust = 1.0;
else thrust = difVel.y / velChange;
thrust *= thrust;
SetThrusterState(ShipType::THRUSTER_BOTTOM, thrust);
}
if(difVel.z > 0) {
float velChange = L3D::GetTimeStep() * stype.linThrust[ShipType::THRUSTER_FRONT] * invMass;
float thrust;
if(velChange < difVel.z) thrust = 1.0;
else thrust = difVel.z / velChange;
thrust *= thrust;
SetThrusterState(ShipType::THRUSTER_FRONT, thrust);
} else {
float velChange = L3D::GetTimeStep() * stype.linThrust[ShipType::THRUSTER_REAR] * invMass;
float thrust;
if(velChange > difVel.z) thrust = 1.0;
else thrust = difVel.z / velChange;
thrust *= thrust;
SetThrusterState(ShipType::THRUSTER_REAR, thrust);
}
}

View File

@ -7,7 +7,7 @@ const ShipType ShipType::types[] = {
* Sirius corporation make a range of lovely ships!
*/
"Sirius Interdictor", 61,
{ 4e8, -4e8, 1e8, -1e8, -1e8, 1e8 },
{ 4e6, -4e6, 1e6, -1e6, -1e6, 1e6 },
1e7,
{
{ vector3f(0, -0.5, 0), vector3f(0, 0, -1) },
@ -22,7 +22,7 @@ const ShipType ShipType::types[] = {
*/
"Ladybird Starfighter",
62,
{ 1e8, -1e8, 1e8, -1e8, -1e8, 1e8 },
{ 1e6, -1e6, 1e6, -1e6, -1e6, 1e6 },
1e7,
{
{ vector3f(0, -0.5, 0), vector3f(0, 0, -1) },
@ -34,7 +34,7 @@ const ShipType ShipType::types[] = {
{
"Flowerfairy Heavy Trader",
63,
{ 1e7, -1e7, 1e6, -1e6, -1e6, 1e6 },
{ 1e6, -1e6, 1e6, -1e6, -1e6, 1e6 },
1e7,
{
{ vector3f(0, -0.5, 0), vector3f(0, 0, -1) },