void CFeature::UpdateTransformAndPhysState() { UpdateDirVectors(!def->upright); UpdateTransform(pos, true); UpdatePhysicalStateBit(CSolidObject::PSTATE_BIT_MOVING, (SetSpeed(speed) != 0.0f)); UpdatePhysicalState(0.1f); }
void CFeature::SetVelocity(const float3& v) { CWorldObject::SetVelocity(v); UpdatePhysicalStateBit(CSolidObject::PSTATE_BIT_MOVING, v != ZeroVector); if (IsMoving()) { featureHandler->SetFeatureUpdateable(this, true); } }
void CFeature::SetVelocity(const float3& v) { CWorldObject::SetVelocity(v * moveCtrl.velocityMask); CWorldObject::SetSpeed(v * moveCtrl.velocityMask); UpdatePhysicalStateBit(CSolidObject::PSTATE_BIT_MOVING, speed.w != 0.0f); if (IsMoving()) { featureHandler->SetFeatureUpdateable(this); } }
bool CFeature::UpdatePosition() { const float3 oldPos = pos; if (udef != NULL) { // we are a wreck of a dead unit, possibly with residual impulse // in this case we do not care about <finalHeight> and are always // affected by gravity // note that def->floating is unreliable (eg. it can be true for // ground-unit wrecks), so just assume wrecks always sink in water // even if their "owner" was a floating object (as is the case for // ships anyway) if (IsMoving()) { const float realGroundHeight = ground->GetHeightReal(pos.x, pos.z); const bool reachedWater = ( pos.y <= 0.1f); const bool reachedGround = ((pos.y - realGroundHeight) <= 0.1f); // NOTE: // all these calls use the base-class because FeatureHandler::Update // iterates over updateFeatures and our ::SetVelocity will insert us // into that CWorldObject::SetVelocity(speed + GetDragAccelerationVec(float4(mapInfo->atmosphere.fluidDensity, mapInfo->water.fluidDensity, 1.0f, 0.1f))); if (speed.SqLength2D() > 0.01f) { UnBlock(); quadField->RemoveFeature(this); // update our forward speed (and quadfield // position) if it is still greater than 0 Move(speed, true); quadField->AddFeature(this); Block(); } else { CWorldObject::SetVelocity(speed * UpVector); } if (!reachedGround) { if (!reachedWater) { // quadratic acceleration if not in water CWorldObject::SetVelocity(speed + (UpVector * mapInfo->map.gravity)); } else { // constant downward speed otherwise CWorldObject::SetVelocity((speed * XZVector) + (UpVector * mapInfo->map.gravity)); } Move(UpVector * speed.y, true); } else { CWorldObject::SetVelocity(speed * XZVector); // last Update() may have sunk us into // ground if pos.y was only marginally // larger than ground height, correct Move(UpVector * (realGroundHeight - pos.y), true); } if (!pos.IsInBounds()) { pos.ClampInBounds(); // ensure that no more forward-speed updates are done // (prevents wrecks floating in mid-air at edge of map // due to gravity no longer being applied either) CWorldObject::SetVelocity(ZeroVector); } eventHandler.FeatureMoved(this, oldPos); CalculateTransform(); } } else { // any feature that is not a dead unit (ie. rocks, trees, ...) // these never move in the xz-plane no matter how much impulse // is applied, only gravity affects them (FIXME: arbitrary..?) if (pos.y > finalHeight) { if (pos.y > 0.0f) { CWorldObject::SetVelocity(speed + (UpVector * mapInfo->map.gravity)); } else { CWorldObject::SetVelocity((speed * XZVector) + (UpVector * mapInfo->map.gravity)); } // stop falling when we reach our finalHeight // (which can be arbitrary, even below ground) Move(UpVector * std::min(pos.y - finalHeight, speed.y), true); eventHandler.FeatureMoved(this, oldPos); } else if (pos.y < finalHeight) { // stop vertical movement and teleport up CWorldObject::SetVelocity(speed * XZVector); Move(UpVector * (finalHeight - pos.y), true); eventHandler.FeatureMoved(this, oldPos); } transMatrix[13] = pos.y; } UpdatePhysicalStateBit(CSolidObject::PSTATE_BIT_MOVING, ((SetSpeed(speed) != 0.0f) || (std::fabs(pos.y - finalHeight) >= 0.01f))); UpdatePhysicalState(0.1f); return (IsMoving()); }
void CFeature::Initialize(const FeatureLoadParams& params) { id = params.featureID; defID = (params.featureDef)->id; def = params.featureDef; udef = params.unitDef; objectDef = params.featureDef; team = params.teamID; allyteam = params.allyTeamID; heading = params.heading; buildFacing = params.facing; smokeTime = params.smokeTime; mass = def->mass; health = def->health; crushResistance = def->crushResistance; xsize = ((buildFacing & 1) == 0) ? def->xsize : def->zsize; zsize = ((buildFacing & 1) == 1) ? def->xsize : def->zsize; noSelect = !def->selectable; // set position before mid-position Move((params.pos).cClampInMap(), false); // use base-class version, AddFeature() below // will already insert us in the update-queue CWorldObject::SetVelocity(params.speed); if (def->drawType == DRAWTYPE_MODEL) { if ((model = def->LoadModel()) == NULL) { LOG_L(L_ERROR, "[%s] couldn't load model for %s", __FUNCTION__, def->name.c_str()); } else { SetMidAndAimPos(model->relMidPos, model->relMidPos, true); SetRadiusAndHeight(model); } } else if (def->drawType >= DRAWTYPE_TREE) { // LoadFeaturesFromMap() doesn't set a scale for trees SetMidAndAimPos(UpVector * TREE_RADIUS, UpVector * TREE_RADIUS, true); SetRadiusAndHeight(TREE_RADIUS, TREE_RADIUS * 2.0f); } UpdateMidAndAimPos(); CalculateTransform(); // note: gets deleted in ~CSolidObject collisionVolume = new CollisionVolume(def->collisionVolume); if (collisionVolume->DefaultToSphere()) collisionVolume->InitSphere(radius); if (collisionVolume->DefaultToFootPrint()) collisionVolume->InitBox(float3(xsize * SQUARE_SIZE, height, zsize * SQUARE_SIZE)); // feature does not have an assigned ID yet // this MUST be done before the Block() call featureHandler->AddFeature(this); quadField->AddFeature(this); ChangeTeam(team); UpdateCollidableStateBit(CSolidObject::CSTATE_BIT_SOLIDOBJECTS, def->collidable); Block(); // allow Spring.SetFeatureBlocking to be called from gadget:FeatureCreated eventHandler.FeatureCreated(this); if (def->floating) { finalHeight = ground->GetHeightAboveWater(pos.x, pos.z); } else { finalHeight = ground->GetHeightReal(pos.x, pos.z); } UpdatePhysicalStateBit(CSolidObject::PSTATE_BIT_MOVING, ((SetSpeed(params.speed) != 0.0f) || (std::fabs(pos.y - finalHeight) >= 0.01f))); }