implemented weapons subsystem for units

This commit is contained in:
devZoGok
2024-01-20 15:50:35 +02:00
parent a956e754bf
commit e1dde2c90f
11 changed files with 167 additions and 123 deletions
@@ -7,8 +7,6 @@ projectiles = {
},
speed = {.5, .06},
rayLength = {1.25, .75},
pos = {{x = 0, y = 2.44, z = -3.5}, {x = 0, y = -.27, z = 4.6}},
rot = {{w = .707, x = -.707, y = 0, z = 0}, {w = 1, x = 0, y = 0, z = 0}},
damage = {450, 300},
name = {
"Guided missile",
+24 -23
View File
@@ -1,4 +1,5 @@
--TYPE = {ATTACK = 0, BUILD = 1, MOVE = 2, GARRISON = 3, EJECT = 4, PATROL = 5, LAUNCH = 6};
WeaponClass = {HITSCAN = 0, SHELL = 1, TORPEDO = 2, CRUISE_MISSILE = 3}
UnitClass = {
WAR_MECH = 0,
TANK = 1,
@@ -24,6 +25,29 @@ vehiclePrefix = modelPrefix .. "Units/Vehicles/"
structurePrefix = modelPrefix .. "Units/Structures/"
units = {
weapons = {
{{hitscan = true, rateOfFire = 100, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 50, maxRange = 3}},
{{hitscan = true, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Tanks/attack.ogg', damage = 200, maxRange = 20}},
{{hitscan = true, rateOfFire = 2000, fireSfx = PATH .. 'Sounds/Units/Tanks/attack.ogg', damage = 5000, maxRange = 45}},
{},
{},
{},
{{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}},
{{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}},
{{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}},
{{hitscan = true, rateOfFire = 200, fireSfx = PATH .. 'Sounds/Units/Cruisers/fire.ogg', damage = 300, maxRange = 15}},
{},
{
{hitscan = false, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Submarines/fire.ogg', damage = 200, maxRange = 20, projectile = {id = 1, pos = {x = 0, y = -.27, z = 4.6}, rot = {w = 1, x = 0, y = 0, z = 0}}},
{hitscan = false, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Submarines/fire.ogg', minRange = 5, maxRange = 30, projectile = {id = 0, pos = {x = 0, y = 2.44, z = -3.5}, rot = {w = .707, x = -.707, y = 0, z = 0}}}
},
{{hitscan = false, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/Submarines/fire.ogg', damage = 200, maxRange = 20, projectile = {id = 1, pos = {x = 0, y = -.27, z = 4.6}, rot = {w = 1, x = 0, y = 0, z = 0}}}},
{},
{},
{},
{},
{{hitscan = true, rateOfFire = 500, fireSfx = PATH .. 'Sounds/Units/WarMechs/fire.ogg', damage = 50, maxRange = 10}},
},
unitClass = {
UnitClass.WAR_MECH,
UnitClass.TANK,
@@ -93,9 +117,6 @@ units = {
health = {500, 500, 600, 200, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500},
cost = {500, 600, 200, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 500},
range = {15, 20, 45, 15, 14, 14, 14, 14, 14, 14, 13, 13, 12, 12, 12, 15, 0, 40},
damage = {15, 120, 250, 15, 14, 14, 13, 13, 12, 12, 15, 15, 100, 100, 100, 100, 100, 100, 100},
rateOfFire = {50, 2000, 5000, 100, 100, 100, 100, 100, 100, 100, 1000, 1000, 100, 100, 100, 100, 100, 100},
garrisonCapacity = {
{},
{},
@@ -664,26 +685,6 @@ units = {
PATH .. 'Sounds/Units/Sample/selection.ogg',
PATH .. 'Sounds/Units/Sample/selection.ogg',
},
fireSfx = {
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/Tanks/attack.ogg',
PATH .. 'Sounds/Units/Tanks/attack.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/Cruisers/fire.ogg',
PATH .. 'Sounds/Units/Cruisers/fire.ogg',
PATH .. 'Sounds/Units/Cruisers/fire.ogg',
PATH .. 'Sounds/Units/Cruisers/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/Submarines/fire.ogg',
PATH .. 'Sounds/Units/Submarines/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
PATH .. 'Sounds/Units/WarMechs/fire.ogg',
},
deathSfx = {
PATH .. 'Sounds/SFX/Explosions/explosion01.ogg',
PATH .. 'Sounds/SFX/Explosions/explosion01.ogg',
+2 -1
View File
@@ -14,8 +14,9 @@ namespace battleship{
void build(Order);
private:
vb01::s64 lastIncrementTime = 0;
int buildRate = 100;
bool canIncrementStructureStatus(){return vb01::getTime() - lastIncrementTime > rateOfFire;}
bool canIncrementStructureStatus(){return vb01::getTime() - lastIncrementTime > buildRate;}
};
}
+21 -5
View File
@@ -1,6 +1,8 @@
#include "gameObject.h"
#include "gameManager.h"
#include "defConfigs.h"
#include "unit.h"
#include "player.h"
#include <solUtil.h>
@@ -102,13 +104,11 @@ namespace battleship{
root->getRootNode()->attachChild(model);
}
//TODO implement death SFX destruction
void GameObject::destroySound(){
}
sf::Sound* GameObject::prepareSfx(sf::SoundBuffer *buffer, string key){
sol::table SOL_LUA_STATE = generateView()[GameObject::getGameObjTableName()];
string sfxPath = SOL_LUA_STATE[key][id + 1];
sf::Sound* GameObject::prepareSfx(sf::SoundBuffer *buffer, string sfxPath){
sf::Sound *sfx = nullptr;
if(buffer->loadFromFile(sfxPath.c_str())){
@@ -121,7 +121,8 @@ namespace battleship{
void GameObject::initSound(){
deathSfxBuffer = new sf::SoundBuffer();
deathSfx = prepareSfx(deathSfxBuffer, "deathSfx");
string sfxPath = generateView()[getGameObjTableName()]["deathSfx"][id + 1];
deathSfx = prepareSfx(deathSfxBuffer, sfxPath);
}
string GameObject::getGameObjTableName(){
@@ -167,4 +168,19 @@ namespace battleship{
float sizeY = cornersOnScreen[bottomMostPointId].y - cornersOnScreen[topMostPointId].y;
return Vector2(sizeX, sizeY);
}
void GameObject::updateGameStats(Unit *targetUnit){
if(targetUnit->getHealth() <= targetUnit->getDeathHp()){
Player *targUnitPlayer = targetUnit->getPlayer();
if(targetUnit->isVehicle()){
player->incVehiclesDestroyed();
targUnitPlayer->incVehiclesLost();
}
else{
player->incStructuresDestroyed();
targUnitPlayer->incStructuresLost();
}
}
}
}
+3 -1
View File
@@ -12,6 +12,7 @@ namespace sf{
namespace battleship{
class Player;
class Unit;
class GameObject{
public:
@@ -25,6 +26,8 @@ namespace battleship{
void orientAt(vb01::Quaternion);
std::string getGameObjTableName();
vb01::Vector2 calculateSelectionRect();
void updateGameStats(Unit*);
static sf::Sound* prepareSfx(sf::SoundBuffer*, std::string);
inline vb01::Vector2 getScreenPos(){return screenPos;}
inline vb01::Vector3 getCorner(int i){return corners[i];}
inline bool isSelectable(){return selectable;}
@@ -53,7 +56,6 @@ namespace battleship{
virtual void destroyHitbox();
virtual void destroySound();
virtual void initSound();
sf::Sound* prepareSfx(sf::SoundBuffer*, std::string);
Type type;
int id;
+3 -3
View File
@@ -11,7 +11,7 @@ namespace battleship{
Unit *targUnit = order.targets[0].unit;
Vector3 targDir = (targUnit ? targUnit->getPos() : order.targets[0].pos) - pos;
if(targDir.getLength() > range){
if(targDir.getLength() > weapons[0]->getMaxRange()){
removeOrder(0);
return;
}
@@ -20,8 +20,8 @@ namespace battleship{
if(angleToTarg > .05)
rotateTurret(calculateRotation(targDir.norm(), angleToTarg, .1));
else if(canFire())
fire();
else
weapons[0]->fire(order);
Unit::attack(order);
}
-24
View File
@@ -1,24 +0,0 @@
#include "submarine.h"
#include "player.h"
#include "gameObjectFactory.h"
#include <solUtil.h>
namespace battleship{
using namespace vb01;
using namespace gameBase;
Submarine::Submarine(Player *player, int id, Vector3 pos, Quaternion rot) : Vehicle(player, id, pos, rot){}
void Submarine::fire(){
int projId = 1;
sol::table SOL_STATE_VIEW = generateView()["projectiles"];
sol::table posTable = SOL_STATE_VIEW["pos"][projId + 1], rotTable = SOL_STATE_VIEW["rot"][projId + 1];
Vector3 projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
projPos = pos + leftVec * projPos.x + upVec * projPos.y + dirVec * projPos.z;
Quaternion projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]) * rot;
player->addProjectile(GameObjectFactory::createProjectile(this, projId, projPos, projRot));
Unit::fire();
}
}
-15
View File
@@ -1,15 +0,0 @@
#ifndef SUBMARINE_H
#define SUBMARINE_H
#include "vehicle.h"
namespace battleship{
class Submarine : public Vehicle{
public:
Submarine(Player*, int, vb01::Vector3, vb01::Quaternion);
private:
void fire();
};
}
#endif
+78 -38
View File
@@ -14,6 +14,7 @@
#include "util.h"
#include "game.h"
#include "vehicle.h"
#include "gameObjectFactory.h"
#include "activeGameState.h"
#include "defConfigs.h"
#include "pathfinder.h"
@@ -24,6 +25,60 @@ using namespace gameBase;
using namespace std;
namespace battleship{
Unit::Weapon::Weapon(Unit *u, sol::table weaponTable) :
unit(u),
hitscan(weaponTable["hitscan"]),
rateOfFire(weaponTable["rateOfFire"]),
damage(weaponTable["damage"].get_or(0)),
minRange(weaponTable["minRange"].get_or(0))
{
maxRange = weaponTable["maxRange"];
fireSfxBuffer = new sf::SoundBuffer();
string sfxPath = weaponTable["fireSfx"];
fireSfx = GameObject::prepareSfx(fireSfxBuffer, sfxPath);
string projTable = "projectile";
sol::optional<sol::table> proj = weaponTable[projTable];
if(proj != sol::nullopt){
projId = weaponTable[projTable]["id"];
sol::table posTable = weaponTable[projTable]["pos"];
projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
sol::table rotTable = weaponTable[projTable]["rot"];
projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
}
}
Unit::Weapon::~Weapon(){
if(fireSfx){
fireSfx->stop();
delete fireSfx;
delete fireSfxBuffer;
}
}
void Unit::Weapon::fire(Order order){
if(!canFire()) return;
fireSfx->play();
Unit *targetUnit = order.targets[0].unit;
if(targetUnit && hitscan){
targetUnit->takeDamage(damage);
unit->updateGameStats(targetUnit);
}
else if(!hitscan){
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();
unit->getPlayer()->addProjectile(GameObjectFactory::createProjectile(unit, projId, p, r));
}
lastFireTime = getTime();
}
Unit::Unit(Player *player, int id, Vector3 pos, Quaternion rot) : GameObject(GameObject::Type::UNIT, id, player, pos, rot){
this->id = id;
this->player = player;
@@ -42,6 +97,7 @@ namespace battleship{
destroySound();
destroyHitbox();
destroyModel();
destroyWeapons();
}
void Unit::init(){
@@ -49,6 +105,7 @@ namespace battleship{
initModel();
initHitbox();
initSound();
initWeapons();
placeAt(pos);
orientAt(rot);
}
@@ -62,9 +119,6 @@ namespace battleship{
health = SOL_LUA_STATE["health"][id + 1];
maxHealth = health;
rateOfFire = SOL_LUA_STATE["rateOfFire"][id + 1];
range = SOL_LUA_STATE["range"][id + 1];
damage = SOL_LUA_STATE["damage"][id + 1];
lineOfSight = SOL_LUA_STATE["lineOfSight"][id + 1];
unitClass = (UnitClass)SOL_LUA_STATE["unitClass"][id + 1];
type = (UnitType)SOL_LUA_STATE["unitType"][id + 1];
@@ -89,27 +143,37 @@ namespace battleship{
armorTypes.push_back(arm);
}
}
void Unit::initWeapons(){
sol::state_view SOL_STATE_VIEW = generateView();
sol::table unitTable = SOL_STATE_VIEW[GameObject::getGameObjTableName()];
string varName = "numWeapons", tblName = "weapons";
SOL_STATE_VIEW.script(varName + " = #units." + tblName + "[" + to_string(id + 1) + "]");
int numWeapons = SOL_STATE_VIEW[varName];
for(int i = 0; i < numWeapons; i++)
weapons.push_back(new Weapon(this, unitTable[tblName][id + 1][i + 1]));
}
void Unit::destroyWeapons(){
for(Weapon *weapon : weapons)
delete weapon;
weapons.clear();
}
void Unit::destroySound(){
selectionSfx->stop();
delete selectionSfx;
delete selectionSfxBuffer;
if(fireSfx){
fireSfx->stop();
delete fireSfx;
delete fireSfxBuffer;
}
}
void Unit::initSound(){
GameObject::initSound();
selectionSfxBuffer = new sf::SoundBuffer();
selectionSfx = GameObject::prepareSfx(selectionSfxBuffer, "selectionSfx");
fireSfxBuffer = new sf::SoundBuffer();
fireSfx = prepareSfx(fireSfxBuffer, "fireSfx");
string sfxPath = generateView()[getGameObjTableName()]["selectionSfx"][id + 1];
selectionSfx = GameObject::prepareSfx(selectionSfxBuffer, sfxPath);
}
void Unit::reinit(){
@@ -163,30 +227,6 @@ namespace battleship{
return rotSpeed;
}
void Unit::fire(){
fireSfx->play();
Unit *targetUnit = orders[0].targets[0].unit;
if(targetUnit){
targetUnit->takeDamage(damage);
if(targetUnit->getHealth() <= DEATH_HP){
Player *targUnitPlayer = targetUnit->getPlayer();
if(targetUnit->isVehicle()){
player->incVehiclesDestroyed();
targUnitPlayer->incVehiclesLost();
}
else{
player->incStructuresDestroyed();
targUnitPlayer->incStructuresLost();
}
}
}
lastFireTime = getTime();
}
void Unit::initUnitStats(){
}
+31 -7
View File
@@ -60,6 +60,31 @@ namespace battleship{
class Unit : public GameObject{
public:
class Weapon{
public:
enum class Type{HITSCAN, SHELL, TORPEDO, CRUISE_MISSILE};
Weapon(Unit*, sol::table);
~Weapon();
virtual void fire(Order);
inline int getRateOfFire(){return rateOfFire;}
inline int getDamage(){return damage;}
inline int getMinRange(){return minRange;}
inline int getMaxRange(){return maxRange;}
inline Unit* getUnit(){return unit;}
private:
bool hitscan;
int projId = -1, rateOfFire, damage = 0, minRange, maxRange;
vb01::Vector3 projPos;
vb01::Quaternion projRot;
vb01::s64 lastFireTime = 0;
Unit *unit = nullptr;
sf::SoundBuffer *fireSfxBuffer;
sf::Sound *fireSfx = nullptr;
inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;}
};
struct GarrisonSlot{
Vehicle *vehicle = nullptr;
int category;
@@ -90,7 +115,6 @@ namespace battleship{
inline PointDefense* toPointDefense(){return (PointDefense*)this;}
inline int getNumGarrisonSlots(){return garrisonSlots.size();}
inline const std::vector<GarrisonSlot>& getGarrisonSlots(){return garrisonSlots;}
inline vb01::Vector3* getPosPtr() {return &pos;}
inline float getLineOfSight() {return lineOfSight;}
inline vb01::Model* getNode() {return model;}
inline UnitType getType() {return type;}
@@ -98,12 +122,15 @@ namespace battleship{
inline void takeDamage(int damage) {health -= damage;}
inline int getPlayerId() {return playerId;}
inline int getHealth(){return health;}
inline int getDeathHp(){return DEATH_HP;}
inline bool isVehicle(){return gameBase::generateView()["units"]["isVehicle"][id + 1];}
inline bool isTargetToTheRight(vb01::Vector3 dir, vb01::Vector3 lv){return lv.getAngleBetween(dir) > vb01::PI / 2;}
private:
void renderOrderLine(bool);
void updateScreenCoordinates();
void init();
void initWeapons();
void destroyWeapons();
inline bool canDisplayOrderLine(){return vb01::getTime() - orderLineDispTime < orderVecDispLength;}
const int orderVecDispLength = 2000, DEATH_HP = 0;
@@ -114,13 +141,12 @@ namespace battleship{
UnitClass unitClass;
UnitType type;
std::vector<Order> orders;
sf::SoundBuffer *fireSfxBuffer;
sf::Sound *fireSfx = nullptr;
int health, damage, maxHealth, cost, id, playerId, lenHpBar = 200, rateOfFire;
int health, maxHealth, cost, id, playerId, lenHpBar = 200;
s64 orderLineDispTime = 0, lastFireTime = 0;
float lineOfSight, range;
float lineOfSight;
std::vector<GarrisonSlot> garrisonSlots;
std::vector<Armor> armorTypes;
std::vector<Weapon*> weapons;
std::vector<Player*> getSelectingPlayers();
void removeOrder(int);
@@ -137,11 +163,9 @@ namespace battleship{
virtual void patrol(Order){}
virtual void launch(Order){}
float calculateRotation(vb01::Vector3, float, float);
virtual void fire();
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);
inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;}
inline std::vector<Armor> getArmorTypes(){return armorTypes;}
};
}
+5 -4
View File
@@ -290,7 +290,8 @@ namespace battleship{
Order::Target target = order.targets[0];
Vector3 targVec = (target.unit ? target.unit->getPos() : target.pos) - pos;
float distToTarg = targVec.getLength();
float minDist = range;
Weapon *weapon = weapons[0];
float minDist = weapon->getMaxRange();
if(distToTarg > minDist)
navigateToTarget(.5 * Map::getSingleton()->getCellSize().x);
@@ -299,9 +300,9 @@ namespace battleship{
float angleToTarg = targVec.norm().getAngleBetween(dirVec);
if(distToTarg <= range){
if(angleToTarg <= anglePrecision && canFire())
fire();
if(distToTarg <= weapon->getMaxRange()){
if(angleToTarg <= anglePrecision)
weapon->fire(order);
else if(angleToTarg > anglePrecision)
turn(calculateRotation(targVec.norm(), angleToTarg, maxTurnAngle));
}