mirror of
https://github.com/devZoGok/PlanetFleet.git
synced 2026-08-26 19:43:29 +00:00
Merge pull request #205 from devZoGok/bf-112-alignment
Bf 112 alignment
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -171,8 +171,8 @@ units = {
|
||||
orderType = OrderType.ATTACK,
|
||||
rateOfFire = 1000,
|
||||
damage = 200,
|
||||
maxRange = 25,
|
||||
horizontalNode = {name = 'Turret', rotationSpeed = .05, maxFireAngle = .1},
|
||||
maxRange = 50,
|
||||
nodes = {{name = 'Turret', rotationSpeed = .05, maxFireAngle = .1}},
|
||||
projectile = {id = ProjectileId.HE_SHELL, parent = 'Turret', pos = {x = 0.06, y = 5.82, z = 11.4}, rot = {w = 1, x = 0, y = 0, z = 0}},
|
||||
fireFx = {
|
||||
{
|
||||
@@ -201,6 +201,7 @@ units = {
|
||||
unitType = UnitType.LAND,
|
||||
armor = {ArmorType.STEEL},
|
||||
isVehicle = true,
|
||||
alignToSurface = true,
|
||||
health = 500,
|
||||
buildTime = 1000,
|
||||
cost = 500,
|
||||
@@ -213,7 +214,7 @@ units = {
|
||||
albedoPath = 'tank.jpg',
|
||||
colorNodes = {'Antenna_S', 'Antenna_L', 'Hatch'},
|
||||
selectionSfx = PATH .. 'Sounds/Units/Tanks/selection.ogg',
|
||||
speed = .1,
|
||||
speed = .4,
|
||||
destinationOffset = .1,
|
||||
anglePrecision = .1,
|
||||
maxTurnAngle = .1,
|
||||
@@ -227,8 +228,10 @@ units = {
|
||||
rateOfFire = 2000,
|
||||
damage = 5000,
|
||||
maxRange = 70,
|
||||
horizontalNode = {name = 'turret', rotationSpeed = .05, maxFireAngle = .1},
|
||||
verticalNode = {name = 'tubes', rotationSpeed = .05, maxFireAngle = .1},
|
||||
nodes = {
|
||||
{name = 'turret', rotationSpeed = .05, maxFireAngle = .1},
|
||||
{name = 'tubes', rotationSpeed = .05, maxFireAngle = .1}
|
||||
},
|
||||
projectile = {id = ProjectileId.MISSILE, parent = 'tubes', pos = {x = 0.95, y = 2.16, z = 4.11}, rot = {w = 1, x = 0, y = 0, z = 0}},
|
||||
fireFx = {
|
||||
{
|
||||
@@ -254,6 +257,7 @@ units = {
|
||||
unitClass = UnitClass.ARTILLERY,
|
||||
unitType = UnitType.LAND,
|
||||
armor = {ArmorType.MECHANIC},
|
||||
alignToSurface = true,
|
||||
isVehicle = true,
|
||||
health = 500,
|
||||
buildTime = 1000,
|
||||
@@ -267,7 +271,7 @@ units = {
|
||||
albedoPath = 'artillery.jpg',
|
||||
colorNodes = {'turret'},
|
||||
selectionSfx = PATH .. 'Sounds/Units/Tanks/selection.ogg',
|
||||
speed = .1,
|
||||
speed = .3,
|
||||
destinationOffset = .1,
|
||||
anglePrecision = .1,
|
||||
maxTurnAngle = .1,
|
||||
@@ -322,6 +326,7 @@ units = {
|
||||
{
|
||||
unitClass = UnitClass.TRANSPORT,
|
||||
unitType = UnitType.HOVER,
|
||||
alignToSurface = true,
|
||||
isVehicle = true,
|
||||
health = 500,
|
||||
buildTime = 1000,
|
||||
@@ -348,6 +353,7 @@ units = {
|
||||
unitClass = UnitClass.TRANSPORT,
|
||||
unitType = UnitType.HOVER,
|
||||
armor = {ArmorType.MECHANIC},
|
||||
alignToSurface = true,
|
||||
isVehicle = true,
|
||||
health = 500,
|
||||
buildTime = 1000,
|
||||
@@ -379,6 +385,7 @@ units = {
|
||||
unitClass = UnitClass.RESOURCE_ROVER,
|
||||
unitType = UnitType.HOVER,
|
||||
armor = {ArmorType.CAST},
|
||||
alignToSurface = true,
|
||||
capacity = 3000,
|
||||
loadRate = 1,
|
||||
loadSpeed = 5,
|
||||
@@ -882,7 +889,7 @@ units = {
|
||||
rateOfFire = 1000,
|
||||
damage = 0,
|
||||
maxRange = 25,
|
||||
horizontalNode = {name = 'turret', rotationSpeed = .05, maxFireAngle = .1},
|
||||
nodes = {{name = 'turret', rotationSpeed = .05, maxFireAngle = .1}},
|
||||
projectile = {id = ProjectileId.EMP_SHELL, parent = 'turret', pos = {x = 0.06, y = 5.82, z = 11.4}, rot = {w = .998, x = -.066, y = 0, z = 0}},
|
||||
fireFx = {
|
||||
{
|
||||
@@ -1009,8 +1016,10 @@ units = {
|
||||
rateOfFire = 100,
|
||||
damage = 50,
|
||||
maxRange = 50,
|
||||
horizontalNode = {name = 'TurretBody', rotationSpeed = .05, maxFireAngle = .1},
|
||||
--verticalNode = {name = 'TurretArms', rotationSpeed = .05, maxFireAngle = .1},
|
||||
nodes = {
|
||||
{name = 'TurretBody', rotationSpeed = .05, maxFireAngle = .1},
|
||||
{name = 'TurretArms', rotationSpeed = .05, maxFireAngle = .1}
|
||||
},
|
||||
fireFx = {
|
||||
{
|
||||
vfx = true,
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ namespace battleship{
|
||||
|
||||
const std::string DEFAULT_TEXTURE = "Textures/defaultTexture.jpg";
|
||||
const double camPanSpeed = .5, CAMERA_DISTANCE = 100, CAMERA_ZOOM_INCREMENT = 1, cellLength = 7, cellWidth = 7, cellDepth = 7, DIST_FROM_RAY = 15;
|
||||
const int maxNumGroups = 10, NUM_MAX_ZOOMS = 75;
|
||||
const int maxNumGroups = 10, NUM_MAX_ZOOMS = 75, NUM_SUBDIVS = 100;
|
||||
const vb01::u32 IMPASS_NODE_VAL = 65535;
|
||||
|
||||
const static int numAppStates = 5;
|
||||
|
||||
Vendored
+1
-1
Submodule external/vb01 updated: 79c33f2f2a...8acc008fa4
@@ -459,7 +459,7 @@ namespace battleship{
|
||||
Vector3 pos = Vector3(unitTable[posInd]["x"], unitTable[posInd]["y"], unitTable[posInd]["z"]);
|
||||
|
||||
string rotInd = "rot";
|
||||
Quaternion rot = Quaternion(unitTable[rotInd]["w"], unitTable[rotInd]["x"], unitTable[rotInd]["x"], unitTable[rotInd]["x"]);
|
||||
Quaternion rot = Quaternion(unitTable[rotInd]["w"], unitTable[rotInd]["x"], unitTable[rotInd]["y"], unitTable[rotInd]["z"]);
|
||||
|
||||
int id = unitTable["id"];
|
||||
int buildStatus = unitTable["buildStatus"].get_or(0);
|
||||
|
||||
@@ -72,7 +72,6 @@ namespace battleship{
|
||||
float *oldLandmassVertHeights = nullptr;
|
||||
bool pushing = false, movingTerrainObject = false, scalingTerrainObject = false, weightsGenerated = false, newMap, cellMarkersVisible = false;
|
||||
const float MIN_RADIUS = 1, MAX_RADIUS = 100, INCREASE_RATE = 1;
|
||||
const int NUM_SUBDIVS = 100;
|
||||
float circleRadius = MIN_RADIUS, guiThreshold = 200;
|
||||
vb01::Vector3 pushPos = vb01::Vector3::VEC_ZERO;
|
||||
std::vector<vb01::Texture*> skyTextures, landmassTextures, waterTextures;
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace battleship{
|
||||
vector<int> currTechs = player->getTechnologies();
|
||||
|
||||
string name = unitTable["name"];
|
||||
alignToSurface = unitTable["alignToSurface"].get_or(false);
|
||||
vehicle = unitTable["isVehicle"];
|
||||
health += game->calcAbilFromTech(Ability::Type::HEALTH, currTechs, (int)GameObject::type, id);
|
||||
maxHealth = unitTable["health"];
|
||||
@@ -513,14 +514,29 @@ namespace battleship{
|
||||
|
||||
//TODO select only the closest cells based on unit size
|
||||
void Unit::placeAt(Vector3 p){
|
||||
Map *map = Map::getSingleton();
|
||||
|
||||
if(alignToSurface){
|
||||
vector<RayCaster::CollisionResult> res = RayCaster::cast(Vector3(p.x, 100, p.z), -Vector3::VEC_J, map->getNodeParent()->getChildren(), 0, 20);
|
||||
|
||||
if(res.empty() || res[0].mesh->getNode() != map->getNodeParent()->getChild(0))
|
||||
model->lookAt(Vector3(dirVec.x, 0, dirVec.z).norm(), Vector3::VEC_J);
|
||||
else if(res[0].mesh->getNode() == map->getNodeParent()->getChild(0)){
|
||||
float angle = upVec.getAngleBetween(res[0].norm);
|
||||
|
||||
//if(angle > 0)
|
||||
model->lookAt(leftVec.cross(res[0].norm), res[0].norm);
|
||||
}
|
||||
}
|
||||
|
||||
ActiveGameState *activeState = (ActiveGameState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::ACTIVE_STATE);
|
||||
|
||||
//check twice in case the unit is warped over a long distance
|
||||
if(activeState) Map::getSingleton()->blockCells(this);
|
||||
if(activeState) map->blockCells(this);
|
||||
GameObject::placeAt(p);
|
||||
|
||||
if(activeState){
|
||||
Map::getSingleton()->blockCells(this);
|
||||
map->blockCells(this);
|
||||
|
||||
if(activeState->getPlayer())
|
||||
Map::Minimap::getSingleton()->updateImage();
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace battleship{
|
||||
sf::SoundBuffer *selectionSfxBuffer;
|
||||
sf::Sound *selectionSfx = nullptr;
|
||||
vb01::Node *hpBackgroundNode = nullptr, *hpForegroundNode = nullptr, *losLightNode = nullptr;
|
||||
bool vehicle, currOrderStarted = false;
|
||||
bool vehicle, currOrderStarted = false, alignToSurface = false;
|
||||
Condition condition = Condition::ABLE;
|
||||
protected:
|
||||
UnitClass unitClass;
|
||||
|
||||
@@ -56,201 +56,20 @@ namespace battleship{
|
||||
stateManager->attachAppState(loadState);
|
||||
}
|
||||
|
||||
void makeTitlescreenButtons(GuiAppState *state) {
|
||||
/*
|
||||
class SpButton : public Button {
|
||||
public:
|
||||
SpButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_S, separate) {
|
||||
this->state = state;
|
||||
}
|
||||
Vector3 getVecToPlane(Vector3 pos, Vector3 dirVec, Vector3 upVec){
|
||||
float baseAngle = upVec.getAngleBetween(dirVec.norm());
|
||||
|
||||
void onMouseOver(){
|
||||
setColor(Vector4(.8, .8, .8, 1));
|
||||
}
|
||||
if(fabs(baseAngle - PI / 2) > .001){
|
||||
bool acuteAngle = (baseAngle < PI / 2);
|
||||
|
||||
void onMouseOff(){
|
||||
setColor(Vector4(.6, .6, .6, 1));
|
||||
}
|
||||
if(acuteAngle) baseAngle = PI / 2 - baseAngle;
|
||||
else baseAngle -= PI / 2;
|
||||
|
||||
void onClick() {
|
||||
vector<string> difficulties, factions;
|
||||
|
||||
class PlayButton : public Button {
|
||||
public:
|
||||
PlayButton(Listbox **difficulties, Listbox **factions, Listbox *mapListbox, int lengths[2], Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_P, separate) {
|
||||
this->state = ((GuiAppState*)GameManager::getSingleton()->getStateManager()->getAppStateByType(AppStateType::GUI_STATE));
|
||||
this->lengths[0] = lengths[0];
|
||||
this->lengths[1] = lengths[1];
|
||||
|
||||
difficultiesListboxes = difficulties;
|
||||
factionsListboxes = factions;
|
||||
this->mapListbox = mapListbox;
|
||||
}
|
||||
|
||||
void onClick() {
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
std::vector<string> difficulties, factions;
|
||||
|
||||
for(int i = 0; i < lengths[0]; i++)
|
||||
difficulties.push_back(wstringToString(difficultiesListboxes[i]->getContents()[difficultiesListboxes[i]->getSelectedOption()]));
|
||||
|
||||
for(int i = 0; i < lengths[1]; i++)
|
||||
factions.push_back(to_string(factionsListboxes[i]->getSelectedOption()));
|
||||
|
||||
|
||||
delete[] difficultiesListboxes;
|
||||
delete[] factionsListboxes;
|
||||
|
||||
StateManager *stateManager = gm->getStateManager();
|
||||
int selectedMap = mapListbox->getSelectedOption();
|
||||
string mapName = wstringToString(mapListbox->getContents()[selectedMap]);
|
||||
stateManager->attachAppState(new InGameAppState(difficulties, factions, mapName));
|
||||
state->removeAllListboxes();
|
||||
state->removeButton("Back");
|
||||
state->removeButton("Play");
|
||||
}
|
||||
private:
|
||||
GuiAppState *state;
|
||||
Listbox **difficultiesListboxes, **factionsListboxes, *mapListbox = nullptr;
|
||||
int lengths[2];
|
||||
};
|
||||
|
||||
class ReturnButton : public Button {
|
||||
public:
|
||||
|
||||
ReturnButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", GLFW_KEY_B, separate) {
|
||||
this->state = state;
|
||||
}
|
||||
|
||||
void onClick() {
|
||||
state->removeAllCheckboxes();
|
||||
state->removeAllListboxes();
|
||||
state->removeAllSliders();
|
||||
state->removeAllTextboxes();
|
||||
makeTitlescreenButtons(state);
|
||||
state->removeButton("Play");
|
||||
state->removeButton("Back");
|
||||
}
|
||||
private:
|
||||
GuiAppState *state;
|
||||
};
|
||||
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
Vector2 pos(gm->getWidth() / 8, gm->getHeight() / 8);
|
||||
difficulties.push_back("Easy");
|
||||
difficulties.push_back("Medium");
|
||||
difficulties.push_back("Hard");
|
||||
factions.push_back("0");
|
||||
factions.push_back("1");
|
||||
|
||||
|
||||
string font = gm->getPath() + "Fonts/batang.ttf";
|
||||
Listbox *cpuDifficulty = new Listbox(Vector2(pos.x, pos.y + 30), Vector2(100, 20), difficulties, 3, font);
|
||||
Listbox *cpuFaction = new Listbox(Vector2(pos.x + 110, pos.y + 30), Vector2(100, 20), factions, 2, font);
|
||||
Listbox *playerFaction = new Listbox(Vector2(pos.x + 110, pos.y), Vector2(100, 20), factions, 2, font);
|
||||
|
||||
vector<string> folders = readDir(gm->getPath() + "Models/Maps", true);
|
||||
int numMinDirs = 3;
|
||||
int numShowDirs = folders.size() < numMinDirs ? folders.size() : numMinDirs;
|
||||
Listbox *map = new Listbox(Vector2(pos.x + 110, pos.y + 100), Vector2(100, 20), folders, numShowDirs, font);
|
||||
Listbox **difficultyListboxes = new Listbox*[1];
|
||||
Listbox **factionListboxes = new Listbox*[2];
|
||||
|
||||
difficultyListboxes[0] = cpuDifficulty;
|
||||
factionListboxes[0] = playerFaction;
|
||||
factionListboxes[1] = cpuFaction;
|
||||
|
||||
int lengths[]{1, 2};
|
||||
PlayButton *playButton = new PlayButton(difficultyListboxes, factionListboxes, map, lengths, Vector2(50, gm->getHeight() - 150), Vector2(140, 50), "Play", true);
|
||||
ReturnButton *returnButton = new ReturnButton(state, Vector2(200, gm->getHeight() - 150), Vector2(140, 50), "Back", true);
|
||||
state->addButton(playButton);
|
||||
state->addButton(returnButton);
|
||||
state->addListbox(cpuDifficulty);
|
||||
state->addListbox(cpuFaction);
|
||||
state->addListbox(playerFaction);
|
||||
state->addListbox(map);
|
||||
state->removeButton("Options");
|
||||
state->removeButton("Exit");
|
||||
state->removeButton("Singleplayer");
|
||||
|
||||
}
|
||||
private:
|
||||
GuiAppState *state;
|
||||
};
|
||||
|
||||
class MainMenuOptionsButton : public OptionsButton {
|
||||
public:
|
||||
|
||||
MainMenuOptionsButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : OptionsButton(pos, size, name, separate) {
|
||||
this->state = state;
|
||||
}
|
||||
|
||||
void onClick() {
|
||||
ReturnButton *returnButton = new ReturnButton(state, Vector2(50, GameManager::getSingleton()->getHeight() - 150), Vector2(150, 50), "Back", true);
|
||||
state->addButton(returnButton);
|
||||
state->removeButton("Singleplayer");
|
||||
state->removeButton("Exit");
|
||||
OptionsButton::onClick();
|
||||
}
|
||||
|
||||
void onMouseOver(){
|
||||
setColor(Vector4(.8, .8, .8, 1));
|
||||
}
|
||||
|
||||
void onMouseOff(){
|
||||
setColor(Vector4(.6, .6, .6, 1));
|
||||
}
|
||||
private:
|
||||
GuiAppState *state;
|
||||
|
||||
class ReturnButton : public Button {
|
||||
public:
|
||||
|
||||
ReturnButton(GuiAppState *state, Vector2 pos, Vector2 size, string name, bool separate) : Button(pos, size, name, GameManager::getSingleton()->getPath() + "Fonts/batang.ttf", -1, separate) {
|
||||
this->state = state;
|
||||
}
|
||||
|
||||
void onClick() {
|
||||
state->removeAllCheckboxes();
|
||||
state->removeAllListboxes();
|
||||
state->removeAllSliders();
|
||||
state->removeAllTextboxes();
|
||||
state->removeButton("Controls");
|
||||
state->removeButton("Mouse");
|
||||
state->removeButton("Video");
|
||||
state->removeButton("Audio");
|
||||
state->removeButton("Multiplayer");
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
SpButton *spButton = new SpButton(state, Vector2(gm->getWidth() / 16, gm->getHeight() / 12), Vector2(150, 40), "Singleplayer", true);
|
||||
MainMenuOptionsButton *optionsButton = new MainMenuOptionsButton(state, Vector2(gm->getWidth() / 16, gm->getHeight() / 12 * 2), Vector2(150, 40), "Options", true);
|
||||
state->addButton(optionsButton);
|
||||
ExitButton *exitButton = new ExitButton(Vector2(gm->getWidth() / 16, gm->getHeight() / 12 * 3), Vector2(150, 40));
|
||||
state->addButton(spButton);
|
||||
state->addButton(exitButton);
|
||||
state->removeButton("Back");
|
||||
}
|
||||
private:
|
||||
GuiAppState *state;
|
||||
};
|
||||
};
|
||||
|
||||
GameManager *gm = GameManager::getSingleton();
|
||||
string font = gm->getPath() + "Fonts/batang.ttf";
|
||||
int width = gm->getWidth(), height = gm->getHeight();
|
||||
Vector2 size = Vector2(150, 40);
|
||||
|
||||
AssetManager::getSingleton()->load(font);
|
||||
|
||||
SpButton *spButton = new SpButton(state, Vector2(width / 16, height / 12), size, "Singleplayer", true);
|
||||
MainMenuOptionsButton *optionsButton = new MainMenuOptionsButton(state, Vector2(width / 16, height / 12 * 2), size, "Options", true);
|
||||
MapEditorButton *editorButton = new MapEditorButton(Vector2(width / 16, height / 12 * 3), size);
|
||||
ExitButton *exitButton = new ExitButton(Vector2(width / 16, height / 12 * 4), size);
|
||||
state->addButton(spButton);
|
||||
state->addButton(optionsButton);
|
||||
state->addButton(editorButton);
|
||||
state->addButton(exitButton);
|
||||
*/
|
||||
}
|
||||
float pointToPlane = dirVec.getLength() * sin(baseAngle);
|
||||
return (dirVec + upVec * pointToPlane * (acuteAngle ? -1 : 1)).norm();
|
||||
}
|
||||
else return dirVec.norm();
|
||||
}
|
||||
|
||||
vector<string> readDir(string path, bool findFolders){
|
||||
tinydir_dir dir;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace battleship{
|
||||
class LoadingAppState;
|
||||
|
||||
void handleLoadingGui(LoadingAppState*);
|
||||
void makeTitlescreenButtons(GuiAppState*);
|
||||
vb01::Vector3 getVecToPlane(vb01::Vector3, vb01::Vector3, vb01::Vector3);
|
||||
std::vector<std::string> readDir(std::string, bool);
|
||||
vb01::Vector2 spaceToScreen(vb01::Vector3);
|
||||
vb01::Vector3 spaceToScreen3d(vb01::Vector3);
|
||||
|
||||
+133
-62
@@ -1,13 +1,16 @@
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#include <solUtil.h>
|
||||
|
||||
#include <util.h>
|
||||
#include <box.h>
|
||||
#include <quad.h>
|
||||
#include <model.h>
|
||||
#include <quaternion.h>
|
||||
|
||||
#include "pathfinder.h"
|
||||
#include "defConfigs.h"
|
||||
#include "structure.h"
|
||||
#include "vehicle.h"
|
||||
#include "weapon.h"
|
||||
@@ -103,76 +106,148 @@ namespace battleship{
|
||||
initProperties();
|
||||
}
|
||||
|
||||
void Vehicle::navigate(float destOffset){
|
||||
Vector3 hypVec = (pathPoints[0] - pos);
|
||||
void Vehicle::arrivedAtPathpoint(bool byPlane, float vertDist){
|
||||
bool orderHasDir = (orders[0].direction != Vector3::VEC_ZERO);
|
||||
float angleToOrderDir = dirVec.getAngleBetween(orders[0].direction);
|
||||
bool destDirWithin = (!orderHasDir || (orderHasDir && angleToOrderDir <= anglePrecision));
|
||||
|
||||
if(pathPoints.size() == 1 && !destDirWithin)
|
||||
turn(calculateRotation(orders[0].direction, angleToOrderDir, maxTurnAngle));
|
||||
|
||||
if(byPlane && (
|
||||
(pathPoints.size() > 1 || (pathPoints.size() == 1 && destDirWithin)) &&
|
||||
(type != UnitType::UNDERWATER || (type == UnitType::UNDERWATER && vertDist < 0.5 * height))
|
||||
)
|
||||
){
|
||||
removePathpoint();
|
||||
}
|
||||
else if(!byPlane && (pathPoints.size() > 1 || (pathPoints.size() == 1 && destDirWithin)))
|
||||
removePathpoint();
|
||||
}
|
||||
|
||||
void Vehicle::moveByTerrainQuads(Vector3 hypVec, float destOffset){
|
||||
Map *map = Map::getSingleton();
|
||||
Quad *terrQuad = (Quad*)map->getNodeParent()->getChild(0)->getMesh(0);
|
||||
int numVertDiv = configData::NUM_SUBDIVS, numHorDiv = configData::NUM_SUBDIVS;
|
||||
Vector3 mapSize = map->getMapSize();
|
||||
Vector2 sqIdsVec = terrQuad->getSubquadIds(numVertDiv, numHorDiv, pos, mapSize);
|
||||
Vector2 sqIdsEndVec = terrQuad->getSubquadIds(numVertDiv, numHorDiv, pathPoints[0], mapSize);
|
||||
|
||||
int sqIds[]{sqIdsVec.x, sqIdsVec.y};
|
||||
vector<Vector3> points = vector<Vector3>{pos};
|
||||
|
||||
// y = ax + b
|
||||
float a = hypVec.z / hypVec.x;
|
||||
float b = pos.z - a * pos.x;
|
||||
|
||||
while(!(sqIds[0] == (int)sqIdsEndVec.x && sqIds[1] == (int)sqIdsEndVec.y)){
|
||||
Vector3 c1 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, true, false); //top left
|
||||
Vector3 c2 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, true, true); //top right
|
||||
Vector3 c3 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, false, false); //bottom left
|
||||
Vector3 c4 = terrQuad->getSubquadCorner(sqIds[0], sqIds[1], numVertDiv, numHorDiv, false, true); //bottom right
|
||||
|
||||
float minX = c1.x, maxX = c2.x, minY = c1.z, maxY = c3.z;
|
||||
bool bottom = (hypVec.z > 0), left = (hypVec.x < 0);
|
||||
float intersecX = (left ? c1.x : c2.x);
|
||||
float intersecY = (bottom ? c3.z : c1.z);
|
||||
|
||||
float xSolY = a * intersecX + b;
|
||||
float ySolX = (hypVec.x != 0 ? (intersecY - b) / a : points[points.size() - 1].x);
|
||||
|
||||
float diff, vertDiff, x, y, z;
|
||||
|
||||
if(minY <= xSolY && xSolY <= maxY){
|
||||
diff = (xSolY - c1.z) / (c3.z - c1.z);
|
||||
vertDiff = (left ? c3.y - c1.y : c4.y - c2.y);
|
||||
|
||||
x = (left ? c1.x : c2.x);
|
||||
y = (left ? c1.y : c2.y) + vertDiff * diff;
|
||||
z = xSolY;
|
||||
|
||||
sqIds[0] += (left ? -1 : 1);
|
||||
}
|
||||
else if(hypVec.x == 0 || (minX <= ySolX && ySolX <= maxX)){
|
||||
diff = (ySolX - c1.x) / (c2.x - c1.x);
|
||||
vertDiff = (bottom ? c4.y - c3.y : c2.y - c1.y);
|
||||
|
||||
x = ySolX;
|
||||
y = (bottom ? c3.y : c1.y) + vertDiff * diff;
|
||||
z = (bottom ? c3.z : c1.z);
|
||||
|
||||
sqIds[1] += (bottom ? 1 : -1);
|
||||
}
|
||||
|
||||
points.push_back(Vector3(x, y, z));
|
||||
}
|
||||
|
||||
points.push_back(pathPoints[0]);
|
||||
|
||||
float movementAmmount = speed, totalDist = 0, eps = .01;
|
||||
Vector3 endPos = pos;
|
||||
|
||||
for(int i = 0; i < points.size() - 1; i++){
|
||||
Vector3 diffVec = (points[i + 1] - points[i]).norm();
|
||||
float dist = points[i].getDistanceFrom(points[i + 1]);
|
||||
float diff = dist;
|
||||
|
||||
if(fabs(totalDist + dist - movementAmmount) > eps)
|
||||
diff = movementAmmount - totalDist;
|
||||
|
||||
endPos += diffVec * diff;
|
||||
totalDist += diff;
|
||||
}
|
||||
|
||||
placeAt(endPos);
|
||||
|
||||
if(fabs(pathPoints[0].x - pos.x) <= destOffset && fabs(pathPoints[0].z - pos.z) <= destOffset)
|
||||
arrivedAtPathpoint(false);
|
||||
}
|
||||
|
||||
void Vehicle::moveByPlane(Vector3 hypVec, float destOffset){
|
||||
float hypAngle = hypVec.norm().getAngleBetween(upVec) - PI / 2;
|
||||
float offset = hypVec.getLength() * sin(hypAngle);
|
||||
|
||||
Vector3 linDest = pathPoints[0] + upVec * offset;
|
||||
float vertDist = fabs(pos.y - pathPoints[0].y);
|
||||
Vector3 destDir = (linDest - pos).norm();
|
||||
float angle = (destDir != Vector3::VEC_ZERO ? dirVec.getAngleBetween(destDir) : -1);
|
||||
|
||||
if(angle > anglePrecision && pos.getDistanceFrom(linDest) > destOffset)
|
||||
turn(calculateRotation(destDir, angle, maxTurnAngle));
|
||||
else{
|
||||
if(pos.getDistanceFrom(linDest) > destOffset){
|
||||
float dist = pos.getDistanceFrom(linDest);
|
||||
float movementAmmount = (speed > dist ? dist : speed);
|
||||
advance(movementAmmount);
|
||||
}
|
||||
|
||||
if(vertDist > .1){
|
||||
float dist = pos.y - pathPoints[0].y;
|
||||
float movementAmmount = (speed > fabs(dist) ? dist : speed);
|
||||
|
||||
if(dist > 0)
|
||||
movementAmmount *= -1;
|
||||
|
||||
advance(movementAmmount, MoveDir::UP);
|
||||
}
|
||||
|
||||
if(pos.getDistanceFrom(linDest) <= destOffset){
|
||||
bool orderHasDir = (orders[0].direction != Vector3::VEC_ZERO);
|
||||
float angleToOrderDir = dirVec.getAngleBetween(orders[0].direction);
|
||||
bool destDirWithin = (!orderHasDir || (orderHasDir && angleToOrderDir <= anglePrecision));
|
||||
|
||||
if(pathPoints.size() == 1 && !destDirWithin)
|
||||
turn(calculateRotation(orders[0].direction, angleToOrderDir, maxTurnAngle));
|
||||
|
||||
if(pathPoints.size() > 1 || (pathPoints.size() == 1 && destDirWithin)){
|
||||
if(type == UnitType::UNDERWATER && vertDist < 0.5 * height)
|
||||
removePathpoint();
|
||||
else if(type != UnitType::UNDERWATER)
|
||||
removePathpoint();
|
||||
}
|
||||
}
|
||||
if(pos.getDistanceFrom(pathPoints[0]) > destOffset){
|
||||
float dist = pos.getDistanceFrom(linDest);
|
||||
float movementAmmount = (speed > dist ? dist : speed);
|
||||
advance(movementAmmount);
|
||||
}
|
||||
|
||||
float vertDist = fabs(pos.y - pathPoints[0].y);
|
||||
|
||||
if(vertDist > .1){
|
||||
float dist = pos.y - pathPoints[0].y;
|
||||
float movementAmmount = (speed > fabs(dist) ? dist : speed);
|
||||
|
||||
if(dist > 0) movementAmmount *= -1;
|
||||
|
||||
advance(movementAmmount, MoveDir::UP);
|
||||
}
|
||||
|
||||
if(pos.getDistanceFrom(linDest) <= destOffset)
|
||||
arrivedAtPathpoint(true, vertDist);
|
||||
}
|
||||
|
||||
void Vehicle::alignToSurface(){
|
||||
/*
|
||||
Map *map = Map::getSingleton();
|
||||
TerrainObject terr = map->getTerrainObject(0);
|
||||
vector<RayCaster::CollisionResult> res = RayCaster::cast(Vector3(pos.x, terr.size.y, pos.z), Vector3(0, -1, 0), terr.node);
|
||||
|
||||
if(!res.empty()){
|
||||
placeAt(res[0].pos);
|
||||
|
||||
float angle = upVec.getAngleBetween(res[0].norm);
|
||||
Vector3 axis = upVec.cross(res[0].norm).norm();
|
||||
Quaternion rotQuat = Quaternion(angle, axis);
|
||||
orientAt(rotQuat * rot);
|
||||
}
|
||||
*/
|
||||
void Vehicle::navigate(float destOffset){
|
||||
Vector3 hypVec = (pathPoints[0] - pos);
|
||||
Vector3 baseDir = getVecToPlane(pos, hypVec, upVec);
|
||||
float angle = baseDir.getAngleBetween(dirVec);
|
||||
|
||||
if(angle > anglePrecision && pos.getDistanceFrom(pathPoints[0]) > destOffset)
|
||||
turn(calculateRotation(baseDir, angle, maxTurnAngle));
|
||||
else if(type == UnitType::LAND)
|
||||
moveByTerrainQuads(hypVec, destOffset);
|
||||
else
|
||||
moveByPlane(hypVec, destOffset);
|
||||
}
|
||||
|
||||
void Vehicle::move(Order order) {
|
||||
navigate(0.5 * Map::getSingleton()->getCellSize().x);
|
||||
|
||||
if(type == UnitType::LAND)
|
||||
alignToSurface();
|
||||
|
||||
if(pathPoints.empty())
|
||||
removeOrder(0);
|
||||
}
|
||||
@@ -255,7 +330,7 @@ namespace battleship{
|
||||
|
||||
int dest = map->getCellId(destPos);
|
||||
|
||||
if(type != UnitType::UNDERWATER && fabs(destPos.y - cells[dest].pos.y) > .1) return;
|
||||
if(type != UnitType::UNDERWATER && type == UnitType::SEA_LEVEL && fabs(destPos.y - cells[dest].pos.y) > .1) return;
|
||||
|
||||
if(cells[dest].blockedBy){
|
||||
vector<int> surrCellIds = map->getSurroundingCells(cells[dest].pos, 1);
|
||||
@@ -273,6 +348,7 @@ namespace battleship{
|
||||
heuristics.push_back(145 * (cells[dest].pos.getDistanceFrom(cell.pos)));
|
||||
|
||||
vector<int> path = Pathfinder::getSingleton()->findPath(cells, heuristics, source, dest, this);
|
||||
path.erase(path.begin());
|
||||
bool pathTruncated = false;
|
||||
|
||||
for(int i = 0; i < path.size(); i++){
|
||||
@@ -367,12 +443,7 @@ namespace battleship{
|
||||
}
|
||||
}
|
||||
}
|
||||
else{
|
||||
navigate(0.5 * Map::getSingleton()->getCellSize().x);
|
||||
|
||||
if(type == UnitType::LAND)
|
||||
alignToSurface();
|
||||
}
|
||||
else navigate(0.5 * Map::getSingleton()->getCellSize().x);
|
||||
}
|
||||
|
||||
void Vehicle::select(){
|
||||
|
||||
@@ -41,10 +41,12 @@ namespace battleship{
|
||||
std::vector<vb01::Vector3> pathPoints;
|
||||
bool pursuingTarget = false;
|
||||
|
||||
void arrivedAtPathpoint(bool, float = 0);
|
||||
void moveByTerrainQuads(vb01::Vector3, float);
|
||||
void moveByPlane(vb01::Vector3, float);
|
||||
void navigate(float = 0.);
|
||||
void navigateToTarget(float);
|
||||
void preparePathpoints(Order&, vb01::Vector3, bool = false);
|
||||
void alignToSurface();
|
||||
virtual void attack(Order);
|
||||
void garrison(Order);
|
||||
void patrol(Order);
|
||||
|
||||
+58
-76
@@ -3,6 +3,7 @@
|
||||
#include <particleEmitter.h>
|
||||
|
||||
#include "map.h"
|
||||
#include "util.h"
|
||||
#include "weapon.h"
|
||||
#include "player.h"
|
||||
#include "fxManager.h"
|
||||
@@ -25,12 +26,7 @@ namespace battleship{
|
||||
orderType = (Order::TYPE)weaponTable["orderType"];
|
||||
|
||||
initProjectileData(weaponTable);
|
||||
|
||||
sol::optional<sol::table> horNodeTblOpt = unitTable["weapons"][wid + 1]["horizontalNode"];
|
||||
sol::optional<sol::table> vertNodeTblOpt = unitTable["weapons"][wid + 1]["verticalNode"];
|
||||
|
||||
if(horNodeTblOpt != sol::nullopt) horNode = initNode(weaponTable, true);
|
||||
if(vertNodeTblOpt != sol::nullopt) vertNode = initNode(weaponTable, false);
|
||||
initNodes(weaponTable);
|
||||
|
||||
sol::optional<sol::table> fireFxOpt = weaponTable["fireFx"];
|
||||
|
||||
@@ -42,52 +38,60 @@ namespace battleship{
|
||||
}
|
||||
}
|
||||
|
||||
void Weapon::initNodes(sol::table weaponTable){
|
||||
sol::optional<sol::table> nodesTblOpt = weaponTable["nodes"];
|
||||
|
||||
Node* Weapon::initNode(sol::table weaponTable, bool horizontal){
|
||||
sol::table nodeTbl = weaponTable[horizontal ? "horizontalNode" : "verticalNode"];
|
||||
maxFireAngle = nodeTbl["maxFireAngle"];
|
||||
rotSpeed = nodeTbl["rotationSpeed"];
|
||||
if(nodesTblOpt == sol::nullopt) return;
|
||||
|
||||
string name = nodeTbl["name"];
|
||||
return unit->getModel()->findDescendant(name, true);
|
||||
sol::table tbl = weaponTable["nodes"];
|
||||
int numNodes = tbl.size();
|
||||
|
||||
for(int i = 0; i < numNodes; i++){
|
||||
sol::table nodeTbl = weaponTable["nodes"][i + 1];
|
||||
maxFireAngle = nodeTbl["maxFireAngle"];
|
||||
rotSpeed = nodeTbl["rotationSpeed"];
|
||||
|
||||
string name = nodeTbl["name"];
|
||||
nodes.push_back(unit->getModel()->findDescendant(name, true));
|
||||
}
|
||||
}
|
||||
|
||||
void Weapon::initProjectileData(sol::table weaponTable){
|
||||
string projTableKey = "projectile";
|
||||
sol::optional<sol::table> proj = weaponTable[projTableKey];
|
||||
|
||||
if(proj != sol::nullopt){
|
||||
projId = weaponTable[projTableKey]["id"];
|
||||
sol::table projTable = generateView()["projectiles"];
|
||||
ProjectileClass pc = (ProjectileClass)projTable[projId + 1]["projectileClass"];
|
||||
if(proj == sol::nullopt) return;
|
||||
|
||||
if(pc == ProjectileClass::CRUISE_MISSILE){
|
||||
minRange = 0;
|
||||
float rotAngle = projTable[projId + 1]["rotAngle"];
|
||||
float speed = projTable[projId + 1]["speed"];
|
||||
float base = PI / 2, alpha = 0;
|
||||
projId = weaponTable[projTableKey]["id"];
|
||||
sol::table projTable = generateView()["projectiles"];
|
||||
ProjectileClass pc = (ProjectileClass)projTable[projId + 1]["projectileClass"];
|
||||
|
||||
while(base - alpha > .001){
|
||||
minRange += speed * sin(alpha);
|
||||
alpha += (base - alpha > rotAngle ? rotAngle : base - alpha);
|
||||
}
|
||||
if(pc == ProjectileClass::CRUISE_MISSILE){
|
||||
minRange = 0;
|
||||
float rotAngle = projTable[projId + 1]["rotAngle"];
|
||||
float speed = projTable[projId + 1]["speed"];
|
||||
float base = PI / 2, alpha = 0;
|
||||
|
||||
minRange *= 2;
|
||||
while(base - alpha > .001){
|
||||
minRange += speed * sin(alpha);
|
||||
alpha += (base - alpha > rotAngle ? rotAngle : base - alpha);
|
||||
}
|
||||
|
||||
projPar = unit->getModel();
|
||||
sol::optional<string> parNameOpt = weaponTable[projTableKey]["parent"];
|
||||
|
||||
if(parNameOpt != sol::nullopt){
|
||||
string parName = weaponTable[projTableKey]["parent"];
|
||||
projPar = unit->getModel()->findDescendant(parName, true);
|
||||
}
|
||||
|
||||
sol::table posTable = weaponTable[projTableKey]["pos"];
|
||||
projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
sol::table rotTable = weaponTable[projTableKey]["rot"];
|
||||
projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
|
||||
minRange *= 2;
|
||||
}
|
||||
|
||||
projPar = unit->getModel();
|
||||
sol::optional<string> parNameOpt = weaponTable[projTableKey]["parent"];
|
||||
|
||||
if(parNameOpt != sol::nullopt){
|
||||
string parName = weaponTable[projTableKey]["parent"];
|
||||
projPar = unit->getModel()->findDescendant(parName, true);
|
||||
}
|
||||
|
||||
sol::table posTable = weaponTable[projTableKey]["pos"];
|
||||
projPos = Vector3(posTable["x"], posTable["y"], posTable["z"]);
|
||||
sol::table rotTable = weaponTable[projTableKey]["rot"];
|
||||
projRot = Quaternion(rotTable["w"], rotTable["x"], rotTable["y"], rotTable["z"]);
|
||||
}
|
||||
|
||||
Weapon::~Weapon(){
|
||||
@@ -96,27 +100,6 @@ namespace battleship{
|
||||
if(fireFx) fm->removeFx(fireFx);
|
||||
}
|
||||
|
||||
Vector3 Weapon::calcOrientVec(int id){
|
||||
Vector3 orientVec;
|
||||
|
||||
switch(id){
|
||||
case 0:
|
||||
orientVec = unit->getDirVec();
|
||||
break;
|
||||
case 1:
|
||||
orientVec = unit->getLeftVec();
|
||||
break;
|
||||
case 2:
|
||||
orientVec = unit->getUpVec();
|
||||
break;
|
||||
}
|
||||
|
||||
if(horNode) orientVec = horNode->getOrientation() * orientVec;
|
||||
if(vertNode) orientVec = vertNode->getOrientation() * orientVec;
|
||||
|
||||
return orientVec;
|
||||
}
|
||||
|
||||
//TODO replace unit pos with absolute weapon pos for withinAngle
|
||||
void Weapon::update(){
|
||||
if(unit->getCondition() != Unit::Condition::ABLE) return;
|
||||
@@ -130,9 +113,12 @@ namespace battleship{
|
||||
float targDist = unit->getPos().getDistanceFrom(targPos);
|
||||
|
||||
bool withinRange = (minRange <= targDist && targDist <= maxRange);
|
||||
bool withinAngle = true;
|
||||
|
||||
Vector3 dirVec = calcOrientVec(0);
|
||||
bool withinAngle = (horNode ? Vector3(dirVec.x, 0, dirVec.z).norm().getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle : true);
|
||||
if(!nodes.empty()){
|
||||
Vector3 dirVec = nodes[0]->getGlobalAxis(2);
|
||||
withinAngle = Vector3(dirVec.x, 0, dirVec.z).norm().getAngleBetween((targPos - unit->getPos()).norm()) <= maxFireAngle;
|
||||
}
|
||||
|
||||
if((Order::TYPE)ordTp == Order::TYPE::ATTACK && withinRange && withinAngle)
|
||||
fire(unit->getOrder(0));
|
||||
@@ -224,26 +210,22 @@ namespace battleship{
|
||||
}
|
||||
|
||||
//TODO improve to allow for vertical alignment
|
||||
void Weapon::alignNode(Vector3 targPos, Node *node, bool horizontal){
|
||||
Vector3 targDir = targPos - unit->getPos();
|
||||
Vector3 targDirHor = Vector3(targDir.x, 0, targDir.z).norm(), targDirVert;
|
||||
void Weapon::trackTarget(Vector3 targPos){
|
||||
if(nodes.empty()) return;
|
||||
|
||||
Vector3 dirVec = calcOrientVec(0);
|
||||
Vector3 dirVecHor = Vector3(dirVec.x, 0, dirVec.z).norm(), dirVecVert;
|
||||
Vector3 unitPos = unit->getPos();
|
||||
Vector3 targDir = (targPos - unitPos).norm();
|
||||
targDir = getVecToPlane(unitPos, targDir, unit->getUpVec());
|
||||
|
||||
Vector3 leftVec = calcOrientVec(1);
|
||||
bool negate = (Vector3(leftVec.x, 0, leftVec.z).norm().getAngleBetween(targDirHor) < PI / 2);
|
||||
Vector3 dirVec = getVecToPlane(unitPos, nodes[0]->getGlobalAxis(2), unit->getUpVec());
|
||||
Vector3 leftVec = nodes[0]->getGlobalAxis(0);
|
||||
bool negate = (leftVec.getAngleBetween(targDir) < PI / 2);
|
||||
|
||||
float angle = dirVecHor.getAngleBetween(targDirHor);
|
||||
float angle = dirVec.getAngleBetween(targDir);
|
||||
float rotAngle = (rotSpeed < angle ? rotSpeed : angle);
|
||||
|
||||
Quaternion rot = Quaternion((negate ? 1 : -1) * rotAngle, unit->getUpVec()) * node->getOrientation();
|
||||
node->setOrientation(rot);
|
||||
}
|
||||
|
||||
void Weapon::trackTarget(Vector3 targPos){
|
||||
if(horNode) alignNode(targPos, horNode, true);
|
||||
//if(vertNode) alignNode(targPos, vertNode, false);
|
||||
Quaternion rot = Quaternion((negate ? 1 : -1) * rotAngle, Vector3::VEC_J) * nodes[0]->getOrientation();
|
||||
nodes[0]->setOrientation(rot);
|
||||
}
|
||||
|
||||
CryoGun::CryoGun(Unit *u, sol::table unitTable, int wid) : Weapon(u, unitTable, wid){}
|
||||
|
||||
@@ -42,13 +42,12 @@ namespace battleship{
|
||||
vb01::Quaternion projRot;
|
||||
vb01::Vector3 projPos;
|
||||
float horConstraint = 1.57, vertConstraint = 1.57;
|
||||
vb01::Node *horNode = nullptr, *vertNode = nullptr, *projPar = nullptr;
|
||||
std::vector<vb01::Node*> nodes;
|
||||
vb01::Node *projPar = nullptr;
|
||||
static std::string LASER_FLAG;
|
||||
|
||||
vb01::Vector3 calcOrientVec(int);
|
||||
void alignNode(vb01::Vector3, vb01::Node*, bool);
|
||||
void initProjectileData(sol::table);
|
||||
vb01::Node* initNode(sol::table, bool);
|
||||
void initNodes(sol::table);
|
||||
void useFx(FxManager::Fx*, vb01::Vector3, bool);
|
||||
inline bool canFire(){return vb01::getTime() - lastFireTime > rateOfFire;}
|
||||
protected:
|
||||
|
||||
Reference in New Issue
Block a user