勘誤:筆者發現,在movePlayer函數中開A,B,C門的部分,askUser詢問玩家的時候,若是按下F2拒絕會有問題
因此這邊麻煩大家在if(askUser())的後面稍微加上一段else
/* File: PlayGround.c */
// 以下是節錄自movePlayer函數內部,處理A,B,C門的部分
if(game_map[y][x] == 'A')
{
if(p.key_a_num > 0)
{
if(askUser("遇到A門,是否開啟?"))
{
game_map[p.y][p.x] = ' ';
game_map[y][x] = p.skin;
p.x = x;
p.y = y;
printf("使用鑰匙a開啟A門!\n");
playMusic(UNLOCK, SE_MODE);
waitForUser(500);
p.key_a_num -= 1;
}
// ------------請各位加上這部分-------------------
else
{
system("cls");
}
// ----------------------------------------------
}
}
if(game_map[y][x] == 'B')
{
if(p.key_b_num > 0)
{
if(askUser("遇到B門,是否開啟?"))
{
game_map[p.y][p.x] = ' ';
game_map[y][x] = p.skin;
p.x = x;
p.y = y;
printf("使用鑰匙b開啟B門!\n");
playMusic(UNLOCK, SE_MODE);
waitForUser(500);
p.key_b_num -= 1;
}
// ------------請各位加上這部分-------------------
else
{
system("cls");
}
// ----------------------------------------------
}
}
if(game_map[y][x] == 'C')
{
if(p.key_c_num > 0)
{
if(askUser("遇到C門,是否開啟?"))
{
game_map[p.y][p.x] = ' ';
game_map[y][x] = p.skin;
p.x = x;
p.y = y;
printf("使用鑰匙c開啟C門!\n");
playMusic(UNLOCK, SE_MODE);
waitForUser(500);
p.key_c_num -= 1;
}
// ------------請各位加上這部分-------------------
else
{
system("cls");
}
// ----------------------------------------------
}
}
引言
昨天我們加上了可以四處撿鑰匙開門的功能後,遊戲變得稍加有挑戰性了吧~
不過我們再來模擬得更像魔塔一點吧!
這次我們為玩家加上 生命、攻擊、防禦,以及金錢 等部分,
是不是越來越像RPG遊戲了呢~
我們先來說說魔塔,魔塔的攻擊怪物方式是全自動的,
只要玩家觸碰怪物,系統就會自動運算戰鬥結果,如果玩家算起來的結果是輸了,
則系統會告知玩家打不過,就避免你攻擊怪物。
換句話說這遊戲玩家不會死亡,只要打不過系統就不讓你打。
而如果系統運算結果是玩家贏了,則會自動殺死怪物,玩家就會被扣除計算後被怪物打的總量。
魔塔的戰鬥系統就是這麼簡單,我們就來試著實作看看囉!
血量、攻擊、防禦,以及金錢
我們需要先在Player結構中加上玩家的新數值:hp, atk, def, money。
/* File: PlayGround.h */
typedef struct player
{
char skin;
int x;
int y;
int key_a_num;
int key_b_num;
int key_c_num;
// ------------新增部分-------------------
int hp;
int atk;
int def;
int money;
// --------------------------------------
}Player;
然後關於初始化,我們必須把initPlayer做個分割,
因為原本的初始化是每個PlayGround都會做一次,但如果每個關卡都初始化鑰匙、生命值等等的,
會非常奇怪而且失去關卡的意義(破關就是要以現有狀態繼續闖關嘛~),
因此我們會定義一個新的函數,稱為initPlayerStatus,
裡頭會初始化hp, atk, def, 鑰匙, 金錢等等,
這個函數將只會執行一次,在遊戲剛開始時。
而原來的initPlayer將會每個關卡都執行,裡頭只會初始化玩家位置等。
因此我們會將三行鑰匙數量的初始化移到initPlayerStatus
/* File: PlayGround.h */
// 新增initPlayerStatus宣告
void initPlayerStatus();
/* File: PlayGround.c */
void initPlayer(char skin, int x, int y)
{
isPlaying = 1;
p.skin = skin;
p.x = x;
p.y = y;
// ------------把鑰匙初始化移到下面的函數-------------------
// ------------------------------------------------------
game_map[y][x] = skin;
}
void initPlayerStatus()
{
// ------------移到這邊-------------------
p.key_a_num = 0;
p.key_b_num = 0;
p.key_c_num = 0;
// --------------------------------------
// ------------新增部分-------------------
p.hp = 1000; // 血量初始化為1000
p.atk = 10; // 攻擊初始化為10
p.def = 10; // 防禦初始化為10
p.money = 0; // 一開始家徒四壁
// --------------------------------------
}
然後到main函數呼叫initPlayerStatus:
/* File: main.c */
.
..
...
// 在playGround函數呼叫前先呼叫
// ------------新增部分-------------------
initPlayerStatus();
// --------------------------------------
playGround(LEVEL0_MAP, 28, 4);
playGround(LEVEL1_MAP, 28, 27);
return 0;
最後,記得在狀態欄加上它們:
/* File: PlayGround.c */
void playerStatus()
{
printf("[道具欄] 鑰匙A: %02d支 鑰匙B: %02d支 鑰匙C: %02d支\n", p.key_a_num, p.key_b_num, p.key_c_num);
// ------------新增部分-------------------
printf("[ 狀態 ] 生命值: %5d 攻擊力: %5d 防禦值: %5d\n", p.hp, p.atk, p.def);
printf("[ 金錢 ] %8d\n", p.money);
// --------------------------------------
}
藥水
有了這些狀態以後,當然也要有一些可以上升這些數值的藥水啦,
我們先在地圖內加上一些代表藥水的字元:
字元 | 哪種藥水 |
---|---|
h | 生命藥水,hp上升100 |
s | 攻擊藥水,atk上升10 |
d | 防禦藥水,def上升10 |
然後我們在程式中加入判斷:
/* File: PlayGround.c */
// 於movePlayer函數內部,加入遇到h,s,d三種字元的情況
if(game_map[y][x] == 'h') // 若遇到h,生命+100
{
game_map[p.y][p.x] = ' ';
game_map[y][x] = p.skin;
p.x = x;
p.y = y;
printf("生命值+100!\n");
playMusic(SYSTEM_OK, SE_MODE);
waitForUser(500);
p.hp += 100;
}
if(game_map[y][x] == 's') // 若遇到s,攻擊+10
{
game_map[p.y][p.x] = ' ';
game_map[y][x] = p.skin;
p.x = x;
p.y = y;
printf("攻擊力上升10!\n");
playMusic(SYSTEM_OK, SE_MODE);
waitForUser(500);
p.atk += 10;
}
if(game_map[y][x] == 'd') // 若遇到d,防禦+10
{
game_map[p.y][p.x] = ' ';
game_map[y][x] = p.skin;
p.x = x;
p.y = y;
printf("防禦值上升10!\n");
playMusic(SYSTEM_OK, SE_MODE);
waitForUser(500);
p.def += 10;
}
執行
狀態欄出現新的項目:
吃到d(防禦藥水)的狀況: