local ThrowGiftsLevelCtrl = class("ThrowGiftsLevelCtrl", BaseCtrl)
local GameResourceLoader = require("Game.Common.Resource.GameResourceLoader")
local ResTypeAny = GameResourceLoader.ResType.Any
local WwiseAudioMgr = CS.WwiseAudioManager.Instance
ThrowGiftsLevelCtrl._mapNodeConfig = {
	Scene = {sComponentName = "Transform"},
	rtScene = {
		sNodeName = "Scene",
		sComponentName = "RectTransform"
	},
	rtGoalRoot = {sComponentName = "Transform"},
	rtObstacleRoot = {sComponentName = "Transform"},
	rtSpecialObstacleRoot = {sComponentName = "Transform"},
	rtBeginning = {
		sComponentName = "RectTransform"
	},
	rttBeginningDrag = {
		sComponentName = "UIDrag",
		callback = "OnDrag_Beginning"
	},
	rtBeginningLine = {
		sComponentName = "RectTransform"
	},
	rtPenguinRoot = {sComponentName = "Transform"},
	BeginningDot = {
		sComponentName = "RectTransform",
		sNodeName = "imgBeginningDot_",
		nCount = 30
	},
	templateBullet = {},
	rtBeginningPos = {
		sComponentName = "RectTransform"
	},
	rtBottle = {
		sComponentName = "RectTransform"
	},
	rtBottleAnim = {sComponentName = "Animator", sNodeName = "rtBottle"},
	BeginningPenguinRoot = {sComponentName = "Animator"},
	rtBlindLevelTrack = {
		sCtrlName = "Game.UI.Activity.ThrowGifts.ThrowGiftLevelTrackLineCtrl"
	},
	rtTemplateTrack = {},
	TMPBeginningCountHint = {sComponentName = "TMP_Text"},
	imgBeginningHint = {},
	rtPenguinBeginningHint = {sComponentName = "Transform"},
	rtPenguinBeginningHintAnim = {
		sNodeName = "rtPenguinBeginningHint",
		sComponentName = "Animator"
	},
	imgInfinite = {},
	penguinRoot = {},
	rtTemplateGuideTrack = {},
	rtDebug = {}
}
ThrowGiftsLevelCtrl._mapEventConfig = {}
ThrowGiftsLevelCtrl._mapRedDotConfig = {}
local rootPath = "UI_Activity/_400005/GoalPerfab/Goal%s.prefab"
function ThrowGiftsLevelCtrl:Awake()
	self.bDebugMode = false
	self.curGiftPenguin = nil
	self.nLevelType = 0
	self.tbObstacle = {}
	self.mapGoal = {}
	self.tbGiftPenguin = {}
	self.sceneSize = {0, 0}
	self.scenePivot = {0, 0}
	self.mapItemPoolConfig = {}
	self.activeGoal = {}
	self.nTotalPenguinCount = -1
	self.curPenguinIdx = 1
	self.curPenguinType = 1
	self.nNextPenguinType = 1
	self.curPenguinSpecialType = 0
	self.nLevelTime = -1
	self.nLevelScore = 0
	self.nTotalThrowGiftCount = 0
	self.nTotalHitGoalCount = 0
	self.nTotalUseItemCount = 0
	self.mapItemUseCount = {}
	self.bProcessing = false
	self.mapExObstacleOrigin = {}
	self.tbExObstacleCur = {}
	self.bFlying = false
	self.nFlyingTime = 0
	self.maxVelocity = 1200
	self.minVelovity = 400
	self.nLinePointInterval = 0.05
	self.nGoalSpeed = 100
	self.nAngelMax = 90
	self.nAngleMin = -30
	self.nAG = 500
	self.nNavigationPenguinSpeed = 600
	self.nCurActiveItem = 0
	self.mapCurActiveState = {}
	self.tbItemTrackCtrl = {}
	self.tbGuideTrackCtrl = {}
	self.curDragBeginPos = nil
	self.dragState = false
	self._mapNode.rtBeginningLine.gameObject:SetActive(false)
	self._mapNode.templateBullet.gameObject:SetActive(false)
	self._mapNode.imgBeginningHint:SetActive(false)
	local forEachItemPool = function(mapData)
		if self.mapItemPoolConfig[mapData.PoolId] == nil then
			self.mapItemPoolConfig[mapData.PoolId] = {}
		end
		table.insert(self.mapItemPoolConfig[mapData.PoolId], {
			nItemId = mapData.ItemId,
			Weight = mapData.Weight
		})
	end
	ForEachTableLine(DataTable.ThrowGiftItemPool, forEachItemPool)
end
function ThrowGiftsLevelCtrl:FadeIn()
end
function ThrowGiftsLevelCtrl:FadeOut()
end
function ThrowGiftsLevelCtrl:OnEnable()
	EventManager.Hit("ThrowGiftSetSpeacialFunc", self)
	self._mapNode.BeginningPenguinRoot.gameObject:SetActive(false)
	self._mapNode.penguinRoot:SetActive(false)
	self._mapNode.rtBottleAnim:Play("rtBottle_Empty")
end
function ThrowGiftsLevelCtrl:OnDisable()
	self:ClearTrackLine()
	if self.tbGuideTrackCtrl ~= nil and #self.tbGuideTrackCtrl ~= 0 then
		self:ClearGuideLine()
	end
end
function ThrowGiftsLevelCtrl:OnDestroy()
end
function ThrowGiftsLevelCtrl:OnRelease()
end
function ThrowGiftsLevelCtrl:ClearTrackLine()
	for _, mapCtrl in ipairs(self.tbItemTrackCtrl) do
		mapCtrl:DestroyAll()
		self:UnbindCtrlByNode(mapCtrl)
	end
	self._mapNode.rtBlindLevelTrack:DestroyAll()
	self.tbItemTrackCtrl = {}
end
function ThrowGiftsLevelCtrl:ClearGuideLine()
	for _, mapCtrl in ipairs(self.tbGuideTrackCtrl) do
		mapCtrl:DestroyAll()
		self:UnbindCtrlByNode(mapCtrl)
	end
	self.tbGuideTrackCtrl = {}
end
function ThrowGiftsLevelCtrl:SetLevel(parent, nLevelId, mapActData)
	self.nLevelScore = 0
	self.parent = parent
	self.actData = mapActData
	self.nLevelId = nLevelId
	self.mapItemUseCount = {}
	local mapLevelCfgData = ConfigTable.GetData("ThrowGiftLevel", nLevelId)
	if mapLevelCfgData == nil then
		return
	end
	self.mapLevelCfgData = mapLevelCfgData
	local mapFloorCfgData = ConfigTable.GetData("ThrowGiftFloor", self.mapLevelCfgData.FloorId)
	if mapFloorCfgData == nil then
		return
	end
	self.maxVelocity = mapFloorCfgData.SpeedMax
	self.minVelovity = mapFloorCfgData.SpeedMin
	self.nAngleMin = mapFloorCfgData.AngelMin
	self.nAG = mapFloorCfgData.Gravity
	if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
		self._mapNode.rtBlindLevelTrack.gameObject:SetActive(true)
	end
	self.mapFloorCfgData = mapFloorCfgData
	self.nTotalPenguinCount = self.mapFloorCfgData.GiftNum
	if self.nTotalPenguinCount == 0 then
		self.nTotalPenguinCount = -1
	end
	self.nLevelTime = self.mapLevelCfgData.CountDownLimit
	if self.nLevelTime == 0 then
		self.nLevelTime = -1
	end
	self.curPenguinIdx = 1
	self.sceneSize = {
		self._mapNode.Scene.rect.width,
		self._mapNode.Scene.rect.height
	}
	self.scenePivot = {
		self._mapNode.Scene.pivot.x,
		self._mapNode.Scene.pivot.y
	}
	local rtView = self.gameObject:GetComponent("RectTransform")
	self.viewSize = {0, 0}
	if rtView ~= nil then
		self.viewSize = {
			rtView.rect.width,
			rtView.rect.height
		}
	end
	self._mapNode.rtDebug:SetActive(self.bDebugMode)
	local nChildCount = self._mapNode.rtObstacleRoot.childCount
	for i = 0, nChildCount - 1 do
		local goObstacle = self._mapNode.rtObstacleRoot:GetChild(i)
		if goObstacle ~= nil then
			local rtObstacle = goObstacle:GetComponent("RectTransform")
			if rtObstacle ~= nil then
				local tbBounds = self:GetLocalSpaceRect(rtObstacle, rtObstacle.parent)
				table.insert(self.tbObstacle, tbBounds)
				print(tbBounds[1] .. " " .. tbBounds[2] .. " " .. tbBounds[3] .. " " .. tbBounds[4] .. " ")
			end
		end
	end
	local nChildCount = self._mapNode.rtSpecialObstacleRoot.childCount
	for i = 0, nChildCount - 1 do
		local goObstacle = self._mapNode.rtSpecialObstacleRoot:GetChild(i)
		if goObstacle ~= nil then
			local rtObstacle = goObstacle:GetComponent("RectTransform")
			if rtObstacle ~= nil then
				local sName = rtObstacle.gameObject.name
				local nId = tonumber(sName)
				if nId == nil then
					printError("Special obstacl name error!" .. sName)
				else
					local mapExObstacleCfgData = ConfigTable.GetData("ThrowGiftSpecialObstacle", nId)
					if mapExObstacleCfgData ~= nil then
						local nInstanceId = rtObstacle.gameObject:GetInstanceID()
						self.mapExObstacleOrigin[nInstanceId] = {}
						local tbBounds = self:GetLocalSpaceRect(rtObstacle, rtObstacle.parent)
						self.mapExObstacleOrigin[nInstanceId].tbBounds = tbBounds
						self.mapExObstacleOrigin[nInstanceId].mapConfig = mapExObstacleCfgData
						self.mapExObstacleOrigin[nInstanceId].gameObject = rtObstacle.gameObject
						table.insert(self.tbExObstacleCur, nInstanceId)
						print(tbBounds[1] .. " " .. tbBounds[2] .. " " .. tbBounds[3] .. " " .. tbBounds[4] .. " ")
					end
				end
			end
		end
	end
	local nGoalSpawnpointCount = self._mapNode.rtGoalRoot.childCount
	for i = 0, nGoalSpawnpointCount - 1 do
		local goGoalSpawnpoint = self._mapNode.rtGoalRoot:GetChild(i)
		if goGoalSpawnpoint ~= nil then
			local sName = goGoalSpawnpoint.gameObject.name
			local nId = tonumber(sName)
			if nId == nil then
				printError("配置错误 无法转换为ID:" .. sName)
			else
				local mapSpConfig = ConfigTable.GetData("ThrowGiftSpawnPoints", nId)
				if mapSpConfig ~= nil then
					self.mapGoal[nId] = {}
					self.mapGoal[nId].rtPoint = goGoalSpawnpoint
					self.mapGoal[nId].mapConfig = mapSpConfig
					self.mapGoal[nId].tbExtractedItems = {}
					local nItemPoolId = mapSpConfig.ItemPool
					self.mapGoal[nId].tbOrginPool = self.mapItemPoolConfig[nItemPoolId] == nil and {} or clone(self.mapItemPoolConfig[nItemPoolId])
					self.mapGoal[nId].curCondId = {}
					self.mapGoal[nId].nCurGoalIdx = 1
					self.mapGoal[nId].VxDir = 1
					self.mapGoal[nId].VyDir = 1
				end
			end
		end
	end
	for nSpawnPointId, mapConfigData in pairs(self.mapGoal) do
		if mapConfigData.mapConfig.InitShow then
			self:CreateGoal(nSpawnPointId, mapConfigData)
		end
	end
	if self.mapUpdateTimer ~= nil then
		self.mapUpdateTimer:Cancel()
		self.mapUpdateTimer = nil
	end
	self.mapUpdateTimer = self:AddTimer(0, 0, "OnUpdate", true, true, true)
	if 0 < #mapFloorCfgData.GuideLine then
		for _, nGuideLineId in ipairs(mapFloorCfgData.GuideLine) do
			local mapGuideLineData = ConfigTable.GetData("ThrowGiftGuideLine", nGuideLineId)
			if mapGuideLineData ~= nil then
				local rtTrack = instantiate(self._mapNode.rtTemplateGuideTrack, self._mapNode.rtScene)
				rtTrack.transform:SetAsFirstSibling()
				rtTrack:SetActive(true)
				local mapTrackCtrl = self:BindCtrlByNode(rtTrack.gameObject, "Game.UI.Activity.ThrowGifts.ThrowGiftLevelGuideTrackLineCtrl")
				mapTrackCtrl:InitLine(mapGuideLineData, self._mapNode.rtBeginning.anchoredPosition, self.nAG, self.maxVelocity)
				table.insert(self.tbGuideTrackCtrl, mapTrackCtrl)
			end
		end
	end
