做遊戲,學程式設計(C語言) 7 學習EasyX圖形互動功能----flappy bird原始碼
經過之前的學習,我們基本掌握了開發小遊戲所需要的語法知識和搭建方法,但是基礎C語言的視覺化與互動功能實在是太弱了
。
利用免費的EasyX外掛,我們可以快速上手,簡單實現很酷的視覺效果
。
EasyX安裝包下載連結:下載 —— EasyX Library for C++
怎樣安裝 EasyX? —— EasyX Library for C++
怎樣使用 EasyX?(Visual C++ 6。0) —— EasyX Library for C++
怎樣使用 EasyX?(Visual C++ 2008) —— EasyX Library for C++
官網還提供了一套非常好的入門教程,大家可以自學:VC繪圖/遊戲簡易教程——前言 —— EasyX Library for C++
對應的目錄:
–前言
–1:建立新專案
–2:簡單繪圖,學習單步執行
–3:熟悉更多的繪圖語句
–4:結合流程控制語句來繪圖
–5:數學知識在繪圖中的運用
–6:實現簡單動畫
–7:捕獲按鍵,實現動畫的簡單控制
–8:用函式簡化相同圖案的製作
–9:繪圖中的位運算
–10:用滑鼠控制繪圖/遊戲程式
–11:隨機函式
–12:陣列
–13:getimage / putimage / loadimag / saveimage / IMAGE 的用法
–14:透過位運算實現顏色的分離與處理
–15:窗體控制代碼(Windows 程式設計入門)
–16:裝置上下文控制代碼(Windows 程式設計入門2)
學習完後,大家可以試著將前面教程中學習的生命遊戲、反彈球、flappy bird、空戰遊戲用EasyX重新實現,達到類似這樣的效果:
大家可以在網上搜索諸如“flappy bird遊戲素材”,下載對應的圖片和音樂素材。也可以直接在原始遊戲中截圖,ps出需要的素材。
下面是用EasyX實現的flappy bird需要的圖片:
素材程式碼可由百度雲盤下載:
http://
pan。baidu。com/s/1o8lnH7
0
,首先大家可以執行flappy bird\easyx bird\Debug\happyhappy。exe 檔案看看遊戲效果。
以下為遊戲程式碼,大家可以參考:
/*
畫面大小350*600
鳥的大小100*70
柱子寬處寬度140,窄處寬度100,寬處厚度30,顏色
*/
#include
#include
#include
#include
#include
// 引用 Windows Multimedia API
#pragma comment(lib,“Winmm。lib”)
void
();
void
begin
();
void
printstone
();
//人家才不是作柱子的呢
void
bird
();
//控制鳥的下降和上升
void
judgement
();
//判斷語句
void
scoleprint
();
void
endorretry
();
int
bird_x
=
150
,
bird_y
=
300
,
i
=
0
,
k
=
0
;
//鳥的左上角座標
int
scole
=
0
,
t
=
0
;
int
stone_x1
,
stone_y1
;
//上截柱子左下座標
int
stone_x2
,
stone_y2
;
//上截柱子左下座標
IMAGE
backgrand
,
bird1
[
4
],
bird2
[
4
],
scole1
[
10
],
scole2
[
10
],
stone_up1
,
stone_up2
,
stone_down1
,
stone_down2
,
stone_up3
,
stone_up4
,
stone_down3
,
stone_down4
;
//圖片儲存變數
MOUSEMSG
m
;
// 定義滑鼠訊息
int
main
()
{
if
(
t
==
0
)
{
begin
();
t
++
;
}
if
(
t
)
();
getch
();
//製造停頓
bird_y
=
300
;
bird_x
=
150
;
i
=
0
;
k
=
0
;
scole
=
0
;
while
(
1
)
{
bird
();
();
judgement
();
}
closegraph
();
return
0
;
}
void
()
{
putimage
(
0
,
0
,
&
backgrand
);
//背景影象
printstone
();
//畫柱子
putimage
(
bird_x
,
bird_y
,
&
bird1
[
i
%
3
],
NOTSRCERASE
);
putimage
(
bird_x
,
bird_y
,
&
bird2
[
i
%
3
],
SRCINVERT
);
if
(
k
%
5
==
0
)
i
++
;
k
++
;
scoleprint
();
FlushBatchDraw
();
// 繪製
}
void
printstone
()
//柱子移動規律/哭
{
Sleep
(
30
);
if
(
stone_x1
>
210
)
//此時畫面存在兩根柱子
{
putimage
(
stone_x1
,
stone_y1
,
&
stone_up2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
,
&
stone_up1
,
SRCINVERT
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down1
,
SRCINVERT
);
putimage
(
stone_x2
,
stone_y2
,
&
stone_up4
,
NOTSRCERASE
);
putimage
(
stone_x2
,
stone_y2
,
&
stone_up3
,
SRCINVERT
);
putimage
(
stone_x2
,
stone_y2
+
750
,
&
stone_down4
,
NOTSRCERASE
);
putimage
(
stone_x2
,
stone_y2
+
750
,
&
stone_down3
,
SRCINVERT
);
stone_x1
——
;
stone_x2
——
;
}
else
if
(
stone_x1
==
210
)
//左柱子消失,將stone_x2,stone_y2值歸位
{
stone_x2
=
stone_x1
;
stone_y2
=
stone_y1
;
putimage
(
stone_x1
,
stone_y1
,
&
stone_up2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
,
&
stone_up1
,
SRCINVERT
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down1
,
SRCINVERT
);
stone_x1
——
;
stone_x2
——
;
}
else
if
(
stone_x1
<
210
&&
stone_x1
>
0
)
//畫面只存在一根柱子的情況
{
putimage
(
stone_x1
,
stone_y1
,
&
stone_up2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
,
&
stone_up1
,
SRCINVERT
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down1
,
SRCINVERT
);
stone_x1
——
;
stone_x2
——
;
}
if
(
stone_x1
==
0
)
//柱子左端到站,生成新柱子
{
stone_y1
=
rand
()
%
310
-
555
;
stone_x1
=
350
;
putimage
(
stone_x1
,
stone_y1
,
&
stone_up2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
,
&
stone_up1
,
SRCINVERT
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down1
,
SRCINVERT
);
stone_x1
——
;
stone_x2
——
;
}
}
void
begin
()
{
mciSendString
(
“open
\”
。。
\\
。。
\\
sounds
\\
background。mp3
\“
alias music ”
,
NULL
,
0
,
NULL
);
//背景音樂
mciSendString
(
“play music”
,
NULL
,
0
,
NULL
);
initgraph
(
350
,
600
);
// 獲取視窗控制代碼
HWND
hwnd
=
GetHWnd
();
// 設定視窗標題文字
SetWindowText
(
hwnd
,
“江超群製作”
);
IMAGE
beforegame
;
loadimage
(
&
beforegame
,
“。。
\\
。。
\\
素材庫
\\
beforegame。jpg”
);
putimage
(
0
,
0
,
&
beforegame
);
Sleep
(
1000
);
getch
();
BeginBatchDraw
();
// 開啟批次繪圖模式
loadimage
(
&
backgrand
,
“。。
\\
。。
\\
素材庫
\\
backgroundfd。jpg”
);
//載入背景圖片
//鳥
loadimage
(
&
bird2
[
0
],
“。。
\\
。。
\\
素材庫
\\
bird1-2。gif”
);
loadimage
(
&
bird1
[
0
],
“。。
\\
。。
\\
素材庫
\\
bird1-1。gif”
);
loadimage
(
&
bird2
[
1
],
“。。
\\
。。
\\
素材庫
\\
bird2-2。gif”
);
loadimage
(
&
bird1
[
1
],
“。。
\\
。。
\\
素材庫
\\
bird2-1。gif”
);
loadimage
(
&
bird2
[
2
],
“。。
\\
。。
\\
素材庫
\\
bird3-2。gif”
);
loadimage
(
&
bird1
[
2
],
“。。
\\
。。
\\
素材庫
\\
bird3-1。gif”
);
loadimage
(
&
bird2
[
3
],
“。。
\\
。。
\\
素材庫
\\
bird4-2。gif”
);
loadimage
(
&
bird1
[
3
],
“。。
\\
。。
\\
素材庫
\\
bird4-1。gif”
);
//柱子
loadimage
(
&
stone_up1
,
“。。
\\
。。
\\
素材庫
\\
stone_up1。gif”
);
loadimage
(
&
stone_up2
,
“。。
\\
。。
\\
素材庫
\\
stone_up2。gif”
);
loadimage
(
&
stone_down1
,
“。。
\\
。。
\\
素材庫
\\
stone_down1。gif”
);
loadimage
(
&
stone_down2
,
“。。
\\
。。
\\
素材庫
\\
stone_down2。gif”
);
loadimage
(
&
stone_up3
,
“。。
\\
。。
\\
素材庫
\\
stone_up1。gif”
);
loadimage
(
&
stone_up4
,
“。。
\\
。。
\\
素材庫
\\
stone_up2。gif”
);
loadimage
(
&
stone_down3
,
“。。
\\
。。
\\
素材庫
\\
stone_down1。gif”
);
loadimage
(
&
stone_down4
,
“。。
\\
。。
\\
素材庫
\\
stone_down2。gif”
);
//數字
loadimage
(
&
scole1
[
0
],
“。。
\\
。。
\\
素材庫
\\
0_1。jpg”
);
loadimage
(
&
scole2
[
0
],
“。。
\\
。。
\\
素材庫
\\
0_2。jpg”
);
loadimage
(
&
scole1
[
1
],
“。。
\\
。。
\\
素材庫
\\
1_1。jpg”
);
loadimage
(
&
scole2
[
1
],
“。。
\\
。。
\\
素材庫
\\
1_2。jpg”
);
loadimage
(
&
scole1
[
2
],
“。。
\\
。。
\\
素材庫
\\
2_1。jpg”
);
loadimage
(
&
scole2
[
2
],
“。。
\\
。。
\\
素材庫
\\
2_2。jpg”
);
loadimage
(
&
scole1
[
3
],
“。。
\\
。。
\\
素材庫
\\
3_1。jpg”
);
loadimage
(
&
scole2
[
3
],
“。。
\\
。。
\\
素材庫
\\
3_2。jpg”
);
loadimage
(
&
scole1
[
4
],
“。。
\\
。。
\\
素材庫
\\
4_1。jpg”
);
loadimage
(
&
scole2
[
4
],
“。。
\\
。。
\\
素材庫
\\
4_2。jpg”
);
loadimage
(
&
scole1
[
5
],
“。。
\\
。。
\\
素材庫
\\
5_1。jpg”
);
loadimage
(
&
scole2
[
5
],
“。。
\\
。。
\\
素材庫
\\
5_2。jpg”
);
loadimage
(
&
scole1
[
6
],
“。。
\\
。。
\\
素材庫
\\
6_1。jpg”
);
loadimage
(
&
scole2
[
6
],
“。。
\\
。。
\\
素材庫
\\
6_2。jpg”
);
loadimage
(
&
scole1
[
7
],
“。。
\\
。。
\\
素材庫
\\
7_1。jpg”
);
loadimage
(
&
scole2
[
7
],
“。。
\\
。。
\\
素材庫
\\
7_2。jpg”
);
loadimage
(
&
scole1
[
8
],
“。。
\\
。。
\\
素材庫
\\
8_1。jpg”
);
loadimage
(
&
scole2
[
8
],
“。。
\\
。。
\\
素材庫
\\
8_2。jpg”
);
loadimage
(
&
scole1
[
9
],
“。。
\\
。。
\\
素材庫
\\
9_1。jpg”
);
loadimage
(
&
scole2
[
9
],
“。。
\\
。。
\\
素材庫
\\
9_2。jpg”
);
srand
(
time
(
0
));
//初始化種子
();
//第一根柱子,初始化
stone_y1
=
rand
()
%
310
-
555
;
stone_x1
=
350
;
stone_x2
=
stone_y2
=-
9999
;
}
void
bird
()
{
char
space
;
if
(
kbhit
())
//讀取空格
{
space
=
getch
();
if
(
space
==
‘ ’
)
{
bird_y
-=
80
;
}
else
if
(
space
==
27
)
getch
();
}
else
{
bird_y
+=
3
;
}
while
(
MouseHit
())
{
// 獲取一條滑鼠訊息
m
=
GetMouseMsg
();
switch
(
m
。
uMsg
)
{
case
WM_LBUTTONDOWN
:
bird_y
-=
80
;
break
;
case
WM_RBUTTONDOWN
:
getch
();
break
;
}
}
}
void
judgement
()
{
if
((
stone_x1
>
10
&&
stone_x1
<
20
)
||
(
stone_x1
>
174
&&
stone_x1
<
184
))
{
if
((
bird_y
>
(
stone_y1
+
576
)
&&
bird_y
<
(
stone_y1
+
600
))
||
((
bird_y
>
(
stone_y1
+
726
))
&&
bird_y
<
(
stone_y1
+
750
)))
endorretry
();
//結束遊戲
}
else
if
(
stone_x1
>=
20
&&
stone_x1
<=
174
)
{
if
(
!
(
bird_y
>
(
stone_y1
+
600
)
&&
bird_y
<
(
stone_y1
+
726
)))
endorretry
();
//結束遊戲
}
if
(
bird_y
>
576
)
endorretry
();
//結束遊戲
if
(
stone_x1
==
150
)
scole
++
;
}
void
endorretry
()
{
if
(
bird_y
<
550
&&
stone_x1
>
160
)
{
while
(
bird_y
<
550
)
{
putimage
(
0
,
0
,
&
backgrand
);
//背景影象
putimage
(
stone_x1
,
stone_y1
,
&
stone_up2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
,
&
stone_up1
,
SRCINVERT
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down2
,
NOTSRCERASE
);
putimage
(
stone_x1
,
stone_y1
+
750
,
&
stone_down1
,
SRCINVERT
);
putimage
(
stone_x2
,
stone_y2
,
&
stone_up4
,
NOTSRCERASE
);
putimage
(
stone_x2
,
stone_y2
,
&
stone_up3
,
SRCINVERT
);
putimage
(
stone_x2
,
stone_y2
+
750
,
&
stone_down4
,
NOTSRCERASE
);
putimage
(
stone_x2
,
stone_y2
+
750
,
&
stone_down3
,
SRCINVERT
);
putimage
(
bird_x
,
bird_y
,
&
bird1
[
3
],
NOTSRCERASE
);
putimage
(
bird_x
,
bird_y
,
&
bird2
[
3
],
SRCINVERT
);
FlushBatchDraw
();
bird_y
++
;
}
}
IMAGE
gameover1
,
gameover2
,
atlast
;
loadimage
(
&
gameover1
,
“。。
\\
。。
\\
素材庫
\\
gameover1。gif”
);
loadimage
(
&
gameover2
,
“。。
\\
。。
\\
素材庫
\\
gameover2。gif”
);
putimage
(
80
,
200
,
&
gameover1
,
NOTSRCERASE
);
putimage
(
80
,
200
,
&
gameover2
,
SRCINVERT
);
FlushBatchDraw
();
Sleep
(
1000
);
loadimage
(
&
atlast
,
“。。
\\
。。
\\
素材庫
\\
atlast。jpg”
);
putimage
(
0
,
0
,
&
atlast
);
scoleprint
();
FlushBatchDraw
();
getch
();
//第一根柱子
stone_y1
=
rand
()
%
310
-
555
;
stone_x1
=
350
;
stone_x2
=
stone_y2
=-
9999
;
bird_y
=
300
;
scole
=
0
;
main
();
}
void
scoleprint
()
{
IMAGE
*
fen1
[
6
],
*
fen2
[
6
];
int
he
,
weishu
=
1
,
i
=
0
,
sdsf
=
scole
;
if
(
sdsf
==
0
)
{
putimage
(
250
,
50
,
&
scole1
[
0
],
NOTSRCERASE
);
putimage
(
250
,
50
,
&
scole2
[
0
],
SRCINVERT
);
}
while
(
sdsf
>
0
)
{
he
=
sdsf
%
10
;
fen1
[
i
]
=&
scole1
[
he
];
fen2
[
i
]
=&
scole2
[
he
];
putimage
(
300
-
50
*
weishu
,
50
,
fen1
[
i
],
NOTSRCERASE
);
putimage
(
300
-
50
*
weishu
,
50
,
fen2
[
i
],
SRCINVERT
);
sdsf
/=
10
;
i
++
;
weishu
++
;
}
}
做出flappy bird,也可以按照我們之前教程的思路,step by step地實現,遇到問題再參考上面的程式碼。自己從無到有實現一遍,就能學會類似遊戲的開發了。大概步驟可以為:
1。 背景圖片的顯示
2。 加入小鳥圖片
3。 小鳥自由下落,按鍵後上升
4。 加入靜態的障礙物
5。 障礙物向左移動
6。 判斷小鳥和障礙物的碰撞
7。 障礙物移動出左邊界後,在右邊重新出現
8。 加入記分模組
9。 加入音效效果
10。 加入開始介面、結束介面
11。 繼續完善細節、整理程式碼
flappy bird相對比較簡單,大家可以先從這個案例開始學習。學會理解別人的程式碼,也是一個非常重要的能力,大家可以透過這種逐步重現的方法來學習。後面我們再一起學習更復雜的EasyX遊戲程式碼,EasyX官網上也有很多遊戲案例可以借鑑參考:
範例程式 —— EasyX Library for C++
CodeBus | 分享程式碼,一起進步~
下一個教程:英雄聯盟連連看 知乎專欄