做單機遊戲的時候,制作人突然提了一個“體力系統”的需求。目前的很多遊戲無論是網遊還是單機,都有體力系統,我想可能是因為平衡玩家而限制遊戲玩法或者是怕玩家無限制的玩遊戲疲憊的原因吧。不管怎麼說,讓我們一起來研究一下體力系統應該怎麼做。
本來我以為體力系統挺容易的,後來一做才發現并不是很簡單。先在網上搜了一下有關體力的系統的設計思路,結果沒有搜到相關資訊,算了,自己設計吧。
對于單機遊戲來說,因為沒有聯網的伺服器驗證,是以隻能靠擷取裝置系統的時間來做體力恢複。這樣的話,我在candycrash的小遊戲中遇到過這種情況:當玩家體力耗盡時,把系統的時間向後調若幹小時,那麼再進遊戲,遊戲體力時滿的,此時遊戲再次用完後 ,仍可以繼續往後調時間,體力繼續恢複滿了。但是,一旦使用者把時間調回目前時間,那麼倒計時顯示的分鐘數将計算為先前調時間最長的時間,也就是幾百甚至上千上萬分鐘,要想繼續玩隻能向後大幅度調時間。這樣做可能有些弊端,就是玩家一旦調整時間,會極大的限制玩家。是以經過商議,我确定将最大體力恢複上限設定一個固定值,當超過上限以後,按最大值倒計時,即使玩家向後調了時間,當改回系統時間的時候,仍然可以等待一點時間繼續遊戲。
體力系統的恢複時間需要涉及到存儲,一旦退出遊戲,再次進入遊戲的時候仍然要顯示體力恢複倒計時。我設計的體力恢複時間存儲的最小機關是分鐘(minute),當然,也可以以秒(second)為機關存儲。存儲的時間是體力不滿時恢複到所有的體力時的時間點(忽略秒),而想到這個存儲的内容,基本上也就解決了體力恢複系統的核心問題。 以下例子是以分鐘為機關編寫的。
1.首先是進入遊戲時體力系統的初始化:
</pre><pre name="code" class="csharp">
</pre><pre name="code" class="csharp">public void DealPower(){
//判斷是不是第一次進遊戲,如果是第一次進遊戲那麼體力給滿格,記錄資料
if(!PlayerPrefs.HasKey("powerMonth")){
//記錄回複滿的時間
NoteRecoverDate(DateTime.Now.Month,DateTime.Now.Day,DateTime.Now.Hour,DateTime.Now.Minute);
Global.CRole.PowerValue = ConstPreference.MAX_NPC_POINT_COUNT;
RefreshPowerShow();
}else{
//如果不是第一次
//1.取出存儲的時間(忽略秒)
DateTime dt = new DateTime(DateTime.Now.Year,PlayerPrefs.GetInt("powerMonth"),PlayerPrefs.GetInt("powerDay"),
PlayerPrefs.GetInt("powerHour"),PlayerPrefs.GetInt("powerMinute"),0);
//2.與目前時間比較
if(DateTime.Compare(DateTime.Now,dt)>=0){
//目前時間比記錄的時間晚:那麼此時應該獲得滿格體力值并且記錄目前時間
NoteRecoverDate(DateTime.Now.Month,DateTime.Now.Day,DateTime.Now.Hour,DateTime.Now.Minute);
Global.CRole.PowerValue = ConstPreference.PLAYER_MAX_POWER;
RefreshPowerShow();//重新整理UI顯示
}else{
//3.目前時間比記錄的時間早:那麼看早多長時間(此種情況适用于體力正在恢複,然後退出遊戲再進入遊戲,體力仍未恢複滿時)
DateTime now = new DateTime(DateTime.Now.Year,DateTime.Now.Month,DateTime.Now.Day,DateTime.Now.Hour,DateTime.Now.Minute,0);
bool isStop = false;//做while循環停止的标記
int minute = 1;//恢複滿所有的體力需要的所有分鐘數
int max = ConstPreference.PLAYER_MAX_POWER*ConstPreference.PLAYER_POWER_RECOVER;//max:設定恢複時間的上限點數乘以恢複一點體力需要的分鐘數即最長分鐘數
while(!isStop){
if(DateTime.Compare(now.AddMinutes(minute),dt)>=0){
isStop = true;
}else{
minute += 1;
}
//4.目前的時間比記錄的時間早minute分鐘
if(minute == max){//如果超過了上限則停止。此種情況适用于玩家修改系統時間後改回原系統時間的情況
isStop = true;
}
}
//4.目前的時間比記錄的時間早minute分鐘
if(minute == max){
//5.提前的時間超過的下限,此時為零體力零計時,應從最大時間開始計時(此種情況适用于玩家故意調時間引起的特殊情況)
Global.CRole.PowerValue = 0;//玩家體力為0
RefreshPowerShow(ConstPreference.PLAYER_POWER_RECOVER);
}else{
//從最大值開始倒計時
Global.CRole.PowerValue = (int)((ConstPreference.PLAYER_MAX_POWER*ConstPreference.PLAYER_POWER_RECOVER - minute)/ConstPreference.PLAYER_POWER_RECOVER);
RefreshPowerShow((ConstPreference.PLAYER_MAX_POWER*ConstPreference.PLAYER_POWER_RECOVER - minute)%ConstPreference.PLAYER_POWER_RECOVER);
}
}
}
}
以上方法是初始化方法。其中,NoteRecoverDate()方式為存儲時間的方法,PlayerPrefs.GetInt("powerMonth")是取出儲存的月份int值。使用系統的時間,需要添加using System。或者使用System.DateTime.Now來擷取時間。在比較時間或者擷取內插補點的時候還可以使用時間的減法來計算。
2.重新整理UI顯示
</pre><pre name="code" class="csharp">
<pre name="code" class="csharp">
public void RefreshPowerShow(int minute = 0){
if(powerValue != null){
powerValue.text = Global.CRole.PowerValue.ToString();
}
if(minute == 0){
//可能是購買體力值,已加滿,或者是剛進遊戲滿格體力
if(Global.CRole.PowerValue >= ConstPreference.PLAYER_MAX_POWER){
if(powerTime != null){
powerTime.text = "00:00";
}
powerTimeInt = 0;//與powerTime同步的int值:為0時靜止,否則就是119-0的倒計時
isTimeByTime = false;//暫停與繼續的标記,開關
}
}else{
powerTimeInt = minute*60-1;
isTimeByTime = true;//開啟計時器
}
}
</pre><p></p><pre>
3.增加體力和減小體力都需要重新計算并存儲恢複滿體力的時間點:
</pre><pre name="code" class="csharp"><pre name="code" class="csharp">public bool CostPower(){//傳回值為布爾值,用來判斷是否還有體力進行遊戲
if(Global.CRole.PowerValue <= 0)
return false;
//如果目前是滿格體力
if(Global.CRole.PowerValue == ConstPreference.PLAYER_MAX_POWER){
Global.CRole.PowerValue -= 1;
//開始倒計時
powerTimeInt = ConstPreference.PLAYER_POWER_RECOVER * 60-1;
RefreshPowerShow();
isTimeByTime = true;
}else{
Global.CRole.PowerValue -= 1;
RefreshPowerShow();
}
DealSaveData();//重新計算并存儲時間
return true;
}
<pre name="code" class="csharp">public void AddPower(int val){
Global.CRole.PowerValue += val;
if(Global.CRole.PowerValue > ConstPreference.PLAYER_MAX_POWER){
Global.TipsFormMgr.OpenForm(null,CConstString.Tips_FullPower,false);//公有提示視窗,提示體力超限
Global.CRole.PowerValue = ConstPreference.PLAYER_MAX_POWER;
}
DealSaveData();//重新計算并存儲時間
RefreshPowerShow();
}
4.倒計時方法
</pre><pre name="code" class="csharp">/// <summary>
/// 每秒執行一次.
/// </summary>
public void RefreshTimeBySceond(){
if(!isTimeByTime){
//暫停遊戲
powerTimeInt = 0;
if(powerTime != null){
powerTime.text = "00:00";
}
}else{
//體力恢複程序
if(powerTime != null){
powerTime.text = SwitchIntToString(powerTimeInt);
}
if(powerTimeInt == 0){
//計時完成,體力值+1
Global.CRole.PowerValue += 1;
if(powerValue != null){
powerValue.text = Global.CRole.PowerValue.ToString();//把int轉換成時間字元串即“00:00”
}
//如果體力值已滿,那麼暫停計時
if(Global.CRole.PowerValue >= ConstPreference.PLAYER_MAX_POWER){
isTimeByTime = false;
}else{
//如果體力值未滿,那麼繼續計時
powerTimeInt = ConstPreference.PLAYER_POWER_RECOVER * 60-1;
}
}else
powerTimeInt -= 1;
}
}
5.恢複體力的計算與存儲
//存儲體力恢複滿的時間點:隻有在消耗體力或者增加體力時才調用此方法
void DealSaveData(){
//計算剩餘分鐘數
int leftmin = (ConstPreference.PLAYER_MAX_POWER - Global.CRole.PowerValue)*ConstPreference.PLAYER_POWER_RECOVER
- (int)((ConstPreference.PLAYER_POWER_RECOVER*60 - powerTimeInt)/60);
if(leftmin<=0){
NoteRecoverDate(DateTime.Now.Month,DateTime.Now.Day,DateTime.Now.Hour,DateTime.Now.Minute);
}else{
DateTime dt = DateTime.Now.AddMinutes(leftmin);
NoteRecoverDate(dt.Month,dt.Day,dt.Hour,dt.Minute);
}
}
以上就是我設計的簡單的單機遊戲的體力系統,歡迎大家提出意見和不足,謝謝!