end
function ThrowGiftsLevelCtrl:FlyOver(nDelayTime, tbHitGoalId)
	self.nLevelType = 0
	self.bProcessing = true
	local waitAnim = function()
		if self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.ThrowCount or self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.ThrowCountAfterTime then
			self.parent:SetTarget(self.nTotalThrowGiftCount)
		elseif self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.Score or self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.ScoreAfterTime then
			self.parent:SetTarget(self.nLevelScore)
		elseif self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.HitCount or self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.HitCountAfterTime then
			self.parent:SetTarget(self.nTotalHitGoalCount)
		end
		if self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.ThrowCount then
			self.parent:SetTarget(self.nTotalThrowGiftCount)
			if self.nTotalThrowGiftCount >= self.mapLevelCfgData.throwGiftLevelParams then
				self:LevelEnd(true, 0)
				return
			end
		elseif self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.Score then
			self.parent:SetTarget(self.nLevelScore)
			if self.nLevelScore >= self.mapLevelCfgData.throwGiftLevelParams then
				self:LevelEnd(true, 0)
				return
			end
		elseif self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.HitCount then
			self.parent:SetTarget(self.nTotalHitGoalCount)
			if self.nTotalHitGoalCount >= self.mapLevelCfgData.throwGiftLevelParams then
				self:LevelEnd(true, 0)
				return
			end
		end
		if self.nTotalPenguinCount ~= 0 then
			self.beginningTweener = DOTween.To(function()
				return self._mapNode.rtBottle.localEulerAngles.z - 360
			end, function(v)
				self._mapNode.rtBottle.localEulerAngles = Vector3(0, 0, v)
			end, 0, 0.5):OnComplete(function()
				self:SetBeginningAngle(0, 0)
				NovaAPI.SetTMPText(self._mapNode.TMPBeginningCountHint, self.nTotalPenguinCount)
				if self.curPenguinIdx > #self.mapFloorCfgData.InitialGiftSort then
					if 0 < #self.mapFloorCfgData.GiftRandom then
						self.curPenguinType = self.nNextPenguinType
					else
						self.curPenguinType = 1
					end
				else
					self.curPenguinType = self.mapFloorCfgData.InitialGiftSort[self.curPenguinIdx]
				end
				self.curPenguinIdx = self.curPenguinIdx + 1
				self._mapNode.BeginningPenguinRoot.gameObject:SetActive(true)
				self._mapNode.rtBottleAnim:Play("rtBottle_in")
				self._mapNode.BeginningPenguinRoot:Play("penguinRoot_jump")
				WwiseAudioMgr:PostEvent("Mode_Present_shylock_jump")
				self:SetPenguinType(self._mapNode.BeginningPenguinRoot.transform, self.curPenguinType, self.curPenguinSpecialType)
				self:SetPenguinType(self._mapNode.rtBottle:Find("AnimRoot/penguinRoot"), self.curPenguinType, self.curPenguinSpecialType)
				self:SetBeginningAngle(0, 0)
				local wait = function()
					self._mapNode.imgBeginningHint:SetActive(true)
					self:SetPenguinType(self._mapNode.rtPenguinBeginningHint, self.curPenguinType, self.curPenguinSpecialType)
					if self.nTotalPenguinCount ~= 0 then
						self._mapNode.BeginningPenguinRoot.gameObject:SetActive(true)
						self._mapNode.BeginningPenguinRoot:Play("penguinRoot_in")
						WwiseAudioMgr:PostEvent("Mode_Present_shylock")
						self.nNextPenguinType = 1
						if self.curPenguinIdx > #self.mapFloorCfgData.InitialGiftSort then
							if 0 < #self.mapFloorCfgData.GiftRandom then
								self.nNextPenguinType = self.mapFloorCfgData.GiftRandom[math.random(#self.mapFloorCfgData.GiftRandom)]
							else
								self.nNextPenguinType = 1
							end
						else
							self.nNextPenguinType = self.mapFloorCfgData.InitialGiftSort[self.curPenguinIdx]
						end
						self:SetPenguinType(self._mapNode.BeginningPenguinRoot.transform, self.nNextPenguinType, 0)
					else
						self._mapNode.BeginningPenguinRoot.gameObject:SetActive(false)
					end
				end
				local waitAnimEnd = function()
					self.nLevelType = 1
					if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
						self.parent:SetViewBtn(1)
					end
				end
				self:AddTimer(1, 0.5, wait, true, true, true)
				self:AddTimer(1, 1, waitAnimEnd, true, true, true)
			end)
		else
			self._mapNode.BeginningPenguinRoot.gameObject:SetActive(false)
			self:LevelEnd(false, 1)
			return
		end
		local bNeedProcessingItem = false
		if tbHitGoalId ~= nil and 0 < #tbHitGoalId then
			local tbItemsRandom = {}
			local tbSpawnPointData = {}
			for _, HitGoalId in ipairs(tbHitGoalId) do
				local mapSpawnPointData = self.mapGoal[HitGoalId]
				if mapSpawnPointData ~= nil and 0 < #mapSpawnPointData.tbOrginPool then
					local tbCurPool = {}
					if mapSpawnPointData.mapConfig.PoolType then
						for _, mapItemData in ipairs(mapSpawnPointData.tbOrginPool) do
							if 1 > table.indexof(mapSpawnPointData.tbExtractedItems, mapItemData.nItemId) then
								table.insert(tbCurPool, mapItemData)
							end
						end
						if #tbCurPool < 2 then
							tbCurPool = {}
							mapSpawnPointData.tbExtractedItems = {}
							for _, mapItemData in ipairs(mapSpawnPointData.tbOrginPool) do
								table.insert(tbCurPool, mapItemData)
							end
						end
					else
						for _, mapItemData in ipairs(mapSpawnPointData.tbOrginPool) do
							table.insert(tbCurPool, mapItemData)
						end
					end
					local tbItems = {}
					for i = 1, 2 do
						local selected = 0
						local totalWeight = 0
						for _, mapItemData in ipairs(tbCurPool) do
							totalWeight = totalWeight + mapItemData.Weight
						end
						local random = math.random(0, totalWeight)
						local curWeight = 0
						for nIdx, mapItemData in ipairs(tbCurPool) do
							curWeight = curWeight + mapItemData.Weight
							if random <= curWeight then
								table.insert(tbItems, mapItemData.nItemId)
								selected = nIdx
								break
							end
						end
						table.remove(tbCurPool, selected)
					end
					if 0 < #tbItems then
						table.insert(tbItemsRandom, tbItems)
						table.insert(tbSpawnPointData, mapSpawnPointData)
					end
				end
			end
			if 0 < #tbItemsRandom then
				do
					local callback = function(tbIdx)
						self:Pause(false)
						self.bProcessing = false
						for i = 1, #tbItemsRandom do
							local nIdx = tbIdx[i]
							local mapSpawnPointData = tbSpawnPointData[i]
							if mapSpawnPointData ~= nil and mapSpawnPointData.mapConfig.PoolType then
								table.insert(mapSpawnPointData.tbExtractedItems, tbItemsRandom[i][nIdx])
							end
						end
					end
					bNeedProcessingItem = true
					self.parent:OpenItemSelect(tbItemsRandom, callback)
					self:Pause(true)
				end
			end
		end
		if not bNeedProcessingItem then
			self.bProcessing = false
		end
		local rtScenePos = self._mapNode.rtScene.anchoredPosition
		self._mapNode.rtScene.anchoredPosition = Vector2(0, rtScenePos.y)
		for nInstanceId, mapConfig in pairs(self.mapExObstacleOrigin) do
			if mapConfig.mapConfig.Reset and table.indexof(self.tbExObstacleCur, nInstanceId) < 1 then
				table.insert(self.tbExObstacleCur, nInstanceId)
				mapConfig.gameObject:SetActive(true)
			end
		end
	end
	if nDelayTime == nil or nDelayTime == 0 then
		waitAnim()
	else
		self:AddTimer(1, nDelayTime, waitAnim, true, true, true)
	end
end
function ThrowGiftsLevelCtrl:LevelEnd(bPass, nCond)
	if self.mapUpdateTimer ~= nil then
		self.mapUpdateTimer:Cancel()
		self.mapUpdateTimer = nil
	end
	self.parent:LevelEnd()
	local bShowPenguin = false
	if bPass and self.mapFloorCfgData.GiftNum > 0 then
		self.nLevelScore = self.nLevelScore + 20 * math.max(0, self.nTotalPenguinCount)
		bShowPenguin = true
	end
	local openSettle = function(changeInfo)
		self.parent:OpenSettle(bPass, self.nLevelScore, self.nTotalHitGoalCount, self.nTotalPenguinCount, bShowPenguin, changeInfo)
	end
	if self.actData ~= nil then
		local tbUseItems = {}
		for nItemId, nCount in pairs(self.mapItemUseCount) do
			table.insert(tbUseItems, {ItemId = nItemId, Count = nCount})
		end
		self.actData:SettleLevels(self.nLevelId, self.nTotalThrowGiftCount, self.nTotalHitGoalCount, self.nLevelScore, tbUseItems, bPass, openSettle)
	else
		openSettle()
	end
end
function ThrowGiftsLevelCtrl:Pause(bPause)
	if bPause then
		WwiseAudioMgr:PostEvent("Mode_Present_sidechain_in")
	else
		WwiseAudioMgr:PostEvent("Mode_Present_sidechain_out")
	end
	if self.mapUpdateTimer ~= nil then
		self.mapUpdateTimer:Pause(bPause)
	end
end
function ThrowGiftsLevelCtrl:ActiveItem(nItemId)
	if self.mapItemUseCount[nItemId] == nil then
		self.mapItemUseCount[nItemId] = 0
	end
	self.mapItemUseCount[nItemId] = self.mapItemUseCount[nItemId] + 1
	if nItemId == 101 then
		if 0 < self.nLevelTime then
			self.nLevelTime = self.nLevelTime + 11
			self.parent:AddTimeAnim()
			WwiseAudioMgr:PostEvent("Mode_Present_prop_overtime")
		end
	elseif 106 <= nItemId and nItemId <= 108 then
		self.curPenguinSpecialType = nItemId
		self._mapNode.rtPenguinBeginningHintAnim:Play("imgBeginningHint_in")
		if not self.bFlying and self.nLevelType == 1 or self.nLevelType == 3 then
			if nItemId == 108 then
				WwiseAudioMgr:PostEvent("Mode_Present_prop_anteena")
			else
				WwiseAudioMgr:PostEvent("Mode_Present_prop_gear")
			end
			self:SetPenguinType(self._mapNode.rtBottle:Find("AnimRoot/penguinRoot"), self.curPenguinType, nItemId)
			self:SetPenguinType(self._mapNode.rtPenguinBeginningHint, self.curPenguinType, nItemId)
			self._mapNode.rtBottleAnim:Play("rtBottle_switch")
			self._mapNode.rtPenguinBeginningHintAnim:Play("imgBeginningHint_in")
		end
	else
		self.mapCurActiveState[nItemId] = 16
		self.parent:SetFx(self.mapCurActiveState)
		if nItemId == 105 then
			WwiseAudioMgr:PostEvent("Mode_Present_prop_power")
			self:SetPenguinType(self._mapNode.BeginningPenguinRoot.transform, self.nNextPenguinType, 0)
			self:SetPenguinType(self._mapNode.rtBottle:Find("AnimRoot/penguinRoot"), self.curPenguinType, self.curPenguinSpecialType)
			self:SetPenguinType(self._mapNode.rtPenguinBeginningHint, self.curPenguinType, self.curPenguinSpecialType)
		elseif nItemId == 102 then
			self._mapNode.imgInfinite:SetActive(true)
			WwiseAudioMgr:PostEvent("Mode_Present_prop_infinite")
			self._mapNode.TMPBeginningCountHint.gameObject:SetActive(false)
		elseif nItemId == 103 then
			WwiseAudioMgr:PostEvent("Mode_Present_lowtime_lp")
		elseif nItemId == 104 then
			WwiseAudioMgr:PostEvent("Mode_Present_doubletime_lp")
		end
		self.parent:SetBuffShow(nItemId, true)
		self.parent:SetBuffTime(nItemId, 15)
	end
end
function ThrowGiftsLevelCtrl:LevelStart()
	self.nLevelType = 0
	local GuideCallback = function()
		self.nLevelType = 1
		self._mapNode.penguinRoot:SetActive(true)
		if self.nTotalPenguinCount ~= 0 then
			if self.nTotalPenguinCount >= 0 then
				NovaAPI.SetTMPText(self._mapNode.TMPBeginningCountHint, self.nTotalPenguinCount)
				self._mapNode.TMPBeginningCountHint.gameObject:SetActive(true)
				self._mapNode.imgInfinite:SetActive(false)
			else
				self._mapNode.TMPBeginningCountHint.gameObject:SetActive(false)
				self._mapNode.imgInfinite:SetActive(true)
			end
			if self.curPenguinIdx > #self.mapFloorCfgData.InitialGiftSort then
				if 0 < #self.mapFloorCfgData.GiftRandom then
					self.curPenguinType = self.mapFloorCfgData.GiftRandom[math.random(#self.mapFloorCfgData.GiftRandom)]
				else
					self.curPenguinType = 1
				end
			else
				self.curPenguinType = self.mapFloorCfgData.InitialGiftSort[self.curPenguinIdx]
			end
			self.curPenguinIdx = self.curPenguinIdx + 1
			self._mapNode.BeginningPenguinRoot.gameObject:SetActive(true)
			self._mapNode.rtBottleAnim:Play("rtBottle_in")
			self._mapNode.BeginningPenguinRoot:Play("penguinRoot_jump")
			WwiseAudioMgr:PostEvent("Mode_Present_shylock_jump")
			self:SetPenguinType(self._mapNode.BeginningPenguinRoot.transform, self.curPenguinType, self.curPenguinSpecialType)
			self:SetPenguinType(self._mapNode.rtBottle:Find("AnimRoot/penguinRoot"), self.curPenguinType, self.curPenguinSpecialType)
			self:SetBeginningAngle(0, 0)
			local wait = function()
				if self.nTotalPenguinCount ~= 0 then
					self._mapNode.BeginningPenguinRoot.gameObject:SetActive(true)
					self._mapNode.BeginningPenguinRoot:Play("penguinRoot_in")
					WwiseAudioMgr:PostEvent("Mode_Present_shylock")
					self.nNextPenguinType = 1
					if self.curPenguinIdx > #self.mapFloorCfgData.InitialGiftSort then
						if 0 < #self.mapFloorCfgData.GiftRandom then
							self.nNextPenguinType = self.mapFloorCfgData.GiftRandom[math.random(#self.mapFloorCfgData.GiftRandom)]
						else
							self.nNextPenguinType = 1
						end
					else
						self.nNextPenguinType = self.mapFloorCfgData.InitialGiftSort[self.curPenguinIdx]
					end
					self:SetPenguinType(self._mapNode.BeginningPenguinRoot.transform, self.nNextPenguinType, 0)
				else
					self._mapNode.BeginningPenguinRoot.gameObject:SetActive(false)
				end
				self._mapNode.imgBeginningHint:SetActive(true)
				self:SetPenguinType(self._mapNode.rtPenguinBeginningHint, self.curPenguinType, self.curPenguinSpecialType)
				self.nLevelType = 1
				if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
					self.parent:SetViewBtn(1)
				end
			end
			wait()
		else
			self._mapNode.BeginningPenguinRoot.gameObject:SetActive(false)
			self:LevelEnd()
		end
	end
	local completeCallback = function()
		if self.actData ~= nil then
			if self.mapFloorCfgData.DictionaryID > 0 and self.actData:GetDicFirstIn(self.mapFloorCfgData.DictionaryID) then
				EventManager.Hit(EventId.OpenPanel, PanelId.DictionaryEntry, self.mapFloorCfgData.DictionaryID, true, GuideCallback)
			else
				GuideCallback()
			end
		else
			GuideCallback()
		end
	end
	if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
		self.nLevelType = 3
		local maxScenePosX = -math.abs((1 - self.scenePivot[1]) * self.sceneSize[1])
		self.beginningTweener = DOTween.To(function()
			return 0
		end, function(v)
			local sum = v <= 0.5 and v or v <= 2.5 and 0.5 or 3 - v
			local posX = math.sin(math.pi * sum) * maxScenePosX
			local rtScenePos = self._mapNode.rtScene.anchoredPosition
			self._mapNode.rtScene.anchoredPosition = Vector2(posX, rtScenePos.y)
		end, 3, 3):OnComplete(function()
			completeCallback()
		end)
	else
		completeCallback()
	end
end
function ThrowGiftsLevelCtrl:ChangeView(bShow)
	if bShow then
		if self.nLevelType == 3 then
			return
		end
		self.nLevelType = 3
		local maxScenePosX = -math.abs((1 - self.scenePivot[1]) * self.sceneSize[1])
		self.beginningTweener = DOTween.To(function()
			return 0
		end, function(v)
			local sum = v <= 0.5 and v or v <= 2.5 and 0.5 or 3 - v
			local posX = math.sin(math.pi * sum) * maxScenePosX
			local rtScenePos = self._mapNode.rtScene.anchoredPosition
			self._mapNode.rtScene.anchoredPosition = Vector2(posX, rtScenePos.y)
		end, 0.5, 0.5):OnComplete(function()
			self.parent:SetViewBtn(2)
		end)
	else
		if self.nLevelType ~= 3 then
			return
		end
		local maxScenePosX = -math.abs((1 - self.scenePivot[1]) * self.sceneSize[1])
		self.beginningTweener = DOTween.To(function()
			return 2.5
		end, function(v)
			local sum = v <= 0.5 and v or v <= 2.5 and 0.5 or 3 - v
			local posX = math.sin(math.pi * sum) * maxScenePosX
			local rtScenePos = self._mapNode.rtScene.anchoredPosition
			self._mapNode.rtScene.anchoredPosition = Vector2(posX, rtScenePos.y)
		end, 3, 0.5):OnComplete(function()
			if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
				self.parent:SetViewBtn(1)
			end
			self.nLevelType = 1
		end)
	end
end
function ThrowGiftsLevelCtrl:CheckCollision(bounds1, bounds2, OffsetX1, OffsetY1, OffsetX2, OffsetY2)
	local bHit = false
	local bestNX, bestNY, minDepth = 0, 0, 0
	bHit = bounds1[2] + OffsetX1 >= bounds2[1] + OffsetX2 and bounds1[1] + OffsetX1 <= bounds2[2] + OffsetX2 and bounds1[4] + OffsetY1 >= bounds2[3] + OffsetY2 and bounds1[3] + OffsetY1 <= bounds2[4] + OffsetY2
	if bHit then
		print("Check SAT")
		bHit, bestNX, bestNY, minDepth = self:CheckSAT(bounds1, bounds2, OffsetX1, OffsetY1, OffsetX2, OffsetY2)
	end
	return bHit, bestNX, bestNY, minDepth
end
function ThrowGiftsLevelCtrl.SATGetAxes(corners)
	local ex1 = corners[2].x - corners[1].x
	local ey1 = corners[2].y - corners[1].y
	local len1 = math.sqrt(ex1 * ex1 + ey1 * ey1)
	local ex2 = corners[3].x - corners[2].x
	local ey2 = corners[3].y - corners[2].y
	local len2 = math.sqrt(ex2 * ex2 + ey2 * ey2)
	local ax1, ay1, ax2, ay2 = 0, 1, 1, 0
	if 1.0E-5 < len1 then
		ax1 = -ey1 / len1
		ay1 = ex1 / len1
	end
	if 1.0E-5 < len2 then
		ax2 = -ey2 / len2
		ay2 = ex2 / len2
	end
	return ax1, ay1, ax2, ay2
end
function ThrowGiftsLevelCtrl.SATProject(corner1, corner2, corner3, corner4, offsetX, offsetY, axisX, axisY)
	local v = (corner1.x + offsetX) * axisX + (corner1.y + offsetY) * axisY
	local pMin, pMax = v, v
	v = (corner2.x + offsetX) * axisX + (corner2.y + offsetY) * axisY
	if pMin > v then
		pMin = v
	end
	if pMax < v then
		pMax = v
	end
	v = (corner3.x + offsetX) * axisX + (corner3.y + offsetY) * axisY
	if pMin > v then
		pMin = v
	end
	if pMax < v then
		pMax = v
	end
	v = (corner4.x + offsetX) * axisX + (corner4.y + offsetY) * axisY
	if pMin > v then
		pMin = v
	end
	if pMax < v then
		pMax = v
	end
	return pMin, pMax
end
function ThrowGiftsLevelCtrl:CheckSAT(tbBounds1, tbBounds2, OffsetX1, OffsetY1, OffsetX2, OffsetY2)
	local minDepth = math.huge
	local bestNX, bestNY = 0, 0
	local ax1, ay1, ax2, ay2 = tbBounds1[9], tbBounds1[10], tbBounds1[11], tbBounds1[12]
	local ax3, ay3, ax4, ay4 = tbBounds2[9], tbBounds2[10], tbBounds2[11], tbBounds2[12]
	local cornersA1, cornersB1, cornersC1, cornersD1 = tbBounds1[5], tbBounds1[6], tbBounds1[7], tbBounds1[8]
	local cornersA2, cornersB2, cornersC2, cornersD2 = tbBounds2[5], tbBounds2[6], tbBounds2[7], tbBounds2[8]
	local min1, max1 = 0, 0
	local min2, max2 = 0, 0
	local overlap = 0
	min1, max1 = self.SATProject(cornersA1, cornersB1, cornersC1, cornersD1, OffsetX1, OffsetY1, ax1, ay1)
	min2, max2 = self.SATProject(cornersA2, cornersB2, cornersC2, cornersD2, OffsetX2, OffsetY2, ax1, ay1)
	if min2 >= max1 or min1 >= max2 then
		return false, 0, 0, 0
	end
	overlap = math.min(max1, max2) - math.max(min1, min2)
	if minDepth > overlap then
		minDepth = overlap
		bestNX = ax1
		bestNY = ay1
	end
	min1, max1 = self.SATProject(cornersA1, cornersB1, cornersC1, cornersD1, OffsetX1, OffsetY1, ax2, ay2)
	min2, max2 = self.SATProject(cornersA2, cornersB2, cornersC2, cornersD2, OffsetX2, OffsetY2, ax2, ay2)
	if min2 >= max1 or min1 >= max2 then
		return false, 0, 0, 0
	end
	overlap = math.min(max1, max2) - math.max(min1, min2)
	if minDepth > overlap then
		minDepth = overlap
		bestNX = ax2
		bestNY = ay2
	end
	min1, max1 = self.SATProject(cornersA1, cornersB1, cornersC1, cornersD1, OffsetX1, OffsetY1, ax3, ay3)
	min2, max2 = self.SATProject(cornersA2, cornersB2, cornersC2, cornersD2, OffsetX2, OffsetY2, ax3, ay3)
	if min2 >= max1 or min1 >= max2 then
		return false, 0, 0, 0
	end
	overlap = math.min(max1, max2) - math.max(min1, min2)
	if minDepth > overlap then
		minDepth = overlap
		bestNX = ax3
		bestNY = ay3
	end
	min1, max1 = self.SATProject(cornersA1, cornersB1, cornersC1, cornersD1, OffsetX1, OffsetY1, ax4, ay4)
	min2, max2 = self.SATProject(cornersA2, cornersB2, cornersC2, cornersD2, OffsetX2, OffsetY2, ax4, ay4)
	if min2 >= max1 or min1 >= max2 then
		return false, 0, 0, 0
	end
	overlap = math.min(max1, max2) - math.max(min1, min2)
	if minDepth > overlap then
		minDepth = overlap
		bestNX = ax4
		bestNY = ay4
	end
	local c1x = (cornersA1.x + OffsetX1 + cornersB1.x + OffsetX1 + cornersC1.x + OffsetX1 + cornersD1.x + OffsetX1) * 0.25
	local c1y = (cornersA1.y + OffsetY1 + cornersB1.y + OffsetY1 + cornersC1.y + OffsetY1 + cornersD1.y + OffsetY1) * 0.25
	local c2x = (cornersA2.x + OffsetX2 + cornersB2.x + OffsetX2 + cornersC2.x + OffsetX2 + cornersD2.x + OffsetX2) * 0.25
	local c2y = (cornersA2.y + OffsetY2 + cornersB2.y + OffsetY2 + cornersC2.y + OffsetY2 + cornersD2.y + OffsetY2) * 0.25
	if (c1x - c2x) * bestNX + (c1y - c2y) * bestNY < 0 then
		bestNX = -bestNX
		bestNY = -bestNY
	end
	return true, bestNX, bestNY, minDepth
end
function ThrowGiftsLevelCtrl.ReflectVelocity(vx, vy, nx, ny, restitution)
	restitution = restitution or 1.0
	local dot = vx * nx + vy * ny
	if 0 <= dot then
		return vx, vy
	end
	local scale = (1.0 + restitution) * dot
	return vx - scale * nx, vy - scale * ny
end
function ThrowGiftsLevelCtrl:GetLocalSpaceRect(rectTransform, parent)
	local corners = CS.System.Array.CreateInstance(typeof(Vector3), 4)
	rectTransform:GetLocalCorners(corners)
	local c0 = corners[0]
	local c1 = corners[1]
	local c2 = corners[2]
	local c3 = corners[3]
	local p0 = parent:InverseTransformPoint(rectTransform:TransformPoint(c0))
	local p1 = parent:InverseTransformPoint(rectTransform:TransformPoint(c1))
	local p2 = parent:InverseTransformPoint(rectTransform:TransformPoint(c2))
	local p3 = parent:InverseTransformPoint(rectTransform:TransformPoint(c3))
	local p0x, p0y = p0.x, p0.y
	local p1x, p1y = p1.x, p1.y
	local p2x, p2y = p2.x, p2.y
	local p3x, p3y = p3.x, p3.y
	local xMin = math.min(p0x, p1x, p2x, p3x)
	local xMax = math.max(p0x, p1x, p2x, p3x)
	local yMin = math.min(p0y, p1y, p2y, p3y)
	local yMax = math.max(p0y, p1y, p2y, p3y)
	local ax1, ay1, ax2, ay2 = self.SATGetAxes({
		p0,
		p1,
		p2,
		p3
	})
	return {
		xMin,
		xMax,
		yMin,
		yMax,
		p0,
		p1,
		p2,
		p3,
		ax1,
		ay1,
		ax2,
		ay2
	}
end
function ThrowGiftsLevelCtrl:OnUpdate()
	if self.mapUpdateTimer == nil then
		return
	end
	local nDeltaTime = math.min(self.mapUpdateTimer:GetDelTime(), 0.032)
	if self.nLevelTime > 0 then
		if self.nLevelType == 1 then
			if self.mapCurActiveState[103] ~= nil then
				self.nLevelTime = self.nLevelTime - nDeltaTime * 0.5
			else
				self.nLevelTime = self.nLevelTime - nDeltaTime
			end
		end
		self.nLevelTime = math.max(self.nLevelTime, 0)
		self.parent:SetTime(self.nLevelTime)
		if self.nLevelTime <= 0 then
			if self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.ThrowCountAfterTime then
				if self.nTotalThrowGiftCount >= self.mapLevelCfgData.throwGiftLevelParams then
					self:LevelEnd(true, 0)
				else
					self:LevelEnd(false, 1)
				end
			elseif self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.ScoreAfterTime then
				if self.nLevelScore >= self.mapLevelCfgData.throwGiftLevelParams then
					self:LevelEnd(true, 0)
				else
					self:LevelEnd(false, 1)
				end
			elseif self.mapLevelCfgData.ThrowGiftLevelCond == GameEnum.ThrowGiftLevelCond.HitCountAfterTime then
				if self.nTotalHitGoalCount >= self.mapLevelCfgData.throwGiftLevelParams then
					self:LevelEnd(true, 0)
				else
					self:LevelEnd(false, 1)
				end
			else
				self:LevelEnd(false, 2)
			end
			return
		end
	end
	local tbRemovedState = {}
	for nState, nTime in pairs(self.mapCurActiveState) do
		self.mapCurActiveState[nState] = self.mapCurActiveState[nState] - nDeltaTime
		self.parent:SetBuffTime(nState, nTime)
		if 0 >= self.mapCurActiveState[nState] then
			table.insert(tbRemovedState, nState)
			self.parent:SetBuffShow(nState, false)
		end
	end
	local bChange = 0 < #tbRemovedState
	for _, nState in ipairs(tbRemovedState) do
		self.mapCurActiveState[nState] = nil
		if nState == 105 then
			self:SetPenguinType(self._mapNode.BeginningPenguinRoot.transform, self.nNextPenguinType, 0)
			self:SetPenguinType(self._mapNode.rtBottle:Find("AnimRoot/penguinRoot"), self.curPenguinType, self.curPenguinSpecialType)
			self:SetPenguinType(self._mapNode.rtPenguinBeginningHint, self.curPenguinType, self.curPenguinSpecialType)
			if self.bFlying and self.curGiftPenguin ~= nil then
				local goPenguin = self.curGiftPenguin.goGiftPenguin
				local rtPenguin = goPenguin:GetComponent("RectTransform")
				local goImgRoot = rtPenguin:Find("imgRoot")
				local imgFx = goImgRoot:Find("imgFx")
				imgFx.gameObject:SetActive(false)
			end
		elseif nState == 103 then
			WwiseAudioMgr:PostEvent("Mode_Present_lowtime_lp_stop")
		elseif nState == 104 then
			WwiseAudioMgr:PostEvent("Mode_Present_doubletime_lp_stop")
		elseif nState == 102 and 0 <= self.nTotalPenguinCount then
			self._mapNode.imgInfinite:SetActive(false)
			self._mapNode.TMPBeginningCountHint.gameObject:SetActive(true)
		end
	end
	if bChange then
		self.parent:SetFx(self.mapCurActiveState)
	end
	for nId, mapAciveGoal in pairs(self.activeGoal) do
		local mapConfig = self.mapGoal[nId]
		local moveX = 0
		local moveY = 0
		if mapConfig ~= nil then
			moveX = mapConfig.mapConfig.MoveX
			moveY = mapConfig.mapConfig.MoveY
			if 0 < moveX or 0 < moveY then
				local curPos = mapAciveGoal.rtGoal.anchoredPosition
				local rtSpawnPoint = mapConfig.rtPoint
				local nXMax = rtSpawnPoint.anchoredPosition.x + moveX
				local nYMax = rtSpawnPoint.anchoredPosition.y + moveY
				local nXMin = rtSpawnPoint.anchoredPosition.x - moveX
				local nYMin = rtSpawnPoint.anchoredPosition.y - moveY
				local nCurMove = 0
				if self.mapCurActiveState[103] ~= nil then
					nCurMove = self.nGoalSpeed * nDeltaTime * 0.5
				else
					nCurMove = self.nGoalSpeed * nDeltaTime
				end
				local nAfterX = curPos.x + nCurMove * mapConfig.VxDir
				local nAfterY = curPos.y + nCurMove * mapConfig.VyDir
				if nXMax < nAfterX then
					nAfterX = nXMax
					mapConfig.VxDir = -mapConfig.VxDir
				elseif nXMin > nAfterX then
					nAfterX = nXMin
					mapConfig.VxDir = -mapConfig.VxDir
				end
				if nYMax < nAfterY then
					nAfterY = nYMax
					mapConfig.VyDir = -mapConfig.VyDir
				elseif nYMin > nAfterY then
					nAfterY = nYMin
					mapConfig.VyDir = -mapConfig.VyDir
				end
				mapAciveGoal.OffsetX = nAfterX - rtSpawnPoint.anchoredPosition.x
				mapAciveGoal.OffsetY = nAfterY - rtSpawnPoint.anchoredPosition.y
			end
		end
	end
	if not self.bFlying then
		return
	end
	if self.curGiftPenguin == nil then
		return
	end
	local nCurPosX, nCurPosY
	if self.curGiftPenguin.nSpecialType == 106 then
		nCurPosX, nCurPosY = self:NavigationPenguinUpdate(nDeltaTime)
	elseif self.curGiftPenguin.nSpecialType == 107 then
		nCurPosX, nCurPosY = self:HelmetPenguinUpdate(nDeltaTime)
	elseif self.curGiftPenguin.nSpecialType == 108 then
		nCurPosX, nCurPosY = self:AntennaPenguinUpdate(nDeltaTime)
	elseif self.curGiftPenguin.nSpecialType == 110 then
		nCurPosX, nCurPosY = self:SplitPenguinUpdate(nDeltaTime)
	else
		nCurPosX, nCurPosY = self:NormalPenguinUpdate(nDeltaTime)
	end
	if not self.bFlying then
		self:FlyOver(0.5)
		return
	end
	local tbHitGoalId = {}
	if self.curGiftPenguin.nSpecialType == 110 and self.curGiftPenguin.bSplit then
		local tbCurHit = self:SplitPenguinGoalCheck()
		if 0 < #tbCurHit then
			for _, tbResult in ipairs(tbCurHit) do
				self:HitGoal(tbResult[2], tbResult[1])
			end
			if not self.bFlying then
				self.curGiftPenguin = nil
				for _, tbResult in ipairs(tbCurHit) do
					table.insert(tbHitGoalId, tbResult[1])
				end
			end
		end
	else
		local hitGoalId, hitPos = self:NormalGoalCheck(nCurPosX, nCurPosY)
		if 0 < hitGoalId then
			self:HitGoal(hitPos, hitGoalId)
			table.insert(tbHitGoalId, hitGoalId)
		end
	end
	if not self.bFlying then
		self:FlyOver(0.5, tbHitGoalId)
		return
	end
	local rtScenePos = self._mapNode.rtScene.anchoredPosition
	local curPosXInScreen = self.sceneSize[1] * 0.5 + nCurPosX + rtScenePos.x
	if curPosXInScreen > self.viewSize[1] / 2 then
		local sumX = curPosXInScreen - self.viewSize[1] / 2
		local nFinX = rtScenePos.x - sumX
		local maxScenePosX = (1 - self.scenePivot[1]) * self.sceneSize[1]
		if nFinX <= -math.abs(maxScenePosX) then
			nFinX = -math.abs(maxScenePosX)
		end
		self._mapNode.rtScene.anchoredPosition = Vector2(nFinX, rtScenePos.y)
	end
end
function ThrowGiftsLevelCtrl:NormalGoalCheck(nCurPosX, nCurPosY)
	local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
	local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
	if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind and self.nFlyingTime - self._mapNode.rtBlindLevelTrack.nPrevTimer >= self.nLinePointInterval * 2 then
		self._mapNode.rtBlindLevelTrack.nPrevTimer = self.nFlyingTime
		self._mapNode.rtBlindLevelTrack:AddDot(Vector2(nCurPosX, nCurPosY))
	end
	local hitGoalId = 0
	local hitPos
	for nId, mapAciveGoal in pairs(self.activeGoal) do
		local GoalParentPos = mapAciveGoal.rtGoal.anchoredPosition
		local bHitGoal = self:CheckCollision(self.curGiftPenguin.tbBounds, mapAciveGoal.tbBoundsHitArea, nSumX, nSumY, mapAciveGoal.OffsetX, mapAciveGoal.OffsetY)
		if bHitGoal then
			local curVy = self.curGiftPenguin.nVelocityY
			if 0 < curVy and self.curGiftPenguin.nSpecialType ~= 106 and self.curGiftPenguin.nSpecialType ~= 107 then
				print("hit goal edge")
				self:DestroyPenguin()
				self.curGiftPenguin = nil
				self.bFlying = false
				break
			else
				print("hit goal！")
				hitPos = Vector2(nCurPosX, nCurPosY)
				destroy(self.curGiftPenguin.goGiftPenguin.gameObject)
				hitGoalId = nId
				self.curGiftPenguin = nil
				self.bFlying = false
				break
			end
		end
		if self.curGiftPenguin.nSpecialType ~= 107 then
			local bHitObstacle = self:CheckCollision(self.curGiftPenguin.tbBounds, mapAciveGoal.tbBoundsObstacle, nSumX, nSumY, mapAciveGoal.OffsetX, mapAciveGoal.OffsetY)
			if bHitObstacle then
				self:DestroyPenguin()
				self.bFlying = false
				break
			end
		end
	end
	return hitGoalId, hitPos
end
function ThrowGiftsLevelCtrl:SplitPenguinGoalCheck()
	local bHasSubPenguin = false
	local tbCurHit = {}
	for _, mapSubPenguin in ipairs(self.curGiftPenguin.tbSubPenguin) do
		if mapSubPenguin.bFlying then
			local hitGoalId = 0
			local hitPos
			local nSumX = mapSubPenguin.curPosX - mapSubPenguin.mapStartPos.x
			local nSumY = mapSubPenguin.curPosY - mapSubPenguin.mapStartPos.y
			for nId, mapAciveGoal in pairs(self.activeGoal) do
				local bHitGoal = self:CheckCollision(mapSubPenguin.tbBounds, mapAciveGoal.tbBoundsHitArea, nSumX, nSumY, mapAciveGoal.OffsetX, mapAciveGoal.OffsetY)
				if bHitGoal then
					print("hit goal！")
					hitPos = Vector2(mapSubPenguin.curPosX, mapSubPenguin.curPosY)
					destroy(mapSubPenguin.goGiftPenguin.gameObject)
					mapSubPenguin.goGiftPenguin = nil
					hitGoalId = nId
					mapSubPenguin.bFlying = false
					table.insert(tbCurHit, {hitGoalId, hitPos})
					table.insert(self.curGiftPenguin.tbCacheSubPenguinGoal, {hitPos, hitGoalId})
					break
				end
				local bHitObstacle = self:CheckCollision(mapSubPenguin.tbBounds, mapAciveGoal.tbBoundsObstacle, nSumX, nSumY, mapAciveGoal.OffsetX, mapAciveGoal.OffsetY)
				if bHitObstacle then
					self:DestroySubPenguin(mapSubPenguin)
					mapSubPenguin.bFlying = false
					break
				end
				if mapSubPenguin.bFlying then
					bHasSubPenguin = true
				end
			end
		end
	end
	self.bFlying = bHasSubPenguin
	return tbCurHit
end
function ThrowGiftsLevelCtrl:NormalPenguinUpdate(nDeltaTime)
	self.nFlyingTime = self.nFlyingTime + nDeltaTime
	local nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
	local nCurPosY = self.curGiftPenguin.curPosY + nDeltaTime * self.curGiftPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
	self.curGiftPenguin.nVelocityY = self.curGiftPenguin.nVelocityY - self.nAG * nDeltaTime
	self.curGiftPenguin.curPosX = nCurPosX
	self.curGiftPenguin.curPosY = nCurPosY
	self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
	local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
	local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
	local curVy = self.curGiftPenguin.nVelocityY
	if self.curGiftPenguin.rtImgRoot ~= nil then
		local nFlyAngle = math.deg(math.atan(curVy, self.curGiftPenguin.nVelocityX))
		self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
	end
	for _, tbBounds in ipairs(self.tbObstacle) do
		local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, tbBounds, nSumX, nSumY, 0, 0)
		if bHit then
			self:DestroyPenguin()
			self.bFlying = false
			break
		end
	end
	if not self.bFlying then
		return
	end
	if nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2] then
		print("hit border")
		self:DestroyPenguin()
		self.bFlying = false
	end
	if not self.bFlying then
		return
	end
	local tbHittedObs = {}
	for _, nSpecialId in ipairs(self.tbExObstacleCur) do
		local mapConfig = self.mapExObstacleOrigin[nSpecialId]
		if mapConfig ~= nil then
			local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
			if bHit then
				local nType, Param, bRemove
				self.bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
				self:SpecialObstacleFunc(self.curGiftPenguin, nDeltaTime, nType, Param)
				if bRemove then
					table.insert(tbHittedObs, nSpecialId)
				end
				if not self.bFlying then
					self:DestroyPenguin()
					break
				end
			end
		end
	end
	for _, nId in ipairs(tbHittedObs) do
		table.removebyvalue(self.tbExObstacleCur, nId, true)
	end
	return nCurPosX, nCurPosY
end
function ThrowGiftsLevelCtrl:BouncePenguinUpdate(nDeltaTime)
	self.nFlyingTime = self.nFlyingTime + nDeltaTime
	local nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
	local nCurPosY = self.curGiftPenguin.curPosY + nDeltaTime * self.curGiftPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
	self.curGiftPenguin.nVelocityY = self.curGiftPenguin.nVelocityY - self.nAG * nDeltaTime
	self.curGiftPenguin.curPosX = nCurPosX
	self.curGiftPenguin.curPosY = nCurPosY
	local curVy = self.curGiftPenguin.nVelocityY
	self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
	local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
	local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
	if self.curGiftPenguin.rtImgRoot ~= nil then
		local nFlyAngle = math.deg(math.atan(curVy, self.curGiftPenguin.nVelocityX))
		self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
	end
	for _, tbBounds in ipairs(self.tbObstacle) do
		local bHit, bestNX, bestNY, minDepth = self:CheckCollision(self.curGiftPenguin.tbBounds, tbBounds, nSumX, nSumY, 0, 0)
		if bHit then
			if self.curGiftPenguin.nHitCount < 3 then
				self.curGiftPenguin.nHitCount = self.curGiftPenguin.nHitCount + 1
				nCurPosX = nCurPosX + bestNX * minDepth
				nCurPosY = nCurPosY + bestNY * minDepth
				nSumX = nSumX + bestNX * minDepth
				nSumY = nSumY + bestNY * minDepth
				self.curGiftPenguin.curPosX = nCurPosX
				self.curGiftPenguin.curPosY = nCurPosY
				self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
				self.curGiftPenguin.mapStartPos = self.curGiftPenguin.goGiftPenguin.anchoredPosition
				local vxAfter, vyAfter = self.ReflectVelocity(self.curGiftPenguin.nVelocityX, curVy, bestNX, bestNY, 1)
				self.curGiftPenguin.nHitTime = self.nFlyingTime
				self.curGiftPenguin.nVelocityX = vxAfter
				self.curGiftPenguin.nVelocityY = vyAfter
				self.curGiftPenguin.tbBounds = self:GetLocalSpaceRect(self.curGiftPenguin.goGiftPenguin, self.curGiftPenguin.goGiftPenguin.parent)
				break
			else
				self:DestroyPenguin()
				self.bFlying = false
				break
			end
		end
	end
	if not self.bFlying then
		return
	end
	if nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2] then
		print("hit border")
		self:DestroyPenguin()
		self.bFlying = false
	end
	if not self.bFlying then
		return
	end
	local tbHittedObs = {}
	for _, nSpecialId in ipairs(self.tbExObstacleCur) do
		local mapConfig = self.mapExObstacleOrigin[nSpecialId]
		if mapConfig ~= nil then
			local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
			if bHit then
				local nType, Param, bRemove
				self.bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
				self:SpecialObstacleFunc(self.curGiftPenguin, nDeltaTime, nType, Param)
				if bRemove then
					table.insert(tbHittedObs, nSpecialId)
				end
				if not self.bFlying then
					self:DestroyPenguin()
					break
				end
			end
		end
	end
	for _, nId in ipairs(tbHittedObs) do
		table.removebyvalue(self.tbExObstacleCur, nId, true)
	end
	return nCurPosX, nCurPosY
end
function ThrowGiftsLevelCtrl:AntennaPenguinUpdate(nDeltaTime)
	self.nFlyingTime = self.nFlyingTime + nDeltaTime
	local nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
	local nCurPosY = self.curGiftPenguin.curPosY + nDeltaTime * self.curGiftPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
	self.curGiftPenguin.nVelocityY = self.curGiftPenguin.nVelocityY - self.nAG * nDeltaTime
	self.curGiftPenguin.curPosX = nCurPosX
	self.curGiftPenguin.curPosY = nCurPosY
	local curVy = self.curGiftPenguin.nVelocityY
	self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
	local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
	local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
	if self.tbItemTrackCtrl[self.curGiftPenguin.nTrackIdx] ~= nil then
		local mapTrackCtrl = self.tbItemTrackCtrl[self.curGiftPenguin.nTrackIdx]
		if self.nFlyingTime - mapTrackCtrl.nPrevTimer >= self.nLinePointInterval * 2 then
			mapTrackCtrl.nPrevTimer = self.nFlyingTime
			mapTrackCtrl:AddDot(Vector2(nCurPosX, nCurPosY))
		end
	end
	if self.curGiftPenguin.rtImgRoot ~= nil then
		local nFlyAngle = math.deg(math.atan(curVy, self.curGiftPenguin.nVelocityX))
		self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
	end
	for _, tbBounds in ipairs(self.tbObstacle) do
		local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, tbBounds, nSumX, nSumY, 0, 0)
		if bHit then
			self:DestroyPenguin()
			self.bFlying = false
			break
		end
	end
	if not self.bFlying then
		return
	end
	if nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2] then
		print("hit border")
		self:DestroyPenguin()
		self.bFlying = false
	end
	if not self.bFlying then
		return
	end
	local tbHittedObs = {}
	for _, nSpecialId in ipairs(self.tbExObstacleCur) do
		local mapConfig = self.mapExObstacleOrigin[nSpecialId]
		if mapConfig ~= nil then
			local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
			if bHit then
				local nType, Param, bRemove
				self.bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
				self:SpecialObstacleFunc(self.curGiftPenguin, nDeltaTime, nType, Param)
				if bRemove then
					table.insert(tbHittedObs, nSpecialId)
				end
				if not self.bFlying then
					self:DestroyPenguin()
					break
				end
			end
		end
	end
	for _, nId in ipairs(tbHittedObs) do
		table.removebyvalue(self.tbExObstacleCur, nId, true)
	end
	return nCurPosX, nCurPosY
end
function ThrowGiftsLevelCtrl:HelmetPenguinUpdate(nDeltaTime)
	self.nFlyingTime = self.nFlyingTime + nDeltaTime
	local nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
	local nCurPosY = self.curGiftPenguin.curPosY + nDeltaTime * self.curGiftPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
	self.curGiftPenguin.nVelocityY = self.curGiftPenguin.nVelocityY - self.nAG * nDeltaTime
	self.curGiftPenguin.curPosX = nCurPosX
	self.curGiftPenguin.curPosY = nCurPosY
	local curVy = self.curGiftPenguin.nVelocityY
	self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
	local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
	local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
	if self.curGiftPenguin.rtImgRoot ~= nil then
		local nFlyAngle = math.deg(math.atan(curVy, self.curGiftPenguin.nVelocityX))
		self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
	end
	if nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2] then
		print("hit border")
		self:DestroyPenguin()
		self.bFlying = false
	end
	if not self.bFlying then
		return
	end
	local tbHittedObs = {}
	for _, nSpecialId in ipairs(self.tbExObstacleCur) do
		local mapConfig = self.mapExObstacleOrigin[nSpecialId]
		if mapConfig ~= nil then
			local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
			if bHit then
				local bFlying, nType, Param, bRemove
				bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
				self:SpecialObstacleFunc(self.curGiftPenguin, nDeltaTime, nType, Param)
				if bRemove then
					table.insert(tbHittedObs, nSpecialId)
				end
			end
		end
	end
	for _, nId in ipairs(tbHittedObs) do
		table.removebyvalue(self.tbExObstacleCur, nId, true)
	end
	return nCurPosX, nCurPosY
