更新
This commit is contained in:
parent
fc39c8c3b3
commit
a01f2ebcad
112
src/ServerStorage/Base/Character.luau
Normal file
112
src/ServerStorage/Base/Character.luau
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
local Character = {}
|
||||
Character.__index = Character
|
||||
|
||||
local TypeList = require(script.Parent.TypeList)
|
||||
|
||||
local LIMIT_ATTRIBUTE = {
|
||||
"health"
|
||||
}
|
||||
|
||||
function Character.new(Player: Player, CharacterModel: Model, CharacterData: table): TypeList.Character
|
||||
local newMobModel = CharacterModel
|
||||
local HumanoidRootPart = newMobModel:FindFirstChild("HumanoidRootPart") :: BasePart
|
||||
local mobHumanoid = newMobModel:FindFirstChild("Humanoid") :: Humanoid
|
||||
|
||||
-- 生成表格数据
|
||||
local self = {}
|
||||
self.Instance = newMobModel
|
||||
self.Config = CharacterData
|
||||
self.Root = HumanoidRootPart
|
||||
self.Humanoid = mobHumanoid
|
||||
self.Origin = HumanoidRootPart:GetPivot()
|
||||
self.TargetPlayerUserID = Player.UserId
|
||||
self.Connections = {}
|
||||
self.Stats = {}
|
||||
|
||||
-- 生成实例身上的配置数据
|
||||
local Attributes = Instance.new("Configuration")
|
||||
Attributes.Name = "Attributes"
|
||||
Attributes.Parent = self.Instance
|
||||
for attributeKey, attributeValue in self.Config do
|
||||
Attributes:SetAttribute(attributeKey, attributeValue)
|
||||
-- 设置限制值
|
||||
if table.find(LIMIT_ATTRIBUTE, attributeKey) then
|
||||
self.Config["max" .. attributeKey] = attributeValue
|
||||
Attributes:SetAttribute("max" .. attributeKey, attributeValue)
|
||||
end
|
||||
|
||||
local conAttribute = self.AttributeChanged:Connect(function(attributeKey: string, attributeValue: number)
|
||||
self:ChangeAttribute(attributeKey, attributeValue)
|
||||
end)
|
||||
table.insert(self.Connections, conAttribute)
|
||||
end
|
||||
|
||||
-- 配置角色状态数据
|
||||
local statsData = {
|
||||
Died = false
|
||||
}
|
||||
local Stats = Instance.new("Configuration")
|
||||
Stats.Name = "Stats"
|
||||
Stats.Parent = self.Instance
|
||||
for statKey, statValue in statsData do
|
||||
self.Stats[statKey] = statValue
|
||||
Stats:SetAttribute(statKey, statValue)
|
||||
end
|
||||
|
||||
-- 初始化原有功能数值
|
||||
mobHumanoid.WalkSpeed = CharacterData.walkSpeed
|
||||
|
||||
-- Set humanoid states (helps prevent falling down & useless calculations - you're unlikely to have an enemy climbing without pathfinding)
|
||||
for _, EnumName in {"FallingDown", "Seated", "Flying", "Swimming", "Climbing"} do
|
||||
local HumanoidStateType = Enum.HumanoidStateType[EnumName]
|
||||
mobHumanoid:SetStateEnabled(HumanoidStateType, false)
|
||||
if mobHumanoid:GetState() == HumanoidStateType then
|
||||
mobHumanoid:ChangeState(Enum.HumanoidStateType.Running)
|
||||
end
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
function Character:GetAttribute(attributeKey: string)
|
||||
return self.Config[attributeKey], self.Instance.Attributes:GetAttribute(attributeKey)
|
||||
end
|
||||
|
||||
function Character:ChangeAttribute(attributeKey: string, value: any)
|
||||
local newValue = value
|
||||
-- 限制最大值
|
||||
if table.find(LIMIT_ATTRIBUTE, attributeKey) then
|
||||
if newValue > self.Config["max" .. attributeKey] then
|
||||
newValue = self.Config["max" .. attributeKey]
|
||||
end
|
||||
end
|
||||
-- 改变值
|
||||
self.Config[attributeKey] = newValue
|
||||
self.Instance.Attributes:SetAttribute(attributeKey, newValue)
|
||||
|
||||
-- 死亡判断
|
||||
if attributeKey == "health" and self.Stats.Died == false then
|
||||
if self.Config[attributeKey] <= 0 then
|
||||
self:Died()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Character:GetState(state: string)
|
||||
return self.Stats[state], self.Instance.Stats:GetAttribute(state)
|
||||
end
|
||||
|
||||
function Character:ChangeState(state: string, value: any)
|
||||
self.Stats[state] = value
|
||||
self.Instance.Stats:SetAttribute(state, value)
|
||||
end
|
||||
|
||||
function Character:Died()
|
||||
self:ChangeState("Died", true)
|
||||
for _, connection in self.Connections do
|
||||
connection:Disconnect()
|
||||
end
|
||||
self.Connections = nil
|
||||
self.Instance:Destroy()
|
||||
self = nil
|
||||
end
|
12
src/ServerStorage/Base/TypeList.luau
Normal file
12
src/ServerStorage/Base/TypeList.luau
Normal file
@ -0,0 +1,12 @@
|
||||
export type Character = {
|
||||
Instance: Model,
|
||||
Config: any,
|
||||
Root: BasePart,
|
||||
Humanoid: Humanoid,
|
||||
Origin: CFrame,
|
||||
TargetPlayerUserID: string,
|
||||
Connections: table,
|
||||
Stats: table,
|
||||
}
|
||||
|
||||
return {}
|
@ -1,6 +1,12 @@
|
||||
-- 伤害代理
|
||||
local DamageProxy = {}
|
||||
|
||||
--> Services
|
||||
local ServerStorage = game:GetService("ServerStorage")
|
||||
|
||||
--> Variables
|
||||
local TypeList = require(ServerStorage.Base.TypeList)
|
||||
|
||||
-- 伤害类型枚举
|
||||
local DamageType = {
|
||||
NORMAL = "Normal", -- 普攻
|
||||
@ -14,22 +20,41 @@ local DamageTag = {
|
||||
export type DamageTag = "Normal" | "Critical"
|
||||
export type DamageType = "Normal" | "Skill"
|
||||
|
||||
|
||||
export type DamageInfo = {
|
||||
Damage: number,
|
||||
Type: DamageType,
|
||||
Tag: DamageTag,
|
||||
}
|
||||
|
||||
function DamageProxy:TakeDamage(Caster: Model, Victim: Model, DamageInfos: {DamageInfo})
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
function DamageProxy:GetHumanoid(Target: Model)
|
||||
if not Target:IsA("Model") then
|
||||
warn("Target is not a Model")
|
||||
return nil
|
||||
end
|
||||
local Humanoid = Target:FindFirstChild("Humanoid")
|
||||
if not Humanoid then
|
||||
warn("Humanoid not found", Target)
|
||||
return nil
|
||||
end
|
||||
return Humanoid
|
||||
end
|
||||
|
||||
function DamageProxy:IsDied(Target: Model)
|
||||
local Humanoid = self:GetHumanoid(Target)
|
||||
return Humanoid:GetAttribute("Health") <= 0
|
||||
end
|
||||
|
||||
function DamageProxy:TakeDamage(Caster: TypeList.Character, Victim: TypeList.Character, DamageInfos: {DamageInfo})
|
||||
for _, DamageInfo in DamageInfos do
|
||||
local Damage = DamageInfo.Damage
|
||||
local DamageType = DamageInfo.DamageType
|
||||
local DamageTag = DamageInfo.DamageTag
|
||||
|
||||
-- 伤害计算
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
@ -10,6 +10,7 @@ local Players = game:GetService("Players")
|
||||
local Utils = require(ReplicatedStorage.Tools.Utils)
|
||||
local PlayerInfoProxy = require(ServerStorage.Proxy.PlayerInfoProxy)
|
||||
local AI = require(script.AI)
|
||||
local Character = require(ServerStorage.Base.Character)
|
||||
|
||||
--> Json
|
||||
local JsonMob = require(ReplicatedStorage.Json.Mob)
|
||||
@ -41,133 +42,43 @@ end
|
||||
local Mob = {}
|
||||
Mob.__index = Mob
|
||||
|
||||
local LIMIT_ATTRIBUTE = {
|
||||
"health"
|
||||
}
|
||||
|
||||
function Mob.new(Player: Player, MobId: number)
|
||||
-- 怪物实例目录判断
|
||||
-- 获取玩家怪物目录
|
||||
local playerMobsFolder = GetPlayerMobsFolder(Player)
|
||||
if not playerMobsFolder then return end
|
||||
-- 怪物数据获取
|
||||
|
||||
-- 获取怪物数据
|
||||
local MobData = Utils:GetJsonData(JsonMob, MobId)
|
||||
if not MobData then warn("Mob Data not found", MobId) return end
|
||||
-- 怪物模型获取
|
||||
|
||||
-- 获取怪物模型
|
||||
local MobInstance = FindMobPrefab(MobData.Model)
|
||||
if not MobInstance then warn("Mob Prefab not found", MobData.Model) return end
|
||||
-- 生成对应实例
|
||||
|
||||
-- 克隆怪物模型
|
||||
local newMobModel = MobInstance:Clone()
|
||||
local HumanoidRootPart = newMobModel:FindFirstChild("HumanoidRootPart") :: BasePart
|
||||
local mobHumanoid = newMobModel:FindFirstChild("Humanoid") :: Humanoid
|
||||
|
||||
-- 生成表格数据
|
||||
local newMob = setmetatable({}, Mob)
|
||||
newMob.Instance = newMobModel
|
||||
newMob.Config = MobData
|
||||
newMob.Root = HumanoidRootPart
|
||||
newMob.Humanoid = mobHumanoid
|
||||
newMob.Origin = HumanoidRootPart:GetPivot()
|
||||
newMob.TargetPlayerUserID = Player.UserId
|
||||
newMob.Connections = {}
|
||||
newMob.Stats = {}
|
||||
-- 调用父类Character的new方法,初始化通用属性
|
||||
local self = Character.new(Player, newMobModel, MobData)
|
||||
setmetatable(self, Mob) -- 继承Mob方法
|
||||
|
||||
-- 生成实例身上的配置数据
|
||||
local Attributes = Instance.new("Configuration")
|
||||
Attributes.Name = "Attributes"
|
||||
Attributes.Parent = newMob
|
||||
for attributeKey, attributeValue in newMob.Config do
|
||||
Attributes:SetAttribute(attributeKey, attributeValue)
|
||||
-- 设置限制值
|
||||
if table.find(LIMIT_ATTRIBUTE, attributeKey) then
|
||||
newMob.Config["max" .. attributeKey] = attributeValue
|
||||
Attributes:SetAttribute("max" .. attributeKey, attributeValue)
|
||||
end
|
||||
|
||||
local conAttribute = newMob.AttributeChanged:Connect(function(attributeKey: string, attributeValue: number)
|
||||
newMob:ChangeAttribute(attributeKey, attributeValue)
|
||||
end)
|
||||
table.insert(newMob.Connections, conAttribute)
|
||||
end
|
||||
|
||||
-- 配置角色状态数据
|
||||
local statsData = {
|
||||
Died = false
|
||||
}
|
||||
local Stats = Instance.new("Configuration")
|
||||
Stats.Name = "Stats"
|
||||
Stats.Parent = newMob
|
||||
for statKey, statValue in statsData do
|
||||
newMob.Stats[statKey] = statValue
|
||||
Stats:SetAttribute(statKey, statValue)
|
||||
end
|
||||
|
||||
-- 初始化原有功能数值
|
||||
mobHumanoid.WalkSpeed = MobData.walkSpeed
|
||||
-- 放入关卡中
|
||||
newMobModel.Parent = playerMobsFolder
|
||||
-- Set humanoid states (helps prevent falling down & useless calculations - you're unlikely to have an enemy climbing without pathfinding)
|
||||
for _, EnumName in {"FallingDown", "Seated", "Flying", "Swimming", "Climbing"} do
|
||||
local HumanoidStateType = Enum.HumanoidStateType[EnumName]
|
||||
mobHumanoid:SetStateEnabled(HumanoidStateType, false)
|
||||
if mobHumanoid:GetState() == HumanoidStateType then
|
||||
mobHumanoid:ChangeState(Enum.HumanoidStateType.Running)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- 接入统一AI
|
||||
-- Following has finished. Anchor assembly to optimize.
|
||||
mobHumanoid.MoveToFinished:Connect(function()
|
||||
self.Humanoid.MoveToFinished:Connect(function()
|
||||
if not AI:GetClosestPlayer(Mob) and not Mob.isDead then
|
||||
HumanoidRootPart.Anchored = true
|
||||
self.Root.Anchored = true
|
||||
else
|
||||
AI:StartTracking(Mob)
|
||||
end
|
||||
end)
|
||||
return newMob
|
||||
end
|
||||
|
||||
function Mob:GetAttribute(attributeKey: string)
|
||||
return self.Config[attributeKey], self.Instance.Attributes:GetAttribute(attributeKey)
|
||||
end
|
||||
|
||||
function Mob:ChangeAttribute(attributeKey: string, value: any)
|
||||
local newValue = value
|
||||
-- 限制最大值
|
||||
if table.find(LIMIT_ATTRIBUTE, attributeKey) then
|
||||
if newValue > self.Config["max" .. attributeKey] then
|
||||
newValue = self.Config["max" .. attributeKey]
|
||||
end
|
||||
end
|
||||
-- 改变值
|
||||
self.Config[attributeKey] = newValue
|
||||
self.Instance.Attributes:SetAttribute(attributeKey, newValue)
|
||||
|
||||
-- 死亡判断
|
||||
if attributeKey == "health" and self.Stats.Died == false then
|
||||
if self.Config[attributeKey] <= 0 then
|
||||
self:Died()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Mob:GetState(state: string)
|
||||
return self.Stats[state], self.Instance.Stats:GetAttribute(state)
|
||||
end
|
||||
|
||||
function Mob:ChangeState(state: string, value: any)
|
||||
self.Stats[state] = value
|
||||
self.Instance.Stats:SetAttribute(state, value)
|
||||
return self
|
||||
end
|
||||
|
||||
function Mob:Died()
|
||||
self:ChangeState("Died", true)
|
||||
MobsProxy:RemoveMob(self.Player, self.Instance)
|
||||
for _, connection in self.Connections do
|
||||
connection:Disconnect()
|
||||
end
|
||||
self.Connections = nil
|
||||
self.Instance:Destroy()
|
||||
self = nil
|
||||
Character.Died(self)
|
||||
end
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
Loading…
x
Reference in New Issue
Block a user