831 lines
27 KiB
Lua
831 lines
27 KiB
Lua
|
---@class BP_WeaponPawnBase_C:APawn
|
|||
|
---@field Sphere USphereComponent
|
|||
|
---@field DefaultRoot USceneComponent
|
|||
|
---@field StaticMesh1 UStaticMeshComponent
|
|||
|
---@field StaticMesh4 UStaticMeshComponent
|
|||
|
---@field StaticMesh3 UStaticMeshComponent
|
|||
|
---@field StaticMesh2 UStaticMeshComponent
|
|||
|
---@field MuzzleParticle UParticleSystem
|
|||
|
--Edit Below--
|
|||
|
local BP_WeaponPawnBase = {
|
|||
|
Activated = false,
|
|||
|
HasBegunPlay = false,
|
|||
|
|
|||
|
InRangeMonsters = {}, -- 检测区域中的 Monster
|
|||
|
TargetMonster = nil, -- 目标 Monster
|
|||
|
MarkPendingInitialized = false,
|
|||
|
|
|||
|
Weapons = {}, --所有的武器 数组类型
|
|||
|
|
|||
|
CurrentWeaponId = 0, -- 这个是 武器表中的 Id
|
|||
|
OwnerCharacter = nil,
|
|||
|
OwningPlayerState = nil, -- 拥有的PlayerState
|
|||
|
OwningPlayerController = nil, -- 拥有的 PlayerController
|
|||
|
DefaultShootCountPerSecond = 1, -- 默认每秒射击次数
|
|||
|
|
|||
|
TimeTemp = 0, -- 射击的定时器
|
|||
|
DefaultSphereRadius = 1200, -- 默认球体半径
|
|||
|
|
|||
|
TempSphereRadius = 0,
|
|||
|
IsPlayerInArena = false; -- 玩家是否在场内,因为玩家默认不在场内
|
|||
|
-- Client
|
|||
|
IsAttackNearestMonster = true; -- 是否攻击离得最近的怪物
|
|||
|
};
|
|||
|
|
|||
|
BP_WeaponPawnBase.OnFireDelegate = Delegate.New()
|
|||
|
|
|||
|
--设置同步的属性
|
|||
|
function BP_WeaponPawnBase:GetReplicatedProperties()
|
|||
|
return
|
|||
|
"Activated",
|
|||
|
"OwnerCharacter",
|
|||
|
"TargetMonster",
|
|||
|
"CurrentWeaponId"
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:ReceiveBeginPlay()
|
|||
|
BP_WeaponPawnBase.SuperClass.ReceiveBeginPlay(self)
|
|||
|
|
|||
|
self.MainMesh = self.StaticMesh1
|
|||
|
self.PartStaticMeshes = { self.StaticMesh2, self.StaticMesh3, self.StaticMesh4 }
|
|||
|
self.MonsterBaseClass = UE.LoadClass(BPClassPath.MonsterBase)
|
|||
|
|
|||
|
self.InRangeMonsters = {}
|
|||
|
self.HasBegunPlay = true
|
|||
|
|
|||
|
if self:HasAuthority() then
|
|||
|
self:LoadPlayerState()
|
|||
|
self:LoadPlayerController()
|
|||
|
--self:SetFireTimer()
|
|||
|
self.OnFireDelegate:Add(BP_WeaponPawnBase.MulticastPlayMuzzleEffectAndSound, self)
|
|||
|
else
|
|||
|
self.Sphere.OnComponentBeginOverlap:Add(BP_WeaponPawnBase.Sphere_OnComponentBeginOverlap, self)
|
|||
|
self.Sphere.OnComponentEndOverlap:Add(BP_WeaponPawnBase.Sphere_OnComponentEndOverlap, self)
|
|||
|
|
|||
|
EventSystem:AddListener(EventType.AsyncLoadWeaponMeshesCompleted, BP_WeaponPawnBase.OnPreLoadAccessable, self)
|
|||
|
EventSystem:AddListener(EventType.AttackRangeChanged, BP_WeaponPawnBase.SetSphereSizeRadius, self)
|
|||
|
|
|||
|
self:OnCreateWeapons()
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:ReceiveEndPlay()
|
|||
|
self.HasBegunPlay = false
|
|||
|
self.MainMesh = nil
|
|||
|
self.PartStaticMeshes = nil
|
|||
|
self.MonsterBaseClass = nil
|
|||
|
self.InRangeMonsters = nil
|
|||
|
|
|||
|
if self:HasAuthority() then
|
|||
|
self:ClearFireTimer()
|
|||
|
self.OnFireDelegate:Remove(BP_WeaponPawnBase.MulticastPlayMuzzleEffectAndSound, self)
|
|||
|
else
|
|||
|
self.Sphere.OnComponentBeginOverlap:Remove(BP_WeaponPawnBase.Sphere_OnComponentBeginOverlap, self)
|
|||
|
self.Sphere.OnComponentEndOverlap:Remove(BP_WeaponPawnBase.Sphere_OnComponentEndOverlap, self)
|
|||
|
EventSystem:RemoveListener(EventType.AsyncLoadWeaponMeshesCompleted, BP_WeaponPawnBase.OnPreLoadAccessable, self)
|
|||
|
EventSystem:RemoveListener(EventType.AttackRangeChanged, BP_WeaponPawnBase.SetSphereSizeRadius, self)
|
|||
|
end
|
|||
|
|
|||
|
BP_WeaponPawnBase.SuperClass.ReceiveEndPlay(self)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:ReceiveTick(DeltaTime)
|
|||
|
BP_WeaponPawnBase.SuperClass.ReceiveTick(self, DeltaTime)
|
|||
|
if not self.HasBegunPlay then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
if self:HasAuthority() then
|
|||
|
-- 获取次数
|
|||
|
if self.OwnerCharacter == nil or not UE.IsValid(self.OwnerCharacter) then
|
|||
|
return
|
|||
|
end
|
|||
|
if self.OwnerCharacter:IsSelfAlive() then
|
|||
|
self:TickFire(DeltaTime)
|
|||
|
end
|
|||
|
else
|
|||
|
if self.MarkPendingInitialized then
|
|||
|
self:ChangeWeaponId(self.CurrentWeaponId)
|
|||
|
end
|
|||
|
|
|||
|
-- 每帧获取对应位置和旋转
|
|||
|
if UE.IsValid(self.OwnerCharacter) then
|
|||
|
self:UpdateTargetMonster()
|
|||
|
if UE.IsValid(self.TargetMonster) then
|
|||
|
local SocketPos = VectorHelper.Add(self.OwnerCharacter:K2_GetActorLocation(), { X = 0, Y = 0, Z = 110 })
|
|||
|
local MonsterPos = VectorHelper.Add(self.TargetMonster:K2_GetActorLocation(), { X = 0, Y = 0, Z = 80 })
|
|||
|
self.StaticMesh1:K2_SetWorldRotation(KismetMathLibrary.FindLookAtRotation(SocketPos, MonsterPos), false)
|
|||
|
else
|
|||
|
self.StaticMesh1:K2_SetWorldRotation(self.OwnerCharacter:K2_GetActorRotation(), false)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
self.TimeTemp = self.TimeTemp + DeltaTime
|
|||
|
if self.TimeTemp > 1 then
|
|||
|
-- print(string.format('[BP_WeaponPawnBase:ReceiveTick] 开始打印怪物名称'))
|
|||
|
if #self.InRangeMonsters > 0 then
|
|||
|
for i, v in pairs(self.InRangeMonsters) do
|
|||
|
-- print(string.format('[BP_WeaponPawnBase:ReceiveTick] MonsterName = %s', KismetSystemLibrary.GetObjectName(v)))
|
|||
|
end
|
|||
|
end
|
|||
|
-- print(string.format('[BP_WeaponPawnBase:ReceiveTick] 结束打印, Target Monster Name = %s', KismetSystemLibrary.GetObjectName(self.TargetMonster)))
|
|||
|
self.TimeTemp = self.TimeTemp - 1
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:OnCreateWeapons()
|
|||
|
if not self.OwnerCharacter then
|
|||
|
return
|
|||
|
end
|
|||
|
-- 先关闭
|
|||
|
local ObjectTypes = {}
|
|||
|
local ActorClassFilter = UE.LoadClass(BPClassPath.MonsterBase)
|
|||
|
local ActorsToIgnore = { }
|
|||
|
local SphereLoc = self.OwnerCharacter:K2_GetActorLocation()
|
|||
|
local Radius = self.Sphere.SphereRadius
|
|||
|
local OutArrs = {}
|
|||
|
local RetVal, OutActors = KismetSystemLibrary.SphereOverlapActors(self.OwnerCharacter, SphereLoc, Radius, ObjectTypes, ActorClassFilter, ActorsToIgnore, OutArrs)
|
|||
|
--STExtraGameplayStatics.ClientDrawDebugSphere(SphereLoc, Radius, 6, {R = 1, G = 0, B = 0, A = 1}, 10, 1)
|
|||
|
--print(string.format('[BP_WeaponPawnBase:OnCreateWeapons] OutArrs Len = %d', #OutArrs))
|
|||
|
|
|||
|
if RetVal then
|
|||
|
--print(string.format('[BP_WeaponPawnBase:OnCreateWeapons] 进来了是进来了,有多少值呢:%d, Radius = %d', table.getCount(OutActors), Radius))
|
|||
|
if table.getCount(OutActors) > 0 then
|
|||
|
for i = 1, #OutActors do
|
|||
|
table.insert(self.InRangeMonsters, OutActors[i])
|
|||
|
end
|
|||
|
self:UpdateTargetMonster()
|
|||
|
end
|
|||
|
else
|
|||
|
print(string.format('[BP_WeaponPawnBase:OnCreateWeapons] 没有用呀~~'))
|
|||
|
end
|
|||
|
|
|||
|
-- 先关闭
|
|||
|
--self.TempSphereRadius = self.Sphere.SphereRadius
|
|||
|
--self.Sphere:SetActive(false, true)
|
|||
|
----self.Sphere:SetSphereRadius(5)
|
|||
|
--EventSystem.SetTimer(self, function()
|
|||
|
-- --self.Sphere:SetSphereRadius(self.TempSphereRadius, true)
|
|||
|
-- self.Sphere:SetActive(true, true)
|
|||
|
--end, 0.2)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:PlayerInArena(IsInArena)
|
|||
|
-- print(string.format('[BP_WeaponPawnBase:PlayerInArena] '.. tostring(IsInArena)))
|
|||
|
self.IsPlayerInArena = IsInArena
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:TickFire(DeltaTime)
|
|||
|
local ShootTime = self:GetShootTime()
|
|||
|
self.TimeTemp = self.TimeTemp + DeltaTime
|
|||
|
if self.TimeTemp > ShootTime then
|
|||
|
-- print(string.format("[BP_WeaponPawnBase:TickFire] 隔 %f 秒进行第二次射击", ShootTime))
|
|||
|
self.TimeTemp = self.TimeTemp - ShootTime
|
|||
|
self:Fire()
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:LoadPlayerController()
|
|||
|
if self.OwnerCharacter ~= nil then
|
|||
|
self.OwningPlayerController = self.OwnerCharacter:GetPlayerControllerSafety()
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:LoadPlayerState()
|
|||
|
if self.OwningPlayerState == nil then
|
|||
|
if self.OwnerCharacter ~= nil then
|
|||
|
self.OwningPlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(self.OwnerCharacter.PlayerKey)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:Fire()
|
|||
|
print(string.format("[BP_WeaponPawnBase:Fire] 开始开火"))
|
|||
|
if not self.Activated then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
if UE.IsValid(self.TargetMonster) == false then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
if UE.IsValid(self.OwnerCharacter) == false then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
if not self.TargetMonster:IsAlive() then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
self:LoadPlayerState()
|
|||
|
if self.OwningPlayerController == nil then
|
|||
|
self:LoadPlayerController()
|
|||
|
end
|
|||
|
if self.OwningPlayerController == nil then
|
|||
|
print(string.format("[BP_WeaponPawnBase:Fire] 玩家控制器设置出错,请检查"))
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
-- 造成的伤害
|
|||
|
local Damage = self.OwningPlayerState:MakeDamage(self.TargetMonster)
|
|||
|
self.OnFireDelegate(self, Damage)
|
|||
|
local RealDamage = UGCGameSystem.ApplyDamage(self.TargetMonster, Damage, self.OwningPlayerController, self.OwnerCharacter, EDamageType.ShootDamage)
|
|||
|
-- 在这进行判断
|
|||
|
if self.TargetMonster then
|
|||
|
GameDataManager.GetMonsterTypeByID(self.TargetMonster.ID)
|
|||
|
end
|
|||
|
--调用PlayerState 射击生命值 和 射击威力值
|
|||
|
self.OwningPlayerState:OnShot()
|
|||
|
UE.Log("[BP_WeaponPawnBase:Fire] RealDamage = %f, Player Key = %d", RealDamage, self.OwnerCharacter.PlayerKey)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:MulticastPlayMuzzleEffectAndSound()
|
|||
|
local SoundConfigId = Tables.WeaponSoundConfig[self.CurrentWeaponId]
|
|||
|
if SoundConfigId then
|
|||
|
UnrealNetwork.CallUnrealRPC_Multicast_Unreliable(self, "Client_MulticastRPC_PlayMuzzleEffectAndSound", SoundConfigId)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- Client
|
|||
|
function BP_WeaponPawnBase:ChangeWeaponId(ID)
|
|||
|
if not self.HasBegunPlay then
|
|||
|
UE.LogError("[BP_WeaponPawnBase:ChangeWeaponId] Has not BegunPlay, Mark Pending Initialized")
|
|||
|
self.MarkPendingInitialized = true
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
self.MarkPendingInitialized = false
|
|||
|
|
|||
|
if ID <= 0 then
|
|||
|
self.MainMesh:SetHiddenInGame(true, false)
|
|||
|
for _, StaticMeshComp in pairs(self.PartStaticMeshes) do
|
|||
|
StaticMeshComp:SetHiddenInGame(true, false)
|
|||
|
end
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
local RowData = GameDataManager.GetWeaponConstructDataByID(ID)
|
|||
|
local MeshInfo = GameDataManager.GetWeaponMeshInfo(ID)
|
|||
|
if RowData == nil or MeshInfo == nil then
|
|||
|
self.MainMesh:SetHiddenInGame(true, false)
|
|||
|
for _, PartMesh in pairs(self.PartStaticMeshes) do
|
|||
|
PartMesh:SetHiddenInGame(true, false)
|
|||
|
end
|
|||
|
UE.Log("[BP_WeaponPawnBase:ChangeWeaponId] RowData or MeshInfo is nil")
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
local MainStaticMesh = MeshInfo.MainMesh
|
|||
|
local PartStaticMeshes = MeshInfo.PartMeshes
|
|||
|
|
|||
|
if MainStaticMesh then
|
|||
|
self.MainMesh:SetStaticMesh(MainStaticMesh)
|
|||
|
end
|
|||
|
|
|||
|
for i, PartMesh in pairs(self.PartStaticMeshes) do
|
|||
|
local PartStaticMesh = PartStaticMeshes[i]
|
|||
|
if PartStaticMesh then
|
|||
|
local SocketName = PartStaticMesh.SocketName
|
|||
|
local Mesh = PartStaticMesh.PartMesh
|
|||
|
|
|||
|
PartMesh:SetHiddenInGame(false, false)
|
|||
|
PartMesh:SetStaticMesh(Mesh)
|
|||
|
PartMesh:K2_AttachTo(self.MainMesh, SocketName, EAttachLocation.SnapToTarget, false)
|
|||
|
else
|
|||
|
PartMesh:SetHiddenInGame(true, false)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
local Trans = MeshInfo.RelativeTransform
|
|||
|
self.MainMesh:K2_SetRelativeTransform(Trans, false, nil, false)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:OnRep_Activated()
|
|||
|
---TODO
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:OnRep_OwnerCharacter()
|
|||
|
-- UE.Log("[BP_WeaponPawnBase:OnRep_OwnerCharacter]")
|
|||
|
if self.OwnerCharacter then
|
|||
|
-- 武器绑定到人物头上
|
|||
|
self:K2_AttachToComponent(self.OwnerCharacter.WeaponActorSocket, "", EAttachmentRule.SnapToTarget, EAttachmentRule.KeepRelative, EAttachmentRule.SnapToTarget, true)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
---Server
|
|||
|
function BP_WeaponPawnBase:SetWeaponID(ID)
|
|||
|
print(string.format("[BP_WeaponPawnBase:SetWeaponID] 设置 Weapon Id = %d", ID))
|
|||
|
self.CurrentWeaponId = ID
|
|||
|
self.Activated = ID > 0
|
|||
|
end
|
|||
|
|
|||
|
---S
|
|||
|
function BP_WeaponPawnBase:SetOwnerCharacter(InCharacter)
|
|||
|
if InCharacter == nil then
|
|||
|
return
|
|||
|
end
|
|||
|
self.OwnerCharacter = InCharacter
|
|||
|
self:SetOwner(InCharacter)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:SetFireTimer()
|
|||
|
if self.OwningPlayerState == nil then
|
|||
|
self.OwningPlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(self.PlayerKey)
|
|||
|
end
|
|||
|
|
|||
|
KismetSystemLibrary.K2_ClearTimerHandle(self, self.TimerHandle)
|
|||
|
if self.FireTimerDelegate then
|
|||
|
ObjectExtend.DestroyDelegate(self.FireTimerDelegate)
|
|||
|
end
|
|||
|
self.FireTimerDelegate = ObjectExtend.CreateDelegate(self,
|
|||
|
function()
|
|||
|
|
|||
|
if self.Activated and UE.IsValid(self.TargetMonster) and UE.IsValid(self.OwnerCharacter) and self.TargetMonster:IsAlive() then
|
|||
|
local PC = self.OwnerCharacter:GetPlayerControllerSafety()
|
|||
|
if PC then
|
|||
|
-- 造成的伤害
|
|||
|
local Damage = self.OwningPlayerState:MakeDamage(self.TargetMonster)
|
|||
|
local RealDamage = UGCGameSystem.ApplyDamage(self.TargetMonster, Damage, PC, self.OwnerCharacter, EDamageType.ShootDamage)
|
|||
|
-- 在这进行判断
|
|||
|
if self.TargetMonster then
|
|||
|
GameDataManager.GetMonsterTypeByID(self.TargetMonster.ID)
|
|||
|
end
|
|||
|
UE.Log("[BP_WeaponPawnBase:FireTimerDelegate] RealDamage = %f", RealDamage)
|
|||
|
end
|
|||
|
end
|
|||
|
end)
|
|||
|
|
|||
|
-- 获取一下默认属性
|
|||
|
self:RefreshShootSpeed()
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:RefreshShootSpeed()
|
|||
|
local bIsActive = KismetSystemLibrary.K2_IsTimerActiveDelegate(self.TimerHandle)
|
|||
|
if bIsActive then
|
|||
|
KismetSystemLibrary.K2_ClearTimerDelegate(self.TimerHandle)
|
|||
|
end
|
|||
|
if self.OwningPlayerState == nil then
|
|||
|
self.OwningPlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(self.PlayerKey)
|
|||
|
end
|
|||
|
|
|||
|
local ShootRate = self.OwningPlayerState:ShootTimeEverSecond()
|
|||
|
--这个 0.5 是一个基础射击数值
|
|||
|
local TimeDelta = 0.5 / ShootRate
|
|||
|
self.TimerHandle = KismetSystemLibrary.K2_SetTimerDelegateForLua(self.FireTimerDelegate, self, TimeDelta, true)
|
|||
|
end
|
|||
|
|
|||
|
-- server 获取射击间隔(s)
|
|||
|
function BP_WeaponPawnBase:GetShootTime()
|
|||
|
if self.OwningPlayerState == nil or self.OwnerCharacter == nil then
|
|||
|
-- 默认情况下攻速
|
|||
|
return 1 / 1.30
|
|||
|
end
|
|||
|
local ShootRate = self.OwningPlayerState:ShootTimeEverSecond()
|
|||
|
--print(string.format("[BP_WeaponPawnBase:GetShootTime] Shoot Rate = %f", ShootRate))
|
|||
|
return 1 / ShootRate
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:ClearFireTimer()
|
|||
|
KismetSystemLibrary.K2_ClearTimerHandle(self, self.TimerHandle)
|
|||
|
ObjectExtend.DestroyDelegate(self.FireTimerDelegate)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetWeaponTypeByWeaponId(InWeaponId)
|
|||
|
return GameDataManager.GetWeaponType(InWeaponId)
|
|||
|
end
|
|||
|
|
|||
|
---C
|
|||
|
function BP_WeaponPawnBase:OnPreLoadAccessable()
|
|||
|
self:OnRep_OwnerCharacter()
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:Sphere_OnComponentBeginOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex, bFromSweep, SweepResult)
|
|||
|
if UE.IsValid(OtherActor) and UE.IsA(OtherActor, self.MonsterBaseClass) then
|
|||
|
self:UpdateMonsterInRange(OtherActor, true)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:Sphere_OnComponentEndOverlap(OverlappedComponent, OtherActor, OtherComp, OtherBodyIndex)
|
|||
|
if UE.IsValid(OtherActor) and UE.IsA(OtherActor, self.MonsterBaseClass) then
|
|||
|
self:UpdateMonsterInRange(OtherActor, false)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:UpdateMonsterInRange(InMonster, IsAdd)
|
|||
|
if not self.OwnerCharacter then
|
|||
|
return
|
|||
|
end
|
|||
|
if IsAdd and InMonster:IsAlive() then
|
|||
|
InMonster.OnDeath:Add(self.OnOverlappedMonsterDeath, self)
|
|||
|
table.insert(self.InRangeMonsters, InMonster)
|
|||
|
else
|
|||
|
InMonster.OnDeath:Remove(self.OnOverlappedMonsterDeath, self)
|
|||
|
table.removeValue(self.InRangeMonsters, InMonster)
|
|||
|
end
|
|||
|
self:UpdateTargetMonster()
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:UpdateTargetMonster()
|
|||
|
if (not UE.IsValid(self.OwnerCharacter)) or (not self.Sphere) then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
local MinDist = self.Sphere:GetScaledSphereRadius()
|
|||
|
local PawnLocation = self.OwnerCharacter:K2_GetActorLocation()
|
|||
|
local CurTarget = nil
|
|||
|
|
|||
|
local Func = function(InMinDist, InMonster, InPawnLoc, InCurr)
|
|||
|
if UE.IsValid(InMonster) and InMonster:IsAlive() then
|
|||
|
local MonsterLocation = InMonster:K2_GetActorLocation()
|
|||
|
local Dist = VectorHelper.GetDistance(InPawnLoc, MonsterLocation)
|
|||
|
if Dist < InMinDist then
|
|||
|
InMinDist = Dist
|
|||
|
InCurr = InMonster
|
|||
|
end
|
|||
|
end
|
|||
|
return InCurr, InMinDist
|
|||
|
end
|
|||
|
|
|||
|
-- 选择最近的怪物
|
|||
|
if self.IsAttackNearestMonster then
|
|||
|
for _, Monster in pairs(self.InRangeMonsters) do
|
|||
|
if UE.IsValid(Monster) then
|
|||
|
local IsInArenaMonster = Monster:GetMonsterType() == EMonsterType.Boss or Monster:GetMonsterType() == EMonsterType.Common
|
|||
|
if self.IsPlayerInArena then
|
|||
|
if IsInArenaMonster then
|
|||
|
CurTarget, MinDist = Func(MinDist, Monster, PawnLocation, CurTarget)
|
|||
|
end
|
|||
|
else
|
|||
|
CurTarget, MinDist = Func(MinDist, Monster, PawnLocation, CurTarget)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
else
|
|||
|
-- 按照权重进行设置,找到 BOSS
|
|||
|
local NiuBiGuai = {}
|
|||
|
for _, Monster in pairs(self.InRangeMonsters) do
|
|||
|
if UE.IsValid(Monster) and Monster:IsAlive() then
|
|||
|
local MonsterType = Tables.MonsterBaseConfig[Monster.ID].Type
|
|||
|
if MonsterType == EMonsterType.Default or MonsterType == EMonsterType.Common or MonsterType == EMonsterType.HangupRoom then
|
|||
|
else
|
|||
|
table.insert(NiuBiGuai, Monster)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if table.getCount(NiuBiGuai) > 0 then
|
|||
|
for _, Monster in pairs(NiuBiGuai) do
|
|||
|
CurTarget, MinDist = Func(MinDist, Monster, PawnLocation, CurTarget)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if CurTarget == nil then
|
|||
|
for _, Monster in pairs(self.InRangeMonsters) do
|
|||
|
CurTarget, MinDist = Func(MinDist, Monster, PawnLocation, CurTarget)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
if CurTarget ~= self.TargetMonster then
|
|||
|
self.TargetMonster = CurTarget
|
|||
|
-- print(string.format('[BP_WeaponPawnBase:UpdateTargetMonster] 设置Target Monster = %s', KismetSystemLibrary.GetObjectName(CurTarget)))
|
|||
|
UnrealNetwork.CallUnrealRPC(self, self, "ServerRPC_SetTargetMonster", CurTarget)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:ServerRPC_SetTargetMonster(InMonster)
|
|||
|
-- print(string.format('[BP_WeaponPawnBase:ServerRPC_SetTargetMonster] 服务端设置 TargetMonster:%s', KismetSystemLibrary.GetObjectName(InMonster)))
|
|||
|
if UE.IsValid(InMonster) and InMonster:IsAlive() then
|
|||
|
self.TargetMonster = InMonster
|
|||
|
else
|
|||
|
self.TargetMonster = nil
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetAvailableServerRPCs()
|
|||
|
return
|
|||
|
-- "Client_MulticastRPC_PlayMuzzleEffectAndSound"
|
|||
|
"ServerRPC_SetTargetMonster"
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:OnOverlappedMonsterDeath(DeadMonster, KillerController, DamageCauser, KillingHitInfo, KillingHitImpulseDir, KillingHitDamageTypeID, DamageTypeClass, IsHeadShotDamage)
|
|||
|
if DeadMonster and UE.IsA(DeadMonster, self.MonsterBaseClass) then
|
|||
|
self:UpdateMonsterInRange(DeadMonster, false)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetPlayerState()
|
|||
|
if UGCGameSystem.IsServer() then
|
|||
|
local PlayerKey = self.OwnerCharacter.PlayerKey
|
|||
|
local PlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(PlayerKey)
|
|||
|
return PlayerState
|
|||
|
else
|
|||
|
local PlayerState = GameDataManager.GetLocalPlayerState()
|
|||
|
return PlayerState
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:FindWeaponById(InWeaponId)
|
|||
|
-- 找到 PS
|
|||
|
return self:GetPlayerState():FindWeaponById(InWeaponId)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetWeaponByFittingItemId(InFittingItemId)
|
|||
|
local WeaponType = GetItemWeaponTypeByItemId(InFittingItemId)
|
|||
|
for i = 1, #self.Weapons do
|
|||
|
local Weapon = self.Weapons[i]
|
|||
|
if Weapon.Type == WeaponType then
|
|||
|
return Weapon
|
|||
|
end
|
|||
|
end
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
-- 查找配件的武器是否存在
|
|||
|
function BP_WeaponPawnBase:FindWeaponExist(InFittingItemId)
|
|||
|
local WeaponType = GetItemWeaponTypeByItemId(InFittingItemId)
|
|||
|
return self:FindWeaponByWeaponType(WeaponType)
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:FindWeaponByWeaponType(InWeaponType)
|
|||
|
for i = 1, #self.Weapons do
|
|||
|
if self.Weapons[i].Type == InWeaponType then
|
|||
|
return self.Weapons[i]
|
|||
|
end
|
|||
|
end
|
|||
|
return nil
|
|||
|
end
|
|||
|
|
|||
|
--Server 获取当前武器的属性,这是一个表:{ { Type = "", Value = 0 },{ Type = "", Value = 0 } }
|
|||
|
function BP_WeaponPawnBase:GetOutProps()
|
|||
|
-- 需要获取手枪属性
|
|||
|
local OutTable = {}
|
|||
|
local TheTable = DropItemMap.WeaponTable[EWeaponClassType.WT_Pistol].Props
|
|||
|
OutTable = TableHelper.DeepCopyTable(TheTable)
|
|||
|
if self.CurrentWeaponId == 0 then
|
|||
|
-- 说明当前是手枪,不进行处理
|
|||
|
return self:MergeOutTable(OutTable)
|
|||
|
end
|
|||
|
print(string.format("[BP_WeaponPawnBase:GetOutProps] 当前武器 Id = %d", self.CurrentWeaponId))
|
|||
|
-- NativeProps
|
|||
|
local Weapon = self:FindWeaponById(self.CurrentWeaponId)
|
|||
|
local SpecialItems = {}
|
|||
|
--print(string.format("[BP_WeaponPawnBase:GetOutProps] 开始打印武器高级属性,数量为:%d", table.getCount(Weapon.NativeProps.Plus)))
|
|||
|
|
|||
|
-- 高级属性
|
|||
|
for i = 1, table.getCount(Weapon.NativeProps.Plus) do
|
|||
|
local Val = Weapon.NativeProps.Plus[i]
|
|||
|
--print(string.format("[BP_WeaponPawnBase:GetOutProps] MainType: %s,类型是:%s", tostring(Val.MainType), type(Val.MainType)))
|
|||
|
local Name = Tables.WeaponPropertyConfig[Val.MainType].PropName
|
|||
|
local ItemData = {
|
|||
|
Type = Name,
|
|||
|
Value = Val.Value
|
|||
|
}
|
|||
|
--print(string.format("[BP_WeaponPawnBase:GetOutProps] 武器高级属性:Name:%s, Value: %s", Name, tostring(Val.Value)))
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
|
|||
|
-- 添加 Properties
|
|||
|
local Properties = Weapon.Properties
|
|||
|
--print(string.format("[BP_WeaponPawnBase:GetOutProps] 开始打印武器属性,数量:%d", table.getCount(Properties)))
|
|||
|
for i = 1, #Properties do
|
|||
|
local Prop = Properties[i]
|
|||
|
local ItemData = {
|
|||
|
Type = Tables.WeaponPropertyConfig[Prop.MainType].PropName,
|
|||
|
Value = Prop.Value
|
|||
|
}
|
|||
|
--print(string.format("[BP_WeaponPawnBase:GetOutProps] 武器属性:Name: %s, Value: %s", ItemData.Type, tostring(Prop.Value)))
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
|
|||
|
-- 处理武器自带属性
|
|||
|
local FittingLevel = Weapon.FittingLevel
|
|||
|
if FittingLevel > 0 then
|
|||
|
local Val = DropItemMap.WeaponTable[Weapon.Type].PlusProps[FittingLevel]
|
|||
|
local ItemData = {
|
|||
|
Type = Val.Type,
|
|||
|
Value = Val.Value
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
|
|||
|
-- FittingItems
|
|||
|
local FittingList = Weapon.Fittings
|
|||
|
for i = 1, #FittingList do
|
|||
|
local FittingItemId = FittingList[i]
|
|||
|
local FittingProps = DropItemMap.FittingItemMap[FittingItemId].Props
|
|||
|
for j = 1, #FittingProps do
|
|||
|
if FittingProps[j].Unit ~= 'Special' then
|
|||
|
local ItemData = {
|
|||
|
Type = FittingProps[j].Type,
|
|||
|
Value = FittingProps[j].Value
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
else
|
|||
|
local ItemData = {
|
|||
|
ItemId = FittingItemId,
|
|||
|
}
|
|||
|
table.insert(SpecialItems, ItemData)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
-- OutTable 是不包含特殊词条属性的,SpecialItems 里面是词条属性
|
|||
|
return self:MergeOutTable(OutTable), SpecialItems
|
|||
|
end
|
|||
|
|
|||
|
-- Server 设置当前的武器,当点击页面上的武器的时候执行这个
|
|||
|
function BP_WeaponPawnBase:SetCurrentWeapon(InId)
|
|||
|
-- 重复点击无效
|
|||
|
if InId == self.CurrentWeaponId then
|
|||
|
print(string.format("[BP_WeaponPawnBase:SetCurrentWeapon] 当前选择的Id与原先的Id相同"))
|
|||
|
return
|
|||
|
end
|
|||
|
if self:FindWeaponById(InId) == nil then
|
|||
|
print(string.format("[BP_WeaponPawnBase:SetCurrentWeapon] 无法找到对应Id"))
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
self.CurrentWeaponId = InId
|
|||
|
-- 通知进行改变
|
|||
|
print(string.format("[BP_WeaponPawnBase:SetCurrentWeapon] WeaponId = %d", self.CurrentWeaponId))
|
|||
|
local PlayerState = UGCGameSystem.GetPlayerStateByPlayerKey(self.OwnerCharacter.PlayerKey)
|
|||
|
PlayerState:OnWeaponAttributeChanged(self.CurrentWeaponId)
|
|||
|
end
|
|||
|
|
|||
|
-- 每操作一下就执行该方法进行检测 FittingLevel,然后刷新全部属性
|
|||
|
function BP_WeaponPawnBase:GetWeaponFittingLevel(InWeaponId)
|
|||
|
if not self:FindWeaponExist(InWeaponId) then
|
|||
|
print(string.format('[BP_WeaponPawnBase:GetWeaponFittingLevel] 找不到对应武器,请检查'))
|
|||
|
return -1
|
|||
|
end
|
|||
|
print(string.format('[BP_WeaponPawnBase:GetWeaponFittingLevel] 找到了对应武器,数量是: %d', InWeaponId))
|
|||
|
return self:FindWeaponById(InWeaponId).FittingLevel
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:OnRep_CurrentWeaponId()
|
|||
|
if self.OwnerCharacter == nil or UE.IsValid(self.OwnerCharacter) == false then
|
|||
|
return
|
|||
|
end
|
|||
|
|
|||
|
EventSystem:SendEvent(EventType.ClientUpdateWeapon, self.CurrentWeaponId, self.OwnerCharacter.PlayerKey)
|
|||
|
|
|||
|
if self.CurrentWeaponId > 0 then
|
|||
|
self:ChangeWeaponId(self.CurrentWeaponId)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetWeaponFittingsById(InItemId)
|
|||
|
print(string.format("[BP_WeaponPawnBase:GetWeaponFittingsById] 开始输入Ids"))
|
|||
|
if self:FindWeaponById(InItemId) == nil then
|
|||
|
for i, v in pairs(self.Weapons) do
|
|||
|
print(i)
|
|||
|
end
|
|||
|
end
|
|||
|
print(string.format("[BP_WeaponPawnBase:GetWeaponFittingsById] 结束输入Ids"))
|
|||
|
return self:FindWeaponById(InItemId).Fittings
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetWeaponCount()
|
|||
|
return #self:GetWeapons()
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:FindWeaponIndexById(InWeaponId)
|
|||
|
local PSWeapons = self:GetWeapons()
|
|||
|
for i = 1, #PSWeapons do
|
|||
|
if PSWeapons[i].WeaponId == InWeaponId then
|
|||
|
return i
|
|||
|
end
|
|||
|
end
|
|||
|
return -1
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetWeapons()
|
|||
|
return self:GetPlayerState().OwnerWeapons
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:FindWeaponIdByIndex(InIndex)
|
|||
|
if InIndex <= 0 or InIndex > self:GetWeaponCount() then
|
|||
|
return
|
|||
|
end
|
|||
|
return self:GetWeapons()[InIndex].WeaponId
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:GetCurrentWeaponIndex()
|
|||
|
return self:FindWeaponIndexById(self.CurrentWeaponId)
|
|||
|
end
|
|||
|
|
|||
|
-- SC
|
|||
|
function BP_WeaponPawnBase:SetSphereSizeRadius(InAddNum)
|
|||
|
self.Sphere:SetSphereRadius(self.DefaultSphereRadius + InAddNum, true)
|
|||
|
end
|
|||
|
|
|||
|
--获取武器基础属性
|
|||
|
function BP_WeaponPawnBase:GetWeaponBaseAttribute()
|
|||
|
local OutTable = {}
|
|||
|
local TheTable = DropItemMap.WeaponTable[EWeaponClassType.WT_Pistol].Props
|
|||
|
OutTable = TableHelper.DeepCopyTable(TheTable)
|
|||
|
if self.CurrentWeaponId == 0 then
|
|||
|
-- 说明当前是手枪,不进行处理
|
|||
|
return self:MergeOutTable(OutTable)
|
|||
|
end
|
|||
|
|
|||
|
local Weapon = self:FindWeaponById(self.CurrentWeaponId)
|
|||
|
--武器基础属性
|
|||
|
local FittingLevel = Weapon.FittingLevel
|
|||
|
if FittingLevel > 0 then
|
|||
|
local Val = DropItemMap.WeaponTable[Weapon.Type].PlusProps[FittingLevel]
|
|||
|
local ItemData = {
|
|||
|
Type = Val.Type,
|
|||
|
Value = Val.Value
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
|
|||
|
-- FittingItems
|
|||
|
local FittingList = Weapon.Fittings
|
|||
|
for i = 1, #FittingList do
|
|||
|
local FittingItemId = FittingList[i]
|
|||
|
local FittingProps = DropItemMap.FittingItemMap[FittingItemId].Props
|
|||
|
for j = 1, #FittingProps do
|
|||
|
if FittingProps[j].Unit ~= 'Special' then
|
|||
|
local ItemData = {
|
|||
|
Type = FittingProps[j].Type,
|
|||
|
Value = FittingProps[j].Value
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
return self:MergeOutTable(OutTable)
|
|||
|
end
|
|||
|
|
|||
|
--获取武器高级属性
|
|||
|
function BP_WeaponPawnBase:GetWeaponSeniorAttribute()
|
|||
|
local OutTable = {}
|
|||
|
if self.CurrentWeaponId == 0 then
|
|||
|
return {}
|
|||
|
end
|
|||
|
|
|||
|
local Weapon = self:FindWeaponById(self.CurrentWeaponId)
|
|||
|
|
|||
|
local Properties = Weapon.Properties
|
|||
|
for i = 1, #Properties do
|
|||
|
local Prop = Properties[i]
|
|||
|
local ItemData = {
|
|||
|
Type = Tables.WeaponPropertyConfig[Prop.MainType].PropName,
|
|||
|
Value = Prop.Value
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
|
|||
|
for i = 1, table.getCount(Weapon.NativeProps.Plus) do
|
|||
|
local Val = Weapon.NativeProps.Plus[i]
|
|||
|
local Name = Tables.WeaponPropertyConfig[Val.MainType].PropName
|
|||
|
local ItemData = {
|
|||
|
Type = Name,
|
|||
|
Value = Val.Value
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
return self:MergeOutTable(OutTable)
|
|||
|
end
|
|||
|
|
|||
|
-- 叠加属性
|
|||
|
function BP_WeaponPawnBase:MergeOutTable(InOutTable)
|
|||
|
local Items = {}
|
|||
|
for i = 1, table.getCount(InOutTable) do
|
|||
|
local Name = InOutTable[i].Type
|
|||
|
local Value = InOutTable[i].Value
|
|||
|
if Items[Name] == nil then
|
|||
|
Items[Name] = Value
|
|||
|
else
|
|||
|
Items[Name] = Items[Name] + Value
|
|||
|
end
|
|||
|
end
|
|||
|
local OutTable = {}
|
|||
|
for i, v in pairs(Items) do
|
|||
|
if string.len(i) < 10 then
|
|||
|
local ItemData = {
|
|||
|
Type = i,
|
|||
|
Value = v
|
|||
|
}
|
|||
|
table.insert(OutTable, ItemData)
|
|||
|
end
|
|||
|
end
|
|||
|
return OutTable
|
|||
|
end
|
|||
|
|
|||
|
function BP_WeaponPawnBase:Client_MulticastRPC_PlayMuzzleEffectAndSound(SoundConfigId)
|
|||
|
if self.OwnerCharacter then
|
|||
|
SoundManager.PlaySoundAtLocation(SoundConfigId, self.OwnerCharacter:K2_GetActorLocation(), self.OwnerCharacter:K2_GetActorRotation())
|
|||
|
end
|
|||
|
|
|||
|
if self.MuzzleParticle and self.MainMesh then
|
|||
|
GameplayStatics.SpawnEmitterAttached(self.MuzzleParticle, self.MainMesh, "MuzzleEffect", VectorHelper.VectorZero(), VectorHelper.RotZero(), VectorHelper.Scale(0.5), EAttachLocation.SnapToTarget, true)
|
|||
|
end
|
|||
|
end
|
|||
|
|
|||
|
return BP_WeaponPawnBase;
|