摘要: 飛機大戰(zhàn)是一款經(jīng)典的游戲,最早應(yīng)追溯到打擊者1945(Strikers 1945),這是日本彩京公司于1995年發(fā)售的飛行射擊游戲。本作是參照打擊者1945基于visual C++寫成的飛行射擊類游戲。本作中實現(xiàn)了敵機的產(chǎn)生功能、子彈的發(fā)射功能、飛機中彈銷毀和計算得分等功能,而且通過文件讀寫的相關(guān)操作完成了存檔與讀檔的相關(guān)操作。本作通過便捷的操作方式,使玩家可以輕易地上手該游戲,在游戲中放松心情,釋放壓力,提高反應(yīng)能力。游玩該游戲可以為玩家?guī)須g樂。
關(guān)鍵詞: 可視化 飛機大戰(zhàn) 游戲設(shè)計
引言 隨著社會的不斷發(fā)展,人們的生活方式也不斷的在變化,人們的娛樂方式也越發(fā)的多種多樣。人們對美好生活的向往,不單單局限于物質(zhì)生活,人們的精神生活也在一天天的豐富。游戲是很多人精神生活中的一種重要組成部分。毫無疑問飛機大戰(zhàn)是一款極其經(jīng)典的游戲,玩家通過鼠標或鍵盤操作飛機攻擊敵方飛機,躲避碰撞和敵方飛機攻擊。極其簡單的操作和輕松的上手,使得這一款游戲帶給了無數(shù)人歡樂。
1 需求分析
在飛行射擊類游戲中,玩家登陸游戲后可以通過鼠標或鍵盤操作飛機前進,躲避敵機攻擊,并通過點擊鼠標左鍵或空格鍵發(fā)射子彈擊敗敵機。
完成這個飛機大戰(zhàn)游戲的設(shè)計,需要完成用戶飛機的移動功能,敵機的產(chǎn)生功能、子彈的發(fā)射功能、飛機中彈銷毀和計算得分等功能。在用戶需要時可以暫停游戲,可以通過文件讀寫完成存檔與讀檔。為豐富游戲的趣味性,相應(yīng)增加了各種音效,并會根據(jù)用戶的得分產(chǎn)生相應(yīng)的敵機。
2 關(guān)鍵技術(shù)
2.1 C++面向?qū)ο蟮某绦蛟O(shè)計
C++起始于C語言。當(dāng)C語言發(fā)展到巔峰時出現(xiàn)了增加關(guān)鍵詞和類的C with class的C語言版本,而這是C語言的一大突破,開發(fā)者將這一種語言命名為C++。這便是C++最早的版本。
美國AT&T貝爾實驗室的本賈尼·斯特勞斯特魯普博士在20世紀80年代初期成功地實現(xiàn)了C++,即C with classes。當(dāng)時C++是作為C語言的加強版本出現(xiàn),從給C增加類開始,不斷增加新的特征[1]。
然而就目前而言,C++可以認為它是一門獨立的編程語言,它源于C語言但是它并不依賴于C語言。C++與C語言也是有本質(zhì)差別:在于C++是面向?qū)ο蟮?,而C語言是面向過程的。或者說C++是在C語言的基礎(chǔ)上增加了面向?qū)ο蟪绦蛟O(shè)計的新內(nèi)容,是對C語言的一次更重要的改革,使得C++成為軟件開發(fā)的重要工具。
2.2 C++語言的優(yōu)點
(1)在C語言的基礎(chǔ)上進行擴充和完善,使C++兼容了C語言的面向過程特點,又成為了一種面向?qū)ο蟮某绦蛟O(shè)計語言; (2)可以使用抽象數(shù)據(jù)類型進行基于對象的編程; (3)可以使用多繼承、多態(tài)進行面向?qū)ο蟮木幊蹋? (4)可以擔(dān)負起以模版為特征的泛型化編程。 (5)C++實現(xiàn)了面向?qū)ο蟪绦蛟O(shè)計。在高級語言當(dāng)中,處理運行速度是最快的,大部分的游戲軟件,系統(tǒng)都是由C++來編寫的。
(6)C++語言非常靈活,功能非常強大。如果說C語言的優(yōu)點是指針,那么C++的優(yōu)點就是性能和類層次結(jié)構(gòu)的設(shè)計。
(7)C++非常嚴謹、精確和數(shù)理化,標準定義很細致。
(8)C++語言的語法思路層次分明、相呼應(yīng);語法結(jié)構(gòu)是顯式的、明確的。
2.3 Visual C++的優(yōu)點
(1)與Windows緊密結(jié)合,MFC類庫集成了大量已經(jīng)預(yù)先定義好的類,用戶可以根據(jù)編程的需要定義相應(yīng)的類,或根據(jù)需要自己定義相應(yīng)的類。因此Visual C++在使用API等方面和Windows聯(lián)系的最為緊密[2]。
(2)強大的類庫支持和類改造能力。代碼重用是C++追求的目標,重用就是從已有的基類派生出新的C++類;MFC提供了大量的基類供程序員們根據(jù)不同的應(yīng)用要求生成新的類以滿足要求。VC++有了MFC,具有非常強大對類改造的能力。只要集成MFC類,稍加修改就可以得到符合要求的控件類或應(yīng)用類。
(3)擁有高效的運行速度。高的運行速度取決于兩點:1.軟件本身編寫的質(zhì)量,2.編程工具的編譯質(zhì)量。因為VC++非常接近Windows底層,所以編譯器所編譯的質(zhì)量相當(dāng)高,從而保證了VC++編寫出來的軟件產(chǎn)品擁有高效的運行速度[3]。
2.4 C++的語言體系
(1)C子語言。C++是以C語言為基礎(chǔ),C++幾乎支持C語言的全部功能。
(2)面向?qū)ο蟮腃++。C++首先是一門面向?qū)ο蟮某绦蛟O(shè)計語言,并以此聞名。
(3)泛型編程語言。相比C語言,C++增加了模板,C++強大的模板功能使系統(tǒng)能夠在編譯期間就能完成許多工作,從而大大提高了運行效率[4]。
(4)STL。隨著STL的不斷發(fā)展,漸漸成為C++程序設(shè)計體系中不可或缺的一部分。其安全性與規(guī)范性的優(yōu)秀使得它受到程序員的歡迎[1]。
3.游戲總體設(shè)計
游戲被分成兩個部分,一部分是與用戶輸入有關(guān)的更新,包括根據(jù)鼠標位置或鍵盤按鍵進行飛機的移動和炮彈發(fā)射等等。另一部分是與用戶輸入無關(guān)的更新,包括子彈移動,敵機移動邏輯等判斷。圖1為飛機大戰(zhàn)程序設(shè)計圖。
[圖片上傳失敗...(image-6b775-1626647574358)]
圖1 飛機大戰(zhàn)程序設(shè)計圖
4 游戲功能實現(xiàn)
4.1 代碼設(shè)計
4.1.1 頭文件
(1) #include<iostream>頭文件,包含頭文件輸入輸出流,c++中沒有c語言中輸入輸出語句(比如#include<stdio>),而是利用數(shù)據(jù)流來解決這個問題。要使用比如cout,cin語句輸入輸出函數(shù)。其中#include文件的目的是把多個編譯單元公用的內(nèi)容單獨放在一個文件里減少整體代碼尺寸,或者提供可跨工程使用的公共代碼;
(2)#include<fstream>頭文件#include 是C++的預(yù)編譯語句,作用是包含對應(yīng)的文件,在這里是包含C++的STL頭文件fstream。在包含了這個文件后,就可以使用fstream中定義的類及各種成員函數(shù)了。fstream是C++ STL中對文件操作的合集,包含了常用的所有文件操作。在C++中,所有的文件操作,都是以流(stream)的方式進行的,fstream也就是文件流file stream[5]。
(3)#include<iomanip>頭文件,這個頭文件是聲明一些 “流操作符”的,比較常用的setw(int);//設(shè)置顯示寬度、left//right//設(shè)置左右對齊、setprecision(int);//設(shè)置浮點數(shù)的精確度。
(4)#include<fstream>包含讀寫文件頭文件,實際上是一個輸出流的類模板,含有ifstream和ofstream兩個派生類。
(5)#include <math.h> 是包含math頭文件的意思,math.h頭文件中聲明了常用的一些數(shù)學(xué)運算,比如乘方,開方運算等等。
(6)#include<graphics.h>頭文件是C語言和visual studio的圖形庫文件,包含像素函數(shù)、線型函數(shù)、畫線函數(shù)、相對畫線函數(shù)等多種函數(shù),可進行圖形的快速編程。這也是實現(xiàn)可視化的最重要工具。使用easyx.exe,可以直接運行安裝圖形庫到visual studio。然后直接使用。
(7)#include<windows.h>頭文件是最重要的頭文件之一,它包含了其他Windows頭文件,這些頭文件也包含了其他頭文件,其中有用戶界面函數(shù)<Winuser.h>、圖形設(shè)備接口函數(shù)<Wingdi.h>[6]。
(8)#include<conio.h>是Console Input/Output(控制臺輸入輸出)的簡寫,其中定義了通過控制臺進行數(shù)據(jù)輸入和數(shù)據(jù)輸出的函數(shù),主要是一些用戶通過按鍵盤產(chǎn)生的對應(yīng)操作,比如getch()函數(shù)等等[4]。
(9)#pragma comment(lib,"Winmm.lib")聲明程序使用了winmm.lib庫,這個庫是是Windows多媒體相關(guān)應(yīng)用程序接口,用于低檔的音頻和游戲手柄??梢杂脕韺崿F(xiàn)音頻的添加和利用。在該飛機大戰(zhàn)程序中這個庫中的內(nèi)容實現(xiàn)了游戲運行時中的背景音樂的開始和結(jié)束放映等功能。
4.1.2使用函數(shù)
settextstyle() 設(shè)置文本型式函數(shù),函數(shù)settextstyle() 設(shè)置圖形文本當(dāng)前字體、文本顯示方向(水平顯示或垂直顯示)以及字符大小。在使用中用于顯示得分和成績。通常與Outtextxy配套使用。
Outtextxy()函數(shù),這個函數(shù)用于在指定位置輸出字符串。
loadimageLoadImage()函數(shù),功能是裝載圖標,光標,或位圖。在本程序中用于加載圖片。
Initgraph()函數(shù)功能為初始化圖形系統(tǒng)。pathtodriver表示存放圖形驅(qū)動文件的路徑。
SetTextColor(),Windows API 函數(shù),設(shè)置指定DC中的文字顏色。
kbhit()是一個C和C++函數(shù),用于非阻塞地響應(yīng)鍵盤輸入事件。其中文可譯為“鍵盤敲擊”(keyboard hit),注意這個函數(shù)在高版本VC下已被淘汰,應(yīng)使用_kbhit()函數(shù)。
MouseHit()函數(shù)是實現(xiàn)鼠標操作最關(guān)鍵的函數(shù),用于判斷是否有鼠標信息。[5]使用MouseHit()函數(shù)效果與kbhit()函數(shù)效果類似,如果沒有鼠標信息自動跳過。避免了因為沒有鼠標信息導(dǎo)致程序無法運行的狀況[7]。
getch()是編程中所用的函數(shù),這個函數(shù)是一個不回顯函數(shù),當(dāng)用戶按下某個字符時,函數(shù)自動讀取,無需按回車,有的C語言命令行程序會用到此函數(shù)做游戲,但是這個函數(shù)并非標準函數(shù)。在高版本VC或者VS中已經(jīng)無法使用應(yīng)該使用_getch()函數(shù)[8]。
SetBkMode()函數(shù)這就需要使用SetBkMode函數(shù)來設(shè)置DrawText函數(shù)的輸出方式,顯示設(shè)備共有兩種輸出方式:OPAQUE和TRANSPARENT。OPAQUE的方式是用當(dāng)前背景的畫刷的顏色輸出顯示文字的背景,而TRANSPARENT是使用透明的輸出,也就是文字的背景是不改變的。
MCI(Media Control Interface,媒體控制接口)函數(shù)中,有些只適用于一種接口方式,有些則兩種接口都可以用。mciSendString只適用于命令串接口方式(命令串中不區(qū)分大小寫)以形如mciSendString("play movie",buf,sizeof(buf),NULL);的方式進行音頻播放,以形如mciSendString("pause movie",buf,sizeof(buf),NULL);的方式暫停播放。以形如mciSendString("close movie",buf,sizeof(buf),NULL)的形式關(guān)閉播放。
4.2操作邏輯
本程序使用兩種操作方式,依靠鍵盤按鍵操作和依靠鼠標位置進行操作。圖2為飛機移動操作邏輯示意圖。
[圖片上傳失敗...(image-cdff38-1626647574358)]
圖2 飛機移動操作邏輯示意圖
使用鼠標操作代碼如下:
if (isExpolde == 0)
{
MOUSEMSG m;
while (MouseHit())
{
m = GetMouseMsg();
if (m.uMsg == WM_MOUSEMOVE)
{
position_x = m.x;
position_y = m.y;
}
else if (m.uMsg == WM_LBUTTONDOWN)
{
bullet_x = position_x;
bullet_y = position_y - 85;
}}
}
對應(yīng)的使用鍵盤操作代碼為:
char input;
if (_kbhit()) // 判斷是否有輸入
{input = _getch(); // 根據(jù)用戶的不同輸入來移動,不必輸入回車
if (input == 27) // ESC鍵的ACSII碼為27
gameStatus = 3;
if (input == 'a')
position_x -= 10;
if (input == 'd')
position_x += 10;
if (input == 'w')
position_y += 10;
if (input == 's')
position_y -= 10;}
先定義MOUSEMSG的鼠標類型參數(shù)m;通過while (MouseHit()) 進行操作,既能保證能夠使用鼠標進行操作也避免了,在沒有鼠標操作時游戲的停止。
類似的有定義char 類型的的變量通過while(_kbhit())來進行是否有鍵盤信息的判斷,用_getch()函數(shù)獲取鍵盤的敲擊值。
4.3 與用戶輸出無關(guān)的邏輯
4.3.1 敵機生成邏輯
使用rand()函數(shù)生成一個最大為32767的數(shù),并通過%(Width-50)得到飛機的初始坐標,并同時將blood等參數(shù)復(fù)原。
4.3.2 敵機簡單移動邏輯
代碼如下:
if (enemy_y < High - 25)
{
if (enemy_x == 0)
flag = 0;
if (enemy_x == 500)
flag = 1;
enemy_y = enemy_y + 1;
if (flag == 1)
enemy_x = enemy_x--;
else enemy_x = enemy_x++;
}
通過定義全局變量static flag 進行操控飛機的飛行方向,同時在每個循環(huán)過程中使飛機能夠?qū)崿F(xiàn)擺動下降。
4.4暫停頁面與存儲邏輯
通過_getch()函數(shù)讀取輸入,如存在按鍵為Esc時,將gameStatus設(shè)置為3,出現(xiàn)暫停頁面,圖3為游戲暫停頁面。
圖3 游戲暫停頁面
游戲數(shù)據(jù)儲存邏輯
void read() {
ifstream file2;//輸入指針
file2.open("../data.txt");
file2 >> position_x >> position_y >> bullet_x >> enemy_x >> enemy_y >> isExpolde >> score;
file2.close();};
void write() {
ofstream file1;
file1.open("./data.txt", std::ios::app);
if (!file1.is_open()) {
std::cout << "打開文件失敗??!\n";
exit(0);
}
file1 << position_x << " " << position_y << " " << bullet_x << " " << enemy_x << " " << enemy_y <<" " << isExpolde <<" " << score << "\n";
file1.close();
};
通過ifstream和ofstream兩個類進行操作,實現(xiàn)數(shù)據(jù)的存儲于寫入。也通過鍵盤操作識別Esc按鈕實現(xiàn)暫停操作。
圖4為飛機大戰(zhàn)程序登錄界面,圖5為程序運行截圖。
圖4 程序登錄界面
圖5 程序運行截圖
5.總結(jié)
基于C++的可視化飛機大戰(zhàn)游戲是一個簡單的可視化的小游戲,玩家能夠通過鼠標或鍵盤進行操控飛機的移動和攻擊,并且運用了文件操作技術(shù),可以實現(xiàn)數(shù)據(jù)的永久性保存?;贑++的飛機大戰(zhàn)游戲是采用C++語言及其easyX拓展模塊開發(fā)完成的。本項目實現(xiàn)了游戲流程中的所有功能,界面布局更加人性化,并有著良好的可擴展性。但游戲依舊存在一些不足之處,比如說本游戲還沒有實現(xiàn)對玩家操縱飛機進行血量的顯示,敵方飛機尚無法發(fā)射子彈,對擊中邏輯的判斷還存在問題。
參考文獻:
[1]黃寶貴等.C++面向?qū)ο蟪绦蛟O(shè)計[M] 北京:清華大學(xué)出版社,2019:2-3
[2]童晶編著.C語言程序設(shè)計與游戲開發(fā)實踐教程[M] 北京:清華大學(xué)出版社 2017:16
[3]黃維通等.Visual C++面向?qū)ο笈c可視化程序設(shè)計[M](第三版)北京:清華大學(xué)出版社 2011:14
[4]鄭莉等編著.C++程序設(shè)計語言(第三版)[M].北京:清華大學(xué)出版社,2005:134-139.
[5]劉振安等編著.C++程序設(shè)計課程設(shè)計[M] 北京:機械工業(yè)出版社,2004:23-31 [6]朱立華等編著.面向?qū)ο蟪淘O(shè)計及C++[M].北京:人民郵電出版社,2008:43 [7]鄭莉,董淵.C++語言程序設(shè)計(第二版) [M].北京清華大學(xué)出版社,2002:23 [8]陳維興,林小茶.C++面向?qū)ο蟪绦蛟O(shè)計教程(第2版)[M].北京清華大學(xué)出版社.2007:34