expanded checks to determine if a game object frame is placeable on a given spot

This commit is contained in:
devZoGok
2026-03-15 15:21:11 +02:00
parent 580659aad5
commit 35b22318c4
10 changed files with 154 additions and 39 deletions
+106 -27
View File
@@ -1,5 +1,6 @@
Player.numStartEngis = 3
Player.baseDir = nil
Player.baseQuat = nil
Player.baseRadius = 180
Player.numDefWarMechs = 1
Player.behaviour = {}
Player.pointDefenseTrans = {}
@@ -37,7 +38,7 @@ Player.taskForceData = {
Player.taskForces = {}
function Player:initBaseDir()
function Player:initBaseQuat()
map = Map.getSingleton()
sp = map:getSpawnPoint(self:getSpawnPointId())
minDistId = nil
@@ -54,45 +55,109 @@ function Player:initBaseDir()
::continue::
end
self.baseDir = map:getSpawnPoint(minDistId):subtr(sp):norm()
dir = map:getSpawnPoint(minDistId):subtr(sp):norm()
left = (Vector3:new(1, 0, 0):getAngleBetween(dir) < .5 * math.pi)
angle = dir:getAngleBetween(Vector3:new(0, 0, 1)) * (left and 1 or -1)
self.baseQuat = Quaternion:new(angle, Vector3:new(0, 1, 0))
end
function Player:initPdSpots()
numPd = 6
radius = 100
map = Map.getSingleton()
mapSize = map:getMapSize()
pdId = self.unitClassMappings[UnitClass.POINT_DEFENSE + 1][self:getFaction() + 1]
pdFrame = GameObjectFrame:new(pdId, 0, self, nil, Vector3:new(0, 0, 0), Quaternion:new(1, 0, 0, 0))
baseDir = self.baseQuat:multVec(Vector3:new(0, 0, 1))
frameCtrl = GameObjectFrameController.getSingleton()
numPd = 12
for i = 1, numPd do
angle = (i - 1) * 2 * math.pi / numPd
rotDir = Quaternion:new(angle, Vector3:new(0, 1, 0)):multVec(self.baseDir)
pdPos = map:getSpawnPoint(self:getSpawnPointId()):add(rotDir:norm():mult(radius))
rotDir = Quaternion:new(angle, Vector3:new(0, 1, 0)):multVec(baseDir)
pdPos = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()):add(rotDir:norm():mult(self.baseRadius))
pdFrame:placeAt(pdPos)
if math.abs(pdPos.x) < .5 * mapSize.x and math.abs(pdPos.z) < .5 * mapSize.z then
frameCtrl:checkPlacement(pdFrame)
if pdFrame.status == 0 then
self.pointDefenseTrans[#self.pointDefenseTrans + 1] = {pos = pdPos, angle = angle}
end
end
pdFrame:destroy()
end
--TODO replace this method with more robust checks to determine the possibility of building on a given spot
function Player:updatePdSpots()
pdId = self.unitClassMappings[UnitClass.POINT_DEFENSE + 1][self:getFaction() + 1]
pdFrame = GameObjectFrame:new(pdId, 0, self, nil, Vector3:new(0, 0, 0), Quaternion:new(1, 0, 0, 0))
gofCtrl = GameObjectFrameController.getSingleton()
delPdTrans = {}
for i = 1, #self.pointDefenseTrans do
pdFrame:placeAt(self.pointDefenseTrans[i].pos)
gofCtrl:checkPlacement(pdFrame)
if pdFrame.status == 1 then
table.insert(delPdTrans, i)
end
end
for i = #delPdTrans, 1, -1 do
table.remove(self.pointDefenseTrans, i)
end
pdFrame:destroy()
end
function Player:init()
self:initBaseDir()
self:initBaseQuat()
self:initPdSpots()
end
function Player:findSuitableSpot(buildingId, startPos)
structFrame = GameObjectFrame:new(buildingId, 0, self, nil, startPos, self.baseQuat)
numYPos = math.floor(2 * self.baseRadius / structFrame:getLength())
numXPos = math.floor(2 * self.baseRadius / structFrame:getWidth())
baseDir = self.baseQuat:multVec(Vector3:new(0, 0, 1))
baseLeft = self.baseQuat:multVec(Vector3:new(1, 0, 0))
point = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()):add(baseDir:mult(self.baseRadius)):add(baseLeft:mult(self.baseRadius))
frameCtrl = GameObjectFrameController.getSingleton()
frameCtrl:checkPlacement(structFrame)
if structFrame.status == 1 then
for i = 1, numXPos do
point = point:add(baseLeft:neg():mult(i - 1))
structFrame:placeAt(point)
frameCtrl:checkPlacement(structFrame)
if structFrame.status == 0 then
structFrame:destroy()
return point
end
end
else
structFrame:destroy()
return startPos
end
structFrame:destroy()
return nil
end
function Player:buildStructure(engineer, buildingId, buildPos, buildAngle)
if not engineer then return BTNodeResult.FAILURE end
print(buildAngle)
self:deselectUnits()
self:selectUnits({engineer})
building = GameObjectFactory.createUnit(self, buildingId, buildPos, Quaternion:new(buildAngle, Vector3:new(0, 1, 0)), 0)
building = GameObjectFactory.createUnit(self, buildingId, buildPos, Quaternion:new(-buildAngle, Vector3:new(0, 1, 0)), 0)
self:issueOrder(OrderType.BUILD, Vector3:new(0, 0, 0), {Target:new(building:toGameObject(), Vector3:new(0, 0, 0))}, false)
end
function Player:findSuitableSpot()
return Vector3:new(0, 0, 0)
end
function Player:findIdleEngineer()
engineers = self:getUnitsByClass(UnitClass.CYBORG_ENGINEER, -1)
@@ -115,7 +180,6 @@ function Player:getBuildableUnitSlotId(buildingUnit, buildableUnitId)
return nil
end
--TODO simplify building construction
function Player:buildLandFactory(arguments)
factory = self:getUnitsByClass(UnitClass.LAND_FACTORY, 1)[1]
@@ -124,10 +188,14 @@ function Player:buildLandFactory(arguments)
end
factId = self.unitClassMappings[UnitClass.LAND_FACTORY + 1][self:getFaction() + 1]
rd = self.baseQuat:multVec(Vector3:new(0, 0, 1)):mult(self.baseRadius)
sp = Map.getSingleton():getSpawnPoint(self:getSpawnPointId())
self:buildStructure(self:findIdleEngineer(), factId, sp, angle)
pos = self:findSuitableSpot(factId, sp:add(rd))
return BTNodeResult.RUNNING
if pos then
self:buildStructure(self:findIdleEngineer(), factId, pos, self.baseQuat:getAngle())
return BTNodeResult.RUNNING
else return BTNodeResult.FAILURE end
end
function Player:trainEngineers(arguments)
@@ -150,16 +218,25 @@ function Player:trainEngineers(arguments)
end
function Player:buildRefinery(arguments)
refinery = self:getUnitsByClass(UnitClass.REFINERY, 1)
if #refinery > 0 then
return (refinery[1]:toStructure():isComplete() and BTNodeResult.SUCCESS or BTNodeResult.RUNNING)
refinery = self:getUnitsByClass(UnitClass.REFINERY, 1)[1]
if refinery then
return (refinery:toStructure():isComplete() and BTNodeResult.SUCCESS or BTNodeResult.RUNNING)
end
buildPos = Map.getSingleton():getSpawnPoint(self:getSpawnPointId()):add(self.baseDir:mult(20))
factId = self.unitClassMappings[UnitClass.REFINERY + 1][self:getFaction() + 1]
self:buildStructure(self:findIdleEngineer(), factId, buildPos, -.0)
refId = self.unitClassMappings[UnitClass.REFINERY + 1][self:getFaction() + 1]
factId = self.unitClassMappings[UnitClass.LAND_FACTORY + 1][self:getFaction() + 1]
return BTNodeResult.RUNNING
rd = self.baseQuat:multVec(Vector3:new(0, 0, 1)):mult(self.baseRadius - .5 * (units[factId + 1].size.z + units[refId + 1].size.z))
sp = Map.getSingleton():getSpawnPoint(self:getSpawnPointId())
buildPos = sp:add(rd)
pos = self:findSuitableSpot(refId, buildPos)
if pos then
buildAngle = (self.baseQuat:getAngle() + math.pi)
self:buildStructure(self:findIdleEngineer(), refId, buildPos, buildAngle)
return BTNodeResult.RUNNING
else return BTNodeResult.FAILURE end
end
-- TODO optimize deposit position check
@@ -281,8 +358,10 @@ function Player:buildLandForce(arguments)
end
function Player:buildPointDefenseRing(arguments)
self:updatePdSpots()
pointDefs = self:getUnitsByClass(UnitClass.POINT_DEFENSE, -1)
if #pointDefs == #self.pointDefenseTrans then return BTNodeResult.SUCCESS end
if #pointDefs >= #self.pointDefenseTrans then return BTNodeResult.SUCCESS end
pdId = self.unitClassMappings[UnitClass.POINT_DEFENSE + 1][self:getFaction() + 1]
pdTrans = self.pointDefenseTrans[#pointDefs + 1]
+2
View File
@@ -36,6 +36,8 @@ for i = 1, #game.cpuPlayers do
type = BTNodeType.PARALLEL,
children = game.cpuPlayers[i]:generateTaskForceActions()
}
--[[
]]--
}
}
end
+1 -1
View File
@@ -311,7 +311,7 @@ namespace battleship{
if(!buildableStructSelected)
for(int i = 0; i < selectedUnits.size(); i++)
fc->addGameObjectFrame(GameObjectFrame(selectedUnits[i]->getId(), GameObject::Type::UNIT, selectedUnits[i], targets[0].pos));
fc->addGameObjectFrame(GameObjectFrame(selectedUnits[i]->getId(), GameObject::Type::UNIT, mainPlayer, selectedUnits[i], targets[0].pos));
selectingDestOrient = true;
fc->setRotating(true);
+1 -1
View File
@@ -29,7 +29,7 @@ namespace battleship{
if(builder->getBuildableUnit(slotId).buildable){
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
ufCtr->addGameObjectFrame(GameObjectFrame(builder->getBuildableUnit(slotId).id, GameObject::Type::UNIT));
ufCtr->addGameObjectFrame(GameObjectFrame(builder->getBuildableUnit(slotId).id, GameObject::Type::UNIT, player));
ufCtr->setPlacingOnSurface(true);
activeState->setBuildableStructSelected(true);
}
+22
View File
@@ -8,6 +8,7 @@
#include <root.h>
#include "gameManager.h"
#include "gameObjectFrameController.h"
#include "gameObjectFactory.h"
#include "map.h"
#include "game.h"
@@ -151,6 +152,7 @@ namespace battleship{
"norm", &Vector3::norm,
"getAngleBetween", &Vector3::getAngleBetween,
"getDistanceFrom", &Vector3::getDistanceFrom,
"neg", [](Vector3 v){return -v;},
"add", [](Vector3 v1, Vector3 v2){return v1 + v2;},
"subtr", [](Vector3 v1, Vector3 v2){return v1 - v2;},
"mult", [](Vector3 v1, float s){return v1 * s;},
@@ -163,6 +165,8 @@ namespace battleship{
"x", &Quaternion::x,
"y", &Quaternion::y,
"z", &Quaternion::z,
"getAngle", &Quaternion::getAngle,
"getAxis", &Quaternion::getAxis,
"multVec", [](Quaternion q, Vector3 v){return q * v;}
);
@@ -189,6 +193,24 @@ namespace battleship{
"calcHeuristics", &Pathfinder::calcHeuristics,
"findPath", &Pathfinder::findPath
);
SOL_LUA_STATE.new_usertype<GameObjectFrame>(
"GameObjectFrame", sol::constructors<GameObjectFrame(int, GameObject::Type, Player*, Unit*, Vector3, Quaternion)>(),
"getOriginalUnit", &GameObjectFrame::getOriginalUnit,
"destroy", &GameObjectFrame::destroy,
"placeAt", &GameObjectFrame::placeAt,
"getDirVec", &GameObjectFrame::getDirVec,
"getLeftVec", &GameObjectFrame::getLeftVec,
"getLength", &GameObjectFrame::getLength,
"getWidth", &GameObjectFrame::getWidth,
"status", &GameObjectFrame::status
);
SOL_LUA_STATE.new_usertype<GameObjectFrameController>(
"GameObjectFrameController",
"getSingleton", &GameObjectFrameController::getSingleton,
"checkPlacement", &GameObjectFrameController::checkPlacement
);
}
void GameManager::initLua(string gameDir){
+1 -1
View File
@@ -153,7 +153,7 @@ namespace battleship{
model->setMaterial(mat);
sol::optional<sol::table> colNodeOpt = gameObjTable["colorNodes"];
if(player && colNodeOpt != sol::nullopt)
if(!(model->isWireframe() || colNodeOpt == sol::nullopt))
useColor(player->getColorMaterial());
root->getRootNode()->attachChild(model);
+2 -2
View File
@@ -10,9 +10,9 @@ namespace battleship{
struct GameObjectFrame : public GameObject{
enum Status{PLACEABLE, NOT_PLACEABLE, PLACED};
GameObjectFrame(int i, GameObject::Type t, Unit *ou = nullptr, vb01::Vector3 pos = vb01::Vector3::VEC_ZERO, vb01::Quaternion rot = vb01::Quaternion::QUAT_W) :
GameObjectFrame(int i, GameObject::Type t, Player *pl, Unit *ou = nullptr, vb01::Vector3 pos = vb01::Vector3::VEC_ZERO, vb01::Quaternion rot = vb01::Quaternion::QUAT_W) :
originalUnit(ou),
GameObject(t, i, nullptr, pos, rot)
GameObject(t, i, pl, pos, rot)
{
initModel(false);
initProperties();
+15 -2
View File
@@ -54,7 +54,7 @@ namespace battleship{
buildDir = gameObjectFrames[1].getModel()->getPosition() - gameObjectFrames[0].getModel()->getPosition();
Vector3 pos = paintSelectRowStart + buildDir.norm() * hypothenuse * gameObjectFrames.size();
addGameObjectFrame(GameObjectFrame(structureId, GameObject::Type::UNIT, nullptr, pos));
addGameObjectFrame(GameObjectFrame(structureId, GameObject::Type::UNIT, gameObjectFrames[0].getPlayer(), nullptr, pos));
}
}
@@ -86,7 +86,8 @@ namespace battleship{
sol::table tbl = generateView()["units"][s.getId() + 1];
UnitType ut = (UnitType)tbl["unitType"];
//vector<Unit*> friendlyUnits = s.getPlayer()->getFriendlyUnits();
vector<Unit*> friendlyUnits = (s.getPlayer() ? s.getPlayer()->getFriendlyUnits() : vector<Unit*>{});
bool withinLos = false;
for(int i = 0; i < 4; i++){
Vector3 cornerPos = (s.getPos() + s.getDirVec() * .5 * dirMult[i][0] * s.getLength() + s.getLeftVec() * .5 * dirMult[i][1] * s.getWidth());
@@ -105,6 +106,18 @@ namespace battleship{
s.status = GameObjectFrame::NOT_PLACEABLE;
return;
}
if(!withinLos)
for(Unit *fu : friendlyUnits)
if(fu->getPos().getDistanceFrom(s.getPos()) < fu->getLineOfSight()){
withinLos = true;
break;
}
}
if(!withinLos){
s.status = GameObjectFrame::NOT_PLACEABLE;
return;
}
MeshData meshData = map->getNodeParent()->getChild(0)->getMesh(0)->getMeshBase();
+1 -1
View File
@@ -18,7 +18,7 @@ namespace battleship{
void GameObjectListbox::onClose(){
GameObjectFrameController *ufCtr = GameObjectFrameController::getSingleton();
GameObject::Type type = (unitListbox ? GameObject::Type::UNIT : GameObject::Type::RESOURCE_DEPOSIT);
ufCtr->addGameObjectFrame(GameObjectFrame(gameObjIds[selectedOption], type));
ufCtr->addGameObjectFrame(GameObjectFrame(gameObjIds[selectedOption], type, nullptr));
ufCtr->setPlacingOnSurface(true);
}
}
+3 -4
View File
@@ -307,13 +307,12 @@ namespace battleship{
return true;
Vector3 obsUnitPos = object->getPos();
obsUnitPos.y = 0;
Vector2 oup2d = Vector2(obsUnitPos.x, obsUnitPos.z);
Vector3 compUnitPos = friendlyUnit->getPos();
compUnitPos.y = 0;
float dist = compUnitPos.getDistanceFrom(obsUnitPos);
Vector2 cup2d = Vector2(compUnitPos.x, compUnitPos.z);
if(dist <= friendlyUnit->getLineOfSight())
if(cup2d.getDistanceFrom(oup2d) <= friendlyUnit->getLineOfSight())
return true;
}