end
function ThrowGiftsLevelCtrl:NavigationPenguinUpdate(nDeltaTime)
	local checkGetGoal = function(nCurPosX, nCurPosY)
		for nId, mapAciveGoal in pairs(self.activeGoal) do
			if nCurPosX >= mapAciveGoal.tbBoundsHitArea[1] and nCurPosX <= mapAciveGoal.tbBoundsHitArea[2] and nCurPosY >= mapAciveGoal.tbBoundsHitArea[4] then
				return mapAciveGoal.rtGoal
			end
		end
		return nil
	end
	self.nFlyingTime = self.nFlyingTime + nDeltaTime
	self.curGiftPenguin.nVelocityY = math.max(0, self.curGiftPenguin.nVelocityY - self.nAG * nDeltaTime)
	local nCurPosY = 0
	local nCurPosX = 0
	if self.curGiftPenguin.targetGoal == nil then
		if self.curGiftPenguin.nVelocityY > 0 then
			nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
			nCurPosY = self.curGiftPenguin.curPosY + nDeltaTime * self.curGiftPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
		else
			nCurPosY = self.curGiftPenguin.curPosY
			nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
			self.curGiftPenguin.nVelocityY = 0
		end
		local checkGoal = checkGetGoal(nCurPosX, nCurPosY)
		if checkGoal ~= nil then
			self.curGiftPenguin.targetGoal = checkGoal
			self.curGiftPenguin.nGetTargetTime = self.nFlyingTime
		end
	else
		nCurPosY = self.curGiftPenguin.curPosY - nDeltaTime * self.nNavigationPenguinSpeed
		local nTargetX = self.curGiftPenguin.targetGoal.anchoredPosition.x
		nCurPosX = self.curGiftPenguin.goGiftPenguin.anchoredPosition.x
		local sumMove = math.min(self.maxVelocity, (nTargetX - nCurPosX) / 0.1) * nDeltaTime
		nCurPosX = sumMove + nCurPosX
	end
	self.curGiftPenguin.curPosX = nCurPosX
	self.curGiftPenguin.curPosY = nCurPosY
	self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
	local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
	local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
	local curVy = self.curGiftPenguin.nVelocityY
	if self.curGiftPenguin.rtImgRoot ~= nil then
		if self.curGiftPenguin.targetGoal == nil then
			local nFlyAngle = math.deg(math.atan(curVy, self.curGiftPenguin.nVelocityX))
			self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
		else
			local nCurAngle = self.curGiftPenguin.rtImgRoot.localEulerAngles.z
			local nAngle = 90 * nDeltaTime
			nCurAngle = math.min(nCurAngle + nAngle, 90)
			self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nCurAngle)
		end
	end
	for _, tbBounds in ipairs(self.tbObstacle) do
		local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, tbBounds, nSumX, nSumY, 0, 0)
		if bHit then
			print("hit Obstacle")
			self:DestroyPenguin()
			self.curGiftPenguin = nil
			self.bFlying = false
			break
		end
	end
	if not self.bFlying then
		return
	end
	if nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2] then
		print("hit border")
		self:DestroyPenguin()
		self.bFlying = false
	end
	if not self.bFlying then
		return
	end
	local tbHittedObs = {}
	for _, nSpecialId in ipairs(self.tbExObstacleCur) do
		local mapConfig = self.mapExObstacleOrigin[nSpecialId]
		if mapConfig ~= nil then
			local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
			if bHit then
				local nType, Param, bRemove
				self.bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
				self:SpecialObstacleFunc(self.curGiftPenguin, nDeltaTime, nType, Param)
				if bRemove then
					table.insert(tbHittedObs, nSpecialId)
				end
				if not self.bFlying then
					self:DestroyPenguin()
					break
				end
			end
		end
	end
	for _, nId in ipairs(tbHittedObs) do
		table.removebyvalue(self.tbExObstacleCur, nId, true)
	end
	return nCurPosX, nCurPosY
