tank turrets tracking targets

This commit is contained in:
devZoGok
2025-05-31 10:06:44 +03:00
parent 94ee446741
commit 5702bc8e82
4 changed files with 129 additions and 32 deletions
+27 -3
View File
@@ -90,6 +90,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 100,
maxRange = 10,
damage = 50,
@@ -161,10 +162,16 @@ units = {
weapons = {
{
type = WeaponClass.SHELL,
orderType = OrderType.ATTACK,
projectile = {id = ProjectileId.SHELL, pos = {x = 0.06, y = 5.82, z = 11.4}, rot = {w = 1, x = 0, y = 0, z = 0}},
rateOfFire = 1000,
damage = 200,
maxRange = 25,
node = {
name = 'Turret',
rotationSpeed = .05,
maxFireAngle = .1
},
fireFx = {
{
vfx = false,
@@ -215,6 +222,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 2000,
damage = 5000,
maxRange = 30,
@@ -265,7 +273,7 @@ units = {
},
{
weapons = {
{type = WeaponClass.HITSCAN, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 20, maxRange = 8},
{type = WeaponClass.HITSCAN, orderType = OrderType.ATTACK, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 20, maxRange = 8},
},
buildableUnits = {
{id = UnitId.LAND_FACTORY, buildable = true, trigger = 76},
@@ -304,7 +312,7 @@ units = {
garrisonCategory = 3
},
{
weapons = {{type = WeaponClass.HITSCAN, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 50, maxRange = 20}},
weapons = {{type = WeaponClass.HITSCAN, orderType = OrderType.ATTACK, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 50, maxRange = 20}},
unitClass = UnitClass.TRANSPORT,
unitType = UnitType.HOVER,
isVehicle = true,
@@ -329,7 +337,7 @@ units = {
garrisonCategory = 3
},
{
weapons = {{type = WeaponClass.HITSCAN, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/Tanks/attack.ogg', damage = 100, maxRange = 25}},
weapons = {{type = WeaponClass.HITSCAN, orderType = OrderType.ATTACK, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/Tanks/attack.ogg', damage = 100, maxRange = 25}},
unitClass = UnitClass.TRANSPORT,
unitType = UnitType.HOVER,
armor = {ArmorType.MECHANIC},
@@ -391,6 +399,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 200,
damage = 300,
maxRange = 15,
@@ -442,6 +451,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 200,
fireFx = {
{
@@ -493,6 +503,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 200,
damage = 300,
maxRange = 15,
@@ -543,6 +554,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 200,
fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg',
damage = 300,
@@ -594,6 +606,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 100,
damage = 80,
maxRange = 100,
@@ -643,6 +656,7 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 450,
damage = 500,
maxRange = 100,
@@ -669,6 +683,7 @@ units = {
},
{
type = WeaponClass.CRUISE_MISSILE,
orderType = OrderType.LAUNCH,
projectile = {id = ProjectileId.CRUISE_MISSILE, pos = {x = 0, y = 15, z = 0}, rot = {w = .707, x = -.707, y = 0, z = 0}},
rateOfFire = 500,
maxRange = 30,
@@ -707,6 +722,7 @@ units = {
weapons = {
{
type = WeaponClass.TORPEDO,
orderType = OrderType.ATTACK,
rateOfFire = 1000,
fireFx = {
{
@@ -721,6 +737,7 @@ units = {
},
{
type = WeaponClass.CRUISE_MISSILE,
orderType = OrderType.LAUNCH,
rateOfFire = 500,
maxRange = 30,
fireFx = {
@@ -759,6 +776,7 @@ units = {
weapons = {
{
type = WeaponClass.TORPEDO,
orderType = OrderType.ATTACK,
projectile = {id = ProjectileId.TORPEDO, pos = {x = 0, y = -.27, z = 4.6}, rot = {w = 1, x = 0, y = 0, z = 0}},
damage = 200,
maxRange = 20,
@@ -885,9 +903,15 @@ units = {
weapons = {
{
type = WeaponClass.HITSCAN,
orderType = OrderType.ATTACK,
rateOfFire = 100,
damage = 50,
maxRange = 50,
node = {
name = 'TurretBody',
rotationSpeed = .05,
maxFireAngle = .1
},
fireFx = {
{
vfx = true,
+83 -15
View File
@@ -41,12 +41,27 @@ namespace battleship{
{
sol::table weaponTable = unitTable["weapons"][wid + 1];
maxRange = weaponTable["maxRange"];
orderType = (Order::TYPE)weaponTable["orderType"];
initProjectileData(weaponTable);
sol::optional<sol::table> nodeTblOpt = unitTable["weapons"][wid + 1]["node"];
if(nodeTblOpt != sol::nullopt) initNode(weaponTable);
fireFx = initFx(weaponTable, "fireFx", true);
if(fireFx) FxManager::getSingleton()->addFx(fireFx);
}
void Unit::Weapon::initNode(sol::table weaponTable){
sol::table nodeTbl = weaponTable["node"];
maxFireAngle = nodeTbl["maxFireAngle"];
rotSpeed = nodeTbl["rotationSpeed"];
string name = nodeTbl["name"];
node = unit->getModel()->findDescendant(name, true);
}
void Unit::Weapon::initProjectileData(sol::table weaponTable){
string projTableKey = "projectile";
sol::optional<sol::table> proj = weaponTable[projTableKey];
@@ -177,23 +192,14 @@ namespace battleship{
flashNode->setVisible(false);
Node *parNode = (attached ? unit->getModel() : Root::getSingleton()->getRootNode());
sol::optional<string> parOpt = compTbl["parent"];
sol::optional<string> parNameOpt = compTbl["parent"];
if(parOpt != sol::nullopt){
vector<Node*> descendants;
unit->getModel()->getDescendants(descendants);
if(parNameOpt != sol::nullopt){
string parName = compTbl["parent"];
parNode = nullptr;
for(Node *desc : descendants)
if(desc->getName() == parName){
parNode = desc;
break;
}
parNode = unit->getModel()->findDescendant(parName, true);
}
parNode->attachChild(flashNode);
fxComponents.push_back(FxManager::Fx::Component((void*)flashNode, vfx, duration, compPos, offset));
}
else{
@@ -212,7 +218,31 @@ namespace battleship{
if(fireFx) fm->removeFx(fireFx);
}
void Unit::Weapon::update(){}
//TODO replace unit pos with absolute weapon pos for withinAngle
void Unit::Weapon::update(){
if(node){
dirVec = rot * unit->getDirVec();
leftVec = rot * unit->getLeftVec();
upVec = rot * unit->getUpVec();
}
int numOrders = unit->getNumOrders();
int ordTp = (numOrders > 0 ? (int)unit->getOrder(0).type : -1);
Unit *targUnit = (ordTp != -1 ? unit->getOrder(0).targets[0].unit : nullptr);
if(ordTp == (int)orderType){
Vector3 targPos = (targUnit ? targUnit->getPos() : unit->getOrder(0).targets[0].pos);
float targDist = unit->getPos().getDistanceFrom(targPos);
bool withinRange = (minRange <= targDist && targDist <= maxRange);
bool withinAngle = (node ? Vector3(dirVec.x, 0, dirVec.z).norm().getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle : true);
if((Order::TYPE)ordTp == Order::TYPE::ATTACK && withinRange && withinAngle)
fire(unit->getOrder(0));
}
else
trackTarget(unit->getPos() + unit->getDirVec());
}
void Unit::Weapon::useFx(FxManager::Fx *fx, Vector3 targPos, bool fire){
if(fx && !fire)
@@ -278,14 +308,36 @@ namespace battleship{
Vector3 leftVec = unit->getLeftVec();
Vector3 upVec = unit->getUpVec();
Vector3 dirVec = unit->getDirVec();
Vector3 p = unit->getPos() + leftVec * projPos.x + upVec * projPos.y + dirVec * projPos.z;
Quaternion r = projRot * unit->getRot();
Vector3 p = unit->getPos() + leftVec * projPos.x + upVec * projPos.y + dirVec * projPos.z;
if(node){
r = node->localToGlobalOrientation(projRot);
p = node->localToGlobalPosition(projPos);
}
unit->getPlayer()->addProjectile(GameObjectFactory::createProjectile(unit, projId, p, r));
}
lastFireTime = getTime();
}
void Unit::Weapon::trackTarget(Vector3 targPos){
if(!node) return;
Vector3 targDir = targPos - unit->getPos();
Vector3 targDirHor = Vector3(targDir.x, 0, targDir.z).norm();
Vector3 dirVecHor = Vector3(dirVec.x, 0, dirVec.z).norm();
float angle = dirVecHor.getAngleBetween(targDirHor);
bool right = (Vector3(leftVec.x, 0, leftVec.z).norm().getAngleBetween(targDirHor) < PI / 2);
float rotAngle = (rotSpeed < angle ? rotSpeed : angle);
rot = Quaternion((right ? 1 : -1) * rotAngle, Vector3::VEC_J) * rot;
node->setOrientation(rot);
}
Unit::Unit(Player *player, int id, Vector3 pos, Quaternion rot, State st) : GameObject(GameObject::Type::UNIT, id, player, pos, rot), state(st){
selectable = true;
@@ -681,12 +733,18 @@ namespace battleship{
removeOrder(0);
}
vector<Weapon*> attackWeapons = getWeaponsByOrder(Order::TYPE::ATTACK);
Vector3 targPos = (order.targets[0].unit ? order.targets[0].unit->getPos() : order.targets[0].pos);
for(Weapon *weapon : attackWeapons)
weapon->trackTarget(targPos);
}
bool Unit::validateOrder(Order order){
switch (order.type) {
case Order::TYPE::ATTACK:
return !weapons.empty();
return !getWeaponsByOrder(Order::TYPE::ATTACK).empty();
case Order::TYPE::BUILD:
return unitClass == UnitClass::ENGINEER;
case Order::TYPE::PATROL:
@@ -721,6 +779,16 @@ namespace battleship{
}
}
vector<Unit::Weapon*> Unit::getWeaponsByOrder(Order::TYPE type){
vector<Weapon*> weaps;
for(Weapon *w : weapons)
if(w->getOrderType() == type)
weaps.push_back(w);
return weapons;
}
void Unit::receiveOrder(Order order, bool add) {
if(!validateOrder(order)) return;
+9 -2
View File
@@ -94,6 +94,7 @@ namespace battleship{
~Weapon();
virtual void update();
virtual void fire(Order);
void trackTarget(vb01::Vector3);
inline Type getType(){return type;}
inline int getProjectileId(){return projId;}
inline int getRateOfFire(){return rateOfFire;}
@@ -101,18 +102,23 @@ namespace battleship{
inline int getMinRange(){return minRange;}
inline int getMaxRange(){return maxRange;}
inline Unit* getUnit(){return unit;}
inline Order::TYPE getOrderType(){return orderType;}
private:
Type type;
int id, projId = -1, rateOfFire, damage = 0;
float minRange = 0, maxRange;
float minRange = 0, maxRange, rotSpeed, maxFireAngle;
vb01::Vector3 projPos;
vb01::Quaternion projRot;
vb01::Quaternion projRot, rot = vb01::Quaternion::QUAT_W;
vb01::s64 lastFireTime = 0;
Unit *unit = nullptr;
FxManager::Fx *fireFx = nullptr;
vb01::Node *node = nullptr;
Order::TYPE orderType;
vb01::Vector3 upVec = vb01::Vector3(0, 1, 0), dirVec = vb01::Vector3(0, 0, 1), leftVec = vb01::Vector3(1, 0, 0);
static std::string LASER_FLAG;
void initProjectileData(sol::table);
void initNode(sol::table);
FxManager::Fx* initFx(sol::table, std::string, bool);
void useFx(FxManager::Fx*, vb01::Vector3, bool);
inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;}
@@ -215,6 +221,7 @@ namespace battleship{
void removeBar(vb01::Node*);
vb01::Node* createBar(vb01::Vector2, vb01::Vector2, vb01::Vector4);
void displayUnitStats(vb01::Node*, vb01::Node*, int, int, bool, vb01::Vector2 offset = vb01::Vector2::VEC_ZERO);
std::vector<Weapon*> getWeaponsByOrder(Order::TYPE);
inline std::vector<Armor> getArmorTypes(){return armorTypes;}
};
}
+9 -11
View File
@@ -316,12 +316,19 @@ namespace battleship{
Unit::attack(order);
int currNumOrders = orders.size();
if(weapons.empty() || prevNumOrders != currNumOrders) return;
if(prevNumOrders != currNumOrders) return;
Order::Target target = order.targets[0];
Vector3 targVec = (target.unit ? target.unit->getPos() : target.pos) - pos;
float distToTarg = targVec.getLength();
Weapon *weapon = weapons[0];
vector<Weapon*> attackWeapons = getWeaponsByOrder(Order::TYPE::ATTACK);
Weapon *weapon = attackWeapons[0];
for(Weapon *w : attackWeapons)
if(w->getMaxRange() > weapon->getMaxRange())
weapon = w;
float minDist = weapon->getMaxRange();
if(order.playerAssigned || (!order.playerAssigned && state == Unit::State::CHASE)){
@@ -334,15 +341,6 @@ namespace battleship{
removeOrder(0);
return;
}
float angleToTarg = targVec.norm().getAngleBetween(dirVec);
if(distToTarg <= weapon->getMaxRange()){
if(angleToTarg <= anglePrecision)
weapon->fire(order);
else if(angleToTarg > anglePrecision)
turn(calculateRotation(targVec.norm(), angleToTarg, maxTurnAngle));
}
}