402 lines
15 KiB
Lua
402 lines
15 KiB
Lua
|
---@class PoisonCircleSystem_C:AActor
|
||
|
---@field DefaultSceneRoot USceneComponent
|
||
|
---@field OuterClass UClass
|
||
|
---@field InnerClass UClass
|
||
|
---@field CenterActorClass UClass
|
||
|
--Edit Below--
|
||
|
require("Script.Blueprint.XinHaoQuan.PoisonConfig")
|
||
|
local PoisonCircleSystem = {};
|
||
|
|
||
|
PoisonCircleState = PoisonCircleState or {
|
||
|
NON_START = 1, -- 未开始
|
||
|
PREPARE = 2, -- 准备开始,此时已经设置显示了
|
||
|
RUNNING = 3, -- 正在运行中
|
||
|
ENDED = 4, -- 结束了
|
||
|
};
|
||
|
|
||
|
--- 设置为未开始
|
||
|
PoisonCircleSystem.CurrState = PoisonCircleState.NON_START;
|
||
|
PoisonCircleSystem.CachedState = PoisonCircleState.NON_START;
|
||
|
|
||
|
--- 配置选项
|
||
|
PoisonCircleSystem.ConfigIndex = 1;
|
||
|
---@type table<int32, CircleConfigItem> 存一份的配置
|
||
|
PoisonCircleSystem.Config = {};
|
||
|
--- 外圈索引
|
||
|
PoisonCircleSystem.OuterIndex = 1;
|
||
|
--- 内圈索引
|
||
|
PoisonCircleSystem.InnerIndex = 2;
|
||
|
---@type BP_Poison_Outer_C 外层的 Actor
|
||
|
PoisonCircleSystem.OuterActor = nil;
|
||
|
---@type BP_Poison_Inner_C 内层的 Actor
|
||
|
PoisonCircleSystem.InnerActor = nil;
|
||
|
---@type table<int32, AActor> 中心点Actor 列表
|
||
|
PoisonCircleSystem.CenterActors = {};
|
||
|
--- 选择的中心点索引
|
||
|
PoisonCircleSystem.SelectCenterIndex = 0;
|
||
|
--- 记录一下开始移动的起始时间
|
||
|
PoisonCircleSystem.StartRunningTime = 0;
|
||
|
PoisonCircleSystem.CachedStartRunningTime = 0;
|
||
|
--PoisonCircleSystem.ConfigTime = 0;
|
||
|
|
||
|
function PoisonCircleSystem:ReceiveBeginPlay()
|
||
|
self.SuperClass.ReceiveBeginPlay(self);
|
||
|
--self:ShowCircle(false);
|
||
|
UGCEventSystem.AddListener(EventTypes.ClientAlready, self.OnClientAlready, self);
|
||
|
end
|
||
|
|
||
|
---@param InIndex int32 状态索引
|
||
|
---@return string 状态名称
|
||
|
function PoisonCircleSystem:GetPoisonCircleStateName(InIndex)
|
||
|
for i, v in pairs(PoisonCircleState) do if v == InIndex then return i; end end
|
||
|
return '';
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:ReceiveTick(DeltaTime)
|
||
|
self.SuperClass.ReceiveTick(self, DeltaTime);
|
||
|
|
||
|
local CurrTime = UGCGameSystem.GameState:GetServerTime();
|
||
|
if self.CachedState == PoisonCircleState.RUNNING then
|
||
|
if CurrTime - self.CachedStartRunningTime >= self.Config[self.OuterIndex].MoveTime then
|
||
|
--self:SetActorCenterAndRadius(self.InnerIndex + 1, self.InnerIndex, self.Config)
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
self.OuterIndex = self.InnerIndex;
|
||
|
self.InnerIndex = self.InnerIndex + 1;
|
||
|
self:ChangeState(PoisonCircleState.PREPARE);
|
||
|
self:StartPoison();
|
||
|
self:SetActorCenterAndRadius_Internal(self.OuterActor, self.Config, self.OuterIndex)
|
||
|
self:SetActorCenterAndRadius_Internal(self.InnerActor, self.Config, self.InnerIndex)
|
||
|
DOREPONCE(self, "OuterIndex");
|
||
|
DOREPONCE(self, "InnerIndex");
|
||
|
if self.Config[self.InnerIndex] == nil then self:ChangeState(PoisonCircleState.ENDED); end
|
||
|
else
|
||
|
self:SetActorCenterAndRadius_Internal(self.OuterActor, self.Config, self.OuterIndex + 1)
|
||
|
self.CachedState = PoisonCircleState.PREPARE;
|
||
|
if self.Config[self.InnerIndex + 1] == nil then
|
||
|
self.CachedState = PoisonCircleState.ENDED;
|
||
|
else
|
||
|
self:SetActorCenterAndRadius_Internal(self.InnerActor, self.Config, self.InnerIndex + 1)
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
local TimeInterval = CurrTime - self.CachedStartRunningTime;
|
||
|
local Rate = TimeInterval / self.Config[self.OuterIndex].MoveTime
|
||
|
local TargetVec = VectorHelper.Sub(self.Config[self.InnerIndex].Center, self.Config[self.OuterIndex].Center)
|
||
|
local TargetLoc = VectorHelper.Add(self.Config[self.OuterIndex].Center, VectorHelper.MulNumber(TargetVec, Rate))
|
||
|
self:FindOuterInnerActor();
|
||
|
self.OuterActor:K2_SetActorLocation(TargetLoc);
|
||
|
|
||
|
local r = ((self.Config[self.InnerIndex].Radius - self.Config[self.OuterIndex].Radius) * Rate) + self.Config[self.OuterIndex].Radius
|
||
|
--UGCLogSystem.Log("[PoisonCircleSystem:ReceiveTick] r = %s", tostring(r))
|
||
|
self:SetTheActorSize(self.OuterActor, r);
|
||
|
end
|
||
|
elseif self.CurrState == PoisonCircleState.PREPARE then
|
||
|
end
|
||
|
self:TakePoisonDamage(DeltaTime);
|
||
|
end
|
||
|
|
||
|
--[[
|
||
|
function PoisonCircleSystem:ReceiveEndPlay()
|
||
|
self.SuperClass.ReceiveEndPlay(self);
|
||
|
end
|
||
|
--]]
|
||
|
|
||
|
function PoisonCircleSystem:GetReplicatedProperties()
|
||
|
return { "CurrState", "Lazy" }
|
||
|
, { "OuterIndex", "Lazy" }
|
||
|
, { "InnerIndex", "Lazy" }
|
||
|
, { "ConfigIndex", "Lazy" }
|
||
|
, { "StartRunningTime", "Lazy" }
|
||
|
, { "Config", "Lazy" }
|
||
|
--, { "ConfigTime", "Lazy" }
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:OnRep_StartRunningTime()
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:OnRep_StartRunningTime] StartRunningTime = %s", tostring(self.StartRunningTime));
|
||
|
if self.StartRunningTime > 0 then self.CachedStartRunningTime = self.StartRunningTime; end
|
||
|
end
|
||
|
|
||
|
--[[
|
||
|
function PoisonCircleSystem:GetAvailableServerRPCs()
|
||
|
return
|
||
|
end
|
||
|
--]]
|
||
|
|
||
|
function PoisonCircleSystem:OnClientAlready()
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:OnClientAlready] 111")
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
if self.ConfigIndex == 0 then
|
||
|
self.ConfigIndex = 1;
|
||
|
DOREPONCE(self, "ConfigIndex");
|
||
|
end
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:OnClientAlready] 执行")
|
||
|
self:FillConfig(true);
|
||
|
self:CheckPoisonConfig();
|
||
|
-- 设置到对应位置
|
||
|
else
|
||
|
self:ShowCircle(false);
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---
|
||
|
function PoisonCircleSystem:StartPoison(InDelay, InCurrTime)
|
||
|
if self.CurrState == PoisonCircleState.ENDED then return end
|
||
|
if self.CurrState == PoisonCircleState.NON_START then self:ChangeState(PoisonCircleState.PREPARE); end
|
||
|
-- 显示出来
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:StartPoison] OuterIndex = %d, InnerIndex = %d", self.OuterIndex, self.InnerIndex);
|
||
|
local Delay = InDelay;
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
self:FillConfig(self.OuterIndex == 1);
|
||
|
Delay = self.Config[self.OuterIndex].Delay;
|
||
|
if self.Config[self.InnerIndex] == nil then self.InnerIndex = self.OuterIndex; end
|
||
|
local CurrTime = UGCGameSystem.GameState:GetServerTime()
|
||
|
self.StartRunningTime = CurrTime + Delay;
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:StartPoison] self.StartRunningTime = %s", tostring(self.StartRunningTime))
|
||
|
DOREPONCE(self, "StartRunningTime");
|
||
|
if self.OuterIndex == self.InnerIndex then
|
||
|
self:ChangeState(PoisonCircleState.ENDED);
|
||
|
return;
|
||
|
else
|
||
|
UnrealNetwork.CallUnrealRPC_Multicast(self, "StartPoison", Delay, CurrTime);
|
||
|
end
|
||
|
else
|
||
|
UITool.ShowTips("安全区还有 %s 秒开始刷新", tostring(InDelay));
|
||
|
self.CachedStartRunningTime = Delay + InCurrTime;
|
||
|
end
|
||
|
UGCEventSystem.SetTimer(self, function()
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
self:ChangeState(PoisonCircleState.RUNNING);
|
||
|
else
|
||
|
UITool.ShowTips("安全区开始刷新");
|
||
|
end
|
||
|
end, Delay);
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:FindCenters()
|
||
|
self.CenterActors = {};
|
||
|
local AllActors = {};
|
||
|
UE.FindActorsByClass(self.CenterActorClass, AllActors)
|
||
|
UGCLogSystem.LogTree(string.format("[PoisonCircleSystem:FindCenters] AllActors ="), AllActors)
|
||
|
UE.FindActorsByClass(self.CenterActorClass, self.CenterActors, function(InIndex, InActor)
|
||
|
if InActor:ActorHasTag("Poison") then
|
||
|
return InActor.Index;
|
||
|
end
|
||
|
return false;
|
||
|
end)
|
||
|
UGCLogSystem.LogTree(string.format("[PoisonCircleSystem:FindCenters] self.CenterActors ="), self.CenterActors)
|
||
|
end
|
||
|
|
||
|
--- 设置配置索引
|
||
|
function PoisonCircleSystem:SetConfigIndex(InIndex)
|
||
|
self.ConfigIndex = InIndex;
|
||
|
self:ResetPoison(true);
|
||
|
self:CheckPoisonConfig();
|
||
|
DOREPONCE(self, "ConfigIndex");
|
||
|
if self.OuterActor then self.OuterActor:InitOuterPoison(); end
|
||
|
end
|
||
|
|
||
|
--- 重置毒圈系统
|
||
|
function PoisonCircleSystem:ResetPoison(IsForce)
|
||
|
self:ChangeState(PoisonCircleState.NON_START);
|
||
|
self.OuterIndex = 1;
|
||
|
self.InnerIndex = 2;
|
||
|
self:FillConfig(true);
|
||
|
DOREPONCE(self, "OuterIndex");
|
||
|
DOREPONCE(self, "InnerIndex");
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:OnRep_InnerIndex()
|
||
|
if table.isEmpty(self.Config) then return; end
|
||
|
if self.InnerActor == nil then return end
|
||
|
self:SetActorCenterAndRadius_Internal(self.InnerActor, self.Config, self.InnerIndex)
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:ChangeState(InState)
|
||
|
self.CurrState = InState;
|
||
|
self.CachedState = InState;
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:ChangeState] CurrState = %s", self:GetPoisonCircleStateName(InState));
|
||
|
DOREPONCE(self, "CurrState");
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:OnRep_CurrState()
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:OnRep_CurrState] CurrState = %d", self.CurrState);
|
||
|
if self.CurrState == PoisonCircleState.ENDED then
|
||
|
self:SetActorCenterAndRadius(#self.Config, #self.Config, self.Config);
|
||
|
end
|
||
|
self.CachedState = self.CurrState;
|
||
|
self:ShowCircle(self.CachedState ~= PoisonCircleState.NON_START);
|
||
|
end
|
||
|
|
||
|
--- 服务器找到即可,到时候在类里面进行设置
|
||
|
function PoisonCircleSystem:FindOuterInnerActor()
|
||
|
if self.InnerActor == nil then self.InnerActor = UE.FindActorByClass(self.InnerClass); end
|
||
|
if self.OuterActor == nil then self.OuterActor = UE.FindActorByClass(self.OuterClass); end
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:ShowCircle(IsShow)
|
||
|
--if self.OuterActor then self.OuterActor:SetShowCircle(IsShow); end
|
||
|
--if self.InnerActor then self.InnerActor:SetShowCircle(IsShow); end
|
||
|
end
|
||
|
|
||
|
---@param InActor AActor
|
||
|
---@param InIndex int32
|
||
|
function PoisonCircleSystem:SetTheActorLocation(InActor, InIndex)
|
||
|
InActor:K2_SetActorLocation(InIndex);
|
||
|
end
|
||
|
|
||
|
---@param InActor AActor
|
||
|
---@param InSize FVector
|
||
|
function PoisonCircleSystem:SetTheActorSize(InActor, InSize)
|
||
|
InActor:SetActorScale3D({ X = InSize, Y = InSize, Z = 1 });
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:FillConfig(IsForce)
|
||
|
if table.isEmpty(self.Config) then
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:FillConfig] self.ConfigIndex = %s", tostring(self.ConfigIndex))
|
||
|
self.Config = TableHelper.DeepCopyTable(PoisonConfig.CircleConfig[self.ConfigIndex]);
|
||
|
end
|
||
|
if not IsForce or self:CheckPoisonCenter() then
|
||
|
return;
|
||
|
end
|
||
|
if table.isEmpty(self.CenterActors) then self:FindCenters(); end
|
||
|
local actor, index = table.random(self.CenterActors);
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:FillConfig] Index = %s, actor = %s", tostring(index), tostring(actor));
|
||
|
self.SelectCenterIndex = index;
|
||
|
PoisonConfig.SelectIndex = index;
|
||
|
local FirstLocation = actor == nil and DefaultSettings.MapCenterLocation or actor:K2_GetActorLocation();
|
||
|
local BigRadius = 0;
|
||
|
for i = 1, table.getCount(self.Config) do
|
||
|
local Item = self.Config[i];
|
||
|
if Item == nil then return; end
|
||
|
if IsForce or Item.Center == nil then
|
||
|
if i == 1 then
|
||
|
Item.Center = VectorHelper.ToLuaTable(FirstLocation);
|
||
|
else
|
||
|
Item.Center = math.randomCircleInCircle(FirstLocation, BigRadius * 100, Item.Radius * 100);
|
||
|
end
|
||
|
end
|
||
|
FirstLocation = VectorHelper.ToLuaTable(Item.Center);
|
||
|
BigRadius = Item.Radius;
|
||
|
end
|
||
|
UGCLogSystem.LogTree(string.format("[PoisonCircleSystem:FillConfig] self.Config ="), self.Config)
|
||
|
DOREPONCE(self, "Config");
|
||
|
end
|
||
|
|
||
|
---@return bool 是否所有中心点都就绪
|
||
|
function PoisonCircleSystem:CheckPoisonCenter()
|
||
|
for i, v in pairs(self.Config) do
|
||
|
if table.isEmpty(v.Center) then return false; end
|
||
|
end
|
||
|
return true;
|
||
|
end
|
||
|
|
||
|
--- 检查一下配置
|
||
|
function PoisonCircleSystem:CheckPoisonConfig(InConfigIndex, InConfig)
|
||
|
if UGCGameSystem.IsServer() then
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerController()) do
|
||
|
UnrealNetwork.CallUnrealRPC(v, self, "Client_CheckPoisonConfig", self.ConfigIndex, self.Config);
|
||
|
end
|
||
|
DOREPONCE(self, "Config");
|
||
|
end
|
||
|
self:SetActorCenterAndRadius(self.InnerIndex, self.OuterIndex, self.Config);
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:Client_CheckPoisonConfig(InIndex, InConfig)
|
||
|
self:SetActorCenterAndRadius(self.InnerIndex, self.OuterIndex, InConfig);
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:OnRep_Config()
|
||
|
if table.isEmpty(self.Config) then return end
|
||
|
PoisonConfig.CircleConfig[self.ConfigIndex] = self.Config;
|
||
|
self:Client_CheckPoisonConfig(self.ConfigIndex, self.Config);
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:SetActorCenterAndRadius(InInner, InOuter, InConfig)
|
||
|
if table.isEmpty(InConfig) then return; end
|
||
|
self:FindOuterInnerActor();
|
||
|
self:SetActorCenterAndRadius_Internal(self.InnerActor, InConfig, InInner - (InConfig[InInner] and 0 or 1));
|
||
|
self:SetActorCenterAndRadius_Internal(self.OuterActor, InConfig, InOuter);
|
||
|
end
|
||
|
|
||
|
---@private
|
||
|
function PoisonCircleSystem:SetActorCenterAndRadius_Internal(InActor, InConfig, InIndex)
|
||
|
self:SetTheActorLocation(InActor, VectorHelper.ToLuaTable(InConfig[InIndex].Center));
|
||
|
self:SetTheActorSize(InActor, InConfig[InIndex].Radius);
|
||
|
end
|
||
|
|
||
|
---@return float
|
||
|
function PoisonCircleSystem:GetPoisonRadius()
|
||
|
return self.OuterActor:GetActorScale3D().X;
|
||
|
end
|
||
|
|
||
|
PoisonCircleSystem.CurrCountTime = 0;
|
||
|
PoisonCircleSystem.ConstCurrCountTime = 0.75;
|
||
|
|
||
|
--- 执行伤害
|
||
|
function PoisonCircleSystem:TakePoisonDamage(InDeltaTime)
|
||
|
if self.CurrState == PoisonCircleState.NON_START then return; end
|
||
|
if not UGCGameSystem.IsServer() then return end
|
||
|
self.CurrCountTime = self.CurrCountTime + InDeltaTime;
|
||
|
if self.CurrCountTime >= self.ConstCurrCountTime then
|
||
|
self.CurrCountTime = self.CurrCountTime - self.ConstCurrCountTime;
|
||
|
local Radius = self:GetPoisonRadius();
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
|
||
|
local Dis = VectorHelper.GetActorDis2D(self.OuterActor, v);
|
||
|
if UE.IsValid(v) and v:IsAlive() and Dis > Radius * 100 then
|
||
|
local Damage = self.Config[self.OuterIndex].Damage * self.ConstCurrCountTime;
|
||
|
UGCLogSystem.Log("[PoisonCircleSystem:TakePoisonDamage] Damage = %s", Damage);
|
||
|
UGCGameSystem.ApplyDamage(v, Damage, nil, self, EDamageType.PoisonDamage);
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
---@return PoisonCircleState
|
||
|
function PoisonCircleSystem:GetCurrState() return self.CurrState; end
|
||
|
---@return float
|
||
|
function PoisonCircleSystem:GetPlayedTime() return UGCGameSystem.GameState:GetServerTime() - self.CachedStartRunningTime; end
|
||
|
|
||
|
--- 获取刷新的时间,前面的是现在已经刷新的时候,后面的是总刷新时间
|
||
|
---@return float, float
|
||
|
function PoisonCircleSystem:GetRefreshTime()
|
||
|
local MoveTime = self.Config[self.OuterIndex].MoveTime;
|
||
|
local PlayedTime = self:GetPlayedTime();
|
||
|
return PlayedTime > MoveTime and MoveTime or PlayedTime, MoveTime;
|
||
|
end
|
||
|
|
||
|
--- 获取在圈内的所有玩家
|
||
|
---@param InTable table<int32, UGCPlayerPawn_C> out
|
||
|
---@return table<int32, UGCPlayerPawn_C>
|
||
|
function PoisonCircleSystem:GetPawnsInCircle(InTable)
|
||
|
if InTable == nil then InTable = {}; end
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
|
||
|
if v:IsAlive() then
|
||
|
if VectorHelper.GetActorDis2D(v, self.OuterActor) <= self:GetPoisonRadius() then table.insert(InTable, v); end
|
||
|
end
|
||
|
end
|
||
|
return InTable;
|
||
|
end
|
||
|
|
||
|
--- 获取在圈外的所有玩家
|
||
|
---@param InTable table<int32, UGCPlayerPawn_C> out
|
||
|
---@return table<int32, UGCPlayerPawn_C>
|
||
|
function PoisonCircleSystem:GetPawnsOutCircle(InTable)
|
||
|
if InTable == nil then InTable = {}; end
|
||
|
for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do
|
||
|
if v:IsAlive() then
|
||
|
if VectorHelper.GetActorDis2D(v, self.OuterActor) > self:GetPoisonRadius() then table.insert(InTable, v); end
|
||
|
end
|
||
|
end
|
||
|
return InTable;
|
||
|
end
|
||
|
|
||
|
function PoisonCircleSystem:GetOuterActor()
|
||
|
if self.OuterActor == nil then self:FindOuterInnerActor(); end
|
||
|
return self.OuterActor;
|
||
|
end
|
||
|
function PoisonCircleSystem:GetInnerActor()
|
||
|
if self.InnerActor == nil then self:FindOuterInnerActor(); end
|
||
|
return self.InnerActor;
|
||
|
end
|
||
|
|
||
|
return PoisonCircleSystem;
|