Ticket #1988: anchor.diff
File anchor.diff, 7.6 KB (added by , 11 years ago) |
---|
-
binaries/data/mods/public/simulation/templates/template_unit_champion_cavalry.xml
42 42 <Obstruction> 43 43 <Unit radius="1.0"/> 44 44 </Obstruction> 45 <Position> 46 <Anchor>pitch</Anchor> 47 </Position> 45 48 <Selectable> 46 49 <Overlay> 47 50 <Texture> -
binaries/data/mods/public/simulation/templates/template_unit_champion_elephant.xml
31 31 <Obstruction> 32 32 <Unit radius="4.0"/> 33 33 </Obstruction> 34 <Position> 35 <Anchor>pitch</Anchor> 36 </Position> 34 37 <Selectable> 35 38 <Overlay> 36 39 <Texture> -
binaries/data/mods/public/simulation/templates/units/maur_support_elephant.xml
38 38 <stone>10</stone> 39 39 <metal>10</metal> 40 40 </Loot> 41 <Position> 42 <Anchor>pitch</Anchor> 43 </Position> 41 44 <ResourceDropsite> 42 45 <Types>food wood stone metal</Types> 43 46 </ResourceDropsite> -
source/simulation2/components/CCmpPosition.cpp
30 30 #include "maths/MathUtil.h" 31 31 #include "maths/Matrix3D.h" 32 32 #include "maths/Vector3D.h" 33 #include "maths/Vector2D.h" 33 34 #include "ps/CLogger.h" 34 35 35 36 /** … … 58 59 UPRIGHT = 0, 59 60 PITCH = 1, 60 61 PITCH_ROLL = 2, 62 ROLL=3, 61 63 } m_AnchorType; 62 64 63 65 bool m_Floating; … … 72 74 entity_pos_t m_YOffset; 73 75 bool m_RelativeToGround; // whether m_YOffset is relative to terrain/water plane, or an absolute height 74 76 75 entity_angle_t m_RotX, m_RotY, m_RotZ; 77 CTerrain* m_Terrain; 78 79 entity_angle_t m_RotX, m_RotY, m_RotZ, m_LastRotX, m_LastRotZ; 76 80 float m_InterpolatedRotY, m_PrevInterpolatedRotY; // not serialized 81 bool recalculateXZRotation; 77 82 83 int widthInTiles, depthInTiles; 84 78 85 static std::string GetSchema() 79 86 { 80 87 return … … 89 96 "<choice>" 90 97 "<value a:help='Always stand straight up'>upright</value>" 91 98 "<value a:help='Rotate backwards and forwards to follow the terrain'>pitch</value>" 99 "<value a:help='Rotate sideways follow the terrain'>roll</value>" 92 100 "<value a:help='Rotate in all direction to follow the terrain'>pitch-roll</value>" 93 101 "</choice>" 94 102 "</element>" … … 110 118 m_AnchorType = PITCH; 111 119 else if (anchor == L"pitch-roll") 112 120 m_AnchorType = PITCH_ROLL; 121 else if (anchor == L"roll") 122 m_AnchorType = ROLL; 113 123 else 114 124 m_AnchorType = UPRIGHT; 115 125 … … 123 133 124 134 m_RotX = m_RotY = m_RotZ = entity_angle_t::FromInt(0); 125 135 m_InterpolatedRotY = m_PrevInterpolatedRotY = 0; 136 137 m_LastRotX = entity_angle_t::Zero(); 138 m_LastRotZ = entity_angle_t::Zero(); 139 140 m_Terrain = &GetSimContext().GetTerrain(); 141 142 recalculateXZRotation = true; 126 143 } 127 144 128 145 virtual void Deinit() … … 197 214 198 215 virtual void MoveTo(entity_pos_t x, entity_pos_t z) 199 216 { 217 200 218 m_X = x; 201 219 m_Z = z; 202 220 … … 207 225 m_LastZ = m_PrevZ = m_Z; 208 226 } 209 227 228 recalculateXZRotation = true; 229 210 230 AdvertisePositionChanges(); 211 231 } 212 232 … … 216 236 m_LastZ = m_PrevZ = m_Z = z; 217 237 m_InWorld = true; 218 238 239 recalculateXZRotation = true; 240 219 241 AdvertisePositionChanges(); 220 242 } 221 243 … … 319 341 320 342 virtual void TurnTo(entity_angle_t y) 321 343 { 344 322 345 m_RotY = y; 323 346 324 347 AdvertisePositionChanges(); … … 330 353 m_InterpolatedRotY = m_RotY.ToFloat(); 331 354 m_PrevInterpolatedRotY = m_InterpolatedRotY; 332 355 356 recalculateXZRotation = true; 357 333 358 AdvertisePositionChanges(); 334 359 } 335 360 … … 371 396 rotY = m_InterpolatedRotY; 372 397 } 373 398 399 400 virtual void UpdateXZRotation() 401 { 402 403 if (m_AnchorType == UPRIGHT) 404 // change nothing if anchor is upright 405 return; 406 407 // TODO average normal (average all the tiles?) for big units or for buildings 408 CFixedVector3D normal; 409 410 m_Terrain->CalcNormalFixed((m_X / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), (m_Z / (int)TERRAIN_TILE_SIZE).ToInt_RoundToZero(), normal); 411 412 // rotate the normal so the positive x direction is in the direction of the unit 413 CFixedVector2D projected = CFixedVector2D(normal.X, normal.Z); 414 projected = projected.Rotate(-entity_pos_t::FromFloat(m_InterpolatedRotY)); 415 416 normal.X = projected.X; 417 normal.Z = projected.Y; 418 419 if (m_AnchorType == PITCH || m_AnchorType == PITCH_ROLL) 420 // project and calculate the angle 421 m_RotX = -atan2_approx(normal.Z, normal.Y); 422 423 if (m_AnchorType == ROLL || m_AnchorType == PITCH_ROLL) 424 // project and calculate the angle 425 m_RotZ = atan2_approx(normal.X,normal.Y); 426 427 return; 428 } 429 374 430 virtual CMatrix3D GetInterpolatedTransform(float frameOffset, bool forceFloating) 375 431 { 432 433 376 434 if (!m_InWorld) 377 435 { 378 436 LOGERROR(L"CCmpPosition::GetInterpolatedTransform called on entity when IsInWorld is false"); … … 401 459 402 460 float y = baseY + m_YOffset.ToFloat(); 403 461 404 // TODO: do something with m_AnchorType405 462 406 CMatrix3D m; 407 m.SetXRotation(m_RotX.ToFloat()); 408 m.RotateZ(m_RotZ.ToFloat()); 463 CMatrix3D m; 464 465 // linear interpolation is good enough (for RotX/Z). 466 // As you always stay close to zero angle. 467 m.SetXRotation(Interpolate(m_LastRotX.ToFloat(), m_RotX.ToFloat(), frameOffset)); 468 m.RotateZ(Interpolate(m_LastRotZ.ToFloat(), m_RotZ.ToFloat(), frameOffset)); 469 409 470 m.RotateY(rotY + (float)M_PI); 410 471 m.Translate(CVector3D(x, y, z)); 411 472 … … 418 479 { 419 480 case MT_Interpolate: 420 481 { 482 421 483 const CMessageInterpolate& msgData = static_cast<const CMessageInterpolate&> (msg); 422 484 423 485 float rotY = m_RotY.ToFloat(); 424 float delta = rotY - m_InterpolatedRotY; 425 // Wrap delta to -M_PI..M_PI 426 delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI 427 if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI 428 delta -= (float)M_PI; // range -M_PI..M_PI 429 // Clamp to max rate 430 float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime); 431 // Calculate new orientation, in a peculiar way in order to make sure the 432 // result gets close to m_orientation (rather than being n*2*M_PI out) 433 m_InterpolatedRotY = rotY + deltaClamped - delta; 486 if (rotY != m_InterpolatedRotY) 487 { 488 float delta = rotY - m_InterpolatedRotY; 489 // Wrap delta to -M_PI..M_PI 490 delta = fmodf(delta + (float)M_PI, 2*(float)M_PI); // range -2PI..2PI 491 if (delta < 0) delta += 2*(float)M_PI; // range 0..2PI 492 delta -= (float)M_PI; // range -M_PI..M_PI 493 // Clamp to max rate 494 float deltaClamped = clamp(delta, -m_RotYSpeed*msgData.deltaSimTime, +m_RotYSpeed*msgData.deltaSimTime); 495 // Calculate new orientation, in a peculiar way in order to make sure the 496 // result gets close to m_orientation (rather than being n*2*M_PI out) 497 m_InterpolatedRotY = rotY + deltaClamped - delta; 498 recalculateXZRotation = true; 499 } 434 500 501 if (recalculateXZRotation) 502 { 503 m_LastRotX = m_RotX; 504 m_LastRotZ = m_RotZ; 505 506 UpdateXZRotation(); 507 508 recalculateXZRotation = false; 509 510 } 511 435 512 break; 436 513 } 437 514 case MT_TurnStart: