diff --git a/lua/app/common/spine_manager.lua b/lua/app/common/spine_manager.lua index 27974425..2084fa83 100644 --- a/lua/app/common/spine_manager.lua +++ b/lua/app/common/spine_manager.lua @@ -34,6 +34,17 @@ function SpineManager:loadUISpineWidgetAsync(name, parent, callback) end) end +function SpineManager:loadUIHeroSpineWidgetAsync(name, parent, callback) + local path = string.format(HERO_SPINE_ASSET_PATH, name, name) + ResourceManager:loadOriginAssetAsync(path, TYPE_OF_SPINE_ASSET, function(spineAssetPath, spineAsset) + if parent and parent:isDestroyed() then + ResourceManager:unload(spineAssetPath) + return + end + self:loadUISpinePrefabAsync(parent, spineAssetPath, spineAsset, callback) + end) +end + function SpineManager:loadUISpinePrefabAsync(parent, spineAssetPath, spineAsset, callback) ResourceManager:loadAsync(UI_SPINE_PREFAB_PATH, TYPE_OF_GAME_OBJECT, function(prefabPath, prefab) if parent and parent:isDestroyed() then diff --git a/lua/app/ui/main_city/component/chapter_comp.lua b/lua/app/ui/main_city/component/chapter_comp.lua index 75dca4b3..36bacfe3 100644 --- a/lua/app/ui/main_city/component/chapter_comp.lua +++ b/lua/app/ui/main_city/component/chapter_comp.lua @@ -1,6 +1,11 @@ -local MainCompBaseCell = require "app/ui/main_city/component/main_comp_base_cell" -local ChapterComp = class("ChapterComp", MainCompBaseCell) -local CHAPTER_PATH = "assets/arts/textures/background/chapter/%s.png" +local ChapterCompBaseCell = require "app/ui/main_city/component/main_comp_base_cell" +local ChapterComp = class("ChapterComp", ChapterCompBaseCell) + +local UISpineObject = require "app/bf/unity/ui_spine_object" + +-- local CHAPTER_PATH = "assets/arts/textures/background/chapter/%s.png" +local HERO_SPINE_ASSET_PATH = "assets/arts/spines/characters/%s/%s_skeletondata.asset" +local CHAPTER_PATH = "assets/arts/textures/background/main/%s.png" local BOX_ICON = { "common_chest_1", @@ -64,6 +69,29 @@ function ChapterComp:initChapter() end) self.uiMap["chapter.effect_node.ui_spine_obj"]:playAnim("idle", true, false) + + self.chapterBg = self.uiMap["chapter_comp.bg"] + self.chapterBg:setAnchoredPositionX(-720) + self.bossSmoke = self.uiMap["chapter_comp.boss_smoke"] + self.bossSmoke:setAnchoredPositionX(10000) + self.smokeNodeTop = self.uiMap["chapter_comp.smoke_node_1"] + self.monsterNodeTop = self.uiMap["chapter_comp.monster_node_1"] + self.bossNode = self.uiMap["chapter_comp.boss_node"] + self.bossNode:setActive(false) + self.bossSpine = self.uiMap["chapter_comp.boss_node.boss"] + self.smokeNodeDown = self.uiMap["chapter_comp.smoke_node_2"] + self.monsterNodeDown = self.uiMap["chapter_comp.monster_node_2"] + self.dialogueTx = self.uiMap["chapter_comp.dialogue_node.bg.text"] + self.dialogueBg = self.uiMap["chapter_comp.dialogue_node.bg"] + self.dialogueNode = self.uiMap["chapter_comp.dialogue_node"] + self.dialogueNode:setAnchoredPositionX(0) + self.monsterSpineTopPool = {} + self.monsterSpineDownPool = {} + self.monsterSpineTopList = {} + self.monsterSpineDownList = {} + -- self.monsterShadowPool = {} + self.monsterSmokePool = {} + self.startMonsterAction = true end function ChapterComp:refresh() @@ -88,7 +116,20 @@ function ChapterComp:refreshChapter(force) local chapterInfo = ConfigManager:getConfig("chapter")[chapterId] local chapterI18NInfo = I18N:getConfig("chapter")[chapterId] if chapterInfo then - self.chapterImg:setTexture(string.format(CHAPTER_PATH, chapterInfo.icon)) + local monsterIdList = chapterInfo.monster_id + if monsterIdList then + local bossId = monsterIdList[1] + if bossId then + local monsterCfg = ConfigManager:getConfig("monster_base") + local monsterInfo = monsterCfg[bossId] + if monsterInfo then + -- self.dialogueBg:setAnchoredPositionY(monsterInfo.blood * monsterInfo.ui/10 + 20) + end + end + end + -- main_bg_1 + -- self.chapterBg:setTexture(string.format(CHAPTER_PATH, chapterInfo.scenes_a)) end + self.chapterBg:setTexture(string.format(CHAPTER_PATH, "main_bg_1")) end if chapterI18NInfo then self.chapterNameTx:setText(chapterI18NInfo.name) @@ -186,7 +227,490 @@ function ChapterComp:refreshChapter(force) end self:refreshFightBtn() + self:doBossAction() + end + self:doChapterMove() + self:doMonsterAction() +end + +function ChapterComp:onOpen() + self.startMonsterAction = true + if self.bossNode then + self.bossNode:setAnchoredPositionX(0) + end + -- if self.bossShadow then + -- self.bossShadow:setAnchoredPositionX(0) + -- end + if self.dialogueNode then + self.dialogueNode:setAnchoredPositionX(0) end end +function ChapterComp:onClose() + if self.chapterMoveSeq then + self.chapterMoveSeq:Kill() + self.chapterMoveSeq = nil + end + if self.chapterMonsterGenerateSeq then + self.chapterMonsterGenerateSeq:Kill() + self.chapterMonsterGenerateSeq = nil + end + self.currChapterId = nil + self.isTopTurn = nil + self.startMonsterAction = false + GFunc.killDOTween(GConst.DOTWEEN_IDS.CHAPTER_MONSTER) + self.monsterSpineTopPool = {} + self.monsterSpineDownPool = {} + self.monsterSpineTopList = {} + self.monsterSpineDownList = {} + -- self.monsterShadowPool = {} + self.monsterSmokePool = {} + self.monsterNodeTop:removeAllChildren() + self.monsterNodeDown:removeAllChildren() + -- self.shadowNode:removeAllChildren() + self.smokeNodeTop:removeAllChildren() + self.smokeNodeDown:removeAllChildren() +end + +-- region 动画 +function ChapterComp:doChapterMove() + if self.chapterMoveSeq then + return + end + self.chapterBg:setAnchoredPositionX(-720) + self.chapterMoveSeq = self.chapterBg:createBindTweenSequence() + local moveTween = self.chapterBg:getTransform():DOAnchorPosX(720, 20):SetEase(CS.DG.Tweening.Ease.Linear) + self.chapterMoveSeq:Append(moveTween) + self.chapterMoveSeq:AppendCallback(function() + self.chapterBg:setAnchoredPositionX(-720) + end) + self.chapterMoveSeq:SetLoops(-1) +end + +function ChapterComp:doBossAction() + if self.currChapterId == nil then + return + end + local chapterInfo = ConfigManager:getConfig("chapter")[self.currChapterId] + if chapterInfo == nil then + return + end + local monsterIdList = chapterInfo.monster_id + monsterIdList = {20001, 10001, 10002} + if monsterIdList == nil then + return + end + self.chapterMonsterShowList = monsterIdList + if self.chapterBossId == nil then -- 还没显示boss模型 + self.chapterBossId = self.chapterMonsterShowList[1] + local chapterBossId = self.chapterBossId + local monsterCfg = ConfigManager:getConfig("monster_base") + local monsterInfo = monsterCfg[self.chapterBossId] + if monsterInfo then + local modelId = monsterInfo.model_id + local path = string.format(HERO_SPINE_ASSET_PATH, modelId, modelId) + self.bossNode:setActive(false) + local scale = monsterInfo.ui or 1 + local shadowScale = (monsterInfo.shadow or 1) * scale + -- local shadowOffset = (monsterInfo.shadow_offset or 0) * scale + -- self.bossShadow:setLocalScale(shadowScale, shadowScale, shadowScale) + -- self.bossShadow:setAnchoredPosition(10000, shadowOffset) + self.bossSmoke:setLocalScale(-shadowScale, shadowScale, shadowScale) + self.bossSmoke:setAnchoredPositionX(10000) + self.bossSpine:loadAssetAsync(modelId, function() + if chapterBossId == self.chapterBossId then + self.bossNode:setActive(true) + self.bossSpine:setLocalScale(-scale, scale, scale) + self.bossSpine:playAnim("move", true, true, true) + -- self.bossShadow:setAnchoredPositionX(0) + self.bossSmoke:playAnim("idle", true, true, true) + self.bossSmoke:setAnchoredPositionX(0) + else -- 加载完成后,已经切换到其他boss了 + self:doChangeBossAction() + end + end, path) + end + else + local chapterBossId = self.chapterMonsterShowList[1] + if self.chapterBossId ~= chapterBossId then + self.chapterBossId = chapterBossId + self:doChangeBossAction() + end + end +end + +-- 切换boss +function ChapterComp:doChangeBossAction() + local chapterBossId = self.chapterBossId + local monsterCfg = ConfigManager:getConfig("monster_base") + local monsterInfo = monsterCfg[self.chapterBossId] + if monsterInfo then + local modelId = monsterInfo.model_id + local path = string.format(HERO_SPINE_ASSET_PATH, modelId, modelId) + self.bossNode:setActive(false) + local scale = monsterInfo.ui or 1 + local shadowScale = (monsterInfo.shadow or 1) * scale + -- local shadowOffset = (monsterInfo.shadow_offset or 0) * scale + -- self.bossShadow:setLocalScale(shadowScale, shadowScale, shadowScale) + -- self.bossShadow:setAnchoredPosition(10000, shadowOffset) + self.bossSmoke:setLocalScale(-shadowScale, shadowScale, shadowScale) + self.bossSmoke:setAnchoredPositionX(10000) + self.bossSpine:loadAssetAsync(modelId, function() + if chapterBossId == self.chapterBossId then + self.bossNode:setActive(true) + self.bossSpine:setLocalScale(-scale, scale, scale) + self.bossSpine:playAnim("move", true, true, true) + -- self.bossShadow:setAnchoredPositionX(0) + self.bossSmoke:playAnim("idle", true, true, true) + self.bossSmoke:setAnchoredPositionX(0) + else -- 加载完成后,已经切换到其他boss了 + self:doChangeBossAction() + end + end, path) + end +end + +function ChapterComp:doMonsterAction() + if self.chapterMonsterGenerateSeq then + return + end + self.chapterMonsterGenerateSeq = DOTweenManager:createSeqWithIntId() + local interval = GFunc.getConstValue("chapter_idel_monster_x") / 1000 + interval = 2 + self.chapterMonsterGenerateSeq:AppendCallback(function() + self:generateChapterMonsters() + end) + self.chapterMonsterGenerateSeq:AppendInterval(interval) + self.chapterMonsterGenerateSeq:SetLoops(-1) +end + +function ChapterComp:generateChapterMonsters() + local monsterId + if #self.chapterMonsterShowList <= 2 then + monsterId = self.chapterMonsterShowList[2] + else + monsterId = self.chapterMonsterShowList[math.random(2, #self.chapterMonsterShowList)] + end + if monsterId == nil then + return + end + local monsterCfg = ConfigManager:getConfig("monster_base") + local monsterInfo = monsterCfg[monsterId] + Logger.logHighlight("================== monsterInfo = %s", monsterInfo) + if monsterInfo == nil then + return + end + if self.isTopTurn == nil then + self.isTopTurn = math.random(1, 100) > 50 + end + local modelId = monsterInfo.model_id + local pool + local list + local parent + local posY + if self.isTopTurn then -- 刷上面 + pool = self.monsterSpineTopPool[modelId] + list = self.monsterSpineTopList + parent = self.monsterNodeTop + posY = math.random(1, 300) + else -- 刷下面 + pool = self.monsterSpineDownPool[modelId] + list = self.monsterSpineDownList + parent = self.monsterNodeDown + posY = -math.random(1, 240) + end + self.isTopTurn = not self.isTopTurn + Logger.logHighlight("================== parent = %s", parent) + Logger.logHighlight("================== modelId = %s", modelId) + if pool and #pool > 0 then + local spine = table.remove(pool) + table.insert(list, spine) + spine:setActive(true) + self:doMonsterMove(modelId, spine, posY, monsterInfo, not self.isTopTurn) + else + SpineManager:loadUIHeroSpineWidgetAsync(modelId, parent, function(spine) + Logger.logHighlight("==================1 self.startMonsterAction = %s", self.startMonsterAction) + if not self.startMonsterAction then + spine:destroy() + return + end + Logger.logHighlight("==================2 self.startMonsterAction = %s", self.startMonsterAction) + table.insert(list, spine) + local scale = monsterInfo.ui or 1 + spine:setLocalScale(-scale, scale, scale) + self:doMonsterMove(modelId, spine, posY, monsterInfo, not self.isTopTurn) + end) + end +end + +function ChapterComp:doMonsterMove(modelId, spine, posY, monsterInfo, isTopTurn) + spine:playAnim("move", true, true, true) + local posX = GConst.UI_SCREEN_WIDTH / 2 + 100 + local targetPosX = -GConst.UI_SCREEN_WIDTH / 2 - 300 + spine:setAnchoredPosition(posX, posY) + local seq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.CHAPTER_MONSTER) + if self.chapterMonsterSpeed == nil then + -- self.chapterMonsterSpeed = GFunc.getConstValue("chapter_idel_monstermove") + self.chapterMonsterSpeed = 150 + end + local distance = posX - targetPosX + local moveTime = distance / self.chapterMonsterSpeed + local moveTween = spine:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + seq:Append(moveTween) + + -- local monsterShadow = self:getMonsterShadow() + local scale = monsterInfo.ui or 1 + local shadowScale = (monsterInfo.shadow or 1) * scale + -- monsterShadow:setLocalScale(shadowScale, shadowScale, shadowScale) + -- local shadowOffset = (monsterInfo.shadow_offset or 0) * scale + -- monsterShadow:setAnchoredPosition(posX, posY + shadowOffset) + -- local moveTween2 = monsterShadow:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + -- seq:Join(moveTween2) + + local monsterSmoke = self:getMonsterSmoke(isTopTurn) + monsterSmoke:setAnchoredPosition(posX, posY) + monsterSmoke:setLocalScale(-shadowScale, shadowScale, shadowScale) + monsterSmoke:playAnim("idle", true, true, true) + local moveTween3 = monsterSmoke:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + seq:Join(moveTween3) + + seq:AppendCallback(function() + spine:setActive(false) + -- monsterShadow:setAnchoredPositionX(10000) + -- table.insert(self.monsterShadowPool, monsterShadow) + monsterSmoke:setAnchoredPositionX(10000) + table.insert(self.monsterSmokePool, monsterSmoke) + if isTopTurn then + local pool = self.monsterSpineTopPool[modelId] + if pool == nil then + pool = {} + self.monsterSpineTopPool[modelId] = pool + end + table.insert(pool, spine) + for k, v in ipairs(self.monsterSpineTopList) do + if v == spine then + table.remove(self.monsterSpineTopList, k) + break + end + end + else + local pool = self.monsterSpineDownPool[modelId] + if pool == nil then + pool = {} + self.monsterSpineDownPool[modelId] = pool + end + table.insert(pool, spine) + for k, v in ipairs(self.monsterSpineDownList) do + if v == spine then + table.remove(self.monsterSpineDownList, k) + break + end + end + end + end) +end + +function ChapterComp:enterChapterBattle() + -- boss等一会再跑 + local bossWaitTime = GFunc.getConstValue("chapter_fight_bosswait") / 1000 + local bossSeq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.CHAPTER_MONSTER) + bossSeq:AppendInterval(bossWaitTime) + local bossSpeed = GFunc.getConstValue("chapter_fight_bossmove") + local distance = GConst.UI_SCREEN_WIDTH/2 + 100 + local moveTime = distance / bossSpeed + local targetPosX = -GConst.UI_SCREEN_WIDTH / 2 - 300 + local moveTween = self.bossNode:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + bossSeq:Append(moveTween) + local moveTween2 = self.dialogueNode:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + bossSeq:Join(moveTween2) + -- local moveTween3 = self.bossShadow:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + -- bossSeq:Join(moveTween3) + + + -- 出来一批小怪从右边跑向左边 + local monsterCount = GFunc.getConstIntValue("chapter_fight_monster_num") + self.chapterFightMonsterCount = monsterCount + local wave = 5 + local monsterCountPerWave = math.ceil(monsterCount / wave) + -- 分批处理 + local monsterSeq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.CHAPTER_MONSTER) + for i = 1, wave do + monsterSeq:AppendCallback(function () + if monsterCountPerWave > monsterCount then + monsterCountPerWave = monsterCount + end + monsterCount = monsterCount - monsterCountPerWave + for j = 1, monsterCountPerWave do + self:generateChapterFightMonsters() + end + end) + monsterSeq:AppendInterval(0.03) + end + return GFunc.getConstValue("chapter_fight_wait") / 1000 +end + +function ChapterComp:generateChapterFightMonsters() + local monsterId + if #self.chapterMonsterShowList <= 2 then + monsterId = self.chapterMonsterShowList[2] + else + monsterId = self.chapterMonsterShowList[math.random(2, #self.chapterMonsterShowList)] + end + if monsterId == nil then + return + end + local monsterCfg = ConfigManager:getConfig("monster_base") + local monsterInfo = monsterCfg[monsterId] + if monsterInfo == nil then + return + end + local modelId = monsterInfo.model_id + local pool + local list + local parent + local posY + if self.isTopTurn then -- 刷上面 + pool = self.monsterSpineTopPool[modelId] + list = self.monsterSpineTopList + parent = self.monsterNodeTop + posY = math.random(1, 300) + else -- 刷下面 + pool = self.monsterSpineDownPool[modelId] + list = self.monsterSpineDownList + parent = self.monsterNodeDown + posY = -math.random(1, 240) + end + self.isTopTurn = not self.isTopTurn + if pool and #pool > 0 then + local spine = table.remove(pool) + table.insert(list, spine) + spine:setActive(true) + self:doMonsterFightMove(modelId, spine, posY, monsterInfo, not self.isTopTurn) + else + SpineManager:loadUIHeroSpineWidgetAsync(modelId, parent, function(spine) + if not self.startMonsterAction then + spine:destroy() + return + end + table.insert(list, spine) + local scale = monsterInfo.ui or 1 + spine:setLocalScale(-scale, scale, scale) + self:doMonsterFightMove(modelId, spine, posY, monsterInfo, not self.isTopTurn) + end) + end +end + +function ChapterComp:doMonsterFightMove(modelId, spine, posY, monsterInfo, isTopTurn) + spine:playAnim("move", true, true, true) + local posX = GConst.UI_SCREEN_WIDTH / 2 + math.random(100, math.floor(GConst.UI_SCREEN_WIDTH*2/3)) + spine:setAnchoredPosition(posX, posY) + local seq = DOTweenManager:createSeqWithIntId(GConst.DOTWEEN_IDS.CHAPTER_MONSTER) + if self.chapterMonsterFightSpeed == nil then + -- self.chapterMonsterFightSpeed = GFunc.getConstValue("chapter_fight_monstermove") + self.chapterMonsterFightSpeed = 880 + end + local distance = posX + GConst.UI_SCREEN_WIDTH/2 + 100 + local moveTime = distance / self.chapterMonsterFightSpeed + local targetPosX = -GConst.UI_SCREEN_WIDTH / 2 - 100 + local moveTween = spine:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + seq:Append(moveTween) + + -- local monsterShadow = self:getMonsterShadow() + local scale = monsterInfo.ui or 1 + local shadowScale = (monsterInfo.shadow or 1) * scale + -- monsterShadow:setLocalScale(shadowScale, shadowScale, shadowScale) + -- local shadowOffset = (monsterInfo.shadow_offset or 0) * scale + -- monsterShadow:setAnchoredPosition(posX, posY + shadowOffset) + -- local moveTween2 = monsterShadow:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + -- seq:Join(moveTween2) + + local monsterSmoke = self:getMonsterSmoke(isTopTurn) + monsterSmoke:setAnchoredPosition(posX, posY) + monsterSmoke:setLocalScale(-shadowScale, shadowScale, shadowScale) + monsterSmoke:playAnim("idle", true, true, true) + local moveTween3 = monsterSmoke:getTransform():DOAnchorPosX(targetPosX, moveTime):SetEase(CS.DG.Tweening.Ease.Linear) + seq:Join(moveTween3) + + seq:AppendCallback(function() + spine:setActive(false) + -- monsterShadow:setAnchoredPositionX(10000) + -- table.insert(self.monsterShadowPool, monsterShadow) + monsterSmoke:setAnchoredPositionX(10000) + table.insert(self.monsterSmokePool, monsterSmoke) + if isTopTurn then + local pool = self.monsterSpineTopPool[modelId] + if pool == nil then + pool = {} + self.monsterSpineTopPool[modelId] = pool + end + table.insert(pool, spine) + for k, v in ipairs(self.monsterSpineTopList) do + if v == spine then + table.remove(self.monsterSpineTopList, k) + break + end + end + else + local pool = self.monsterSpineDownPool[modelId] + if pool == nil then + pool = {} + self.monsterSpineDownPool[modelId] = pool + end + table.insert(pool, spine) + for k, v in ipairs(self.monsterSpineDownList) do + if v == spine then + table.remove(self.monsterSpineDownList, k) + break + end + end + end + end) + + if self.chapterFightMonsterCount then + self.chapterFightMonsterCount = self.chapterFightMonsterCount - 1 + if self.chapterFightMonsterCount == 0 then -- 最后一个怪物生成完毕后,重新排一下序 + self:sortChapterFightMonstersOrder() + self:sortChapterFightMonstersOrder() + self:sortChapterFightMonstersOrder() + self:sortChapterFightMonstersOrder() + end + end +end + +function ChapterComp:sortChapterFightMonstersOrder() + self:sortChildrenOrder(self.monsterNodeTop) + self:sortChildrenOrder(self.monsterNodeDown) + self:sortChildrenOrder(self.smokeNodeTop) + self:sortChildrenOrder(self.smokeNodeDown) +end + +function ChapterComp:sortChildrenOrder(parent) + local children = parent:getChildList() + if children and #children > 0 then + table.sort(children, function(a, b) + return a:getAnchoredPositionY() > b:getAnchoredPositionY() + end) + + for i = #children, 1, -1 do + children[i]:getTransform():SetSiblingIndex(i - 1) + end + end +end + +function ChapterComp:getMonsterSmoke(isTop) + local monsterSmoke + if #self.monsterSmokePool > 0 then + monsterSmoke = table.remove(self.monsterSmokePool) + monsterSmoke:setParent(isTop and self.smokeNodeTop or self.smokeNodeDown, false) + else + local shadowObj = CS.UnityEngine.Object.Instantiate(self.bossSmoke:getGameObject()) + monsterSmoke = UISpineObject:create() + monsterSmoke:initWithPrefab(GConst.EMPTY_STRING, shadowObj) + monsterSmoke:getAnimationState() + monsterSmoke:setParent(isTop and self.smokeNodeTop or self.smokeNodeDown, false) + end + return monsterSmoke +end +-- endregion + return ChapterComp \ No newline at end of file