1.设计初心
在玩家接取任务/交付任务时,界面弹出的UI ,需要与玩家互动,点击“接取”“完成”。等等字样
【改动前】
频繁的手动点击会中断玩家跑图的流畅性,也降低了任务寻路系统的实际体验。
于是现在变成类似FakeObj + 对话框的模式去显示任务的提示字。不再显示任务的接取 / 完成 状态。
自动接取任务。
【改动后】
2.逻辑梳理
在任务完成时通过ObjNpc.ShowDialg(); 显示弹窗
现在需要改动这里面的内容。
bool ShowMission(){if (true == SetFindNpcMisCompleted()){return true;} // 弹出已完成任务if (true == PopCommitNpcDialog()){return true;}// 弹出可接任务if (true == PopAcceptNpcDialog()){return true;}return false;}
拿已经完成的任务来说,需要改动 PopCommitNpcDialog()
现在在任务MisBase配置表中加了新的一列,决定是否启用对话框代替任务弹板。当PopType 字段为1 表示启用
第一步读取字典,判断显示方式
Tab_MisBase misBase = TableManager.GetMisBaseByID(nMisID);//弹窗
if (misBase.PopType == 0)
{//...
}
else
{//...StoryPlayerController.PlayMisDialogue(1, MissionManager.MisCommit,nMisID);
}
在PlayMisDialogue方法中我们需要一个任务ID 和 当前任务状态来标识。
public static bool PlayMisDialogue(int misState,OnFinshMisTips finshMisTips = null,int param = -1){m_curMisState = misState;Init(finshMisTips, param);UIManager.CloseUI(UIInfo.OnlineReminderWindow);return UIManager.ShowUI(UIInfo.StoryPlayer);}
我设置了三个参数,第一个是任务号标识当前任务,第二个需要接受一个对话框显示结束后的逻辑,可能需要更新任务状态,同步服务器(已完成)等等。
static void Init(OnFinshMisTips finshMisTips = null, int param = -1){m_finshMisTips = finshMisTips;misID = param;m_StoryTab = null;isMisTips = true;if (m_Instance != null){m_Instance.isPlayFinish = false;m_Instance.m_BaseOffset.SetActive(true);}}
Init作为初始化对话框的前序操作。主要是存储数据到文件里。
接下来是异步的关闭提示窗口打开剧情对话框。
播放剧情逻辑
private void PlayMissionTips(int misState){if (!isMisTips){OnPlayOver();return;}Tab_MisDictionary misDictionary = TableManager.GetMisDictionaryByID(misID);string dialogue = string.Empty;if (misState == 0){dialogue = misDictionary.GetAceptDescbyIndex(0); }else{dialogue = misDictionary.GetComitDescbyIndex(0);}int curNpcId = misState == 0 ? misDictionary.AceptNpcDataID : misDictionary.ComitNpcDataID;//生成对话框头像InitCharUI(curNpcId);m_strAniDialog = dialogue;ShowAniDialogEnd();m_fStoryTimer = 5f;isMisTips = false;//播放结束后处理m_curMisState = -1;}
初始化对话框人物头像和角色信息
private void InitCharUI(int nSpeakerID){string strSpeakerName = string.Empty;int nDataID = nSpeakerID;Obj_Char objChar = null;if (GlobeVar.INVALID_ID == nDataID){// 主角nDataID = ObjManager.MainPlayer.RoleBaseID;strSpeakerName = ObjManager.MainPlayer.RoleName;m_SpeakerName.text = strSpeakerName;if (m_NpcFakeObj){m_NpcFakeObj.gameObject.SetActive(false);}if (m_ChildFakeObj){m_ChildFakeObj.gameObject.SetActive(false);}// 已经有缓存了if (m_PlayerFakeObj != null){m_PlayerFakeObj.gameObject.SetActive(true);m_PlayerFakeObj.ResetFakeObjTransform();RefixFakeObjCamera(m_PlayerFakeObj);return;}// 创建模型GameManager.CurActiveScene.ShowFakeCamera(true);m_PlayerFakeObj = m_UIObjTexture.ShowMainPlayerFakeObj(FAKEOBJTYPE.HALF, RefixFakeObjCamera);return;}else if (-2 == nDataID){// 孩子if (m_PlayerFakeObj){m_PlayerFakeObj.gameObject.SetActive(false);}if (m_NpcFakeObj){m_NpcFakeObj.gameObject.SetActive(false);}// 已经有缓存了if (m_ChildFakeObj != null){m_ChildFakeObj.gameObject.SetActive(true);m_ChildFakeObj.ResetFakeObjTransform();RefixFakeObjCamera(m_ChildFakeObj);return;}ChildInfo m_CurChild = null;if (GameManager.PlayerDataPool.PlayerBirthManager.IsHaveSelfChild(true)){m_CurChild = GameManager.PlayerDataPool.PlayerBirthManager.m_ChildInfo;}if (m_CurChild == null){return;}else{strSpeakerName = m_CurChild.m_Name;m_SpeakerName.text = strSpeakerName;int childType = m_CurChild.GetChildType();Tab_ChildInfo tabChildInfo = TableManager.GetChildInfoByID(childType);if (tabChildInfo != null){Tab_CharModel charModel = TableManager.GetCharModelByID(tabChildInfo.BodyIdFakeObj);if (charModel != null){AvatarLoadInfo info = ChildFashionManager.GetChildAvatarInfo(m_CurChild);GameManager.CurActiveScene.ShowFakeCamera(true);//m_ChildFakeObj = ObjManager.CreateFakeObj(charModel.HalfFakeOjbID, info, GlobeVar.INVALID_ID, "Child", null, GlobeVar.FAKEOBJ_LAYER, GlobeVar.INVALID_ID, RefixFakeObjCamera);m_ChildFakeObj = m_UIObjTexture.ShowFakeObj(charModel.HalfFakeOjbID, info, -1, -1, -1,RefixFakeObjCamera);return;}}}}else{// 普通NPCTab_NpcAttr NpcAttr = TableManager.GetNpcAttrByID(nDataID);if (NpcAttr != null){//冒牌师姐任务特殊处理,npc名字改成玩家名字if (nDataID == 8345 && GameManager.RunningScene == (int)SCENE_DEFINE.SCENE_MAOPAISHIJIE){strSpeakerName = ObjManager.MainPlayer.RoleName; }else {strSpeakerName = NpcAttr.Name;}m_SpeakerName.text = strSpeakerName;if (m_PlayerFakeObj){m_PlayerFakeObj.gameObject.SetActive(false);}if (m_ChildFakeObj){m_ChildFakeObj.gameObject.SetActive(false);}// 已经有缓存了if (m_NpcFakeObj != null && m_NpcFakeObj.gameObject.name == nDataID.ToString()){m_NpcFakeObj.gameObject.SetActive(true);m_NpcFakeObj.ResetFakeObjTransform();RefixFakeObjCamera(m_NpcFakeObj);return;}// 创建模型Tab_RoleBaseAttr RoleBase = TableManager.GetRoleBaseAttrByID(nDataID);if (RoleBase != null){objChar = ObjManager.FindObjCharInSceneByData(nDataID);if (objChar != null){Tab_CharModel charModel = TableManager.GetCharModelByID(RoleBase.CharModelID);if (charModel != null){if (m_NpcFakeObj != null){GameObject.DestroyImmediate(m_NpcFakeObj.gameObject);}GameManager.CurActiveScene.ShowFakeCamera(true);//m_NpcFakeObj = ObjManager.CreateFakeObj(charModel.HalfFakeOjbID, objChar, nDataID.ToString(), null, GlobeVar.FAKEOBJ_LAYER, RefixFakeObjCamera); m_NpcFakeObj = m_UIObjTexture.ShowFakeObj(charModel.HalfFakeOjbID, objChar, RefixFakeObjCamera);return;}}else{// 找不到Tab_CharModel charModel = TableManager.GetCharModelByID(RoleBase.CharModelID);if (charModel != null){if (m_NpcFakeObj != null){GameObject.DestroyImmediate(m_NpcFakeObj.gameObject);}int nNpcProfession = GlobeVar.INVALID_ID;AvatarLoadInfo info = new AvatarLoadInfo();info.m_BodyId = charModel.Id;//增加Npc头身分离逻辑Tab_NpcAttr npcAttr = TableManager.GetNpcAttrByID(nDataID);if (npcAttr != null && npcAttr.IsHeadBodyLeave == 1){Tab_NpcModelInfo modelinfo = TableManager.GetNpcModelInfoByID(nDataID);if (modelinfo != null){info.m_FaceId = modelinfo.FaceModelId;info.m_HairId = modelinfo.HairModelId;if (modelinfo.WeaponModelId != -1){info.m_WeaponId = modelinfo.WeaponModelId;nNpcProfession = modelinfo.AvatarProfession;}}}GameManager.CurActiveScene.ShowFakeCamera(true);//m_NpcFakeObj = ObjManager.CreateFakeObj(charModel.HalfFakeOjbID, info, -1, nDataID.ToString(), null, GlobeVar.FAKEOBJ_LAYER, GlobeVar.INVALID_ID, RefixFakeObjCamera); m_NpcFakeObj = m_UIObjTexture.ShowFakeObj(charModel.HalfFakeOjbID, info, nNpcProfession, -1, -1,RefixFakeObjCamera);return;}}}}}}
他会根据NPCid 分为三类,玩家、场景NPC 和其他Obj 头像(可能是一团火、或者怪物 )
他们读取的配置表不同。
ShowAniDialogEnd()的内容很简单,大概就是把任务提示的内容,保存到本地str,便于后续播放。
播放字幕
在FixUpdate中更新内容
void FixedUpdate(){if(isPlayFinish)return;Tick_PlayStory();}
逻辑如下
void Tick_PlayStory(){if (false != m_bAniDialog){return;}if (StoryTriggerCtl.Instance.IsPlaying()){return;}if (m_fStoryTimer == GlobeVar.INVALID_ID || m_fStoryTimer <= 0){if (!isMisTips){if (m_nextBlackScreenId > 0 && !m_bAniDialog){StoryTriggerCtl.Instance.ToStartBlackScreen(m_nextBlackScreenId, onPlayFinished: PlayNextCallback);m_nextBlackScreenId = -1;}else{PlayNext();}}else{PlayMissionTips(m_curMisState);}}else{m_fStoryTimer -= Time.fixedDeltaTime;}}
当下一个对话内容不为空的时候,PlayNext()
主要是从对应的剧情字典Tab_StoryContent中取相应播放的文案。
void PlayNext(){if (m_bAniDialog){// 动态文字展示ShowAniDialogEnd();}else{if (m_StoryTab == null){OnPlayOver();return; }m_nStoryIndex++;Tab_StoryContent mStoryItem = TableManager.GetStoryContentByID(m_StoryTab.StoryID, m_nStoryIndex);if (null == mStoryItem){OnPlayOver();return; }UpdateStoryUI(mStoryItem);//更新下一组对话框时间m_fStoryTimer = mStoryItem.LifeTime;JudgeSpeaker(mStoryItem);if (mStoryItem.BlackScreenEffect > 0)m_nextBlackScreenId = mStoryItem.BlackScreenEffect;}}
更新时间间隔在 m_fStoryTimer = mStoryItem.LifeTime;中
在FixUpdate中
m_fStoryTimer -= Time.fixedDeltaTime;计时