end
function ThrowGiftsLevelCtrl:SplitPenguinUpdate(nDeltaTime)
	local nCurPosX, nCurPosY = 0, 0
	local Split = function(mapPenguin, nAngle, nVelocity, initPos)
		mapPenguin.bSplit = true
		local goPenguin = instantiate(self._mapNode.templateBullet, self._mapNode.rtPenguinRoot)
		local rtPenguin = goPenguin:GetComponent("RectTransform")
		local goImgRoot = rtPenguin:Find("imgRoot")
		local imgFx = goImgRoot:Find("imgFx")
		local rtRed = goImgRoot:Find("penguin_red")
		local rtYellow = goImgRoot:Find("penguin_yellow")
		local rtGreen = goImgRoot:Find("penguin_green")
		local rtGoggles = goImgRoot:Find("penguin_goggles")
		local rtAntenna = goImgRoot:Find("penguin_antenna")
		local rtHelmet = goImgRoot:Find("penguin_helmet")
		local rtImgRoot
		if goImgRoot ~= nil then
			rtImgRoot = goImgRoot:GetComponent("RectTransform")
		end
		rtPenguin.anchoredPosition = initPos
		rtRed.gameObject:SetActive(mapPenguin.nType == 2)
		rtYellow.gameObject:SetActive(mapPenguin.nType == 3)
		rtGreen.gameObject:SetActive(mapPenguin.nType == 1)
		rtGoggles.gameObject:SetActive(false)
		rtAntenna.gameObject:SetActive(false)
		rtHelmet.gameObject:SetActive(false)
		imgFx.gameObject:SetActive(self.mapCurActiveState[105] ~= nil)
		rtPenguin.anchoredPosition = initPos
		goPenguin:SetActive(true)
		if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
			self._mapNode.rtBlindLevelTrack:Reset()
		end
		local mapGiftPenguin = {
			goGiftPenguin = rtPenguin,
			nState = 0,
			nType = mapPenguin.nType,
			nStartAngle = nAngle,
			nVelocityX = nVelocity * math.cos(math.rad(nAngle)),
			nVelocityY = nVelocity * math.sin(math.rad(nAngle)),
			mapStartPos = initPos,
			rtImgRoot = rtImgRoot,
			tbBounds = self:GetLocalSpaceRect(rtPenguin, rtPenguin.parent),
			curPosX = initPos.x,
			curPosY = initPos.y,
			bFlying = true,
			nHitTime = 0
		}
		return mapGiftPenguin
	end
	if self.curGiftPenguin.bSplit then
		local bHasSubPenguin = false
		for _, mapSubPenguin in ipairs(self.curGiftPenguin.tbSubPenguin) do
			if mapSubPenguin.bFlying then
				self.nFlyingTime = self.nFlyingTime + nDeltaTime
				nCurPosX = mapSubPenguin.curPosX + nDeltaTime * mapSubPenguin.nVelocityX
				nCurPosY = mapSubPenguin.curPosY + nDeltaTime * mapSubPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
				mapSubPenguin.nVelocityY = mapSubPenguin.nVelocityY - self.nAG * nDeltaTime
				mapSubPenguin.curPosX = nCurPosX
				mapSubPenguin.curPosY = nCurPosY
				mapSubPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
				local nSumX = nCurPosX - mapSubPenguin.mapStartPos.x
				local nSumY = nCurPosY - mapSubPenguin.mapStartPos.y
				local curVy = mapSubPenguin.nVelocityY
				if mapSubPenguin.rtImgRoot ~= nil then
					local nFlyAngle = math.deg(math.atan(curVy, mapSubPenguin.nVelocityX))
					mapSubPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
				end
				for _, tbBounds in ipairs(self.tbObstacle) do
					local bHit = self:CheckCollision(mapSubPenguin.tbBounds, tbBounds, nSumX, nSumY, 0, 0)
					if bHit then
						print("hit Obstacle")
						self:DestroySubPenguin(mapSubPenguin)
						mapSubPenguin.bFlying = false
						break
					end
				end
				if mapSubPenguin.bFlying and (nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2]) then
					print("hit border")
					self:DestroySubPenguin(mapSubPenguin)
					mapSubPenguin.bFlying = false
				end
				if mapSubPenguin.bFlying then
					local tbHittedObs = {}
					for _, nSpecialId in ipairs(self.tbExObstacleCur) do
						local mapConfig = self.mapExObstacleOrigin[nSpecialId]
						if mapConfig ~= nil then
							local bHit = self:CheckCollision(mapSubPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
							if bHit then
								local nType, Param, bRemove
								mapSubPenguin.bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
								self:SpecialObstacleFunc(mapSubPenguin, nDeltaTime, nType, Param)
								if bRemove then
									table.insert(tbHittedObs, nSpecialId)
								end
								if not mapSubPenguin.bFlying then
									self:DestroySubPenguin(mapSubPenguin)
									break
								end
							end
						end
					end
					for _, nId in ipairs(tbHittedObs) do
						table.removebyvalue(self.tbExObstacleCur, nId, true)
					end
				end
				if mapSubPenguin.bFlying then
					bHasSubPenguin = true
				end
			end
		end
		self.bFlying = bHasSubPenguin
		if not self.bFlying then
			self.curGiftPenguin = nil
		end
	else
		self.nFlyingTime = self.nFlyingTime + nDeltaTime
		nCurPosX = self.curGiftPenguin.curPosX + nDeltaTime * self.curGiftPenguin.nVelocityX
		nCurPosY = self.curGiftPenguin.curPosY + nDeltaTime * self.curGiftPenguin.nVelocityY - 0.5 * self.nAG * nDeltaTime * nDeltaTime
		self.curGiftPenguin.nVelocityY = self.curGiftPenguin.nVelocityY - self.nAG * nDeltaTime
		self.curGiftPenguin.curPosX = nCurPosX
		self.curGiftPenguin.curPosY = nCurPosY
		self.curGiftPenguin.goGiftPenguin.anchoredPosition = Vector2(nCurPosX, nCurPosY)
		local nSumX = nCurPosX - self.curGiftPenguin.mapStartPos.x
		local nSumY = nCurPosY - self.curGiftPenguin.mapStartPos.y
		local curVy = self.curGiftPenguin.nVelocityY
		if self.curGiftPenguin.rtImgRoot ~= nil then
			local nFlyAngle = math.deg(math.atan(curVy, self.curGiftPenguin.nVelocityX))
			self.curGiftPenguin.rtImgRoot.localEulerAngles = Vector3(0, 0, nFlyAngle)
		end
		for _, tbBounds in ipairs(self.tbObstacle) do
			local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, tbBounds, nSumX, nSumY, 0, 0)
			if bHit then
				self:DestroyPenguin()
				self.bFlying = false
				break
			end
		end
		if not self.bFlying then
			return
		end
		if nCurPosX > 0.5 * self.sceneSize[1] or nCurPosX < -0.5 * self.sceneSize[1] or nCurPosY > 0.5 * self.sceneSize[2] or nCurPosY < -0.5 * self.sceneSize[2] then
			print("hit border")
			self:DestroyPenguin()
			self.bFlying = false
		end
		if not self.bFlying then
			return
		end
		local tbHittedObs = {}
		for _, nSpecialId in ipairs(self.tbExObstacleCur) do
			local mapConfig = self.mapExObstacleOrigin[nSpecialId]
			if mapConfig ~= nil then
				local bHit = self:CheckCollision(self.curGiftPenguin.tbBounds, mapConfig.tbBounds, nSumX, nSumY, 0, 0)
				if bHit then
					local nType, Param, bRemove
					self.bFlying, nType, Param, bRemove = self:HitSpecialObstacle(nSpecialId)
					self:SpecialObstacleFunc(self.curGiftPenguin, nDeltaTime, nType, Param)
					if bRemove then
						table.insert(tbHittedObs, nSpecialId)
					end
					if not self.bFlying then
						self:DestroyPenguin()
						break
					end
				end
			end
		end
		for _, nId in ipairs(tbHittedObs) do
			table.removebyvalue(self.tbExObstacleCur, nId, true)
		end
		if self.bFlying and curVy <= 0 then
			self.curGiftPenguin.bSplit = true
			local initPos = self.curGiftPenguin.goGiftPenguin.anchoredPosition
			local nCurVelocity = math.sqrt(self.curGiftPenguin.nVelocityY * self.curGiftPenguin.nVelocityY + self.curGiftPenguin.nVelocityX * self.curGiftPenguin.nVelocityX)
			local nFlyAngle = math.deg(math.atan(self.curGiftPenguin.nVelocityY, self.curGiftPenguin.nVelocityX))
			for i = -1, 1 do
				local mapSubPenguin = Split(self.curGiftPenguin, nFlyAngle + 20 * i, nCurVelocity, initPos)
				table.insert(self.curGiftPenguin.tbSubPenguin, mapSubPenguin)
			end
			self:DestroySubPenguin(self.curGiftPenguin)
		end
	end
	return nCurPosX, nCurPosY
