手遊《奧林劈圖》的開發日記(一)
我最近將手遊《奧林劈圖》上線到蘋果商店,了卻了一樁三年的心願,心情也由之前的燥動不安迴歸平靜。現在我真的有時間和一顆平常心去擁抱機器學習和資料探勘了。
幾年前自己剛開始學習cocos2dx的時候,腦子經常冒出各種各樣的奇怪的遊戲創意,害怕下一分鐘可能會忘卻,就習慣了把它們記錄在有道筆記上。至今翻看那些筆記,可以零星的回憶起這個遊戲創作和開發的軌跡和新路歷程。
[2016年4月19日]
任務目標設計(舊)
新增3根木棒,獲得:
2個L2 (該設計太抽象)
1個Z1 (該設計太抽象)
(其它圖形數量不限)
除去3根棍棍兒,獲得:
3個O4 (該設計太抽象)
用給定的棍棍兒, 將圖形分為4個大小和形狀相同的圖形。
放置所有積木到灰色圖形內,即可過關。
任務id:
任務目標:新增%d根木棒,獲得:
* %d個%s
* %d個%s
(其它形狀數量不限)
任務驗證函式
任務完成狀態提示:打勾
TaskPopup和TaskStatus的UI根據StageTask的引數配置生成。
複雜困難的任務分步讓玩家完成。
[2016年4月20日]
StageLayer (經典模式)
|----背景層
|----StatusBar
|----scrollview
|----stageN (sp1.csb, sp2.csb, sp3.csb e.g.)
|----task (type=0, pieces=3,award:{wall=3,coin=100})
|----mapboard (W=100, H=100)
|----dimension (size = 700x1100 e.g.)
|----fields
|----walls
|----blocks
|----TaskPopup (跟據stageN的配置資訊生成)
|----ResultPopup (獎勵根據stageN的配置資訊生成)
|----HintPopup (createNode by stageN.csb)
任務目標:
通過新增牆,將圖形分成若干個子圖形,然後移動子圖形填充到下方的陰影圖形中。
任務完成:
您消耗了6個牆完成本次任務,目前世界最好成績為使用5個牆。
您的過關獎勵為: 牆: 6 金幣:100
[返回] [確定]
過關獎勵:
恭喜你獲得: 牆: 6 金幣:100
(此處與伺服器通訊,wall +6, coin +100, usewall 6, 如果好於預設牆數傳送:牆的佈局資料)
牆佈局: {stage=sp5, num=6, pos: [{x:1,y:2,d=1},{x:2,y:3,d=0}]}
[2016年4月22日]
[難]:
面積大
融合度高
規定劈開的圖形數目,大小或形狀
規定使用圍牆數目
[易]:
面積小
離散
原圖形面積大於目標圖形面積 (原圖形允許有剩餘)
基本上,可新增圍牆數目決定答案的難度
[2016年4月23日]
1. 經典模式 (暗黑夜空)
2. PVP模式設計,每天10:00 (或整點)釋出一個新副本,30分鐘內完成,牆數少者獲勝。牆數相同時間早者獲勝。前10名有獎品。
bool g2Grid::hasPart() bool g2Grid::getField() g2Body -> [covered grids]集合 ->遍歷 Body::isLanded() g2ShapeModel, g2ShapeClip ==> g2Shape (巢狀結構) bool g2ShapeClip::isFieldLaid() { int xnum = xNum(); int ynum = yNum(); for (int i = 0; i < xnum; i++) { for (int j = 0; j < ynum; j++) { auto pt = m_origin + GridPoint(i, j); auto grid = getGrid(pt); if (!grid || !grid->getField()) return false; } } return true; }
[2016年4月25日]
1. 環狀圖形允許
2. CShape : g2Mapboard { std::<CShape*> m_children; }
Sharesdk整合
Sqlite加密
主介面設計
關卡選擇介面
關卡背景
iOS內購整合
[2016年4月26日]
一個Zone由關卡選擇器和若干關卡組成。
關卡選擇器中包含若干Button,每個Button是一個關卡的入口。
StagePicker
|--------Button1 {version:1, source:"xxx.csb"}
|--------Button2 {version:2, source:"xxx.csb"}
|--------Button3 {version:2, source:"xxx.csb"}
StageLayer1 {wall:3, award:{coin:100,wall:4}}
StageLayer2 {wall:3, award:{coin:100,wall:4}}
StageLayer3 {wall:3, award:{coin:100,wall:4}}
[2016年4月26日]
伺服器與客戶端同步設計
通用格式:
send: req={op:xxx, opdata}&cct=yyy
resp: ret=0&rsp={op:xxx, respdata, cmd:{jsondata}}&cct=yyy
定時請求server端的scounter
通訊協議:
1. 第三方鑑權成功後,開始登陸游戲伺服器
send: msg={op:login, account:{uid3:124234135,type:QQ,name:氣昏頭}}&cct=0
resp: ret=0&rsp={accountuid: xxx, roleuid:AABB112233}}&cct=0
2. 選擇一個從伺服器返回的角色
send: msg={op:selectrole, roleuid:AABB112233}&cct=xxx
resp: ret=0&rsp={roleuid:AABB112233,cct=xxx,sct:yyy}&cct=xxx
3. 請求慢同步 when ccounter (client) < ccounter(server) (伺服器資料覆蓋客戶端)
send: msg={op:slowsync, roleuid:AABB112233}&cct=0
resp: ret=0&rsp={roledata:{...},sct:xxx}&cct=0
角色使用者資料:
{
role:{uid=xxx,name=yyy,coin=500,wall=12,zone1Prog=7,accountUid=zzz,ccounter=11,scounter=9},
zone1:{s1:{..},s2:{..},s3:{..},s4:{..},s5:{..},s6:{..},s7:{..}}
}
4. 合併本地帳號 (when ccounter=0 on server side) (客戶端資料覆蓋伺服器)
send: msg={op:merge, roledata:{...}}&cct=xxx
resp: ret=0&rsp={roleuid:AABB112233,cct=xxx,sct:yyy,cmd:{op:slowsync}&cct=xxx
5. 花費金幣500購買當前關卡hint
send: msg={op:buyhint, roleuid:AABB112233, cost:{coin:500}}&cct=xxx
resp: ret=0&&rsp={op:buyhint, coin: 1500, sct:yyy}&cct=xxx
6. 使用5個圍牆條,通過關卡 (zone=zone1 sn=57)
send: msg={op:pass, roleuid:AABB112233, stage:{zone:zone1,group:0,sn: s27}, cost:{wall:5}, award:{coin:100, wall:6}, misc:{time=300}}&cct=xxx
resp: ret=0&rsp={op:pass, coin: 1500, wall: 11, sct:yyy}&cct=xxx
7. 請求獲得伺服器的新事項
send: msg={op:getupdate,roleuid:AABB112233,sct:25}&cct=xxx (獲取伺服器中scounter為25的更新事項)
resp: ret=0&rsp={jsondata},sct:xxx}&cct=xxx
說明:
1. ccounter_on_client >= ccounter_on_server
99.99%的時間ccounter_on_client應該大於counter_on_server, 如果相等意味最後一次操作的返回資料未到達客戶端。
2. 當scounter_on_client <= scounter_on_server, 伺服器有更新的事件需要客戶端獲得。
設計目標:
1. 沒有連線伺服器的條件下,遊戲可以正常執行。當連線伺服器後,客戶端實現與伺服器的資料同步。
2. 多客戶端交替玩遊戲不會有嚴重問題。
3. 客戶端資料永遠與伺服器端相同或更新(離線玩),當客戶端資料舊的時候需要與伺服器同步。
1. 增量資料同步:
json queue:
0 {type:"login", data: }
1 {type:"stage", data:{id=sp2, usedwall=8, layout:[], wall=5,coin=100}
2 {type:"useitem", data: }
1. 全資料同步
使用者資料包括:
1. 過關數(例如:通過23關,第24關解鎖但未過)
2. 通過的關卡的資訊: 使用的牆數,時間
3. 賬戶擁有的牆數和金幣數量。
4. 牆佈局在離線狀態丟棄。
同步錨: 通關序號(如23),counter0(每次資料通訊標識), counter1(每次資料通訊標識)
[2016年4月27日]
寵物系統
某一關通過後,贈送玩家一種圖形:
恭喜你獲得寵物: 馬蹄型 (圖)
又某一關通過後,贈送玩家一種圖形:
恭喜你獲得寵物: 直角型 (圖)
玩家攜帶一個寵物參戰,每一關如果劈出寵物圖形,則獎勵增加xx%。
通關後寵物獲得經驗,當經驗滿足升級條件,可以手動升級,升級需要花費一定的金錢。
寵物級別越高,如果劈出與寵物相同圖形,通關獲得的金錢獎勵和圍牆獎勵越多。
您確定更換參戰的寵物嗎? 更換後,原寵物的連勝次數被清除。 連勝越多,通關後獲得的經驗越多。
[2016年4月29日]
提示設計 (HintPopup)
HintPopup (經典模式)
|----背景層
|----scrollview
|----stageN (sp1.csb, sp2.csb, sp3.csb e.g.)
|----task (type=0, pieces=3,award:{wall=3,coin=100})
|----mapboard (W=100, H=100)
|----dimension (size = 700x1100 e.g.)
|----fields
|----walls
|----blocks
|----hints (visible)
花錢買過提示,會記錄在案,以後可以自由檢視。
[2016年5月6日]
過關檢查
觸發事件: block moved
檢查:
1) dstShape檢查
每一個方格都已被block覆蓋。
2) srcShape檢查
劈分的每一個clip,都已經生成block,每一個block都至少覆蓋一個目標方格。
3) Limit檢查
呼叫limit::isAllOk(),沒一個檢查道具均檢查通過。
[2016年5月9日]
資料庫設計
伺服器:
account
[uid] [uid3] [type]
role
[uid] [name] [coin] [wall] [zone1Prog] [accountUid]
zone1_by_role
[roleUid] [groupId] [s1] [s2] ... [s40]
欄位s(n): json format e.g. {w:5, playtime:300, version:1}
zone1_by_stage (主要用於遊戲統計)
[uid] [version] [source] [playerNum] [playTimes] [wallNum] [spentTime] [hintTimes] [minWallNum] [maxWallNum] [bestSolution] [bestRoleUid] [bestCreateTime]
s1 1 split1 57 6 241 8 4 9 {jsondata}
客戶端: (Logined Account -> Active Role)
account
[uid] [uid3] [type]
role
[uid] [name] [coin] [wall] [Zone1Prog] [accountUid] [ccounter] [scounter]
zone1
[roleUid] [groupId] [s1] [s2] ... [s40]
欄位s(n): json format e.g. {w:5, playtime:300, version:1}
opmsg
[_id] [msg] [md5] [roleUid]
[2016年5月9日]
使用者資料管理
class Role 是所有使用者資料入口類
Role -> Udb -> Local Database
Role::init 載入表role和zone1中的資料。
提供對本地使用者資料的getter和setter
setCoin() getCoin()
setWall() getWall()
setCCounter() getCCounter()
setSCounter() getSCounter()
pushOpMsg() popOpMsg()
Udb嚴禁Remote訪問,保證資料在客戶端和伺服器的一致性和可維護性。
[2016年5月12日]
帳號登入及角色初始化過程
1. 帳號和角色必須在伺服器建立。 (本地角色除外)
2. xxxManager is not also to manager xxx but also to give life to xxx.
3. 使用帳號資料的前提與聯網無關,而是:本地資料庫中的帳號和角色資料完整。所以需要先檢查這兩個。
4. 帳號表以伺服器為準,角色表需要比較ccounter.
5. 只有使用者選擇“遊客模式”才會啟用本地角色
6. 登入失敗或者選擇角色失敗,仍然使用帳號角色,前提是地資料庫完整。
bool Role::checkUserDataIntegrity() AccountManager::onAuthenticated() -> (uid3, type) { find(uid3, type) -> (accountUid); //首先本地搜尋帳號: find(accountUid) -> (roleUid) //搜尋角色 (-->onAccountSelected) AccountManager::login() //如果本地無此帳號或角色,啟動登入 (-->onAccountSelected) } AccountManager::onAccountSelected(accountUid, roleUid) { account = Account::create(); Account::init() //讀資料庫初始化account RoleManager::selectRole(roleUid) } RoleManager::selectRole(roleUid) { RoleManager::find(accountUid) -> (roleUid) //首先本地搜尋角色: (-->onSelected) //沒有找到, 查詢伺服器 (-->onSelected) } RoleManager::onSelected(roleUid) { role = Role::create(); //讀資料庫初始化role }
相關文章
- 手遊《奧林劈圖》的開發日記(二)
- 手遊《奧林劈圖》的開發日記(三)
- 安卓APP開發日記1——名為Another的日記APP開發安卓APP
- 開發日記10
- 小辣椒開發日記
- 安卓開發日記57安卓
- 安卓開發日記56安卓
- 安卓開發日記55安卓
- 安卓開發日記26安卓
- 安卓開發日記25安卓
- 安卓開發日記24安卓
- 安卓開發日記28安卓
- 安卓開發日記27安卓
- 安卓開發日記4安卓
- 安卓開發日記13安卓
- 安卓開發日記14安卓
- 安卓開發日記12安卓
- 安卓開發日記17安卓
- 安卓開發日記16安卓
- 安卓開發日記15安卓
- 安卓開發日記19安卓
- 安卓開發日記18安卓
- 安卓開發日記46安卓
- 安卓開發日記45安卓
- 安卓開發日記47安卓
- PHP手遊開發(手遊專案)PHP
- 5.13安卓開發日記34安卓
- 5.9安卓開發日記31安卓
- 社交網站後端專案開發日記(一)網站後端
- Unity3D手遊開發系列筆記(一)——前言:選擇什麼樣的遊戲引擎來開發你的遊戲?Unity3D筆記遊戲引擎
- FLOWERS開發日誌(一)
- 開發日記(一)JAVA中變數初始化流程Java變數
- 軟銀1500億日元收購手遊開發商Supercell
- 雲音樂vue開發日記Vue
- 5.11安卓開發日記32安卓
- 5.16安卓開發日記37安卓
- 5.12安卓開發日記33安卓
- 5.14安卓開發日記35安卓