GameEffect.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <Source/Effects/GameEffect.h>
  9. #include <AzCore/Console/IConsole.h>
  10. #if AZ_TRAIT_CLIENT
  11. # include <PopcornFX/PopcornFXBus.h>
  12. #endif
  13. namespace MultiplayerSample
  14. {
  15. AZ_CVAR(bool, cl_KillEffectOnRestart, false, nullptr, AZ::ConsoleFunctorFlags::Null, "Controls whether or not to kill current effects on restart");
  16. void GameEffect::Reflect(AZ::ReflectContext* context)
  17. {
  18. AZ::SerializeContext* serializeContext = azrtti_cast<AZ::SerializeContext*>(context);
  19. if (serializeContext)
  20. {
  21. serializeContext->Class<GameEffect>()
  22. ->Version(1)
  23. ->Field("ParticleAsset", &GameEffect::m_particleAssetId)
  24. ->Field("AudioTrigger", &GameEffect::m_audioTrigger)
  25. ->Field("EffectOffset", &GameEffect::m_effectOffset);
  26. AZ::EditContext* editContext = serializeContext->GetEditContext();
  27. if (editContext)
  28. {
  29. editContext->Class<GameEffect>("GameEffect", "A single game effect, consisting of a particle effect and a sound trigger pair")
  30. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  31. ->DataElement(AZ::Edit::UIHandlers::Default, &GameEffect::m_particleAssetId, "ParticleAsset", "The particle effect to play upon effect trigger")
  32. #if AZ_TRAIT_CLIENT
  33. ->Attribute(AZ_CRC_CE("SupportedAssetTypes"), []() { return AZStd::vector<AZ::Data::AssetType>({ PopcornFX::AssetTypeId }); })
  34. #endif
  35. ->DataElement(AZ::Edit::UIHandlers::Default, &GameEffect::m_audioTrigger, "AudioTrigger", "The audio trigger name of the sound to play upon effect trigger")
  36. ->DataElement(AZ::Edit::UIHandlers::Default, &GameEffect::m_effectOffset, "EffectOffset", "The offset to apply when triggering an effect");
  37. }
  38. }
  39. }
  40. GameEffect::~GameEffect()
  41. {
  42. #if AZ_TRAIT_CLIENT
  43. if (m_popcornFx != nullptr)
  44. {
  45. if (m_popcornFx->IsEffectAlive(m_emitter))
  46. {
  47. m_popcornFx->DestroyEffect(m_emitter);
  48. }
  49. m_emitter = nullptr;
  50. }
  51. if (m_audioSystem != nullptr)
  52. {
  53. m_audioTriggerId = INVALID_AUDIO_CONTROL_ID;
  54. if (m_audioProxy != nullptr)
  55. {
  56. m_audioSystem->RecycleAudioProxy(m_audioProxy);
  57. m_audioProxy = nullptr;
  58. }
  59. }
  60. #endif
  61. }
  62. void GameEffect::Initialize()
  63. {
  64. #if AZ_TRAIT_CLIENT
  65. m_popcornFx = PopcornFX::PopcornFXRequestBus::FindFirstHandler();
  66. m_audioSystem = AZ::Interface<Audio::IAudioSystem>::Get();
  67. if (m_popcornFx != nullptr)
  68. {
  69. if (m_particleAssetId.IsValid())
  70. {
  71. const PopcornFX::SpawnParams params = PopcornFX::SpawnParams(true, false, AZ::Transform::CreateIdentity());
  72. m_emitter = m_popcornFx->SpawnEffectById(m_particleAssetId, params);
  73. }
  74. }
  75. if (m_audioSystem != nullptr)
  76. {
  77. m_audioProxy = m_audioSystem->GetAudioProxy();
  78. m_audioProxy->Initialize(m_audioTrigger.c_str(), this);
  79. m_audioProxy->SetObstructionCalcType(Audio::ObstructionType::Ignore);
  80. m_audioTriggerId = m_audioSystem->GetAudioTriggerID(m_audioTrigger.c_str());
  81. }
  82. #endif
  83. }
  84. bool GameEffect::SetAttribute([[maybe_unused]] const char* attributeName, [[maybe_unused]] float value) const
  85. {
  86. #if AZ_TRAIT_CLIENT
  87. if (m_popcornFx != nullptr)
  88. {
  89. if (m_popcornFx->IsEffectAlive(m_emitter))
  90. {
  91. int32_t attrId = m_popcornFx->EffectGetAttributeId(m_emitter, attributeName);
  92. if (attrId >= 0)
  93. {
  94. return m_popcornFx->EffectSetAttributeAsFloat(m_emitter, attrId, value);
  95. }
  96. }
  97. else
  98. {
  99. AZ_Assert(false, "Setting attribute on an emitter that isn't active.");
  100. return false;
  101. }
  102. }
  103. #endif
  104. return false;
  105. }
  106. bool GameEffect::SetAttribute([[maybe_unused]] const char* attributeName, [[maybe_unused]] const AZ::Vector2& value) const
  107. {
  108. #if AZ_TRAIT_CLIENT
  109. if (m_popcornFx != nullptr)
  110. {
  111. if (m_popcornFx->IsEffectAlive(m_emitter))
  112. {
  113. int32_t attrId = m_popcornFx->EffectGetAttributeId(m_emitter, attributeName);
  114. if (attrId >= 0)
  115. {
  116. return m_popcornFx->EffectSetAttributeAsFloat2(m_emitter, attrId, value);
  117. }
  118. }
  119. else
  120. {
  121. AZ_Assert(false, "Setting attribute on an emitter that isn't active.");
  122. return false;
  123. }
  124. }
  125. #endif
  126. return false;
  127. }
  128. bool GameEffect::SetAttribute([[maybe_unused]] const char* attributeName, [[maybe_unused]] const AZ::Vector3& value) const
  129. {
  130. #if AZ_TRAIT_CLIENT
  131. if (m_popcornFx != nullptr)
  132. {
  133. if (m_popcornFx->IsEffectAlive(m_emitter))
  134. {
  135. int32_t attrId = m_popcornFx->EffectGetAttributeId(m_emitter, attributeName);
  136. if (attrId >= 0)
  137. {
  138. return m_popcornFx->EffectSetAttributeAsFloat3(m_emitter, attrId, value);
  139. }
  140. }
  141. else
  142. {
  143. AZ_Assert(false, "Setting attribute on an emitter that isn't active.");
  144. return false;
  145. }
  146. }
  147. #endif
  148. return false;
  149. }
  150. bool GameEffect::SetAttribute([[maybe_unused]] const char* attributeName, [[maybe_unused]] const AZ::Vector4& value) const
  151. {
  152. #if AZ_TRAIT_CLIENT
  153. if (m_popcornFx != nullptr)
  154. {
  155. if (m_popcornFx->IsEffectAlive(m_emitter))
  156. {
  157. int32_t attrId = m_popcornFx->EffectGetAttributeId(m_emitter, attributeName);
  158. if (attrId >= 0)
  159. {
  160. return m_popcornFx->EffectSetAttributeAsFloat4(m_emitter, attrId, value);
  161. }
  162. }
  163. else
  164. {
  165. AZ_Assert(false, "Setting attribute on an emitter that isn't active.");
  166. return false;
  167. }
  168. }
  169. #endif
  170. return false;
  171. }
  172. void GameEffect::TriggerEffect([[maybe_unused]] const AZ::Transform& transform) const
  173. {
  174. #if AZ_TRAIT_CLIENT
  175. const AZ::Vector3 offsetPosition = transform.TransformPoint(m_effectOffset);
  176. AZ::Transform transformOffset = transform;
  177. transformOffset.SetTranslation(offsetPosition);
  178. if (m_emitter != nullptr)
  179. {
  180. if (PopcornFX::PopcornFXRequests* popcornFx = PopcornFX::PopcornFXRequestBus::FindFirstHandler())
  181. {
  182. if (m_popcornFx->IsEffectAlive(m_emitter))
  183. {
  184. popcornFx->EffectSetTransform(m_emitter, transformOffset);
  185. popcornFx->EffectSetTeleportThisFrame(m_emitter);
  186. popcornFx->EffectRestart(m_emitter, cl_KillEffectOnRestart);
  187. }
  188. else
  189. {
  190. AZ_Assert(false, "Triggering an inactive emitter.");
  191. }
  192. }
  193. }
  194. if ((m_audioProxy != nullptr) && (m_audioTriggerId != INVALID_AUDIO_CONTROL_ID))
  195. {
  196. m_audioProxy->SetPosition(offsetPosition);
  197. m_audioProxy->ExecuteTrigger(m_audioTriggerId);
  198. }
  199. #endif
  200. }
  201. const AZ::Vector3& GameEffect::GetEffectOffset() const
  202. {
  203. return m_effectOffset;
  204. }
  205. }