end
function ThrowGiftsLevelCtrl:SetBeginningAngle(nAngle, nVelocity)
	local fixedAngle = nAngle == 0 and 0 or nAngle - 90
	self._mapNode.rtBottle.localEulerAngles = Vector3(0, 0, fixedAngle)
	local sumScale = nVelocity / self.maxVelocity * 0.2
	self._mapNode.rtBottle.localScale = Vector3(1 + sumScale, 1 - sumScale, 1)
end
function ThrowGiftsLevelCtrl:SetBeginningLine(nAngle, nVelocity)
	if self.curPenguinSpecialType == 106 then
		if nVelocity == 0 then
			self._mapNode.rtBeginningLine.gameObject:SetActive(false)
			return
		end
		self._mapNode.rtBeginningLine.gameObject:SetActive(true)
		self._mapNode.rtBeginningLine.position = self._mapNode.rtBeginningPos.position
		local vX = nVelocity * math.cos(math.rad(nAngle))
		local vY = nVelocity * math.sin(math.rad(nAngle))
		local t_stop = vY / self.nAG
		if t_stop < 0 then
			t_stop = 0
		end
		for i = 1, 30 do
			if i <= 10 then
				local dotx = self.nLinePointInterval * i * vX
				local dotY = 0
				if t_stop >= self.nLinePointInterval * i then
					dotY = self.nLinePointInterval * i * vY - 0.5 * self.nAG * (self.nLinePointInterval * i) * (self.nLinePointInterval * i)
				else
					dotY = t_stop * vY - 0.5 * self.nAG * t_stop * t_stop
				end
				self._mapNode.BeginningDot[i].anchoredPosition = Vector2(dotx, dotY)
				self._mapNode.BeginningDot[i].gameObject:SetActive(true)
			else
				self._mapNode.BeginningDot[i].gameObject:SetActive(false)
			end
		end
	elseif self.curPenguinSpecialType == 108 then
		if nVelocity == 0 then
			self._mapNode.rtBeginningLine.gameObject:SetActive(false)
			return
		end
		self._mapNode.rtBeginningLine.gameObject:SetActive(true)
		self._mapNode.rtBeginningLine.position = self._mapNode.rtBeginningPos.position
		local vX = nVelocity * math.cos(math.rad(nAngle))
		local vY = nVelocity * math.sin(math.rad(nAngle))
		for i = 1, 30 do
			local dotx = self.nLinePointInterval * i * vX
			local dotY = self.nLinePointInterval * i * vY - 0.5 * self.nAG * (self.nLinePointInterval * i) * (self.nLinePointInterval * i)
			self._mapNode.BeginningDot[i].anchoredPosition = Vector2(dotx, dotY)
			self._mapNode.BeginningDot[i].gameObject:SetActive(true)
		end
	else
		if nVelocity == 0 then
			self._mapNode.rtBeginningLine.gameObject:SetActive(false)
			return
		end
		self._mapNode.rtBeginningLine.gameObject:SetActive(true)
		self._mapNode.rtBeginningLine.position = self._mapNode.rtBeginningPos.position
		local vX = nVelocity * math.cos(math.rad(nAngle))
		local vY = nVelocity * math.sin(math.rad(nAngle))
		for i = 1, 30 do
			if i <= 10 then
				local dotx = self.nLinePointInterval * i * vX
				local dotY = self.nLinePointInterval * i * vY - 0.5 * self.nAG * (self.nLinePointInterval * i) * (self.nLinePointInterval * i)
				self._mapNode.BeginningDot[i].anchoredPosition = Vector2(dotx, dotY)
				self._mapNode.BeginningDot[i].gameObject:SetActive(true)
			else
				self._mapNode.BeginningDot[i].gameObject:SetActive(false)
			end
		end
	end
