成语json_cocos creator实战(2)成语小秀才ts版
生活随笔
收集整理的這篇文章主要介紹了
成语json_cocos creator实战(2)成语小秀才ts版
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1 分析
公司要求做h5小游戲之前,想要做的一款類似成語小秀才的小游戲。學了一段時間ccc后回頭填坑,嘗試仿制一波,剛好發現論壇有套開源的ui素材。花了兩天做的demo。做完后發現最難的是生成隨機關卡,由于益智類小游戲動輒幾百上千關,編寫較高質量的關卡隨機算法還是很有難度的。
- 玩法:每個成語最多空缺兩個位置,選擇對應的詞填入成語中,全對即可過關。
界面分三部分,頂部關卡信息、成語區、選詞區。
- 成語區實際上是9*9的布局,共81的格子,只顯示了有詞的格子,開啟調試模式可以顯示所有的格子。
- 選詞區顯示成語中空缺的詞
2 代碼結構
2.1 關卡數據結構
正式上線的話,需要開發服務端用于返回關卡數據和保存用戶信息。客戶端通過http請求獲取關卡數據,同時可以上傳分數等信息。demo中沒有用到服務端,直接本地掛載關卡數據,關卡數據保存在json文件中。
id????--->?成語id,對應成語庫中的成語grids?--->?保存成語中四個字的位置
???????????id?--->?所處的格子位置
???????????space?--->?該字是否為空缺
{
????"id":?4959,
????"grids":?[
????????{
????????????"id":?18,
????????????"space":?false
????????},
????????{
????????????"id":?27,
????????????"space":?true
????????},
????????{
????????????"id":?36,
????????????"space":?false
????????},
????????{
????????????"id":?45,
????????????"space":?true
????????}
????]
}
2.2 詞條數據對象
用一個類來描述成語詞條的基本數據,它對應詞庫中的一條成語。
//?IdiomData.tsexport?class?IdiomData?{
????public?id:?number?=?0;??????????//?詞條id
????public?chars:?string?=?null;????//?完整成語,例如"一馬當先"
????public?pinyin:?string?=?null;???//?詞條拼音
????public?note:?string?=?null;?????//?詞條出處和釋義
}
2.3 詞條對象
用一個類來描述關卡中出現的每一條成語對象。
- 記錄占用的格子
- 保存詞條數據對象
export?class?Idiom?{
????public?grids?=?[];??????//?記錄占用的格子
????public?data?=?null;?????//?詞條數據
????public?constructor(grids,?idiomdataObj)?{
????????this.data?=?idiomdataObj;
????????for?(let?i?=?0;?i?????????????this.grids.push(grids[i]);
????????}
????}
}
2.4 格子對象
用一個類來描述每個格子的狀態和行為。
- 記錄格子id
- 該格子使用狀態
- 保存完整的成語數據
- 格子上需要填寫的字符
- 保存被哪些詞條對象使用
- 格子是否為空缺狀態
- 格子填詞是否成功,用來判斷填詞是否成功
- 當前格子上的詞id
????public?gridId:?number?=?0;??????????????????//?格子id
????public?isUsed:?boolean?=?false;?????????????//?是否是被使用的格子
????public?data:?string?=?null;?????????????????//?完整的成語
????public?char:?string?=?"";???????????????????//?使用的成語字符,單個字
????public?idioms?=?[];?????????????????????????//?反向保存idiom引用????這個是用來保存這個格子被哪些詞條引用
????public?isSpaceGrid:?boolean?=?false;????????//?是否是?被?去字?狀態
????public?isSelectMode:?boolean?=?false;???????//?是否是?填字?模式
????public?isSuccess:?boolean?=?false;??????????//?標注該位置詞?是否正確
????public?currentId:?number?=?0;???????????????//?記錄當前格子上?選詞?的id,用來判斷回退
????
????//?重置?格子數據,關卡切換復用
????public?resetGrid()?{
????????……
????}
????//?格子注冊監聽事件
????public?addListener(fn:?Function,?target)?{
????????this.node.on(cc.Node.EventType.TOUCH_END,?fn,?target);
????}
????//?格子移除監聽事件
????public?removeListener(fn:?Function,?target)?{
????????this.node.off(cc.Node.EventType.TOUCH_END,?fn,?target);
????}
2.5 關卡對象
用一個類來描述游戲關卡。關卡對象讀取關卡json文件,返回詞條對象數組。http請求獲取關卡數據可以放在這里。
//?Level.ts????public?initLevelData()?{
????????let?idioms?=?this._levelData.json["idioms"];
????????let?idiomArr?=?[];
????????for?(let?i?=?0;?i?????????????let?_id?=?idioms[i].id
????????????let?idiomdataObj?=?new?IdiomData(this._jsonData.json[_id]);
????????????//?詞條對象?存詞條數據,占位
????????????let?idiomObj:?Idiom?=?new?Idiom(idioms[i].grids,?idiomdataObj);
????????????idiomArr.push(idiomObj);
????????}
????????return?idiomArr;
????}
3 界面設計
3.1 節點結構
節點結構3.2 結算界面
展示詞條成語,提供下一關切換按鈕。
節點結構3.3 詞條詳情界面
展示詞條拼音、釋義、出處。
詞條詳情游戲邏輯
4.1 成語區
- 制作一個格子的預制體,一次性創建81個格子對象。
????private?init()?{
????????//?9*9=81塊????rows?col
????????for?(let?index?=?0;?index?81;?index++)?{
????????????let?node?=?cc.instantiate(this.piece_prefab);
????????????node.parent?=?this.qipan;
????????????let?tile:?Grid?=?node.getComponent(Grid);
????????????tile.gridId?=?index;
????????????if?(!this.isDebug)?{
????????????????tile.hide();
????????????}
????????????this.tiles.push(tile);
????????}
????????……?……
????}
- 遍歷成語對象后,給指定格子位置添加對應的成語字符并綁定數據。從成語對象中拿到成語,將每個成語都分割成單獨的字符存入數組中,將字符循環插入到格子中,如果該位置的格子為去字狀態,就把該位置的字符隱藏,并記錄空缺字符的id和字符用于初始化選詞區。
????????for?(let?i?=?0;?i?????????????let?chars?=?idiomArr[i].data.chars;
????????????let?grids?=?idiomArr[i].grids;
????????????//?分割拿到單獨的字符
????????????let?arr?=?chars.split("");
????????????for?(let?j?=?0;?j?????????????????let?gid?=?grids[j].id;
????????????????let?space?=?grids[j].space;
????????????????this.tiles[gid].bg.node.active?=?true;
????????????????this.tiles[gid].word.node.active?=?true;
????????????????//?設置?格子信息
????????????????this.tiles[gid].gridId?=?gid;
????????????????this.tiles[gid].char?=?arr[j];
????????????????this.tiles[gid].data?=?chars;
????????????????this.tiles[gid].idioms.push(idiomArr[i]);
????????????????//?判斷是否為?去字?狀態,如果是去字,那么就隱藏上面的word
????????????????if?(space)?{
????????????????????this.tiles[gid].isSpaceGrid?=?true;?????//?空格子
????????????????????if?(!this.tiles[gid].isSelectMode)?{????//?判斷?該空是否為選詞
????????????????????????this.tiles[gid].isSelectMode?=?true;
????????????????????????this.tiles[gid].bg.spriteFrame?=?this.word_tile;
????????????????????????//?添加點擊事件
????????????????????????this.tiles[gid].addListener(this.onSpaceGridClick,?this);
????????????????????????this.selectWords.push({"id":?gid,?"char":?arr[j]});
????????????????????}
????????????????}?else?{
????????????????????this.tiles[gid].word.string?=?arr[j];
????????????????????this.tiles[gid].bg.spriteFrame?=?this.word_normal;
????????????????}
????????????}
????????}
- 空位置觸摸事件。空位置需要實現兩個功能:顯示字符和回退選詞區。
????????if?(grid.isUsed)?{
????????????let?char?=?grid.word.string;
????????????this.tiles[gridId].isUsed?=?false;
????????????this.tiles[gridId].word.string?=?"";
????????????this.tiles[gridId].isSuccess?=?false;
????????????this.tiles[gridId].bg.spriteFrame?=?this.word_selected;
????????????this.currentSelectGrid?=?gridId;
????????????let?currentid?=?grid.currentId;
????????????for?(let?i?=?0;?i?this.selectNode.length;?i++)?{
????????????????if?(this.selectNode[i].gridId?===?currentid)?{
????????????????????this.selectNode[i].node.getComponent(cc.Animation).play("show_word");
????????????????}
????????????}
????????}
4.2 選詞區
- 復用格子預制體,遍歷記錄空缺字符的selectWordsArr數組里的數據。
????private?initSelectGroup()?{
????????for?(let?s?=?0;?s?this.selectWords.length;?s++)?{
????????????let?gid?=?this.selectWords[s].id;
????????????let?char?=?this.selectWords[s].char;
????????????let?node?=?cc.instantiate(this.piece_prefab);
????????????node.parent?=?this.selectGroup;
????????????let?tile:?Grid?=?node.getComponent(Grid);
????????????tile.gridId?=?gid;
????????????tile.char?=?char;
????????????tile.word.string?=?char;
????????????tile.addListener(this.onSelectGridClick,?this);
????????????this.selectNode.push(tile);
????????}
????}
- 為了可玩性,隨機打亂selectWordsArr里的數據,將選詞打亂。
????this.selectWords.sort(()?=>?{
????????return?Math.random()?>?0.5???-1?:?1;
????});
- 選詞區觸摸回調,判斷選詞與空缺位置是否匹配,如果匹配將該格子的isSuccess設為true,表明該位置字符正確。這里判斷字符正確的依據不能通過比較id的方式,因為有可能選詞區出現若干個相同字符的格子,所以選擇任意一個都要能達到字符正確的效果。
????private?onSelectGridClick(e)?{
????????……?……
????????//?隱藏該選詞?
????????e.target.getComponent(cc.Animation).play("hide_word");
????????if?(this.tiles[this.currentSelectGrid].isUsed)?{
????????????let?char?=?this.tiles[this.currentSelectGrid].word.string;
????????????let?nowId?=?this.tiles[this.currentSelectGrid].currentId;
????????????this.selectNode[nowId].node.active?=?true;
????????????this.tiles[this.currentSelectGrid].word.string?=?grid.char;
????????}?else?{
????????????this.tiles[this.currentSelectGrid].word.string?=?grid.char;
????????????this.tiles[this.currentSelectGrid].isUsed?=?true;
????????????this.tiles[this.currentSelectGrid].bg.spriteFrame?=?this.word_finished;
????????????this.tiles[this.currentSelectGrid].currentId?=?gridId;
????????}
????????//?判斷是否填詞成功??通過比較字符的方式?gridId?===?this.currentSelectGrid
????????if?(char?===?this.tiles[this.currentSelectGrid].char)?{
????????????//?記錄該位置詞語正確
????????????this.tiles[this.currentSelectGrid].isSuccess?=?true;
????????}
????????this.judgeSuccess(this.currentSelectGrid);
????}
4.3 填詞邏輯
- 每填一個詞都要判斷格子上綁定的成語是否填詞成功。找出空位置,然后判斷空位置上所有的isSuccess是否為true,滿足條件則播放填詞動畫,查找下一個空缺位置。
????private?judgeSuccess(gridId:?number)?{
????????……?……
????????if?(this.tiles[gridId].idioms.length?>?0)?{
????????????for?(let?i?=?0;?i?this.tiles[gridId].idioms.length;?i++)?{
????????????????let?idiom?=?this.tiles[gridId].idioms[i];
????????????????let?flag?=?true;
????????????????spaceArr?=?[];
????????????????//?遍歷去字?位置
????????????????for?(let?j?in?idiom.grids)?{
????????????????????let?id?=?idiom.grids[j].id;
????????????????????if?(idiom.grids[j].space?===?true)?{
????????????????????????spaceArr.push(id);
????????????????????}
????????????????}
????????????????//?判斷成功
????????????????for?(let?s?=?0;?s?????????????????????if?(this.tiles[spaceArr[s]].isSuccess?!==?true)?{
????????????????????????flag?=?false;
????????????????????}
????????????????}
????????????//?填詞動畫后,找下一個?空位置
????????????this.findNextSpaceGrid();
????????????……?……
????}
4.4 過關邏輯
- 尋找下一個空位置。遍歷格子對象,篩選isSelectMode為true同時isUsed為false,也就是未被占用的格子。滿足條件的格子設置當前選中狀態即可。
????????????if?(this.tiles[i].isSelectMode?&&?this.tiles[i].isUsed?===?false)?{
????????????????//?記錄選中的格子位置
????????????????this.currentSelectGrid?=?i;
????????????????this.tiles[i].bg.spriteFrame?=?this.word_selected;
????????????????return;
????????????}
????????}
- 如果尋找下一個空位置失敗,那么說明不存在下一個空格子,就要判斷過關。
????????let?flag?=?true;
????????for?(let?sw?=?0;?sw?this.selectWords.length;?sw++)?{
????????????let?id?=?this.selectWords[sw].id;
????????????if?(this.tiles[id].isSuccess?!==?true)?{
????????????????flag?=?false;
????????????}
????????}
????????if?(flag)?{
????????????//?執行過關函數
????????????cc.log("過關");
????????????this.gameSuccess();
????????}
4.5 動畫效果
- 選詞觸摸動畫,對照小秀才發現當選詞點擊時只需要把scale執行從1到0的動畫就可以達到同樣的效果。如果直接將active置false,layout的格子布局就會自動調整可見選詞區的位置,導致每個選詞的位置出現變化。
- 填詞動畫。對比發現,填詞正確動畫拆分看,每個位置的動畫都是一樣的,將格子進行快速縮放并設置不同的延遲,看上去有跳動的效果。
????private?fillGrid(grids,?arr)?{
????????for?(let?i?=?0;?i?????????????let?id?=?grids[i].id;
????????????this.tiles[id].isSelectMode?=?false;
????????????//?每個字延遲動畫
????????????setTimeout(()?=>?{
????????????????this.tiles[id].getComponent(cc.Animation).play("word_success");
????????????},?100?*?i);
????????}
????????for?(let?j?=?0;?j?????????????this.tiles[arr[j]].removeListener(null,?this);
????????}
????}
4.6 詞條成功邏輯
- 判斷詞條中空位置格子是否都正確,如果正確就執行填詞動畫,查找下一個空位。如果沒有空位置且填詞全都正確,則說明過關,展示結算界面。
- 詞條詳情界面,顯示拼音、釋義、出處。
5 演示
demo完整演示6 總結
- 項目開始前把結構劃分清除,每個模塊之間的聯系都確定好,可以提高開發效率。
- 第一次仿制游戲,得益于有完整的ui素材,論壇也有類似的帖子介紹。拿這類的小游戲練手對提高學習信心很有幫助。
- 關于隨機關卡,跟壇友交流過,隨機生成的成語質量無法保證,也就是有可能生僻詞混搭,能實現但體驗會變差。還有另一種手動標注成語,人工干預的方式去生成關卡。隨機關卡思路是有了,但是具體沒實現,暫時用不上。什么時候有心情做了再發出來。
- 使用cocos creator2.3.2版本,typescript語言
總結
以上是生活随笔為你收集整理的成语json_cocos creator实战(2)成语小秀才ts版的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mpvue 微信小程序api_第三方框架
- 下一篇: vivo解bl锁_黔隆科技刷机教程酷派B