❶ 大魚吃小魚游戲中用到過哪些演算法
大魚吃小魚游戲中用到過ZooKeeper的演算法。
ZooKeeper是一個分布式的,開放源碼的分布式應用程序協調服務,是Google的Chubby一個開源的實現(Chubby是不開源的),它是集群的管理者,監視著集群中各個節點的狀態根據節點提交的反饋進行下一步合理操作。最終,將簡單易用的介面和性能高效、功能穩定的系統提供給用戶 。
Zookeeper一個最常用的使用場景就是用於擔任服務生產者和服務消費者的注冊中心,服務生產者將自己提供的服務注冊到Zookeeper中心,服務的消費者在進行服務調用的時候先到Zookeeper中查找服務,獲取到服務生產者的詳細信息之後,再去調用服務生產者的內容與數據。
ZooKeeper 的架構圖中我們需要了解和掌握的主要有:
(1)ZooKeeper分為伺服器端(Server) 和客戶端(Client),客戶端可以連接到整個 ZooKeeper服務的任意伺服器上(除非 leaderServes 參數被顯式設置, leader 不允許接受客戶端連接)。
(2)客戶端使用並維護一個 TCP 連接,通過這個連接發送請求、接受響應、獲取觀察的事件以及發送信息。如果這個 TCP 連接中斷,客戶端將自動嘗試連接到另外的 ZooKeeper伺服器。
客戶端第一次連接到 ZooKeeper服務時,可以接受這個連接的 ZooKeeper伺服器會為這個客戶端建立一個會話。當這個客戶端連接到另外的伺服器時,這個會話會被新的伺服器重新建立。
(3)上圖中每一個Server代表一個安裝Zookeeper服務的機器,即是整個提供Zookeeper服務的集群(或者是由偽集群組成)。
❷ 棋類游戲的演算法有哪些
棋類游戲的演算法有哪些
棋類游戲通常包含三大要素:棋盤、棋子和游戲規則,其中游戲規則又包括勝負判定規則、落子的規則以及游戲的基本策略。下面我來給大家講講各類棋類游戲的演算法。
除了棋盤和棋子的建模,棋類游戲最重要的部分就是AI演算法的設計。目前棋類游戲的AI基本上就是帶啟發的搜索演算法,那麼常用的搜索演算法有哪些呢?
1. 博弈與博弈樹
博弈可以理解為有限參與者進行有限策略選擇的競爭性活動,比如下棋、打牌、競技、戰爭等。根據參與者種類和策略選擇的方式可以將博弈分成很多種,比如“二人零和、全信息、非偶然”博弈,也就是我們常說的零和博弈(Zero-sum Game)。所謂“零和”,就是有贏必有輸,不存在雙贏的結果。所謂“全信息”,是指參與博弈的雙方進行決策時能夠了解的信息是公開和透明的,不存在信息不對稱的情況。比如棋類游戲的棋盤和棋子狀態是公開的,下棋的雙方都可以看到當前所有棋子的位置,但是很多牌類游戲則不滿足全信息的條件,因為牌類游戲都不會公開自己手中的牌,也看不到對手手中的牌。所謂的“非偶然”,是指參與博弈的雙方的決策都是“理智”的行為,不存在失誤和碰運氣的情況。
在博弈過程中,任何一方都希望自己取得勝利,當某一方當前有多個行動方案可供選擇時,他總是挑選對自己最為有利同時對對方最為不利的那個行動方案。當然,博弈的另一方也會從多個行動方案中選擇一個對自己最有利的方案進行對抗。參與博弈的雙方在對抗或博弈的過程中會遇到各種狀態和移動(也可能是棋子落子)的選擇,博弈雙方交替選擇,每一次選擇都會產生一個新的棋局狀態。
假設兩個棋手(可能是兩個人,也可能是兩台計算機)MAX和MIN正在一個棋盤上進行博弈。當MAX做選擇時,主動權在MAX手中,MAX可以從多個可選決策方案中任選一個行動,一旦MAX選定某個行動方案後,主動權就轉移到了MIN手中。MIN也會有若干個可選決策方案,MIN可能會選擇任何一個方案行動,因此MAX必須對做好應對MIN的每一種選擇。如果把棋盤抽象為狀態,則MAX每選擇一個決策方案就會觸發產生一個新狀態,MIN也同樣,最終這些狀態就會形成一個狀態樹,這個附加了MAX和MIN的決策過程信息的狀態樹就是博弈樹(Game Tree)。
2. 極大極小值搜索演算法
極大極小值(Min-Max)搜索演算法是各種博弈樹搜索演算法中最基礎的搜索演算法。假如MAX和MIN兩個人在下棋,MAX會對所有自己可能的落子後產生的局面進行評估,選擇評估值最大的局面作為自己落子的選擇。這時候就該MIN落子,MIN當然也會選擇對自己最有利的局面,這就是雙方的博弈,即總是選擇最小化對手的'最大利益(令對手的最大利益最小化)的落子方法。作為一種博弈搜索演算法,極大極小值搜索演算法的名字就由此而來。
3. 負極大值搜索演算法
博弈樹的搜索是一個遞歸的過程,極大極小值演算法在遞歸搜索的過程中需要在每一步區分當前評估的是極大值節點還是極小值節點。1975年Knuth和Moore提出了一種消除MAX節點和MIN節點區別的簡化的極大極小值演算法,稱為負極大值演算法Negamax。該演算法的理論基礎是:
max(a,b) = -min(-a, -b)
簡單地將遞歸函數MiniMax()返回值取負再返回,就可以將所有的MIN 節點都轉化為MAX節點,對每個節點的搜索都嘗試讓節點值最大,這樣就將每一步遞歸搜索過程都統一起來。
4. “α-β”剪枝演算法
有很多資料將“α-β”剪枝演算法稱為“α-β”搜索演算法,實際上,它不是一種獨立的搜索演算法,而是一種嫁接在極大極小值演算法和負極大值演算法上的一種優化演算法。“α-β”剪枝演算法維護了一個搜索的極大極小值窗口:[α,β]。其中α表示在搜索進行到當前狀態時,博弈的MAX一方所追尋的最大值中最小的那個值(也就是MAX的最壞的情況)。在每一步的搜索中,如果MAX所獲得的極大值中最小的那個值比α大,則更新α值(用這個最小值代替α),也就是提高α這個下限。
而β表示在搜索進行到當前狀態時,博弈的MIN一方的最小值中最大的那個值(也就是MIN的最壞的情況)。在每一步的搜索中,如果MIN所獲得的極小值中最大的那個值比β小,則更新β值(用這個最大值代替β),也就是降低β這個上限。當某個節點的α≥β時,說明該節點的所有子節點的評估值既不會對MAX更有利,也不會對MIN更有利,也就是對MAX和MIN的選擇不會產生任何影響,因此就沒有必要再搜索這個節點及其所有子節點了。
5. 估值函數
對於很多啟發式搜索演算法,其“智力”的高低基本上是由估值函數(評估函數)所決定,棋類游戲的博弈樹搜索演算法也不例外。
估值函數的作用是把一個棋局量化成一個可直接比較的數字,這個數字在一定程度上能反映取勝的概率。棋局的量化需要考慮很多因素,量化結果是這些因素按照各種權重組合的結果。這些因素通常包括棋子的戰力(棋力)、雙方棋子佔領的空間、落子的機動性、威脅性(能吃掉對方的棋子)、形和勢等。
6. 置換表與哈希函數
置換表(transposition table)也是各種啟發式搜索演算法中常用的輔助演算法,它是一種以空間換時間的策略,使用置換表的目的就是提高搜索效率。一般情況下,置換表中的每一項代表者一個棋局中最好的落子方法,直接查找置換表獲得這個落子方法能避免耗時的重復搜索,這就是使用置換表能大幅提高搜索效率的原理。
使用置換表最大的問題是置換表的組織和查找的效率。一般來說,置換表越大,查找的命中率就越高。但這個關系不是絕對的,當置換表大小達到一定規模後,不僅不會再提高命中率,反而會因為耗時的查找操作影響演算法的效率。所以置換表不是越大越好,需要根據計算機的性能以及搜索的深度選擇一個合適的大小。此外,為了查找操作更高效,通常都會用可直接訪問的哈希表方式組織置換表,哈希函數的性能就成為影響置換表性能的重要因素。棋類游戲普遍採用Zobrist哈希演算法。
❸ 游戲中為什麼用啟發式a星演算法
首先,A* 是啟發式演算法,在尋路過程中搜索的范圍相比 Dijsktra 一般要小得多(當然,有時也可能一樣)
其次,A* 演算法的搜索速度和效率可控,可以通過控制代價函數來權衡搜索的速度和精度之間的關系
❹ 游戲攻擊判定的三種模式
轉自:http://www.gameres.com/677620.html
攻擊判定流程幾乎是所有包含戰斗玩法的游戲都無法繞過的一塊內容,常見的攻擊判定流程有瀑布演算法、圓桌演算法以及混合演算法三種。本文簡述了這三種判定流程的特徵,以實例對比分析了瀑布演算法與圓桌演算法各自的優點,以期為後續其他戰斗數值設計內容的論述提供一定的基礎。
攻擊判定流程概述
自此開始正文內容的敘述——讓我們直接代入一個實例:
在一款游戲中,攻擊方有命中率和暴擊率兩個攻擊屬性,而防守方有閃避率、招架率和格擋率三個防禦屬性。於是相應的,一次攻擊有可能產生6種判定結果:未命中、普通命中、閃避、招架、格擋和暴擊。當採用不同的判定流程進行攻擊結算時,6種判定結果出現的頻率會截然不同。
1. 瀑布演算法
顧名思義,在瀑布演算法中,各事件的判定順序如同瀑布一般自上而下。如果「水流」在某個位置被截斷,則後面的流程都將不再繼續進行。據我所知,瀑布演算法是大多數游戲所採用的攻擊判定演算法。
上述實例若採用瀑布演算法,則會以如下方式進行判定:
先判定攻方是否命中
再判定是否被守方閃避
再判定是否被守方招架
再判斷是否被守方格擋
最後判定該次攻擊是否為暴擊
瀑布演算法流程圖
由此我們可以得出:
瀑布演算法特徵1:多次擲骰,一次擲骰只判定單個事件的發生與否
瀑布演算法特徵2:後置判定依賴於前置判定的通過
註:有的游戲會將命中和閃避合並在一次擲骰中判定,這意味著將攻方命中率與守方閃避率合並計算出實際擊中概率後再進行擲骰判定,仍是瀑布演算法
我們再代入一些具體的數值,設攻守雙方角色的面板屬性如下:
攻方命中率=90%
攻方暴擊率=25%
守方閃避率=20%
守方招架率=15%
守方格擋率=30%
按照上述的流程判定,6種判定結果將會按如下的概率分布:
實際未命中概率=1-命中率=1-90%=10%
實際閃避概率=命中率*閃避率=90%*20%=18%
實際招架概率=命中率*(1-閃避率)*招架率=90%*(1-20%)*15%=10.8%
實際格擋概率=命中率*(1-閃避率)*(1-招架率)*格擋率=90%*(1-20%)*(1-15%)*30%=18.36%
實際暴擊概率=命中率*(1-閃避率)*(1-招架率)*(1-格擋率)*暴擊率=90%*(1-20%)*(1-15%)*(1-30%)*25%=10.71%
實際普通命中概率=命中率*(1-閃避率)*(1-招架率)*(1-格擋率)*(1-暴擊率)=90%*(1-20%)*(1-15%)*(1-30%)*(1-25%)=32.13%
瀑布演算法的判定結果分布
由此我們可以得出:
l 瀑布演算法特徵3:各事件出現的概率符合經典的概率計算方法
l 瀑布演算法特徵4:擲骰輪次越偏後的屬性衰減程度越大,但不會出現無效的屬性
2.圓桌演算法
將所有可能出現的事件集合抽象成一個圓桌桌面,便是圓桌演算法這一稱呼的由來。圓桌演算法的實質,是將所有可能發生的事件狀態按優先順序依次放上桌面,直至所有事件被放完或桌面被填滿。圓桌演算法正是史詩級巨作魔獸世界中所採用的演算法。據筆者了解,使用該演算法的游戲並不多見,但即便僅魔獸世界這一款,已足以使這種演算法成為永恆的經典~
上述實例若採用圓桌演算法,則會用一次擲骰判定該次攻擊的結果。
圓桌演算法流程圖
圓桌演算法的操作步驟可以歸納為:
(1)攻方角色的命中率決定圓桌桌面的大小
(2)將各個事件狀態按優先順序依次放上桌面,直至所有的事件均放置完或桌面被填滿
(3)若桌面還未填滿,則用普通命中填滿空桌面
將先前設定的數值代入,6種判定結果將會按如下的概率分布:
實際未命中概率=10%
實際閃避概率=20%
實際招架概率=15%
實際格擋概率=30%
實際暴擊概率=25%
實際普通命中概率=90%-實際閃避概率-實際招架概率-實際格擋概率-實際暴擊概率=90%-20%-15%-30%-25%=0%
註:在上述計算中,優先順序按如下排序:閃避>招架>格擋>暴擊>普通命中
圓桌演算法的判定結果分布
可以看出,由於普通命中的優先順序最低,所以它被完全擠出了桌面。這意味著,若攻守雙方以此數值模型進行對決,則攻擊方的攻擊結果中將不存在普通命中。
由此我們可以得出:
圓桌演算法特徵1:一次擲骰即得出該次攻擊的判定結果
圓桌演算法特徵2:事件有優先順序,圓桌放滿後優先順序低的事件將被擠出桌面。這意味著那部分溢出的屬性將不再生效
圓桌演算法特徵3:圓桌內的各事件出現概率不會衰減,只要優先順序低的屬性沒有被擠出圓桌,各種事件的實際發生概率就與面板屬性數值吻合
3. 混合演算法
這是一種先判定攻方事件,再判定守方事件的判定流程。筆者曾在一篇帖子中看到過這樣判定流程,不確定是否有實際的游戲應用,故僅在此做一些簡單的理論分析。
混合演算法在單方事件的判定中採用圓桌演算法,即:
攻方判定結果:普通命中OR未命中OR暴擊
守方判定結果:閃避OR招架OR格擋OR被命中
混合演算法流程圖
註:上面這個圖僅作示意之用,從流程圖的角度來看可能不太嚴謹
將先前設定的數值代入,6種判定結果將會按如下的概率分布:
實際未命中概率=10%
實際閃避概率=攻方命中率*閃避率=90%*20%=18%
實際招架概率=攻方命中率*招架率=90%*15%=13.5%
實際格擋概率=攻方命中率*格擋率=90%*30%=27%
實際暴擊概率=攻方暴擊率*敵方被命中概率=25%*(1-20%-15%-30%)=8.75%
實際普通命中概率=攻方普通命中概率*敵方被命中概率=(90%-25%)*(1-20%-15%-30%)=22.75%
混合演算法的判定結果分布
由此我們可以得出:
混合演算法特徵1:先判定攻方事件,再判定守方事件,共進行兩次擲骰
混合演算法特徵2:先在單方事件的判定中採用圓桌演算法,再用瀑布演算法串聯攻守雙方事件
混合演算法特徵3:會產生並發動作,例如暴擊被閃避等
註:這也正是實際暴擊率較低原因所在
瀑布演算法與圓桌演算法的特性對比
在上一塊內容的鋪墊之下,我們不妨繼續以魔獸世界中的攻擊判定流程設計實例作為切入點,對比分析一下圓桌演算法與瀑布演算法各自的特性。
(1)面板屬性傳遞信息的直觀性
瀑布:由於各屬性在判定流程上的生效時間有先後之分,所以各屬性的實際效用與面板顯示的不符。
圓桌:由於屬性的判定沒有先後之分,只要沒有屬性被擠出圓桌,則所有屬性的實際效用與面板顯示的相當。
這里可以看出圓桌演算法的優點:
屬性的實際效用與面板顯示相符顯然更易於普通玩家的理解,便於玩家掌握自身的戰力情況。
(2)屬性的價值
瀑布:擲骰輪次越偏後的屬性衰減程度越大,但所有的屬性均會生效。
圓桌:只要沒有屬性被擠出圓桌,則不存在屬性效用的衰減。
這里可以看出圓桌演算法的優點:
由於不存在判定流程上的先後,所以各屬性的實際價值會比較接近,一般不會出現玩家堆了某個判定流程靠後的屬性結果很廢的情況。
同樣也可以看出其缺點:
一旦有屬性溢出,則該部分屬性的效用為0,完全沒有價值。
(3)相同面板數值下的生存能力
圓桌:在面板數值相同的情況下,魔獸世界用圓桌演算法大大提高了坦克角色的生存能力,使得他們可以應對來自首領怪的超高攻擊,匹配大型團隊副本的玩法設計。
瀑布演算法下,免傷概率=18%+10.8%+18.36%=47.16%
圓桌演算法下,免傷概率=20%+15%+30%=65%
傳統的概率為相乘關系,圓桌為相加關系,後者的概率總和要大的多
並且,當防禦職業將三維堆至一個閾值(70%)後,配合技能可達100%的免傷覆蓋,將命中和暴擊全部擠出桌面,從而衍生出特定的玩法(70級年代伊利丹的剪切技能)。
瀑布:相同的面板數值在瀑布演算法的框架下,免傷概率相較於圓桌演算法要低得多。換言之,角色達到相同的有效生命值,所需的免傷屬性要高得多。
這里可以看出:
在圓桌演算法的框架之下,屬性投放若是脫離了控制超過了閾值,將對平衡性產生較大的沖擊(70級的盜賊單刷格魯爾——當然在暴雪光環的作用下,玩家會認為這是精妙的設計~)。
在國產游戲收入導向的大環境下,設計者是否能頂住收入壓力,嚴守屬性投放的極值不越界,是值得慎思的問題。採用瀑布演算法,能有更大的數值空間用於能力投放,更為適合現階段的市場環境。
(4)運算量
瀑布:多次擲骰
圓桌:單次擲骰
顯而易見:
擲骰次數越多,運算量越大。圓桌相較於瀑布,有著相對較小的運算量。簡單即是美。
註:除魔獸世界外,《冒險與挖礦》的技能施放也採用了圓桌演算法,大大簡化了技能施放的判定流程。可以想像一下,一次攻擊至多發動一個技能。而每一次攻擊,一個隊伍中有幾十個角色的技能施放需要判定,如果採用瀑布演算法,將產生多大的運算量。
思考與總結
對戰斗數值的研究,應該基於理論推導而歸於實踐應用。畢竟游戲數值設計不是做數學研究,其本質應是一種體驗設計。最後希望交流的是筆者個人對於這兩種演算法的一些理解。
(1)不同的攻擊判定流程會向玩家傳達不同的戰斗感受
究其本質,不同的攻擊判定流程,影響著一場戰斗中的各種攻擊判定結果將以何種概率分布出現。
假設在一款游戲中,閃避率的投放上限是30%,暴擊率的投放上限是40%,命中率的投放上限是100%。瀑布演算法下,出現閃避、暴擊和普通命中的概率是30%、28%和42%;圓桌演算法下,則為30%、40%和30%。這兩種不同的概率分布,必然會帶給玩家不同的戰斗體驗,但在缺少其他條件的情況下,並不能判斷孰優孰劣。
使戰斗體驗匹配游戲的核心玩法,使屬性投放的極限值能滿足游戲的商業化需要,是設計攻擊判定流程時首先要考慮的。
註:甚至於部分競技游戲強調公平性,將暴擊做成了偽隨機。
使用瀑布演算法,則不應該設計種類繁多的事件狀態
若是仿照魔獸世界的做法設計一連串的事件狀態(未命中、閃避、招架、格擋、暴擊、普通命中、偏斜、碾壓),非但運算繁雜,而且後置判定的屬性衰減幅度較大,效果極不明顯。這種隱晦的設計將不易傳達,同時還會影響玩家的游戲感受(某個判定流程靠後的屬性堆得很高結果卻沒用)。
使用圓桌演算法,則應該嚴守屬性投放的上限,防止平衡崩壞的情況發生
需要澄清的是,並不是說使用瀑布演算法就可以無限投放數值,而是說,相較於瀑布演算法,圓桌演算法的屬性投放上限會低很多(免傷概率的相加與相乘)
(2)不同的攻擊判定流程將影響有效生命EHP和有效攻擊EDPS的表達式
幾乎每個數值策劃都會將角色的屬性轉化為EHP和EDPS以衡量其的戰斗能力,但曾見過不少人對所有的游戲都用統一的EHP、EDPS表達式進行分析模擬。這種偏差較大的模擬方式必然會影響體驗設計的精準性。在不同的攻擊判定流程之下,EHP與EDPS有著截然不同的表達式,舉例說明如下。
瀑布演算法下:
若命中閃避分兩次判定:
EHP=HP/(1-免傷率)/(1-閃避率)/(1-招架率)
EDPS=DPS*命中率*[1+暴擊率*(暴擊傷害倍率-1)]
若命中閃避合並判定:
EHP=HP/(1-免傷率)/(命中率-閃避率)/(1-招架率)
EDPS=DPS*(1+暴擊率*(暴擊傷害倍率-1))
圓桌演算法下:
EHP=HP/(1-免傷率)/(1-閃避率-招架率)
EDPS=DPS*[命中率-敵方閃避率-敵方招架率+暴擊率*(暴擊傷害倍率-1)]
註:閃避、招架>暴擊>普通命中,且各狀態發生概率之和未超過圓桌大小
混合演算法下:
EHP=HP/(1-免傷率)/(1-閃避率-招架率)
EDPS=DPS*[命中率+暴擊率*(暴擊傷害倍率-1)]
可能有人會覺得:模擬得這么准又有什麼卵用,數值平衡最後還不是靠調?誠然,在數值設計領域,確實有名言曰:數值平衡是調出來的。但在筆者看來,調節應該建立在正確的理論推導的基礎之上。依靠調節來掩蓋數值模型的錯誤設計,是本末倒置的行為。即便達到了所謂的平衡,也不過是扭曲的平衡,會為後續版本的迭代埋下隱患。
寫在最後
市面上的大多數游戲,都不會設計復雜繁多的攻擊事件,且基本採用瀑布演算法。如此看來,攻擊判定流程的設計十分簡單。那麼為什麼要大費周章地將簡單問題復雜化呢?
愛因斯坦曾說過:Everythingmust be made as simple as possible, but not one bit simpler——凡事應該力求簡單,但不能過於簡單。從了解一種數值設計方法到理解如此設計的目的,從模仿成功游戲的數值設計到理解其設計的內在意義,這是每個數值策劃成長的必經之路。
從全盤照搬一種數值體繫到能夠融會貫通並根據實際情況靈活運用,這是一條並不好走的路。知其然,也應知其所以然——這是一個入行一年有餘的新人的一點感悟。
免責申明:
1.筆者無法保證本文所用詞彙的普適性,能力所限,請多包涵~
2.不保證文中魔獸世界實例中的設定均與原作完全相符。但即便不相符,也不會影響圓桌理論的推
❺ 游戲中的常用的尋路演算法有哪些
f(n)=g(n)+h(n) 從起始點到目的點的最佳評估值
– 每次都選擇f(n)值最小的結點作為下一個結點,
直到最終達到目的結點
– A*演算法的成功很大程度依賴於h(n)函數的構建
?;) = g(n? 在各種游戲中廣泛應用 Open列表和Closed列表
– Open列表
A*演算法
? h(n) = 從結點n到目的結點的耗費評估值,啟發函數
?,程序返回n
else 生成結點n的每一個後繼結點n;
foreach 結點n的後繼結點n;{
將n』的父結點設置為n
計算啟發式評估函數h(n『)值,評估從n『到node_goal的費用
計算g(n『) = g(n) + 從n』到n的開銷
計算f(n?? 在演算法啟動時,Closed列表為空 A* 演算法偽代碼初始化OPEN列表
初始化CLOSED列表
創建目的結點;稱為node_goal
創建起始結點;稱為node_start
將node_start添加到OPEN列表
while OPEN列表非空{
從OPEN列表中取出f(n)值最低的結點n
將結點n添加到CLOSED列表中
if 結點n與node_goal相等then 我們找到了路徑;)
if n『位於OPEN或者CLOSED列表and 現有f(n)較優then丟棄n』 ;) + h(n?? 包含我們還沒有處理到的結點
? g(n) = 從初始結點到結點n的耗費
?? 包含我們已經處理過的結點
,處理後繼n』
將結點n『從OPEN和CLOSED中刪除
添加結點n『到OPEN列表
}
}
return failure (我們已經搜索了所有的結點?? 啟發式搜索
– 在搜索中涉及到三個函數
??? 我們最開始將起始結點放入到Open列表中
– Closed列表
?
❻ 游戲攻擊演算法
普攻傷害為攻擊力(基礎傷害加裝備加成)。ad技能傷害為基礎傷害加攻擊力ad加成(比如一個技能ad加成0.5,就是你攻擊力乘0.5)。ap傷害為基礎傷害加法強加成,具體同攻擊力加成一樣。還有的技能加成特殊,比如流浪的技能受魔法值加成。狗頭的q殺死目標積累傷害。但計算是一樣的有的技能沒有加成,比如蓋倫的大招。收到的物理傷害會受護甲見面,比如100的護甲則你受到的傷害會減免100/(100+護甲值),即減傷50%。魔法傷害受魔抗減免,計算同物理傷害。真實傷害無視抗性。ps,點燃為真實傷害,傷害隨等級提升。日炎斗篷造成魔法傷害 ,也隨等級等級提升。
❼ 連連看的游戲,用的是什麼原理演算法,求指教一二
連連看核心演算法如下:
#include <iostream>
using namespace std;
int board[102][102];
int nRowCount, nColCount;
bool isHorizontalLineValid(int c1, int c2, int r)
{
if(c1>c2) // 交換 C1, C2
{
c1 ^= c2 ^= c1 ^= c2;
}
for(int i=c1+1; i<=c2-1; i++)
{
if(board[r][i]!=0)
return false;
}
return true;
}
bool isVerticalLineValid(int r1, int r2, int c)
{
if(r1>r2) // 交換 r1, r2
{
r1 ^= r2 ^= r1 ^= r2;
}
for(int i=r1+1; i<=r2-1; i++)
{
if(board[i][c]!=0)
return false;
}
return true;
}
bool check(int r1, int c1, int r2, int c2)
{
// 如果該位置沒有棋子或者兩棋子不一致,則返回假
if(board[r1][c1]==0 || board[r2][c2]==0 || board[r1][c1]!=board[r2][c2])
return false;
// 兩條水平線和一條垂直線
for(int i=0; i<=nColCount+1; i++)
{
if( (i!=c1 && board[r1][i]!=0) || (i!=c2 && board[r2][i]!=0) )
continue;
if( isHorizontalLineValid(i, c1, r1) &&
isVerticalLineValid(r1, r2, i) &&
isHorizontalLineValid(i, c2, r2))
{
board[r1][c1] = board[r2][c2] = 0;
return true;
}
}
// 兩條垂直線和一條水平線
for(int i=0; i<=nRowCount+1; i++)
{
if( (i!=r1 && board[i][c1]!=0) || (i!=r2 && board[i][c2]!=0) )
continue;
if( isVerticalLineValid(i, r1, c1) &&
isHorizontalLineValid(c1, c2, i) &&
isVerticalLineValid(i, r2, c2))
{
board[r1][c1] = board[r2][c2] = 0;
return true;
}
}
return false;
}
int main(int argc, char** argv)
{
int nRound, nSuccess;
int x1, y1, x2, y2;
// 輸入棋盤數據
cin >> nRowCount >> nColCount;
for(int i = 1; i <= nRowCount; ++i)
for(int j = 1; j <= nColCount; ++j)
cin >> board[i][j];
cin >> nRound;
for(int i = 0; i < nRound; ++i)
{
cin >> x1 >> y1 >> x2 >> y2;
if( check(x1, y1, x2, y2) )
cout << "Yes\n";
else
cout << "No\n";
}
system("pause");
return 0;
}
測試數據:
3 4
1 1 2 2
3 3 4 4
2 2 1 1
6
1 1 1 2
1 3 1 4
2 1 2 2
2 3 2 4
3 1 3 2
3 3 3 4
c1 ^= c2 ^= c1 ^= c2;語句中對於a^=b就相當於a=a^b,即代表a與b取位異或運算之後再把值賦給a的。樓主如果覺得還行的話請加點分的哦。
❽ 即時戰略游戲中實用的尋路演算法都有哪些
Potential Field,它是將地圖用一個矩陣來表示,矩陣儲存著大小不同的電勢(整數)。例如,正電勢表示吸引,負電勢表示排斥。而游戲中的單位本身是一個負電勢,游戲以一個數組儲存所有單位的電勢和位置。這樣,在計算一個單位需要怎麼從A點到B點時,我們可以用一個新的矩陣將目的地B點設成正電勢,並以不同方式(如圓形、四邊形等)輻射開來,離B點越遠電勢越低,直到0。然後將地圖矩陣,目的地矩陣,和所有單位數組的電勢相加,得出一個新的、反映當前游戲世界的電勢矩陣,然後單位再選擇周圍所有電勢點中的最高電勢點去走。不過這里坑很多,因為它本質上是Greedy Algorithm,所以它未必能找出解。然而在某些設定中,例如在沒有過於復雜地形,並且需要單位自動不相互覆蓋的情況下,Potential Field還是可以完成任務。
Flocking Behavior,在對於一大群單位的尋路,計算量是很大的,而且往往會有很多的重復,這些都是可以避免的。如果單位的移動是利用Steering Behavior來實現的話,那麼就可以為其中一個單位,稱之為Leader,計算路徑(例如用導航網格),然後其他單位按照以下Flocking原則來移動:1. 分離,避開相鄰單位2. 一致,和整體的移動方向一致,這里應該是Leader的移動方向3. 聚合,向整體的平均位置靠攏這樣的話,就可以降低尋路的計算量,並且得到更加真實的群體單位行進效果。