end
function ThrowGiftsLevelCtrl:HitSpecialObstacle(nSpecialId)
	local mapOriginConfig = self.mapExObstacleOrigin[nSpecialId]
	local nType = 0
	local Param = {}
	if mapOriginConfig ~= nil then
		if mapOriginConfig.mapConfig.Type == GameEnum.SpecialObstacleType.Obstacle then
			mapOriginConfig.gameObject:SetActive(false)
			return false, nType, Param, true
		elseif mapOriginConfig.mapConfig.Type == GameEnum.SpecialObstacleType.Score then
			mapOriginConfig.gameObject:SetActive(false)
			local nScore = mapOriginConfig.mapConfig.Param[1]
			if nScore ~= nil then
				self:AddScore(nScore)
			end
			return true, nType, Param, true
		elseif mapOriginConfig.mapConfig.Type == GameEnum.SpecialObstacleType.WindForce then
			nType = 1
			Param.WindForce = mapOriginConfig.mapConfig.Param[1] * 10
			return true, nType, Param, false
		elseif mapOriginConfig.mapConfig.Type == GameEnum.SpecialObstacleType.Portal then
			nType = 2
			Param.Exit = mapOriginConfig.mapConfig.Param[1]
			return true, nType, Param, false
		end
	end
	return true, nType, Param, true
