6.游戲中的智能系統處理
游戲中的智能對手
AI在游戲中最普通的形式是創建計算機控制的對手。因為大多數游戲是單人游戲,所以要設計游戲者在游戲中必須戰勝對手。為了達到這個目的,你可以使用某種類似A*搜索的簡單AI算法,以幫助對手穿過迷宮向游戲者發起進行。你也可以使用簡單的算法預測游戲者的反應。
但是,記住沒有必要創建世界上最強大的對手。你的對手只要能給游戲者提供足夠的挑戰性就可以了。還有,要注意游戲的內容。例如:一個戰棋式RPG游戲中策略占的是主要地位;而在純RPG中故事情節和角色開發就更重要一些。千萬不要因為計算機對手太強大而讓游戲者們陷入失敗的泥沼。
游戲中的非智能對手
通常,在游戲開發中AI技術是與計算機對手緊緊聯系在一起的。這是因為早期的大部分類似角棋的游戲是一對一的。但是,任何好的探險游戲或RPG 游戲開發者都知道,AI同樣可以用于非對手角色。例如:如果你正在建立一個RPG游戲并且你想讓你的世界活起來,這就是說,讓城市里的人以智能的方式活動,那么你可以使用某種算法確定在一天中的某個時候,角色應該在那里。你可以使用類似于AI算法如A*來輔助你將一個對象從一處移動到另一處并繞過障礙物。
游戲中的智能系統
游戲中的AI在本質上是最具有模仿性的,但它們基本上是依賴一些AI要素。 你可以將所有具有決策功能的對象在一個游戲中融合為一個整體。例如:在一個戰爭游戲中,你的各個部分可以依據各自所處的具體環境來作出各自的AI決策。
使用這種方法,你得把精力集中于怎樣在各個獨立的決策個體之間建立聯系,以及這些聯系怎樣才能使游戲成為融會貫通的整體。是用一個高級決策影 響其它決策,還是各個決策個體之間平等地互相影響呢?舉個戰爭游戲來說, 你有十輛坦克,它們的思維模式基本相同。所以它們都決定去攻擊敵人陣營中 HP值最低的一輛坦克。但是這時其中一輛坦克說:“這個敵人歸我了!”那么 剩下的九輛坦克就應該依據這條信息各自調整下一步的攻擊目標。當你建立智能個體時,要考慮在一個智能系統整體環境下,它應該如何行動。
7.電腦游戲中的人工智能制作
電腦游戲隨著硬件執行效率與顯示解析度等大幅提升,以往很多不可能或非常難以實現的電腦游戲如此都得以順利完成。雖然電腦游戲的呈現是那么地多樣化,然而卻與我們今日所要探討的主題,人工智能幾乎都有著密不可分的關系。
在角色扮演游戲中,程序員與企劃人員需要精確地在電腦上將一個個所謂的“怪物”在戰門過程中栩栩如生地制作出來;所以半獸人受了重傷懂得逃跑,法師懂得施展攻性法術。
目前能讓人立刻想到與人工智能有密切關系的游戲有兩種:
一是所謂的戰棋/策略模擬游戲,二則是棋弈游戲。人工智能的比重與深淺度,在不同的游戲類型中各有不一。有的電腦游戲非標榜著高人工智能不可,不然沒有人買;有的則是幾乎渺茫到讓玩家無法感覺有任何人工智能的存在。
導向式思考
AI最容易制作的的方式,同時也是早期游戲AI發展的主要方向就是規則導向或稱之為假設導向。在一些比較簡單的電腦游戲中,程序員可以好不困難地將游戲中的規則與設定轉化成一條條的規則,然后將它們寫成電腦程序。讓我們以角色扮演游戲為例。決大多數的企畫在設定所謂電腦怪物時,所設定的屬性通常有以下幾種:
生命值 攻擊力 防御力 法力 屬性
最后一個“屬性”是我在設定時喜歡增加的項目之一。透過這項屬性的設定,我可以把怪物設定成“貪生怕死的”,也可以把戰士設定為“視死如歸”。以目前我們所掌握的資料,在戰門系統中的大綱如是誕生了:
規則一
if (生命值< 10) // 邊臨死亡了嗎
{ if (屬性== 貪生怕死)
結果 = 試圖逃跑
if (有任何恢復生命值的物品或法術可用)
結果 = 使用或施展相關物品或法術
}
規則二
if (可施攻擊性法術 && 有足夠法力)
{
結果 = 施展攻攻擊性法術
}
由以上一連串的“如果--就--”規則設定,建立了最基本的AI。說這樣的制方式只能建立基本AI其實并不當然正確。只要建立足夠及精確的規則,這樣的方式仍然有一定水準的表現。
規則導向的最大優點就是易學易用。在沒有深奧的理論概念的前提下,仍有廣大的使用群。所以很多老道的玩家常常沒兩下就摸清楚敵人的攻擊策略,移動方式等等。
推論式思考
相信曾經接觸過電腦語言課程,或是自習過相關書籍的朋友們,都曾曾經聽過一個著名的程序,那就是井字游戲。用井字游戲作為討論AI的入門教材,我個人覺得是最適當的例子。或許有人還不知道井字游戲怎么玩。只要任何一方在三乘三的方格中先先成一線便勝利了。我們在前面談過的規則導向,在這里也可以派得上用場。
if任何一線已有我方兩子&&另外一格仍空//我方即將成一線嗎
結果 = 該空格
if任何一線已有敵方兩子&&另外一格仍空//防止敵方作成一線
結果 = 該空格
if任何一線已有我方一子&&另外兩格仍空//作成兩子
結果 = 該空格
有一次我在某本電腦書上,同樣地也看到某些以井字游戲為介紹的范例。不同的是,我幾乎看不到任何規則導向的影子。但在仔細分析該程序碼后,我得到了極大的啟發,原來AI是可以不用這么多規則來制作的。它用的方法正是在電腦AI課程中重要的概念:極大極小法。我在這里只說明這法則的概念。繼續以井字游戲為例,電腦先在某處下子,接著會以假設的方式,替對方下子,當然,必須假設對方下的是最佳位置,否則一切則毫無意義。在假設對方下子的過程中,自然又需要假設我方的下一步回應,如此一來一往,直到下完整局游戲為止。 底下是節錄書中的程序片段:
bestMove(int p, int*v)
{ int i;
int lastTie;
int lastMove;
int subV;
/*First, check for a tie*/
if (isTie()) {
*v=0;
return(0);
};
/*If not a tie, try each potential move*/
for (*v=-1, lastTie=lastMove=-1,i=0;i<9;i++)
{
/*If this isn’t a possible, skip it*/
if (board[i]!=0) continue;
/* Make the move. */
lastMove=i;
board[i]=p;
/* Did it win? */
if (hasWon) *v=1;
else{
/*If not, find out how good the other side can do*/
bestMove(-p,&subV);
/* If they can only lose, this is still a win.*/
if (subV==-1) *v=1;
/* Or, if it’s a tie, remember it. */
else if (subV==0){
*v=0;
lastTie=i;
};
};
/* Take back the move. */
board[i]=0;
/*If we found a win, return immediately
(can’t do any better than that)*/
if (*v==1) return;
/*If we didn’t find any wins, return a tie move.*/
if (*v==0) return(lastTie);
/*If there weren’t even any ties, return a loosing move.*/
else return(lastMove);
};
國外的一些論壇曾舉行過256字節的游戲設計比賽。作品非常多,其中有一件作品正巧也是井字游戲。作者用區區兩百多行就寫了與上述程序演算方式完全相同的作品,可見功力確實了的。另外,我也很希望類似的活動能在國內推展起來。對了,在這樣的比賽條件限制下,除了匯編語言外,幾乎沒有其它的選擇了。 .386c
code segment byte public use16
assume cs:code, ds:code
org 100h
tictac proc far
start:
push cs
pop ds
mov ax,0B800h ; 清除屏幕
mov es,ax;
xor di,di;
mov cx,7D0h ;
mov ax,0F20h ;
rep stosw;
xor cx,cx;
mov dl,5
loc_1:
call printBoard
loc_2:
mov ah,8 ; 等待按鍵
int 21h
movzx bx,al
sub bl,31h ; 如果不是1..9
jcloc_2; 則重新輸入
cmp bl,8
jaloc_2
cmp data_1[bx],al
jne loc_2
mov byte ptr data_1[bx],’x’
dec dl
jzshort loc_3
mov al,’o’
call bestMove
mov [si],al
call isWin; 判斷是否已取得勝利
jnc loc_1
loc_3:
call printBoard
mov ax,4C00h
int 21h
data_1 db’12’
data_2 db’3456789’
data_3 db0
tictac endp
printBoardproc near
mov si,offset data_1
mov di,548h
mov cl,3
locloop_4:
movsb
add di,5
movsb
add di,5
movsb
add di,133h
loop locloop_4
retn
printBoardendp
isWin proc near
mov bx,1
mov bp,3
call sub_3; 檢查橫向是否完成
inc bx
inc bx
dec bp
dec bp
call sub_3; 檢查縱向是否完成
call sub_4; 檢查斜向是否完成
clc
retn
isWin endp
loc_5:
stc
retn
sub_3 proc near
mov ah,3
mov si,offset data_1
loc_6:
mov di,si
call sub_5
add si,bp
dec ah
jnz loc_6
retn
sub_3 endp
sub_4 proc near
mov di,offset data_1
inc bx
call sub_5
mov di,offset data_2
dec bx
dec bx
call sub_5
retn
sub_4 endp
sub_5 proc near
mov cl,3
locloop_7:
cmp [di],al
jne short loc_ret_8
add di,bx
loop locloop_7
add sp,4
jmp short loc_5
loc_ret_8:
retn
sub_5 endp
bestMoveproc near
mov bx,31FEh
mov cl,9
mov di,offset data_1
locloop_9:
cmp [di],bh ; #empty?
jne short loc_12 ; #no, skip
mov [di],al
pusha
call isWin ; #CY: Win
popa ;
jnc short loc_10 ;
mov bl,1
mov si,di
mov [di],bh
retn
loc_10:
pusha
xor al,17h ; good! toggle ’o’ / ’x’
call bestMove
mov data_3,bl
popa
mov ah,data_3
neg ah
cmp ah,bl
jle short loc_11
mov bl,ah
mov si,di
loc_11:
mov [di],bh
loc_12:
inc bh
inc di
loop locloop_9
cmp bl,0FEh
jne short loc_ret_13
xor bl,bl
loc_ret_13:
retn
bestMoveendp
code ends
end start
文章定位: