--- --- 宿舍家具对象 --- local TEST_FURNITURE_NAME = "Furniture003" --Test local XSceneObject = require("XHome/XSceneObject") local XHomeFurnitureObj = XClass(XSceneObject, "XHomeFurnitureObj") local Vector3 = CS.UnityEngine.Vector3 local WallNum = 4 local PutOnOffeY = 0.75 function XHomeFurnitureObj:Ctor(data, room) self.Data = data self.Room = room self.ConfirmGridX = self.Data.GridX self.ConfirmGridY = self.Data.GridY self.ConfirmRotate = self.Data.RotateAngle self.CfgId = self.Data.CfgId self.GridOffset = CS.XGame.ClientConfig:GetFloat("DormGroundGridMeshHighOffset") self.OnWallFixGridPos = {} self.OnWallFixGridPos[0] = Vector3(0, 0.5 * XHomeDormManager.GetMapTall() * XHomeDormManager.GetCeilSize(), 0.5 * XHomeDormManager.GetMapHeight() * XHomeDormManager.GetCeilSize() - self.GridOffset) self.OnWallFixGridPos[1] = Vector3(0.5 * XHomeDormManager.GetMapWidth() * XHomeDormManager.GetCeilSize() - self.GridOffset, 0.5 * XHomeDormManager.GetMapTall() * XHomeDormManager.GetCeilSize(), 0) self.OnWallFixGridPos[2] = Vector3(0, 0.5 * XHomeDormManager.GetMapTall() * XHomeDormManager.GetCeilSize(), -0.5 * XHomeDormManager.GetMapHeight() * XHomeDormManager.GetCeilSize() + self.GridOffset) self.OnWallFixGridPos[3] = Vector3(-0.5 * XHomeDormManager.GetMapWidth() * XHomeDormManager.GetCeilSize() + self.GridOffset, 0.5 * XHomeDormManager.GetMapTall() * XHomeDormManager.GetCeilSize(), 0) self.InteractInfoList = {} self.InterGos = {} self.Cfg = XFurnitureConfigs.GetFurnitureTemplateById(self.Data.CfgId) if self.Cfg then self.PlaceType = XFurnitureConfigs.GetFurniturePlaceType(self.Cfg.TypeId) end self.HomePlatType = nil if self.PlaceType == XFurniturePlaceType.OnGround then self.HomePlatType = XFurnitureConfigs.HomePlatType.Ground elseif self.PlaceType == XFurniturePlaceType.OnWall then self.HomePlatType = XFurnitureConfigs.HomePlatType.Wall end self:SetPos(self.ConfirmGridX, self.ConfirmGridY, self.ConfirmRotate) self.IsSelected = false self.IsMapBlock = false self.IsFurnitureBlock = false self.IsColliderBlock = false self.IsShowGlow = false self.IsAddDragComponent = false self.AninationIndex = 0 self.RippleWater = nil end function XHomeFurnitureObj:Dispose() XHomeFurnitureObj.Super.Dispose(self) self:HideAttrTag() if not XTool.UObjIsNil(self.GridComponent) then CS.XGridManager.Instance:FreeGrid(self.GridComponent) end self.GridComponent = nil if not XTool.UObjIsNil(self.GoInputHandler) then self.GoInputHandler:RemoveAllListeners() end self.GoInputHandler = nil if self.NavMeshSurface and self.NavMeshSurface:Exist() then self.NavMeshSurface:RemoveData() end self.CanChange = false self.ChangeFurnitureData = nil self.RippleWater = nil end function XHomeFurnitureObj:GetWallEffectsByRot(rot) return self.WallEffects and self.WallEffects[rot] or nil end function XHomeFurnitureObj:GetFurntiureEffect() return self.EffectComp end function XHomeFurnitureObj:OnLoadComplete() self.Colliders = {} local list = self.GameObject:GetComponentsInChildren(typeof(CS.UnityEngine.Collider)) for i = 0, list.Length - 1 do table.insert(self.Colliders, list[i]) end self.Effect = self.Transform:Find("Effect") if not XTool.UObjIsNil(self.Effect) then self.EffectComp = self.Effect:GetComponent(typeof(CS.XPrefabLoader)) end self.RippleWater = self.Transform:GetComponentInChildren(typeof(CS.XRippleWater)) -- 行为代理 if self.Cfg.HasBehavior then self.Agent = self.GameObject:GetComponent(typeof(CS.BehaviorTree.XAgent)) if XTool.UObjIsNil(self.Agent) then self.Agent = self.GameObject:AddComponent(typeof(CS.BehaviorTree.XAgent)) self.Agent.ProxyType = "HomeFurniture" self.Agent:InitProxy() end self.Agent.Proxy.LuaAgentProxy:SetHomeFrunitureObj(self) end self.DormPutOnAnimaTime = CS.XGame.ClientConfig:GetFloat("DormPutOnAnimaTime") self.IsPressing = false self.CanChange = false self.ChangeFurnitureData = nil -- 监听点击 self.GoInputHandler = self.Transform:GetComponent(typeof(CS.XGoInputHandler)) if XTool.UObjIsNil(self.GoInputHandler) then self.GoInputHandler = self.GameObject:AddComponent(typeof(CS.XGoInputHandler)) end if not XTool.UObjIsNil(self.GoInputHandler) then self.GoInputHandler:AddPointerClickListener(function(eventData) self:OnClick(eventData) end) if self.Cfg.HasBehavior then self.GoInputHandler:AddDragListener(function(eventData) self:OnDrag(eventData) end) end self.GoInputHandler:AddPressListener(function(pressTime) self:OnPress(pressTime) end) self.GoInputHandler:AddPointerExitListener(function(eventData) self:OnPointerExit(eventData) end) self.GoInputHandler:AddPointerUpListener(function(eventData) self:OnPointerUp(eventData) end) end self.WallEffects = {} for i = 1, WallNum do local wallIndex = tostring(i - 1) local wallEffect = self.Transform:Find(string.format("WallEffect%s", wallIndex)) if wallEffect then self.WallEffects[wallIndex] = {} local effectIndex = 1 local subEffect = self.Transform:Find(string.format("WallEffect%s/Effect%d", wallIndex, effectIndex)) if not XTool.UObjIsNil(subEffect) then self.SubEffectComp = subEffect:GetComponent(typeof(CS.XPrefabLoader)) end while (self.SubEffectComp) do table.insert(self.WallEffects[wallIndex], effectIndex, self.SubEffectComp) effectIndex = effectIndex + 1 subEffect = self.Transform:Find(string.format("WallEffect%s/Effect%d", wallIndex, effectIndex)) if not XTool.UObjIsNil(subEffect) then self.SubEffectComp = subEffect:GetComponent(typeof(CS.XPrefabLoader)) else self.SubEffectComp = nil end end end end if self.PlaceType == XFurniturePlaceType.Ceiling then self.GameObject:SetLayerRecursively(CS.UnityEngine.LayerMask.NameToLayer(HomeSceneLayerMask.Block)) else self.GameObject:SetLayerRecursively(CS.UnityEngine.LayerMask.NameToLayer(HomeSceneLayerMask.Device)) end self:SetData(self.Data) if self.PlaceType == XFurniturePlaceType.Ground then self.NavMeshSurface = CS.XNavMeshUtility.SetNavMeshSurfaceAndBuild(self.GameObject) --self.GameObject:AddComponent(typeof(CS.UnityEngine.AI.NavMeshSurface)) elseif self.Cfg.IsObstacle == 1 then CS.XNavMeshUtility.AddNavMeshObstacle(self.GameObject) end self.Animator = self.GameObject:GetComponent(typeof(CS.UnityEngine.Animator)) self:ChangeStatus(XHomeBehaviorStatus.IDLE, true) end function XHomeFurnitureObj:SetData(data) self.Data = data self.ConfirmGridX = self.Data.GridX self.ConfirmGridY = self.Data.GridY self.ConfirmRotate = self.Data.RotateAngle self:SetPos(self.ConfirmGridX, self.ConfirmGridY, self.ConfirmRotate) end function XHomeFurnitureObj:GetData() return self.ConfirmGridX, self.ConfirmGridY, self.ConfirmRotate end function XHomeFurnitureObj:GetXHomePlatType() if self.Cfg == nil then return end if self.Cfg.LocateType ~= XFurnitureConfigs.HomeLocateType.Replace then if self.Cfg.Model == TEST_FURNITURE_NAME then -- Test local scale = self.Transform.localScale self.Transform.localScale = Vector3(self.Cfg.Width, scale.y, self.Cfg.Height) end end return XFurnitureConfigs.LocateTypeToXHomePlatType(self.Cfg.LocateType) end function XHomeFurnitureObj:GetSize() if self.Cfg == nil then return 0, 0 end return self.Cfg.Width, self.Cfg.Height end function XHomeFurnitureObj:RippleAddChar(charTrans) if self.RippleWater then self.RippleWater:AddTriggerRippleObject_Unique(charTrans) end end function XHomeFurnitureObj:RippleRemoveChar(charTrans) if self.RippleWater then self.RippleWater:RemoveTriggerRippleObject(charTrans) end end function XHomeFurnitureObj:RippleClearChar() if self.RippleWater then self.RippleWater:ClearTriggerRippleObject() end end -- 检测是否可在该位置摆放 function XHomeFurnitureObj:CheckCanLocate() return not self.IsMapBlock and not self.IsFurnitureBlock and not self.IsColliderBlock end -- 设置家具位置 function XHomeFurnitureObj:SetPos(x, y, rotate) self.GridX = x self.GridY = y self.RotateAngle = rotate if XTool.UObjIsNil(self.Transform) then return end if self.Cfg == nil then return end if self.PlaceType == XFurniturePlaceType.Ground or self.PlaceType == XFurniturePlaceType.Wall or self.PlaceType == XFurniturePlaceType.Ceiling then --地板、墙、天花板为固定 self.GridX = 0 self.GridY = 0 self.RotateAngle = 0 elseif self.PlaceType == XFurniturePlaceType.OnWall then -- 摆放在墙上的家具 local platCfgId = self.Room:GetPlatId(CS.XHomePlatType.Wall) -- 检测是否有家具阻挡 self.IsFurnitureBlock = XHomeDormManager.CheckRoomFurnitureBlock(self.Room.Data.Id, self.Data.Id, self.GridX, self.GridY, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Wall, self.RotateAngle) -- 检测地表是否有障碍阻挡 local isBlock, pos = XHomeDormManager.CheckMultiBlock(platCfgId, self.GridX, self.GridY, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Wall, self.RotateAngle) -- 合并两种阻挡 self.IsMapBlock = isBlock pos = self.Room.Transform.localToWorldMatrix:MultiplyPoint(pos) self.Transform.position = pos self.Transform.localEulerAngles = Vector3(0, self.RotateAngle * 90, 0) elseif self.PlaceType == XFurniturePlaceType.OnGround then --摆放在地板上家具 if self.Cfg.LocateType ~= XFurnitureConfigs.HomeLocateType.Replace then if self.Cfg.Model == TEST_FURNITURE_NAME then -- Test local scale = self.Transform.localScale self.Transform.localScale = Vector3(self.Cfg.Width, scale.y, self.Cfg.Height) end end local platCfgId = self.Room:GetPlatId(CS.XHomePlatType.Ground) -- 检测是否有家具阻挡 self.IsFurnitureBlock = XHomeDormManager.CheckRoomFurnitureBlock(self.Room.Data.Id, self.Data.Id, self.GridX, self.GridY, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Ground, self.RotateAngle) -- 检测地表是否有障碍阻挡 local isBlock, pos = XHomeDormManager.CheckMultiBlock(platCfgId, self.GridX, self.GridY, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Ground, self.RotateAngle) -- 合并两种阻挡 self.IsMapBlock = isBlock pos = self.Room.Transform.localToWorldMatrix:MultiplyPoint(pos) self.Transform.position = pos self.Transform.localEulerAngles = Vector3(0, self.RotateAngle * 90, 0) end self.IsColliderBlock = XHomeDormManager.CheckRoomFurnitureCollider(self, self.Room.Data.Id) self:ShowSelectGrid() end -- 生成家具交互信息 function XHomeFurnitureObj:GenerateInteractInfo(roomMap) if not roomMap then return end self.InteractInfoList = {} local sumIndex = self.Cfg.InteractPos or 0 for k=1, sumIndex do local stayPoint = self.GameObject:FindGameObject("StayPos" .. tostring(k)) local interactPoint = self.GameObject:FindGameObject("Interactpos" .. tostring(k)) if interactPoint == nil then if XMain.IsEditorDebug then XLog.Error(string.format("%s 缺少交互点%s号", self.Cfg.Name, k)) end break end local gridPos, isValid = self:GetInteractGridPos(interactPoint.transform) local block = roomMap:GetGridInfo(gridPos.x, gridPos.y) local blockMask = CS.XRoomMapInfo.GetMapGridMask(block, CS.XRoomBlockType.Blocked, CS.XRoomBlockType.Furniture) local info = {} info.Index = k info.GridPos = gridPos if isValid and (blockMask <= 0) then info.UsedType = XFurnitureInteractUsedType.None else info.UsedType = XFurnitureInteractUsedType.Block if XMain.IsEditorDebug then -- XLog.Error(string.format("家具(%s)的%s号交互点被遮挡,网格坐标:%s,%s (仅作提示不卡流程)", self.Cfg.Name, k, gridPos.x, gridPos.y)) end end if not XTool.UObjIsNil(stayPoint) then local stayPos = stayPoint.transform.position local stayIsInBound = XHomeDormManager.WorldPosCheckIsInBound(stayPos, self.Room.Transform) if stayIsInBound then info.StayType = XFurnitureInteractUsedType.None else info.StayType = XFurnitureInteractUsedType.Block end end info.StayPos = stayPoint info.InteractPos = interactPoint info.PosIndex = k info.BehaviorType = self.Cfg.BehaviorType[k] or self.Cfg.BehaviorType[1]-- 标记互动点序号以分别不同角色在不同点的互动 info.AttractBehaviorType = self.Cfg.AttractBehaviorType[k] or self.Cfg.AttractBehaviorType[1]-- 标记互动点序号以分别不同角色在不同点的互动 table.insert(self.InteractInfoList, info) end return self.InteractInfoList end function XHomeFurnitureObj:GetInteractGridPos(transform) local isValid = true local gridPos = XHomeDormManager.GetGridPosByWorldPos(transform.position, transform, 0, 0) if gridPos.x > XHomeDormManager.GetMapWidth() or gridPos.y > XHomeDormManager.GetMapHeight() or gridPos.x < 0 or gridPos.y < 0 then isValid = false XLog.Error("交互位置信息无效,不在地图绑定范围内") end return gridPos, isValid end -- 获取家具交互点信息 function XHomeFurnitureObj:GetInteractInfoList() if not self.InteractInfoList or _G.next(self.InteractInfoList) == nil then local roomMap = CS.XRoomMapInfo.GenerateMap(self.CfgId) self:GenerateInteractInfo(roomMap) end return self.InteractInfoList end -- 设置家具交互点信息 function XHomeFurnitureObj:SetInteractInfoGo() if self.IsSetInterGo then if _G.next(self.InterGos) then for _, v in pairs(self.InterGos) do if v then v.gameObject:SetActive(true) end end return end end local intergo = self.Room.FurnitureRoot.gameObject:FindGameObject("InterPosIcon") if not intergo then return end local infos = self:GetInteractInfoList() for k, v in pairs(infos) do local itemobj = CS.UnityEngine.Object.Instantiate(intergo, v.InteractPos.transform) itemobj.transform.localPosition = Vector3(0, 0.1, 0) itemobj.transform.localRotation = CS.UnityEngine.Quaternion.Euler(90, 0, 0) itemobj.gameObject:SetActive(true) self.InterGos[k] = itemobj end self.IsSetInterGo = true end function XHomeFurnitureObj:HideInteractInfoGo() if self.IsSetInterGo and self.InterGos then for _, v in pairs(self.InterGos) do if v then v.gameObject:SetActive(false) end end end end function XHomeFurnitureObj:GetInteractInfoGo() return self.InterGos end -- 获取最近家具交互点信息 function XHomeFurnitureObj:GetNearAvailableInteract(position, characterId) local interactInfo = nil local lastDistance = 0 for _, info in ipairs(self.InteractInfoList) do local haveBehavior = false local relation = XDormConfig.GetDormF2CBehaviorRelative(self.Cfg.Id, characterId, info.PosIndex) if relation then haveBehavior = true else if info.UsedType == XFurnitureInteractUsedType.None or info.UsedType == XFurnitureInteractUsedType.Block and XDormConfig.GetCharacterBehavior(characterId, info.AttractBehaviorType) then haveBehavior = true end end if haveBehavior then local distance = Vector3.Distance(position, info.StayPos.transform.position) if lastDistance <= 0 or distance < lastDistance then interactInfo = info lastDistance = distance end end end return interactInfo end -- 获取家具交互点信息 function XHomeFurnitureObj:GetAvailableInteract(characterId) for _, info in ipairs(self.InteractInfoList) do local relation = XDormConfig.GetDormF2CBehaviorRelative(self.Cfg.Id, characterId, info.PosIndex) if relation then return info end if info.UsedType == XFurnitureInteractUsedType.None or info.UsedType == XFurnitureInteractUsedType.Block then if info.StayType and info.StayType ~= XFurnitureInteractUsedType.Block and XDormConfig.GetCharacterBehavior(characterId, info.BehaviorType) then return info end end end return nil end -- 通过构造体ID获取交互中的家具交互点信息 function XHomeFurnitureObj:GetInteractById(characterId) if not self.InteractInfoList then return nil end for _, v in ipairs(self.InteractInfoList) do if (v.UsedType & XFurnitureInteractUsedType.Character) > 0 and characterId == v.CharacterId then return v end end return nil end --=================== -- 检测交互点是否能交互 -- @param gridX:要检测的网格位置X坐标 -- @param gridY:要检测的网格位置Y坐标 -- @param charId:角色ID --=================== function XHomeFurnitureObj:CheckCanInteract(gridX, gridY, charId) for _, info in ipairs(self.InteractInfoList) do local haveBehavior = false local relation = XDormConfig.GetDormF2CBehaviorRelative(self.Cfg.Id, charId, info.PosIndex) if relation then haveBehavior = true else local state = XDormConfig.GetCharacterBehavior(charId, info.BehaviorType) haveBehavior = state ~= nil end if haveBehavior and info.GridPos.x == gridX and info.GridPos.y == gridY then return info.UsedType == XFurnitureInteractUsedType.None end end return false end -- 获取交互点 function XHomeFurnitureObj:GetInteract(gridX, gridY) for _, info in ipairs(self.InteractInfoList) do if info.GridPos.x == gridX and info.GridPos.y == gridY then return info end end return nil end -- 显示占位网格 function XHomeFurnitureObj:ShowFixGrid(isShow, rotate) if not isShow then if not XTool.UObjIsNil(self.WallFixGridComponents) then self.WallFixGridComponents.gameObject:SetActive(false) end if not XTool.UObjIsNil(self.GroundFixGridComponent) then self.GroundFixGridComponent.gameObject:SetActive(false) end return end if not self.PlaceType or self.PlaceType == XFurniturePlaceType.Ceiling or self.PlaceType == XFurniturePlaceType.OnGround or self.PlaceType == XFurniturePlaceType.OnWall then return end if self.PlaceType == XFurniturePlaceType.Ground then local w = XHomeDormManager.GetMapWidth() local h = XHomeDormManager.GetMapHeight() if XTool.UObjIsNil(self.GroundFixGridComponent) then self.GroundFixGridComponent = CS.XGridManager.Instance:GetGrid(h, w, false, XHomeDormManager.GetCeilSize()) local fixtransform = self.GroundFixGridComponent.transform fixtransform.eulerAngles = self.Transform.eulerAngles fixtransform.position = self.Transform.position + Vector3(0, self.GridOffset, 0) end self.GroundFixGridComponent.gameObject:SetActive(true) local so = XHomeDormManager.GetGridColorSO(GridColorType.Default) self.GroundFixGridComponent:SetGridColorInfo(so.Asset) elseif self.PlaceType == XFurniturePlaceType.Wall then if not rotate then return end local mapWidth, mapHeight local rot = rotate % 2 if rot == 0 then mapWidth = XHomeDormManager.GetMapWidth() mapHeight = XHomeDormManager.GetMapTall() else mapWidth = XHomeDormManager.GetMapHeight() mapHeight = XHomeDormManager.GetMapTall() end if XTool.UObjIsNil(self.WallFixGridComponents) then self.WallFixGridComponents = CS.XGridManager.Instance:GetGrid(mapHeight, mapWidth, true, XHomeDormManager.GetCeilSize()) end local fixtransform = self.WallFixGridComponents.transform local offset = self.OnWallFixGridPos[rotate] fixtransform.position = self.Transform.position + offset fixtransform.eulerAngles = self.Transform.eulerAngles + Vector3(0, 90 * rotate, 0) self.WallFixGridComponents.gameObject:SetActive(true) local so = XHomeDormManager.GetGridColorSO(GridColorType.Default) self.WallFixGridComponents:SetGridColorInfo(so.Asset) end end -- 显示选中网格 function XHomeFurnitureObj:ShowSelectGrid() if self.IsSelected and not self.IsAddDragComponent then if not self.Cfg.HasBehavior then self.GoInputHandler:AddDragListener(function(eventData) self:OnDrag(eventData) end) end self.IsAddDragComponent = true end if not self.IsSelected and self.IsAddDragComponent then if not self.Cfg.HasBehavior then self.GoInputHandler:RemoveDragListener() end self.IsAddDragComponent = false end local isBlock = not self:CheckCanLocate() if not self.IsSelected then if not XTool.UObjIsNil(self.GridComponent) then self.GridComponent.gameObject:SetActive(false) end if not XTool.UObjIsNil(self.FurniturePlaceHolder) then self.FurniturePlaceHolder.gameObject:SetActive(false) end return end if not self.PlaceType then return end if self.PlaceType == XFurniturePlaceType.OnGround then local rot = self.RotateAngle % 2 local w, h if rot == 0 then w = self.Cfg.Width h = self.Cfg.Height else w = self.Cfg.Height h = self.Cfg.Width end local left = self.GridX local right = XHomeDormManager.GetMapWidth() - self.GridX - w local up = XHomeDormManager.GetMapHeight() - self.GridY - h local down = self.GridY if left < 0 then left = 0 end if right < 0 then right = 0 end if up < 0 then up = 0 end if down < 0 then down = 0 end if XTool.UObjIsNil(self.GridComponent) then self.GridComponent = CS.XGridManager.Instance:GetCrossGrid(h, w, left, right, up, down, false, XHomeDormManager.GetCeilSize()) self.GridComponent.gameObject.name = "GridComponent" self.GridComponent.transform.localEulerAngles = Vector3.zero self.GridComponent.transform.localScale = Vector3.one else self.GridComponent.gameObject:SetActive(true) self.GridComponent:GenerateCrossGrid(h, w, left, right, up, down, false, XHomeDormManager.GetCeilSize()) end local so if isBlock then so = XHomeDormManager.GetGridColorSO(GridColorType.Red) else so = XHomeDormManager.GetGridColorSO(GridColorType.Blue) end self.GridComponent:SetGridColorInfo(so.Asset) self.GridComponent.transform.position = self.Transform.position + Vector3(0, self.GridOffset, 0) elseif self.PlaceType == XFurniturePlaceType.OnWall then local w = self.Cfg.Width local h = self.Cfg.Height local mapWidth, mapHeight local rot = self.RotateAngle % 2 if rot == 0 then mapWidth = XHomeDormManager.GetMapWidth() mapHeight = XHomeDormManager.GetMapTall() else mapWidth = XHomeDormManager.GetMapHeight() mapHeight = XHomeDormManager.GetMapTall() end local left = self.GridX local right = mapWidth - self.GridX - w local up = mapHeight - self.GridY - h local down = self.GridY if left < 0 then left = 0 end if right < 0 then right = 0 end if up < 0 then up = 0 end if down < 0 then down = 0 end if XTool.UObjIsNil(self.GridComponent) then self.GridComponent = CS.XGridManager.Instance:GetCrossGrid(h, w, left, right, up, down, true, XHomeDormManager.GetCeilSize()) self.GridComponent.gameObject.name = "GridComponent" self.GridComponent.transform.localEulerAngles = Vector3.zero self.GridComponent.transform.localScale = Vector3.one else self.GridComponent.gameObject:SetActive(true) self.GridComponent:GenerateCrossGrid(h, w, left, right, up, down, true, XHomeDormManager.GetCeilSize()) end local offset if self.RotateAngle == 0 then offset = Vector3(0, 0, -0.01 - self.GridOffset) elseif self.RotateAngle == 1 then offset = Vector3(-0.01 - self.GridOffset, 0, 0) elseif self.RotateAngle == 2 then offset = Vector3(0, 0, 0.01 + self.GridOffset) elseif self.RotateAngle == 3 then offset = Vector3(0.01 + self.GridOffset, 0, 0) end self.GridComponent.transform.position = self.Transform.position + Vector3(0, 0.5 * h * XHomeDormManager.GetCeilSize(), 0) + offset self.GridComponent.transform.eulerAngles = self.Transform.eulerAngles local so if isBlock then so = XHomeDormManager.GetGridColorSO(GridColorType.Red) else so = XHomeDormManager.GetGridColorSO(GridColorType.Blue) end self.GridComponent:SetGridColorInfo(so.Asset) end end -- 获取家具位置 function XHomeFurnitureObj:GetPos() return self.GridX, self.GridY, self.RotateAngle end -- 恢复家具位置 function XHomeFurnitureObj:RevertPosition() self.IsSelected = false self:SetPos(self.ConfirmGridX, self.ConfirmGridY, self.ConfirmRotate) end -- 收纳家具 function XHomeFurnitureObj:Storage(isMulti) self.IsSelected = false self.InteractInfoList = {} self:RippleClearChar() self.GameObject:SetActive(false) if not XTool.UObjIsNil(self.GridComponent) then CS.XGridManager.Instance:FreeGrid(self.GridComponent) end self.GridComponent = nil if not isMulti then XHomeDormManager.RemoveFurniture(self.Room.Data.Id, self) end CsXGameEventManager.Instance:Notify(XEventId.EVENT_FURNITURE_ONDRAGITEM_CHANGED, true, self.Data.Id) self:Dispose() self:HideInteractInfoGo() end -- 检测类型数量限制 function XHomeFurnitureObj:CheckPutTypeCountReachLimit() return XHomeDormManager.CheckFurnitureCountReachLimit(self.Room.Data.Id, self) end -- 确定放置家具 function XHomeFurnitureObj:LocateFurniture() self.ConfirmGridX = self.GridX self.ConfirmGridY = self.GridY self.ConfirmRotate = self.RotateAngle self.IsSelected = false self:ShowSelectGrid() XHomeDormManager.AddFurniture(self.Room.Data.Id, self) self:ShowAttrTag() CsXGameEventManager.Instance:Notify(XEventId.EVENT_FURNITURE_ONDRAGITEM_CHANGED, false, self.Data.Id) end function XHomeFurnitureObj:CancelSelect() --TODO self:ShowSelectGrid() end -- 点击家具 function XHomeFurnitureObj:OnClick(eventData) if self.PlaceType == XFurniturePlaceType.Ground or self.PlaceType == XFurniturePlaceType.Wall or self.PlaceType == XFurniturePlaceType.Ceiling then return end if self.IsDrag then self.IsDrag = false return end if XHomeDormManager.CheckSelectedFurniture() then return end if not XDataCenter.FurnitureManager.GetInRefeform() then if not self:CheckCanBehavior() then self:PlayClickAnimation() else self:OnBehaviorClick(eventData) end end CsXGameEventManager.Instance:Notify(XEventId.EVENT_CLICKFURNITURE_ONROOM, self.Data.Id) XHomeDormManager.FireClickFurnitureCallback(self) self:ShowSelectGrid() end -- 拖动家具 function XHomeFurnitureObj:OnDrag(eventData) if self.PlaceType == XFurniturePlaceType.Ground or self.PlaceType == XFurniturePlaceType.Wall or self.PlaceType == XFurniturePlaceType.Ceiling then return end if not XDataCenter.FurnitureManager.GetInRefeform() then self:OnBehaviorDrag(eventData) return false end if not self.IsSelected then return false end self.IsDrag = true local pos = eventData.position return self:AdjustPosition(pos) end function XHomeFurnitureObj:GetCenterPosition() if self.CenterObj then return self.CenterObj.position else self.CenterObj = self.Transform:Find("CenterPos") if self.CenterObj then return self.CenterObj.position else return self.Transform.position end end end -- 调整家具位置 function XHomeFurnitureObj:AdjustPosition(screenPos) if self.Cfg == nil then return false end local camera = XHomeSceneManager.GetSceneCamera() if XTool.UObjIsNil(camera) then return false end local ray = camera:ScreenPointToRay(Vector3(screenPos.x, screenPos.y, 0)) local layerMask = CS.UnityEngine.LayerMask.GetMask("HomeSurface") if (layerMask) then local ret, hit = ray:RayCast(layerMask) if ret then local width = self.Cfg.Width local height = self.Cfg.Height if self.PlaceType == XFurniturePlaceType.OnGround then local rot = self.RotateAngle % 2 if rot == 1 then width = self.Cfg.Height height = self.Cfg.Width end end local gridPos = XHomeDormManager.GetGridPosByWorldPos(hit.point, hit.transform, width, height) self:SetPos(gridPos.x, gridPos.y, self.RotateAngle) end end self:SetInteractInfoGo() return true end -- 播放家具交互动画 function XHomeFurnitureObj:PlayInteractAnimation(characterId) if not characterId then return end local animationName = XFurnitureConfigs.GetDormFurnitureAnimationByCharId(self.Data.CfgId, characterId) if not animationName then return end self.Animator:Play(animationName) end -- 播放家具点击动画 function XHomeFurnitureObj:PlayClickAnimation() local animationType = XFurnitureConfigs.GetOnceAnimationType(self.Data.CfgId) if animationType == XFurnitureConfigs.FurnitureAnimationType.None then return end local animationName = XFurnitureConfigs.GetOnceAnimationName(self.Data.CfgId) if not animationName then return end -- 判断是否在和构造体交互 for _, v in ipairs(self.InteractInfoList) do if (v.UsedType & XFurnitureInteractUsedType.Character) > 0 then return end end if animationType == XFurnitureConfigs.FurnitureAnimationType.Once then self.Animator:Play(animationName) elseif animationType == XFurnitureConfigs.FurnitureAnimationType.Repeat then if self.AninationIndex >= #animationName then self.AninationIndex = 0 end self.AninationIndex = self.AninationIndex + 1 self.Animator:Play(animationName[self.AninationIndex]) end end -- 检测家具碰撞 function XHomeFurnitureObj:CheckFurnitureCollision(x, y, width, height, type, rotate) local homePlatType = XFurnitureConfigs.LocateTypeToXHomePlatType(self.Cfg.LocateType) -- 1.不同地表的物体,永不相交 if homePlatType ~= type then return false end -- 2.墙上 if type == CS.XHomePlatType.Wall then if rotate ~= self.ConfirmRotate then -- 2.1不在同一面墙,永不相交 return false end -- 2.2检测两个正矩形碰撞 local deltaX = x - self.ConfirmGridX local deltaY = y - self.ConfirmGridY if (deltaX > 0 and deltaX >= self.Cfg.Width) or (deltaX < 0 and deltaX <= -width) or (deltaY > 0 and deltaY >= self.Cfg.Height) or (deltaY < 0 and deltaY <= -height) then return false end end -- 3.地板上 if type == CS.XHomePlatType.Ground then local deltaX = x - self.ConfirmGridX local deltaY = y - self.ConfirmGridY local rot1 = self.ConfirmRotate % 2 local w1, h1 if rot1 == 0 then w1 = self.Cfg.Width h1 = self.Cfg.Height else w1 = self.Cfg.Height h1 = self.Cfg.Width end local rot2 = rotate % 2 local w2, h2 if rot2 == 0 then w2 = width h2 = height else w2 = height h2 = width end -- 3.1旋转后,检测正矩形碰撞 if (deltaX > 0 and deltaX >= w1) or (deltaX < 0 and deltaX <= -w2) or (deltaY > 0 and deltaY >= h1) or (deltaY < 0 and deltaY <= -h2) then return false end end return true end function XHomeFurnitureObj:RayCastSelected(isSelect) if self.IsShowGlow == isSelect then return end if isSelect then CS.XMaterialContainerHelper.AddRoomRim(self.GameObject) else CS.XMaterialContainerHelper.RemoveRoomRim(self.GameObject) end self.IsShowGlow = isSelect end function XHomeFurnitureObj:ShowAttrTag(attrIndex) if not attrIndex then attrIndex = XHomeDormManager.FurnitureShowAttrType end if attrIndex > 0 then local furnitureData = XDataCenter.FurnitureManager.GetFurnitureById(self.Data.Id) local furnitureType = XDataCenter.FurnitureManager.GetFurnitureConfigByUniqueId(self.Data.Id).TypeId local attrValue local quality local max if attrIndex == XFurnitureConfigs.AttrType.AttrAll then attrValue = furnitureData:GetScore() quality, max = XFurnitureConfigs.GetFurnitureTotalAttrLevel(furnitureType, attrValue) else attrValue = furnitureData:GeAttrtScore(attrIndex, furnitureData.AttrList[attrIndex]) quality, max = XFurnitureConfigs.GetFurnitureSingleAttrLevel(furnitureType, attrIndex, attrValue) end local offset = self.Cfg.AttrTagY local color = XFurnitureConfigs.FurnitureAttrTagColor[quality] or XFurnitureConfigs.FurnitureAttrTagColor[1] local level = XFurnitureConfigs.FurnitureAttrLevel[quality] or XFurnitureConfigs.FurnitureAttrLevel[1] local desc = string.format("%s%d", color, level, attrValue) CsXGameEventManager.Instance:Notify(XEventId.EVENT_DORM_FURNITURE_ATTR_TAG_DETAIL, self.Room.Data.Id, self.Data.Id, self.Transform, desc, attrValue / max, color, offset) else CsXGameEventManager.Instance:Notify(XEventId.EVENT_DORM_FURNITURE_HIDE_ATTR_TAG_DETAIL, self.Data.Id) end end function XHomeFurnitureObj:HideAttrTag() CsXGameEventManager.Instance:Notify(XEventId.EVENT_DORM_FURNITURE_HIDE_ATTR_TAG_DETAIL, self.Data.Id) end function XHomeFurnitureObj:OnStateChange(state) if state == "Enter" then self:ShowAttrTag() self:ShowFurnitureEffect() self:EnableBoxColliders() else self:HideAttrTag() self:HideFurnitureEffect() self:DisableBoxColliders() end end function XHomeFurnitureObj:ShowFurnitureEffect() if self.EffectComp and self.EffectComp.GameObject then self.EffectComp.GameObject:SetActiveEx(true) end end function XHomeFurnitureObj:HideFurnitureEffect() if self.EffectComp and self.EffectComp.GameObject then self.EffectComp.GameObject:SetActiveEx(false) end end function XHomeFurnitureObj:EnableBoxColliders() for _, v in pairs(self.Colliders or {}) do v.enabled = true end end function XHomeFurnitureObj:DisableBoxColliders() for _, v in pairs(self.Colliders or {}) do v.enabled = false end end -------------------------------家具行为树相关(Start)---------------------------- -- 家具变换位置 function XHomeFurnitureObj:ChangeFurnituePositionNode() if not self.CanChange then return false end -- 处理直接收纳逻辑 if not self.ChangeFurnitureData then self.GameObject.transform.localScale = Vector3.one self:Storage() self.CanChange = false return true end local x = self.ChangeFurnitureData.X local y = self.ChangeFurnitureData.Y local rotate = self.ChangeFurnitureData.R self:SetPos(x, y, rotate) self.ConfirmGridX = x self.ConfirmGridY = y self.ConfirmRotate = rotate self.GameObject.transform.localScale = Vector3.one self.ChangeFurnitureData = nil self.CanChange = false return true end -- 播放动作 function XHomeFurnitureObj:DoActionNode(actionId, needFadeCross, crossDuration) if (needFadeCross) then self.Animator:CrossFade(actionId, crossDuration, -1, 0) else self.Animator:Play(actionId, -1, 0) end end -- 播放特效 function XHomeFurnitureObj:DoEffectNode(effectId) local effectConfig = XDormConfig.GetMoodEffectConfig(effectId) self.EffectObj = self.Transform:LoadPrefab(effectConfig.Path, false) self.EffectObj.transform:SetParent(self.Transform, false) local position = CS.UnityEngine.Vector3(0, effectConfig.Hight, 0) self.EffectObj.transform.localPosition = position end -- 隐藏家具 function XHomeFurnitureObj:HideFurnitureNode() self.GameObject.transform.localScale = Vector3.zero end -- 还原家具位置 function XHomeFurnitureObj:ResetFurnituePistionNode() self:SetPos(self.ConfirmGridX, self.ConfirmGridY, self.ConfirmRotate) end -- 检测是否在家具上方 function XHomeFurnitureObj:CheckRayCastFurnitureNode() return self.IsRayCastFurniture end -- 保存家具变更所在房间 function XHomeFurnitureObj:SaveFurnitureInRoomNode() local isBehavior = true XHomeDormManager.SaveRoomModification(self.Room.Data.Id, isBehavior, function(isSuccess) CsXGameEventManager.Instance:Notify(XEventId.EVENT_DORM_FURNITURE_PUT_SUCCESS, self.Data.Id, isSuccess) end) end -- 设置位置交换数据 function XHomeFurnitureObj:SetChangeFurnitureData(furniture) if not furniture then self.ChangeFurnitureData = nil return end self.ChangeFurnitureData = {} self.ChangeFurnitureData.X = furniture.ConfirmGridX self.ChangeFurnitureData.Y = furniture.ConfirmGridY self.ChangeFurnitureData.R = furniture.ConfirmRotate end -- 隐藏特效 function XHomeFurnitureObj:HideEffect() if not self.EffectObj then return end self.EffectObj:SetActiveEx(false) end --改变状态 function XHomeFurnitureObj:ChangeStatus(state, ignoreReform) if not self:CheckCanBehavior(ignoreReform) then return end if self.Status == state and self.Status ~= XHomeBehaviorStatus.IDLE then return end self:HideEffect() self.Status = state local temp = XFurnitureConfigs.GetFurnitureBehavior(self.Data.CfgId, state) local behaviorTreeId = temp.BehaviorId XLuaBehaviorManager.PlayId(behaviorTreeId, self.Agent) end function XHomeFurnitureObj:CheckCanBehavior(ignoreReform) if XDataCenter.FurnitureManager.GetInRefeform() and not ignoreReform then return end if self.Room.Data.RoomDataType ~= XDormConfig.DormDataType.Self then return false end if not self.Cfg.HasBehavior then return false end return true end -- 家具侧面面对相机 function XHomeFurnitureObj:SidewaysSceneCamera() local currentCamera = XHomeSceneManager.GetSceneCamera() local direction = currentCamera.transform.position - self.Transform.position local Direct = CS.UnityEngine.Vector3(direction.z, 0, -direction.x); self.Transform.rotation = CS.UnityEngine.Quaternion.LookRotation(Direct, CS.UnityEngine.Vector3.up); end --长按 function XHomeFurnitureObj:OnPress(pressTime) if not self:CheckCanBehavior() then return end if self.Status ~= XHomeBehaviorStatus.GRAB_UP then if not self.IsPressing then XEventManager.DispatchEvent(XEventId.EVENT_CHARACTER_PUT_ON, self.Data.CfgId, self.Transform, false) self.IsPressing = true elseif pressTime >= self.DormPutOnAnimaTime then self.GameObject:SetLayerRecursively(CS.UnityEngine.LayerMask.NameToLayer(HomeSceneLayerMask.HomeCharacter)) self:SidewaysSceneCamera() self.OrignalPosition = self.Transform.position self.Transform.position = CS.UnityEngine.Vector3(self.OrignalPosition.x, self.OrignalPosition.y + PutOnOffeY, self.OrignalPosition.z) self:ChangeStatus(XHomeBehaviorStatus.GRAB_UP) XEventManager.DispatchEvent(XEventId.EVENT_CHARACTER_CATCH) self.IsPressing = false end end end --手指退出 function XHomeFurnitureObj:OnPointerExit() if not self:CheckCanBehavior() then return end if self.IsPressing then XEventManager.DispatchEvent(XEventId.EVENT_CHARACTER_EXIT) self.IsPressing = false end end --点击 function XHomeFurnitureObj:OnBehaviorClick() -- 家具行为点击预留接口 end function XHomeFurnitureObj:OnBehaviorDrag(eventData) if not self:CheckCanBehavior() then return end if self.Status ~= XHomeBehaviorStatus.GRAB_UP then return end -- 托起 local currentCamera = XHomeSceneManager.GetSceneCamera() local direction = self.Transform.position - currentCamera.transform.position local z = CS.UnityEngine.Vector3.Dot(direction, currentCamera.transform.forward) local screenPos = CS.UnityEngine.Vector3(eventData.position.x, eventData.position.y, z) local pos = currentCamera:ScreenToWorldPoint(screenPos) local gridPos = XHomeDormManager.WorldPosToGroundGridPos(pos, self.Room.Transform) --判断拖拽越界 if gridPos.x <= 0 or gridPos.y <= 0 or gridPos.x >= XHomeDormManager.GetMapWidth() - 1 or gridPos.y >= XHomeDormManager.GetMapHeight() - 1 then return end self.Transform.position = CS.UnityEngine.Vector3(pos.x, self.OrignalPosition.y + PutOnOffeY, pos.z) --判断射线碰到家私 local layerMask = CS.UnityEngine.LayerMask.GetMask("Device") if layerMask then local hit = self.Transform:PhysicsRayCast(CS.UnityEngine.Vector3.up * 100, CS.UnityEngine.Vector3.down, layerMask) if not XTool.UObjIsNil(hit) then local obj = XSceneEntityManager.GetEntity(hit.gameObject) if obj.Data.Id == self.Data.Id then return end if self.PreInteractFurniture ~= nil and (obj == nil or obj.Data.Id ~= self.PreInteractFurniture.Data.Id) then self.PreInteractFurniture:RayCastSelected(false) self.IsRayCastFurniture = false end if obj then local selfPosChangeType = self.Cfg.PosChangeType local targetPosChangeType = obj.Cfg.PosChangeType local typeNoe = XFurnitureConfigs.PosChangeType.None local canChange = targetPosChangeType ~= typeNoe and selfPosChangeType ~= typeNoe if canChange then self.PreInteractFurniture = obj self.PreInteractFurniture:RayCastSelected(true) self.IsRayCastFurniture = true else if self.PreInteractFurniture then self.PreInteractFurniture:RayCastSelected(false) end self.IsRayCastFurniture = false self.PreInteractFurniture = nil end end else if self.PreInteractFurniture ~= nil then self.PreInteractFurniture:RayCastSelected(false) self.PreInteractFurniture = nil self.IsRayCastFurniture = false end end end end --手指松开 function XHomeFurnitureObj:OnPointerUp(eventData) if not self:CheckCanBehavior() then return end if self.Status == XHomeBehaviorStatus.GRAB_UP or self.IsPressing then self.GameObject:SetLayerRecursively(CS.UnityEngine.LayerMask.NameToLayer(HomeSceneLayerMask.Device)) XEventManager.DispatchEvent(XEventId.EVENT_CHARACTER_PUT_DOWN) end if self.Status == XHomeBehaviorStatus.GRAB_UP then if not self.PreInteractFurniture then local canChange, x, y, r = self:CheckCanPudownLocate(eventData) if canChange then self.CanChange = true self.ChangeFurnitureData = {} self.ChangeFurnitureData.X = x self.ChangeFurnitureData.Y = y self.ChangeFurnitureData.R = r self:ChangeStatus(XHomeBehaviorStatus.CHNGEPOS) end CsXGameEventManager.Instance:Notify(XEventId.EVENT_DORM_FURNITURE_POINTER_UP_SUCCESS, self.Data.Id) else self.PreInteractFurniture:RayCastSelected(false) self.IsRayCastFurniture = false self.CanChange = true self.PreInteractFurniture.CanChange = true local selfPosChangeType = self.Cfg.PosChangeType local targetPosChangeType = self.PreInteractFurniture.Cfg.PosChangeType if selfPosChangeType == targetPosChangeType then self.PreInteractFurniture:SetChangeFurnitureData(self) self:SetChangeFurnitureData(self.PreInteractFurniture) else self.PreInteractFurniture:SetChangeFurnitureData(nil) self:SetChangeFurnitureData(self.PreInteractFurniture) end local state = self.PreInteractFurniture.Cfg.FunitureBehaviorType self:ChangeStatus(state) self.PreInteractFurniture:ChangeStatus(state) end end self.PreInteractFurniture = nil if self.IsPressing then self.IsPressing = false end end -- 处理家具放到空位置 function XHomeFurnitureObj:CheckCanPudownLocate(eventData) local currentCamera = XHomeSceneManager.GetSceneCamera() local direction = self.Transform.position - currentCamera.transform.position local z = CS.UnityEngine.Vector3.Dot(direction, currentCamera.transform.forward) local screenPos = CS.UnityEngine.Vector3(eventData.position.x, eventData.position.y, z) local pos = currentCamera:ScreenToWorldPoint(screenPos) local gridPos = XHomeDormManager.WorldPosToGroundGridPos(pos, self.Room.Transform) local x = gridPos.x local y = gridPos.y local r = self.RotateAngle local canChange local isMapBlock = false local isFurnitureBlock = false local isColliderBlock if self.PlaceType == XFurniturePlaceType.OnWall then local platCfgId = self.Room:GetPlatId(CS.XHomePlatType.Wall) isFurnitureBlock = XHomeDormManager.CheckRoomFurnitureBlock(self.Room.Data.Id, self.Data.Id, x, y, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Wall, r) local isBlock = XHomeDormManager.CheckMultiBlock(platCfgId, x, y, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Wall, r) isMapBlock = isBlock elseif self.PlaceType == XFurniturePlaceType.OnGround then local platCfgId = self.Room:GetPlatId(CS.XHomePlatType.Ground) isFurnitureBlock = XHomeDormManager.CheckRoomFurnitureBlock(self.Room.Data.Id, self.Data.Id, x, y, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Ground, r) local isBlock = XHomeDormManager.CheckMultiBlock(platCfgId, x, y, self.Cfg.Width, self.Cfg.Height, CS.XHomePlatType.Ground, r) isMapBlock = isBlock end isColliderBlock = XHomeDormManager.CheckRoomFurnitureCollider(self, self.Room.Data.Id) canChange = not isMapBlock and not isFurnitureBlock and not isColliderBlock return canChange, x, y, r end -------------------------------家具行为树相关(End)---------------------------- return XHomeFurnitureObj