end
function ThrowGiftsLevelCtrl:SpecialObstacleFunc(mapPenguin, nDeltaTime, nType, Param)
	if nType == nil or Param == nil then
		return
	end
	if nType == 1 then
		mapPenguin.nVelocityX = mapPenguin.nVelocityX - Param.WindForce * nDeltaTime
	elseif nType == 2 then
		local nExitId = Param.Exit
		local mapExitConfig
		for nInstanceId, mapObstacle in pairs(self.mapExObstacleOrigin) do
			if mapObstacle.mapConfig.Id == nExitId then
				mapExitConfig = mapObstacle
				break
			end
		end
		if mapExitConfig ~= nil then
			local rtExit = mapExitConfig.gameObject:GetComponent("RectTransform")
			local nCurVelocity = math.sqrt(mapPenguin.nVelocityY * mapPenguin.nVelocityY + mapPenguin.nVelocityX * mapPenguin.nVelocityX)
			local nFlyAngle = rtExit.localEulerAngles.z
			mapPenguin.goGiftPenguin.anchoredPosition = rtExit.anchoredPosition
			mapPenguin.nVelocityX = nCurVelocity * math.cos(math.rad(nFlyAngle))
			mapPenguin.nVelocityY = nCurVelocity * math.sin(math.rad(nFlyAngle))
			mapPenguin.tbBounds = self:GetLocalSpaceRect(mapPenguin.goGiftPenguin.transform, mapPenguin.goGiftPenguin.transform.parent)
			mapPenguin.curPosX = rtExit.anchoredPosition.x
			mapPenguin.curPosY = rtExit.anchoredPosition.y
			mapPenguin.mapStartPos = rtExit.anchoredPosition
		end
	end
end
function ThrowGiftsLevelCtrl:AddScore(nScore)
	self.nLevelScore = self.nLevelScore + nScore
	if self.mapCurActiveState[104] ~= nil then
		self.nLevelScore = self.nLevelScore + nScore
	end
	self.parent:SetScore(self.nLevelScore)
end
function ThrowGiftsLevelCtrl:SetPenguinType(rtPenguinRoot, nType, nSpecialType)
	if rtPenguinRoot == nil then
		return
	end
	local rtRed = rtPenguinRoot:Find("penguin_red")
	local rtYellow = rtPenguinRoot:Find("penguin_yellow")
	local rtGreen = rtPenguinRoot:Find("penguin_green")
	local rtGoggles = rtPenguinRoot:Find("penguin_goggles")
	local rtAntenna = rtPenguinRoot:Find("penguin_antenna")
	local rtHelmet = rtPenguinRoot:Find("penguin_helmet")
	local imgFx = rtPenguinRoot:Find("imgFx")
	rtRed.gameObject:SetActive(nType == 2)
	rtYellow.gameObject:SetActive(nType == 3)
	rtGreen.gameObject:SetActive(nType == 1)
	rtGoggles.gameObject:SetActive(nSpecialType == 106)
	rtAntenna.gameObject:SetActive(nSpecialType == 108)
	rtHelmet.gameObject:SetActive(nSpecialType == 107)
	imgFx.gameObject:SetActive(self.mapCurActiveState[105] ~= nil)
