(笔记)《游戏脚本高级编程》——第2章 脚本编程系统的应用(上)
本章內容:
- 介紹腳本系統是如何用于解決下列問題的:
- RPG游戲中與內容相關的部分——非玩家角色和場景細節
- RPG游戲中的物品、武器和敵人
- 第一人稱射擊游戲中的物品、謎題和機關
- 第一人稱射擊游戲中敵人的行為
1.游戲引擎和內容是完全分離的,所以當游戲玩家購買游戲軟件的時候,實際上購買了兩個部分:一個編譯過的游戲引擎和一系列可以對游戲功能進行擴展的腳本。這種結構稱之為模塊化結構。這種方法一種常見的應用是以“情節(episode)”的形式發布游戲。這就意味著游戲軟件店在在銷售游戲軟件的時候只出售一部分游戲內容以及可以在上面運行游戲的游戲引擎。當游戲玩家完成了第一個游戲情節的時候,他們就可以以較少的費用下載或者購買另外的如patches和add-ons樣式的游戲情節(這不就類似于DLC嗎)。
2.角色扮演游戲(Role Playing Games,RPGs)
RPG游戲一般要比其他類型的游戲要使用更多的腳本,原因就在于RPG游戲的確適宜于使用腳本,它們確確實實需要大量的游戲內容。自然而然,RPG的游戲開發人員就需要一個很好的方法以一種結構化的、有組織的方式來開發這些內容。
下面將分析一下RPG游戲的傳統內容,以便理解為什么腳本對于設計角色扮演的游戲來說那么適用。
①復雜而又有深度的故事情節:
RPG游戲看起來更像是一部交互式小說,這就意味著游戲中將會出現進行無窮行對話的人物角色和帶有無數“場景點”的高度結構化的游戲場景。而在玩家冒險經歷的每一個場景點,游戲都需要玩家在到達該處之前完成了哪些主要的事情以確定游戲世界中的現在狀態以及將要發生的事情。解決的方法就是采用一組“標記(flags)”來記錄場景點或者是游戲世界中的現在狀態。每個標記代表游戲中的一個事件,可以為TRUE或者FALSE(當然可以不是布爾類型)。
這套系統的實現方法有很多種。一種就是在引擎的源代碼中直接建立標技術組,并向游戲腳本提供一個訪問接口,這個接口允許腳本對于數組進行讀寫操作。這種方法將所有邏輯和功能都寫在了腳本上,腳本只需通過接口訪問數組就可以完成這套系統。第二種方法就是如果腳本系統能力很強的話,甚至可以將數組從引擎中剝離,直接將數組存儲到腳本內部并訪問,這種方法是最理想的,因為這讓游戲邏輯和引擎進行了分離。不過前者也是可用的。
②非玩家角色(Non-Player Characters, NPCs)
NPC在游戲里也是至關重要的,他們可以為主角進行劇情的引導,或是和他們交換物品。因此,條件邏輯、循環以及讀取游戲flags的能力等就會變得很關鍵。解決方法如下:
一些簡單的對話,只需在NPC和腳本之間建立一些一對一的對應關系。當有NPC問一些帶有選項的問題時,系統會根據玩家應答的結果的不同而采用不同的對話策略。或者其他的一些不同的情況,使得NPC變得十分逼真和靈活,這就需要一種更加強大的描述語言來描述他們的行為。
這種語言所需要的特征:
(1)應該具備基本的對話能力
(2)在對話中可以通知游戲引擎在什么時候加入動畫
(3)能夠查看玩家的物品清單
(4)能夠提供一組定做的答案
(5)記錄玩家和這個角色的交往歷史。此外,理論上游戲玩家在這些單獨的對話期間可能會退出游戲然后又重新進入,那么就不僅需要在游戲期間在內存上保留信息,在不同的游戲期間還要把它們保存到磁盤上。即無限期地保存這個NPC相關的變化信息
(6)能夠改變flags
下面有段對話:
(游戲玩家第一次和NPC進行對話)
NPC:"Hey, you look familiar."(斜著眼睛盯著玩家的臉)
Player:"Do I?I don't believe we've met."
NPC:"Wait a sec- you're the guy who's gonna save the world from the vampires,right?"
NPC:(如果游戲玩家說的是Yes)"I knew it!Here, take this garlic!"(將大蒜交給游戲玩家)
Player:"Thanks!"
(游戲玩家再次和NPC進行對話)
NPC:"Sorry, I don't have any more garlic.I gave you all I had last time we spoke."
Player:"Well that sucks."(跺腳)
(游戲玩家第三次和非玩家角色進行對話)
NPC:"Dude I told you, I gave you all my garlic.Leave me alone!"
Player:"But I ran out, and there's still like 10 more vampires that need to be valiantly defeated!"
NPC:"Hmm...well, my brother lives in the next town over, and he owns a garlic processing plant.I'll tell him you're in the area,and to batch ready for you.Next time you're there,just talk to him, and he'll give you all the garlic you need."
Player:"Thanks, mysterious garlic-dispensing stranger!"
NPC:"My name's Gary."
Player:"Whatever."
(游戲玩家和NPC進行了三次以上的對話)
NPC:"So,have you seen my brother yet?"
這段對話可以用以下類似于C/C++的腳本代碼編寫:
static int iConverseCount = 0; static bool bIsPlayerHero = FALSE; main() {string strAnswer;if(iConverseCount == 0){NPCTalk("Hey, you look familiar.");PlayAnim(NPC, SQUINT);PlayerTalk("Do I?I don't believe we've met.");strAnswer = NPCAsk("Wait a sec- you're the guy who's gonna save the world from the vampires,right?", "Yes", "No");if(iAnswer == "Yes"){NPCTalk("I knew it!Here, take this garlic!");GiveItem(GARLIC, 4);PlayerTalk("Thanks!");bIsPlayerHero = TRUE;}else{NPCTalk("Ah.My mistake.");bIsPlayerHero = FALSE;{}else{if(bIsPlayerHero){if(iConverseCount == 1){NPCTalk("Sorry, I don't have any more garlic.I gave you all I had last time we spoke.");PlayerTalk("Well that sucks.");PlayAnim(PLAYER, STAMP_FEET);}else if(iConverseCount == 2){NPCTalk("Dude I told you, I gave you all my garlic.Leave me alone!");PlayerTalk("But I ran out, and there's still like 10 more vampires that need to be valiantly defeated!");NPCTalk("Hmm...well, my brother lives in the next town over, and he owns a garlic processing plant.I'll tell him you're in the area,and to batch ready for you.Next time you're there,just talk to him, and he'll give you all the garlic you need.")PlayerTalk("Thanks, mysterious garlic-dispensing stranger!");NPCTalk("My name's Gary");PlayerTalk("Whatever.");SetGameFlag(GET_GARLIC_FROM_GARYS_BROTHER);}else{NPCTalk("So,have you seen my brother yet?");}}else{NPCTalk("Hello again.");{}iConverseCount ++; }會發現僅僅只是添加了一些新的特征,這個語言就突然變得和C/C++語言相似了。同樣的,在編寫一個RPG游戲的過程中,數組、指針、動態資源分配等許多更加高級的語言特性也會大放異彩。通常有兩種方法來設計腳本:①先設計一個類似于C/C++的語法體系,然后在你需要的時候添加新內容;②同時設計語法和語言的總體結構。前者要比后者容易的多。采用C/C++也會是你的系統更加統一和標準
③物品和武器:
因為很多物品的行為都非常像是宏,可以采用基于指令的語言來編寫它們。
物品腳本和游戲腳本一般都需要完成一系列的任務。首先要提到的就是它的后臺功能,即這個物品是攻擊敵人的,還是治療友軍的,還是打開一道門,還是清理一個過道等等。這個功能只要簡單地更改一些代碼就可以實現。基于命令的語言可以滿足。然而,另一個方面是玩家可以感受到這種武器或者物品的功能的具體表現,比如武器的動畫效果等。基于命令的語言就不能滿足這個需求了。
解決方法:
最好還是采用那些C/C++樣式的、面向對象的語言,因為它們允許物品和武器在腳本內部定義自己的圖形效果并且直到最為細節的部分。整個過程很簡單,只是涉及到至少要提供一組可供腳本調用的基本的圖形程序。所有這些所必須必備的不過就是下面這些常見的東西——制作圖形、繪制精靈,也可能是播放電影文件使得玩家可以預覽動畫效果,通常由DirectX、OpenGL以及SDL所提供的圖形API的精選子集組成。
下面舉例寫一個武器實例:
武器名為Fire Sword。Fire Sword的功能是向敵人發射火球,對于冰系或水系的怪物尤其有效。相反,對火屬性的敵人效果較差。同時,由于它的熱量,當游戲玩家每次使用這個武器時也會對自身造成一定程度上的傷害。我們就可以通過編寫一個火球的動畫來完成這個想法。綜上,從技術層面來考慮這個武器的功能:
(1)需要能夠修改游戲中人物的統計數據,也就是他們的體力值。還要考慮屬性的克制時的傷害結算
(2)需要能夠真正在屏幕上看到由玩家所在位置到敵人所在位置發射的火球,以及爆炸聲。需要處理動畫和聲音,因此需要條件邏輯和循環。基于命令的語言已經不適用了。此外,主應用程序還應提供一個基本的多媒體API使得腳本最起碼能夠在屏幕上繪制精靈和播放聲音。
(3)還要處理由寶劍發射出來的熱量對于自身所造成的的輕微傷害。與(1)類似,僅僅涉及到一些數據的問題,這意味著需要能夠訪問到玩家的具體狀態。
以上任務(2)比較難以解決,其余兩個只要基于命令的語言就可解決。這就排除了基于命令的語言而改用C/C++體系的語言。代碼如下:
Player.HP -= 4;int Y = Player.OnScreenY; for(int X=Player.OnScreenY; X<Enemy.OnScreenX; X++)BlitSprite(FIREBALL, X, Y); PlaySound(KA_BOOM);if(Enemy.Type==ICE || Enemy.Type==WATER)Enemy.HP -= 16; else if(Enemy.Type == FIRE)Enemy.HP -= 4; elseEnemy.HP -= 8;④敵人:
敵人最為主要的部分在于它同時利用了前面的兩個概念:它具有NPC的特征或者是個性為中心的方面,同時它還具有物品和武器的功能以及破壞特性。因此敵人是這兩個實體背后的概念相結合的過程。
解決方法:
RPG的打斗場面的主體框架是循環的,再循環過程的每一次迭代過程中,游戲玩家和敵人都要對輸入進行分析。當敵人執行相應的打斗腳本時,玩家要準備接受輸入的數據;當玩家執行相應的打斗腳本時,敵人要準備接受輸入的數據。代碼如下:
void Act() {int iWeakestPlayer, iLastAttacker;if(iHitPoints < 20)if(rand() % 10 == 1)Flee();else{iWeakestPlayer = GetWeakestPlayer();if(Player[iWeakestPlayer].iHitPoints<20)Attack(iWeakestPlayer, METEOR_SHOWER);else{iLastAttacker = GetLastAttacker();switch(Player[iLastAttacker].iType){case NINJA:{Attack(iLastAttacker, THROW_FIREBALL);break;}case MAGE:{Attack(iLastAttacker, BROADSWORD);break;}case WARRIOR:{Attack(iLastAttacker, SUMMON_DEMON);break;}}}} }代碼解釋:首先,敵人腳本會根據它會被打敗的可能性有多大。如果這個結果低于一定的臨界值(上述代碼是低于20個體力值),那么它就會模擬一個試圖從打斗現場逃跑的動作。如果在隨機1~10之間隨到了1,那么就會逃跑。然而,如果他覺著有必要接著繼續打斗,那么它就會調用引擎提供的函數來確定哪個是對手中最弱的。如果敵人覺著玩家比較接近被打敗的狀態(上述代碼是玩家體力值低于20),那么就會進行Meteor Shower來將對手打敗。如果這個最弱的敵人并不是十分的弱小以至于很容易被打敗出局,敵人就會轉去襲擊那個最后攻擊他的人,并會基于對手的類型選擇一個具體的進攻策略。總結
以上是生活随笔為你收集整理的(笔记)《游戏脚本高级编程》——第2章 脚本编程系统的应用(上)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用ps删除多余的内容
- 下一篇: matlab coefs,MATLAB小