3D Sprite

Actor Sprites

Actor Sprites
3D Sprite
void Actor::Render( Camera const& camera ) const
{
if (g_theRenderer != nullptr)
{
for (int i = 0; i < g_theGame->m_playerControllers.size(); i++)
{
if (m_currentController == g_theGame->m_playerControllers[i] && &g_theGame->m_playerControllers[i]->m_playerCamera == &camera)
{
return;
}
}
Vec3 const& cameraPosition = camera.GetPosition();
Vec3 toActorVec = (m_position - cameraPosition);
Vec3 toActorVec2D( toActorVec.x, toActorVec.y, 0.f );
std::string currentStateName;
if (m_actorState == ActorState::WALK)
{
currentStateName = "Walk";
}
else if (m_actorState == ActorState::ATTACK)
{
currentStateName = "Attack";
}
else if (m_actorState == ActorState::HURT)
{
currentStateName = "Hurt";
}
else if (m_actorState == ActorState::DEATH)
{
currentStateName = "Death";
}
else if (m_actorState == ActorState::IDLE)
{
currentStateName = "Walk";
}
toActorVec2D = m_orientation.GetAsMatrix_IFwd_JLeft_KUp().GetOrthonormalInverse().TransformVectorQuantity3D( toActorVec2D ).GetNormalized();
for (int j = 0; j < m_actorDefinition->m_animationGroups.size(); j++)
{
if (currentStateName == m_actorDefinition->m_animationGroups[j].m_groupName)
{
int animDefIndex = 0;
float maxDotValue = -99999.f;
for (int k = 0; k < m_actorDefinition->m_animationGroups[j].m_animDefinitions.size(); k++)
{
Vec3 const& spriteDirection = m_actorDefinition->m_animationGroups[j].m_vectorDirections[k];
float dotValue = DotProduct3D( spriteDirection, toActorVec2D );
if (dotValue > maxDotValue)
{
maxDotValue = dotValue;
animDefIndex = k;
}
}
m_currentAnimDef = &m_actorDefinition->m_animationGroups[j].m_animDefinitions[animDefIndex];
std::vector spriteVerts;
std::vector spriteIndexes;
spriteVerts.reserve( 4 );
spriteIndexes.reserve( 6 );
AABB2 spriteAABB;
if (m_actorState != ActorState::IDLE)
{
if (m_actorDefinition->m_animationGroups[j].m_isScaleBySpeed)
{
float speedScaleRatio = m_velocity.GetLength() / m_actorDefinition->m_runSpeed;
spriteAABB = m_currentAnimDef->GetSpriteDefAtTime( m_animationTimer * speedScaleRatio ).GetUVs();
}
else
{
spriteAABB = m_currentAnimDef->GetSpriteDefAtTime( m_animationTimer ).GetUVs();
}
}
else
{
spriteAABB = m_currentAnimDef->GetSpriteDefAtTime( 0.f ).GetUVs();
}
Vec3 pointBL = Vec3( -m_actorDefinition->m_size.x * m_actorDefinition->m_pivot.x, -m_actorDefinition->m_size.y * m_actorDefinition->m_pivot.y, 0.f );
Vec3 pointBR = Vec3( m_actorDefinition->m_size.x * (1.f - m_actorDefinition->m_pivot.x), -m_actorDefinition->m_size.y * m_actorDefinition->m_pivot.y, 0.f );
Vec3 pointTR = Vec3( m_actorDefinition->m_size.x * (1.f - m_actorDefinition->m_pivot.x), m_actorDefinition->m_size.y * (1.f - m_actorDefinition->m_pivot.y), 0.f );
Vec3 pointTL = Vec3( -m_actorDefinition->m_size.x * m_actorDefinition->m_pivot.x, m_actorDefinition->m_size.y * (1.f - m_actorDefinition->m_pivot.y), 0.f );
//If Rounded render
if (m_actorDefinition->m_isRenderRounded)
{
AddVertsForRoundedQuad3D( spriteVerts, spriteIndexes, pointBL, pointBR, pointTR, pointTL, Rgba8::WHITE, spriteAABB );
}
else
{
AddVertsForQuad3D( spriteVerts, spriteIndexes, pointBL, pointBR, pointTR, pointTL, Rgba8::WHITE, spriteAABB );
}
Mat44 cameraMat = camera.GetOrientation().GetAsMatrix_IFwd_JLeft_KUp();
cameraMat.SetTranslation3D( camera.GetPosition() );
Mat44 transformMat;
transformMat = GetBillboardMatrix( m_actorDefinition->m_billboardType, cameraMat, m_position, Vec2( 1.f, 1.f ) );
if (m_actorDefinition->m_shader!= nullptr)
{
g_theRenderer->BindShader( m_actorDefinition->m_shader );
}
g_theRenderer->SetRasterizerMode( RasterizerMode::SOLID_CULL_NONE );
g_theRenderer->SetModelConstants( transformMat, m_color );
g_theRenderer->BindTexture( &m_currentAnimDef->GetSpriteSheet().GetTexture() );
g_theRenderer->DrawVertexArray( (int)spriteVerts.size(), spriteVerts.data(), (int)spriteIndexes.size(), spriteIndexes.data() );
g_theRenderer->SetRasterizerMode( RasterizerMode::SOLID_CULL_BACK );
}
}
}
}
给Actor绘制3D Sprite
XML数据驱动
所有武器和Actor的属性都从XML文件中读取。
WeaponDefinition::WeaponDefinition( XmlElement* weaponElement )
{
m_weaponName = ParseXmlAttribute( *weaponElement, "name", m_weaponName );
m_refireTime = ParseXmlAttribute( *weaponElement, "refireTime", m_refireTime );
m_rayCount = ParseXmlAttribute( *weaponElement, "rayCount", m_rayCount );
m_rayCone = ParseXmlAttribute( *weaponElement, "rayCone", m_rayCone );
m_rayRange = ParseXmlAttribute( *weaponElement, "rayRange", m_rayRange );
m_rayDamage = ParseXmlAttribute( *weaponElement, "rayDamage", m_rayDamage );
m_rayImpulse = ParseXmlAttribute( *weaponElement, "rayImpulse", m_rayImpulse );
m_projectileCount = ParseXmlAttribute( *weaponElement, "projectileCount", m_projectileCount );
m_projectileActorName = ParseXmlAttribute( *weaponElement, "projectileActor", m_projectileActorName );
m_projectileCone = ParseXmlAttribute( *weaponElement, "projectileCone", m_projectileCone );
m_projectileSpeed = ParseXmlAttribute( *weaponElement, "projectileSpeed", m_projectileSpeed );
m_meleeCount = ParseXmlAttribute( *weaponElement, "meleeCount", m_meleeCount );
m_meleeArc = ParseXmlAttribute( *weaponElement, "meleeArc", m_meleeArc );
m_meleeRange = ParseXmlAttribute( *weaponElement, "meleeRange", m_meleeRange );
m_meleeDamage = ParseXmlAttribute( *weaponElement, "meleeDamage", m_meleeDamage );
m_meleeImpulse = ParseXmlAttribute( *weaponElement, "meleeImpulse", m_meleeImpulse );
m_isReload = ParseXmlAttribute( *weaponElement, "isReload", m_isReload );
m_bulletCount = ParseXmlAttribute( *weaponElement, "bulletCount", m_bulletCount );
m_reloadingTime = ParseXmlAttribute( *weaponElement, "reloadingTime", m_reloadingTime );
m_canAiming = ParseXmlAttribute( *weaponElement, "canAiming", m_canAiming );
m_recoilSpeed = ParseXmlAttribute( *weaponElement, "recoilSpeed", m_recoilSpeed );
m_recoilTime = ParseXmlAttribute( *weaponElement, "recoilTime", m_recoilTime );
XmlElement* hudElement = weaponElement->FirstChildElement( "HUD" );
if (hudElement != nullptr)
{
std::string hudShader = ParseXmlAttribute( *hudElement, "shader", "None" );
std::string baseTexture = ParseXmlAttribute( *hudElement, "baseTexture", "None" );
std::string reticleTexture = ParseXmlAttribute( *hudElement, "reticleTexture", "None" );
std::string aimingTexture = ParseXmlAttribute( *hudElement, "aimingTexture", "None" );
m_hudShader = g_theRenderer->GetLoadedShaderByName( hudShader.c_str() );
m_baseTexture = g_theRenderer->CreateTextureFromFile( baseTexture.c_str() );
m_reticleTexture = g_theRenderer->CreateTextureFromFile( reticleTexture.c_str() );
if (aimingTexture != "None")
{
m_aimingTexture = g_theRenderer->CreateTextureFromFile( aimingTexture.c_str() );
}
m_reticleSize = ParseXmlAttribute( *hudElement, "reticleSize", m_reticleSize );
m_spriteSize = ParseXmlAttribute( *hudElement, "spriteSize", m_spriteSize );
m_spritePivot = ParseXmlAttribute( *hudElement, "spritePivot", m_spritePivot );
XmlElement* animationElement = hudElement->FirstChildElement( "Animation" );
while (animationElement)
{
WeaponAnimation weaponAnim;
weaponAnim.m_name = ParseXmlAttribute( *animationElement, "name", weaponAnim.m_name );
weaponAnim.m_shader = ParseXmlAttribute( *animationElement, "shader", weaponAnim.m_shader );
weaponAnim.m_spriteSheetName = ParseXmlAttribute( *animationElement, "spriteSheet", weaponAnim.m_spriteSheetName );
weaponAnim.m_cellCount = ParseXmlAttribute( *animationElement, "cellCount", weaponAnim.m_cellCount );
Texture* tex = g_theRenderer->CreateTextureFromFile( weaponAnim.m_spriteSheetName.c_str() );
weaponAnim.m_spriteSheet = new SpriteSheet( *tex, weaponAnim.m_cellCount );
int startFrame = ParseXmlAttribute( *animationElement, "startFrame", 0 );
int endFrame = ParseXmlAttribute( *animationElement, "endFrame", 0 );
float durationSeconds = ParseXmlAttribute( *animationElement, "secondsPerFrame", 0.f );
int animNum = endFrame - startFrame + 1;
SpriteAnimDefinition* animDefinition = new SpriteAnimDefinition( *weaponAnim.m_spriteSheet, startFrame, endFrame, durationSeconds * animNum );
weaponAnim.m_animationDef = animDefinition;
m_weaponAnimations.push_back( weaponAnim );
animationElement = animationElement->NextSiblingElement();
}
}
XmlElement* soundsElement = weaponElement->FirstChildElement( "Sounds" );
if (soundsElement != nullptr)
{
XmlElement* soundElement = soundsElement->FirstChildElement( "Sound" );
m_sound = ParseXmlAttribute( *soundElement, "sound", m_sound );
m_soundName = ParseXmlAttribute( *soundElement, "name", m_soundName );
m_soundID = g_audio->CreateOrGetSound( m_soundName, AudioFMode::AUDIO_FMOD_3D );
}
}
解析 XML 文件
<Definitions>
<!-- Pistol -->
<WeaponDefinition name="Pistol" refireTime="0.75" rayCount="1" rayCone="0.0" rayRange="40.0" rayDamage="10.0~15.0" rayImpulse="4.0">
<HUD shader="Default" baseTexture="Data/Images/Hud_Base.png" reticleTexture="Data/Images/Reticle.png" reticleSize="16,16" spriteSize="256,256" spritePivot="0.5,0.0">
<Animation name="Idle" shader="Default" spriteSheet="Data/Images/Weapon_Pistol.png" cellCount="5,1" secondsPerFrame="0.1" startFrame="0" endFrame="0"/>
<Animation name="Attack" shader="Default" spriteSheet="Data/Images/Weapon_Pistol.png" cellCount="5,1" secondsPerFrame="0.1" startFrame="1" endFrame="3" />
</HUD>
<Sounds>
<Sound sound="Fire" name="Data/Audio/PistolFire.wav"/>
</Sounds>
</WeaponDefinition>
<!-- Plasma Rifle -->
<WeaponDefinition name="PlasmaRifle" refireTime="0.2" projectileCount="1" projectileActor="PlasmaProjectile" projectileCone="4.0" projectileSpeed="4.0">
<HUD shader="Default" baseTexture="Data/Images/Hud_Base.png" reticleTexture="Data/Images/Reticle.png" reticleSize="16,16" spriteSize="256,256" spritePivot="0.5,0.0">
<Animation name="Idle" shader="Default" spriteSheet="Data/Images/Weapon_Plasma.png" cellCount="4,1" secondsPerFrame="0.125" startFrame="0" endFrame="0" />
<Animation name="Attack" shader="Default" spriteSheet="Data/Images/Weapon_Plasma.png" cellCount="4,1" secondsPerFrame="0.125" startFrame="1" endFrame="2" />
</HUD>
<Sounds>
<Sound sound="Fire" name="Data/Audio/PlasmaFire.wav"/>
</Sounds>
</WeaponDefinition>
<!-- Demon Melee -->
<WeaponDefinition name="DemonMelee" refireTime="2.0" meleeCount="1" meleeArc="180.0" meleeRange="0.75" meleeDamage="2.0~4.0" meleeImpulse="2.0">
<Sounds>
<Sound sound="Fire" name="Data/Audio/DemonAttack.wav"/>
</Sounds>
</WeaponDefinition>
<!-- SubMachine Gun -->
<WeaponDefinition name="SubMachine" refireTime="0.1" rayCount="1" rayCone="0.0" rayRange="40.0" rayDamage="5.0~10.0" rayImpulse="4.0" isReload ="true" bulletCount ="20" reloadingTime ="2.0">
<HUD shader="Default" baseTexture="Data/Images/Hud_Base.png" reticleTexture="Data/Images/Reticle.png" reticleSize="16,16" spriteSize="256,256" spritePivot="0.5,0.0">
<Animation name="Idle" shader="Default" spriteSheet="Data/Images/WeaponShoot.png" cellCount="6,1" secondsPerFrame="0.1" startFrame="0" endFrame="0"/>
<Animation name="Attack" shader="Default" spriteSheet="Data/Images/WeaponShoot.png" cellCount="6,1" secondsPerFrame="0.1" startFrame="1" endFrame="5" />
<Animation name="Reload" shader="Default" spriteSheet="Data/Images/WeaponReload.png" cellCount="5,1" secondsPerFrame="0.4" startFrame="0" endFrame="4" />
</HUD>
<Sounds>
<Sound sound="Fire" name="Data/Audio/PistolFire.wav"/>
</Sounds>
</WeaponDefinition>
<!-- Sword -->
<WeaponDefinition name="Sword" refireTime="0.8" meleeCount="1" meleeArc="180.0" meleeRange="1.2" meleeDamage="50.0~60.0" meleeImpulse="2.0">
<HUD shader="Default" baseTexture="Data/Images/Hud_Base.png" reticleTexture="Data/Images/Reticle.png" reticleSize="16,16" spriteSize="600,400" spritePivot="0.6,0.0">
<Animation name="Idle" shader="Default" spriteSheet="Data/Images/Sword.png" cellCount="2,2" secondsPerFrame="0.2" startFrame="0" endFrame="0"/>
<Animation name="Attack" shader="Default" spriteSheet="Data/Images/Sword.png" cellCount="2,2" secondsPerFrame="0.2" startFrame="1" endFrame="3" />
</HUD>
<Sounds>
<Sound sound="Fire" name="Data/Audio/Sword.mp3"/>
</Sounds>
</WeaponDefinition>
</Definitions>
武器的XML
碰撞
与地图碰撞
与演员发生碰撞
void Map::CollideActorWithMap( Actor* actor )
{
if (actor != nullptr && !actor->m_isDead)
{
Vec2 actorPos = Vec2( actor->GetActorPosition().x, actor->GetActorPosition().y );
if (actor->m_actorDefinition->m_collidesWithWorld)
{
for (int i = 0; i < (int)m_tiles.size(); i++)
{
if (DoDiscOverlapFixedAABB2D( actorPos, actor->GetActorPhysicsRadius(), m_tiles[i].GetBounds() ))
{
if (!actor->m_actorDefinition->m_dieOnCollide)
{
actor->m_position.z = GetClamped( actor->m_position.z, 0.f, 10.f - actor->m_actorDefinition->m_physicsHeight );
}
else
{
if (actor->m_position.z >= 10.f - actor->m_actorDefinition->m_physicsHeight || actor->m_position.z <= 0.f)
{
actor->m_isDead = true;
}
}
if (m_tiles[i].m_tileDefinition->m_isTrap)
{
m_tiles[i].m_damageTimer += g_theApp->m_gameClock->GetDeltaSeconds();
if (m_tiles[i].m_damageTimer >= m_tiles[i].m_tileDefinition->m_damageTime)
{
m_tiles[i].m_damageTimer = 0.f;
actor->m_currentHealth -= m_tiles[i].m_tileDefinition->m_damage;
actor->AddImpulse( m_tiles[i].m_tileDefinition->m_damageImpulse * Vec3(0.f,0.f,1.f) );
}
}
}
}
IntVec2 tileCoords = GetTileCoordsForWorldPos( actorPos );
PushActorOutOfWall( actor, tileCoords + IntVec2( 1, 0 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( 0, 1 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( -1, 0 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( 0, -1 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( 1, 1 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( -1, 1 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( -1, -1 ) );
PushActorOutOfWall( actor, tileCoords + IntVec2( 1, -1 ) );
}
}
}
与地图碰撞的代码
void Map::CollideBetweenTwoActors( Actor* actorA, Actor* actorB )
{
if (actorA != nullptr && actorB != nullptr)
{
if (actorA->m_actorDefinition->m_name != "SpawnPoint" && actorB->m_actorDefinition->m_name != "SpawnPoint")
{
if (!actorA->m_actorDefinition->m_isProjectile && !actorB->m_actorDefinition->m_isProjectile)
{
if (actorA->m_actorDefinition->m_collidesWithActors && actorB->m_actorDefinition->m_collidesWithActors)
{
Vec2 actorAPos = Vec2( actorA->m_position.x, actorA->m_position.y );
Vec2 actorBPos = Vec2( actorB->m_position.x, actorB->m_position.y );
FloatRange actorARangeZ( actorA->m_position.z, actorA->m_position.z + actorA->m_actorDefinition->m_physicsHeight );
FloatRange actorBRangeZ( actorB->m_position.z, actorB->m_position.z + actorB->m_actorDefinition->m_physicsHeight );
if (actorARangeZ.DoFloatRangeOverlapEachOther( actorBRangeZ ))
{
PushDiscsOutOfEachOther2D( actorAPos, actorA->m_actorDefinition->m_physicsRadius, actorBPos, actorB->m_actorDefinition->m_physicsRadius );
actorA->m_position.x = actorAPos.x;
actorA->m_position.y = actorAPos.y;
actorB->m_position.x = actorBPos.x;
actorB->m_position.y = actorBPos.y;
}
}
else if (actorA->m_actorDefinition->m_collidesWithActors && !actorB->m_actorDefinition->m_collidesWithActors)
{
Vec2 actorAPos = Vec2( actorA->m_position.x, actorA->m_position.y );
Vec2 actorBPos = Vec2( actorB->m_position.x, actorB->m_position.y );
FloatRange actorARangeZ( actorA->m_position.z, actorA->m_position.z + actorA->m_actorDefinition->m_physicsHeight );
FloatRange actorBRangeZ( actorB->m_position.z, actorB->m_position.z + actorB->m_actorDefinition->m_physicsHeight );
if (actorARangeZ.DoFloatRangeOverlapEachOther( actorBRangeZ ))
{
PushDiscOutOfFixedDisc2D( actorAPos, actorA->m_actorDefinition->m_physicsRadius, actorBPos, actorB->m_actorDefinition->m_physicsRadius );
actorA->m_position.x = actorAPos.x;
actorA->m_position.y = actorAPos.y;
}
}
else if (!actorA->m_actorDefinition->m_collidesWithActors && actorB->m_actorDefinition->m_collidesWithActors)
{
Vec2 actorAPos = Vec2( actorA->m_position.x, actorA->m_position.y );
Vec2 actorBPos = Vec2( actorB->m_position.x, actorB->m_position.y );
FloatRange actorARangeZ( actorA->m_position.z, actorA->m_position.z + actorA->m_actorDefinition->m_physicsHeight );
FloatRange actorBRangeZ( actorB->m_position.z, actorB->m_position.z + actorB->m_actorDefinition->m_physicsHeight );
if (actorARangeZ.DoFloatRangeOverlapEachOther( actorBRangeZ ))
{
PushDiscOutOfFixedDisc2D( actorBPos, actorB->m_actorDefinition->m_physicsRadius, actorAPos, actorA->m_actorDefinition->m_physicsRadius );
actorB->m_position.x = actorBPos.x;
actorB->m_position.y = actorBPos.y;
}
}
}
else if (actorA->m_actorDefinition->m_isProjectile && !actorB->m_actorDefinition->m_isProjectile && actorA->m_owner != actorB)
{
Vec2 actorAPos = Vec2( actorA->m_position.x, actorA->m_position.y );
Vec2 actorBPos = Vec2( actorB->m_position.x, actorB->m_position.y );
FloatRange actorARangeZ( actorA->m_position.z, actorA->m_position.z + actorA->m_actorDefinition->m_physicsHeight );
FloatRange actorBRangeZ( actorB->m_position.z, actorB->m_position.z + actorB->m_actorDefinition->m_physicsHeight );
if (actorARangeZ.DoFloatRangeOverlapEachOther( actorBRangeZ ))
{
if (DoDiscsOverlap( actorAPos, actorA->m_actorDefinition->m_physicsRadius, actorBPos, actorB->m_actorDefinition->m_physicsRadius ))
{
if (actorA->m_actorDefinition->m_dieOnCollide)
{
if (!actorB->m_isInvincible)
{
actorB->m_currentHealth -= rng->RollRandomFloatInRange( actorA->m_actorDefinition->m_damageOnCollide.m_min, actorA->m_actorDefinition->m_damageOnCollide.m_max );
}
Vec3 impuseDirection( -actorA->m_velocity.GetNormalized() );
actorB->AddImpulse( actorA->m_ownerWeapon->m_weaponDef->m_rayImpulse * impuseDirection );
if (actorB->m_AIController != nullptr)
{
actorB->m_AIController->m_targetActor = actorA->m_owner;
actorB->m_AIController->m_isHitByOtherActors = true;
}
if (actorA->m_actorDefinition->m_canFrozenTarget)
{
actorB->m_isFrozen = true;
actorB->m_frozenTime = actorA->m_actorDefinition->m_frozenTime;
}
actorA->m_isDead = true;
if (g_theGame->m_playerControllers.size() > 1 && actorB->m_actorDefinition->m_name == "Marine" && actorB->m_currentHealth <= 0.f)
{
for (int i = 0; i < g_theGame->m_playerControllers.size(); i++)
{
if (g_theGame->m_playerControllers[i] != nullptr)
{
if (g_theGame->m_playerControllers[i]->GetActor() != actorB)
{
g_theGame->m_playerControllers[i]->m_killNum++;
}
}
}
}
}
}
}
}
else if (!actorA->m_actorDefinition->m_isProjectile && actorB->m_actorDefinition->m_isProjectile && actorB->m_owner != actorA)
{
Vec2 actorAPos = Vec2( actorA->m_position.x, actorA->m_position.y );
Vec2 actorBPos = Vec2( actorB->m_position.x, actorB->m_position.y );
FloatRange actorARangeZ( actorA->m_position.z, actorA->m_position.z + actorA->m_actorDefinition->m_physicsHeight );
FloatRange actorBRangeZ( actorB->m_position.z, actorB->m_position.z + actorB->m_actorDefinition->m_physicsHeight );
if (actorARangeZ.DoFloatRangeOverlapEachOther( actorBRangeZ ))
{
if (DoDiscsOverlap( actorAPos, actorA->m_actorDefinition->m_physicsRadius, actorBPos, actorB->m_actorDefinition->m_physicsRadius ))
{
if (actorB->m_actorDefinition->m_dieOnCollide)
{
if (!actorA->m_isInvincible)
{
actorA->m_currentHealth -= rng->RollRandomFloatInRange( actorB->m_actorDefinition->m_damageOnCollide.m_min, actorB->m_actorDefinition->m_damageOnCollide.m_max );
}
Vec3 impuseDirection( actorB->m_velocity.GetNormalized() );
actorA->AddImpulse( actorB->m_actorDefinition->m_impulseOnCollide * impuseDirection );
if (actorA->m_AIController != nullptr)
{
actorA->m_AIController->m_targetActor = actorB->m_owner;
actorA->m_AIController->m_isHitByOtherActors = true;
}
if (actorB->m_actorDefinition->m_canFrozenTarget)
{
actorA->m_isFrozen = true;
actorA->m_frozenTime = actorB->m_actorDefinition->m_frozenTime;
}
actorB->m_isDead = true;
if (actorA->m_actorDefinition->m_name == "Marine" && actorA->m_currentHealth <= 0.f)
{
for (int i = 0; i < g_theGame->m_playerControllers.size(); i++)
{
if (g_theGame->m_playerControllers[i] != nullptr)
{
if (g_theGame->m_playerControllers[i]->GetActor() != actorA)
{
g_theGame->m_playerControllers[i]->m_killNum++;
}
}
}
}
}
}
}
}
}
}
}
与 Actor 碰撞的代码
截图