end
function ThrowGiftsLevelCtrl:CreateGoal(nSpawnPointId, mapConfig)
	local pointOriginPosX = mapConfig.rtPoint.anchoredPosition.x
	local pointOriginPosY = mapConfig.rtPoint.anchoredPosition.y
	local randomX = math.random(-mapConfig.mapConfig.SpawnRangeTypeX, mapConfig.mapConfig.SpawnRangeTypeX)
	local randomY = math.random(-mapConfig.mapConfig.SpawnRangeTypeY, mapConfig.mapConfig.SpawnRangeTypeY)
	local nType = 0
	if mapConfig.mapConfig.IsRandom then
		nType = mapConfig.mapConfig.GoalType[math.random(1, #mapConfig.mapConfig.GoalType)]
	else
		if mapConfig.nCurGoalIdx > #mapConfig.mapConfig.GoalType then
			mapConfig.nCurGoalIdx = 1
		end
		nType = mapConfig.mapConfig.GoalType[mapConfig.nCurGoalIdx]
		mapConfig.nCurGoalIdx = mapConfig.nCurGoalIdx + 1
	end
	local sPath = string.format(rootPath, nType)
	local goGoalPerfab = GameResourceLoader.LoadAsset(ResTypeAny, Settings.AB_ROOT_PATH .. sPath, typeof(Object))
	if goGoalPerfab ~= nil then
		local goGoal = instantiate(goGoalPerfab, self._mapNode.rtGoalRoot)
		if self.activeGoal[nSpawnPointId] ~= nil then
			destroy(self.activeGoal[nSpawnPointId].rtGoal.gameObject)
			self.activeGoal[nSpawnPointId].rtGoal = nil
			self.activeGoal[nSpawnPointId].rtHitArea = nil
			self.activeGoal[nSpawnPointId].rtObstacle = nil
			self.activeGoal[nSpawnPointId].nType = 0
			self.activeGoal[nSpawnPointId].TMPScore = nil
			self.activeGoal[nSpawnPointId].OffsetX = 0
			self.activeGoal[nSpawnPointId].OffsetY = 0
		end
		self.activeGoal[nSpawnPointId] = {}
		local rtGoal = goGoal:GetComponent("RectTransform")
		rtGoal.anchoredPosition = Vector2(pointOriginPosX + randomX, pointOriginPosY + randomY)
		local rtHitArea = rtGoal:Find("HitArea")
		local rtObstacle = rtGoal:Find("Obstacle")
		local rtItemBuff = rtGoal:Find("AnimRoot/imgItembuff")
		if rtItemBuff ~= nil then
			rtItemBuff.gameObject:SetActive(0 < mapConfig.mapConfig.ItemPool)
		end
		if rtHitArea == nil or rtObstacle == nil then
			printError("预制体结构错误：" .. sPath)
			destroy(goGoal)
			return
		end
		self.activeGoal[nSpawnPointId].rtGoal = rtGoal
		self.activeGoal[nSpawnPointId].nType = nType
		local rtCompHitArea = rtHitArea:GetComponent("RectTransform")
		local rtCompObstacle = rtObstacle:GetComponent("RectTransform")
		self.activeGoal[nSpawnPointId].tbBoundsHitArea = self:GetLocalSpaceRect(rtCompHitArea, rtGoal.parent)
		self.activeGoal[nSpawnPointId].tbBoundsObstacle = self:GetLocalSpaceRect(rtCompObstacle, rtGoal.parent)
		self.activeGoal[nSpawnPointId].OffsetX = 0
		self.activeGoal[nSpawnPointId].OffsetY = 0
		local TMPNode
		local rtTMPScore = rtGoal:Find("AnimRoot/TMPLevelScoreAdd")
		if rtTMPScore ~= nil then
			TMPNode = rtTMPScore:GetComponent("TMP_Text")
		end
		self.activeGoal[nSpawnPointId].TMPScore = TMPNode
	end
end
function ThrowGiftsLevelCtrl:CreateThrowPenguin(nAngle, nVelocity, initPos, nType, nSpecialType)
	self._mapNode.imgBeginningHint:SetActive(false)
	local goPenguin = instantiate(self._mapNode.templateBullet, self._mapNode.rtPenguinRoot)
	local rtPenguin = goPenguin:GetComponent("RectTransform")
	local goImgRoot = rtPenguin:Find("imgRoot")
	local imgFx = goImgRoot:Find("imgFx")
	local rtRed = goImgRoot:Find("penguin_red")
	local rtYellow = goImgRoot:Find("penguin_yellow")
	local rtGreen = goImgRoot:Find("penguin_green")
	local rtGoggles = goImgRoot:Find("penguin_goggles")
	local rtAntenna = goImgRoot:Find("penguin_antenna")
	local rtHelmet = goImgRoot:Find("penguin_helmet")
	local rtImgRoot
	if goImgRoot ~= nil then
		rtImgRoot = goImgRoot:GetComponent("RectTransform")
	end
	rtRed.gameObject:SetActive(nType == 2)
	rtYellow.gameObject:SetActive(nType == 3)
	rtGreen.gameObject:SetActive(nType == 1)
	rtGoggles.gameObject:SetActive(nSpecialType == 106)
	rtAntenna.gameObject:SetActive(nSpecialType == 108)
	rtHelmet.gameObject:SetActive(nSpecialType == 107)
	imgFx.gameObject:SetActive(self.mapCurActiveState[105] ~= nil)
	rtPenguin.anchoredPosition = initPos
	goPenguin:SetActive(true)
	if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
		self._mapNode.rtBlindLevelTrack:Reset()
	end
	local mapGiftPenguin = {
		goGiftPenguin = rtPenguin,
		nState = 0,
		nSpecialType = nSpecialType,
		nType = nType,
		nStartAngle = nAngle,
		nVelocityX = nVelocity * math.cos(math.rad(nAngle)),
		nVelocityY = nVelocity * math.sin(math.rad(nAngle)),
		mapStartPos = initPos,
		rtImgRoot = rtImgRoot,
		tbBounds = self:GetLocalSpaceRect(rtPenguin, rtPenguin.parent),
		curPosX = initPos.x,
		curPosY = initPos.y,
		targetGoal = nil,
		nGetTargetTime = 0,
		nTrackIdx = 0,
		nHitCount = 0,
		tbSubPenguin = {},
		bSplit = false,
		tbCacheSubPenguinGoal = {},
		nHitTime = 0
	}
	if nSpecialType == 108 then
		local rtTrack = instantiate(self._mapNode.rtTemplateTrack, self._mapNode.rtScene)
		rtTrack.transform:SetAsFirstSibling()
		rtTrack:SetActive(true)
		local mapTrackCtrl = self:BindCtrlByNode(rtTrack.gameObject, "Game.UI.Activity.ThrowGifts.ThrowGiftLevelTrackLineCtrl")
		mapTrackCtrl:Reset()
		table.insert(self.tbItemTrackCtrl, mapTrackCtrl)
		mapGiftPenguin.nTrackIdx = #self.tbItemTrackCtrl
	end
	return mapGiftPenguin
end
function ThrowGiftsLevelCtrl:HitGoal(hitPos, hitGoalId)
	local mapSpawnPointData = self.mapGoal[hitGoalId]
	if mapSpawnPointData == nil then
		return
	end
	local mapCurGoalCfg = self.activeGoal[hitGoalId]
	if mapCurGoalCfg == nil then
		return
	end
	if self.tbGuideTrackCtrl ~= nil and #self.tbGuideTrackCtrl ~= 0 then
		self:ClearGuideLine()
	end
	local nType = self.activeGoal[hitGoalId].nType % 10
	local nScore = (self.curPenguinType == nType or self.mapCurActiveState[105] ~= nil) and 200 or 100
	self:AddScore(nScore)
	if self.activeGoal[hitGoalId].TMPScore ~= nil then
		if self.mapCurActiveState[104] ~= nil then
			nScore = nScore * 2
		end
		NovaAPI.SetTMPText(self.activeGoal[hitGoalId].TMPScore, string.format("+%d", nScore))
	end
	self.nTotalHitGoalCount = self.nTotalHitGoalCount + 1
	WwiseAudioMgr:PostEvent("Mode_Present_in")
	self.activeGoal[hitGoalId] = nil
	local AfterAnim = function()
		destroy(mapCurGoalCfg.rtGoal.gameObject)
		if mapSpawnPointData.mapConfig.ActiveCond == GameEnum.ThrowGiftSpawnCond.Random then
			local tbRandom = {}
			for _, nCondSpawnId in ipairs(mapSpawnPointData.mapConfig.SpawnParam) do
				if self.activeGoal[nCondSpawnId] == nil then
					table.insert(tbRandom, nCondSpawnId)
				end
			end
			if 0 < #tbRandom then
				local nRandomId = tbRandom[math.random(1, #tbRandom)]
				if nRandomId ~= nil then
					local mapConfig = self.mapGoal[nRandomId]
					if mapConfig ~= nil then
						self:CreateGoal(nRandomId, mapConfig)
					end
				end
			end
		else
			for nId, mapGoalCfg in pairs(self.mapGoal) do
				if mapGoalCfg.mapConfig.ActiveCond > 0 and #mapGoalCfg.mapConfig.SpawnParam > 0 and 0 < table.indexof(mapGoalCfg.mapConfig.SpawnParam, hitGoalId) then
					if mapGoalCfg.mapConfig.ActiveCond == GameEnum.ThrowGiftSpawnCond.Partial then
						if self.activeGoal[nId] == nil then
							self:CreateGoal(nId, mapGoalCfg)
						end
					elseif mapGoalCfg.mapConfig.ActiveCond == GameEnum.ThrowGiftSpawnCond.All then
						table.insert(mapGoalCfg.curCondId, hitGoalId)
						local bActive = true
						for _, nCondSpawnId in ipairs(mapGoalCfg.mapConfig.SpawnParam) do
							if 1 > table.indexof(mapGoalCfg.curCondId, nCondSpawnId) then
								bActive = false
								break
							end
						end
						if bActive and self.activeGoal[nId] == nil then
							mapGoalCfg.curCondId = {}
							self:CreateGoal(nId, mapGoalCfg)
						end
					end
				end
			end
		end
	end
	local rtAnimRoot = mapCurGoalCfg.rtGoal:Find("AnimRoot")
	local rtItemBuff = mapCurGoalCfg.rtGoal:Find("AnimRoot/imgItembuff")
	if rtItemBuff ~= nil then
		rtItemBuff.gameObject:SetActive(false)
	end
	if rtAnimRoot == nil then
		AfterAnim()
	else
		local animComp = rtAnimRoot:GetComponent("Animator")
		if animComp == nil then
			AfterAnim()
		else
			animComp:Play("BasketFx_in")
			self:AddTimer(1, 0.5, AfterAnim, true, true, true)
		end
	end
end
function ThrowGiftsLevelCtrl:DestroyPenguin()
	WwiseAudioMgr:PostEvent("Mode_Present_out")
	local tempPenguin = self.curGiftPenguin.goGiftPenguin.gameObject.transform
	self.curGiftPenguin = nil
	local wait = function()
		destroy(tempPenguin.gameObject)
	end
	local imgRoot = tempPenguin:Find("imgRoot")
	local imgSmoke = tempPenguin:Find("imgSmoke")
	if imgRoot == nil or imgSmoke == nil then
		wait()
		return
	end
	imgRoot.gameObject:SetActive(false)
	imgSmoke.gameObject:SetActive(true)
	self:AddTimer(1, 0.5, wait, true, true, true)
end
function ThrowGiftsLevelCtrl:DestroySubPenguin(mapSubPenguin)
	WwiseAudioMgr:PostEvent("Mode_Present_out")
	local tempPenguin = mapSubPenguin.goGiftPenguin.gameObject.transform
	local wait = function()
		destroy(tempPenguin.gameObject)
	end
	mapSubPenguin.goGiftPenguin = nil
	local imgRoot = tempPenguin:Find("imgRoot")
	local imgSmoke = tempPenguin:Find("imgSmoke")
	if imgRoot == nil or imgSmoke == nil then
		wait()
		return
	end
	imgRoot.gameObject:SetActive(false)
	imgSmoke.gameObject:SetActive(true)
	self:AddTimer(1, 0.5, wait, true, true, true)
end
function ThrowGiftsLevelCtrl:OnDrag_Beginning(mDrag)
	if self.nLevelType ~= 1 or self.bFlying then
		return
	end
	if mDrag.DragEventType == AllEnum.UIDragType.DragStart then
		local a = self.sceneSize[1] * self.scenePivot[1]
		local b = self.sceneSize[1] / 2
		local c = a - b
		self.curDragBeginPos = {
			x = self._mapNode.rtBeginning.anchoredPosition.x - c,
			y = self._mapNode.rtBeginning.anchoredPosition.y
		}
		local uipos = GameUIUtils.ScreenPointToLocalPoint(mDrag.EventData.position, self._mapNode.rtScene)
		local nSumX = self.curDragBeginPos.x - uipos.x
		local nSumY = self.curDragBeginPos.y - uipos.y
		local nVelocity = 0
		if 0 < nSumX then
			nVelocity = math.sqrt(nSumY * nSumY + nSumX * nSumX) * 2.5
			if nVelocity > self.maxVelocity then
				nVelocity = self.maxVelocity
			elseif nVelocity < 10 then
				nVelocity = 0
			end
		end
		local nAngle = math.atan(nSumY, nSumX) * 180 / math.pi
		if nAngle > self.nAngelMax then
			nAngle = self.nAngelMax
		elseif nAngle < self.nAngleMin then
			nAngle = self.nAngleMin
		end
		self.nCurAngle = nAngle
		if nVelocity < self.minVelovity then
			nVelocity = self.minVelovity
		end
		self.nCurVelocity = nVelocity
		self:SetBeginningAngle(nAngle, nVelocity)
		self:SetBeginningLine(nAngle, nVelocity)
		WwiseAudioMgr:PostEvent("Mode_Present_pre_lp")
		self.parent:SetViewBtn(0)
	elseif mDrag.DragEventType == AllEnum.UIDragType.Drag then
		if self.curDragBeginPos == nil then
			return
		end
		local uipos = GameUIUtils.ScreenPointToLocalPoint(mDrag.EventData.position, self._mapNode.rtScene)
		local nSumX = self.curDragBeginPos.x - uipos.x
		local nSumY = self.curDragBeginPos.y - uipos.y
		local nVelocity = 0
		if 0 < nSumX then
			nVelocity = math.min(1, math.sqrt(nSumY * nSumY + nSumX * nSumX) / 400) * self.maxVelocity
			if nVelocity > self.maxVelocity then
				nVelocity = self.maxVelocity
			elseif nVelocity < 10 then
				nVelocity = 0
			end
		end
		local nAngle = math.atan(nSumY, nSumX) * 180 / math.pi
		if nAngle > self.nAngelMax then
			nAngle = self.nAngelMax
		elseif nAngle < self.nAngleMin then
			nAngle = self.nAngleMin
		end
		self.nCurAngle = nAngle
		if nVelocity < self.minVelovity then
			nVelocity = self.minVelovity
		end
		self.nCurVelocity = nVelocity
		self:SetBeginningAngle(nAngle, nVelocity)
		self:SetBeginningLine(nAngle, nVelocity)
		if self.tbGuideTrackCtrl ~= nil then
			for _, mapLineCtrl in ipairs(self.tbGuideTrackCtrl) do
				mapLineCtrl:SetLineActive(nAngle, nVelocity)
			end
		end
	elseif mDrag.DragEventType == AllEnum.UIDragType.DragEnd then
		if self.curDragBeginPos == nil then
			return
		end
		if self.nCurVelocity == 0 then
			if self.mapLevelCfgData.Difficulty == GameEnum.ThrowGiftDifficulty.Blind then
				self.parent:SetViewBtn(1)
			end
			self.curDragBeginPos = nil
			return
		end
		self.nTotalThrowGiftCount = self.nTotalThrowGiftCount + 1
		self.curDragBeginPos = nil
		self.bFlying = true
		self.nFlyingTime = 0
		self:SetBeginningAngle(self.nCurAngle, 0)
		self:SetBeginningLine(0, 0)
		local nStartVelocity = self.nCurVelocity
		local nStartAngle = self.nCurAngle
		self.nCurAngle = 0
		self.nCurVelocity = 0
		self._mapNode.rtBottleAnim:Play("rtBottle_out")
		WwiseAudioMgr:PostEvent("Mode_Present_pre_lp_stop")
		WwiseAudioMgr:PostEvent("Mode_Present_fire")
		local wait = function()
			local worldPos = self._mapNode.rtBeginningPos:TransformPoint(Vector3.zero)
			local sumPos = self._mapNode.rtBeginning:InverseTransformPoint(worldPos)
			local beginningPos = self._mapNode.rtBeginning.anchoredPosition
			local mapGiftPenguin = self:CreateThrowPenguin(nStartAngle, nStartVelocity, Vector2(beginningPos.x + sumPos.x, beginningPos.y + sumPos.y), self.curPenguinType, self.curPenguinSpecialType)
			self.curPenguinSpecialType = 0
			self.curGiftPenguin = mapGiftPenguin
			if 0 < self.nTotalPenguinCount and self.mapCurActiveState[102] == nil then
				self.nTotalPenguinCount = self.nTotalPenguinCount - 1
			end
			NovaAPI.SetTMPText(self._mapNode.TMPBeginningCountHint, self.nTotalPenguinCount)
		end
		self:AddTimer(1, 0.12, wait, true, true, true)
	end
end
return ThrowGiftsLevelCtrl
