天天酷跑

这是siren第一次编写基于 “easyx”图形库 的小游戏。如果你想学习如何使用各种图形库或者其他引擎来编写自己的小游戏, 可以仔细阅读这篇文章哟。

开发日志

  1. 创建项目
  2. 导入素材
  3. 创建游戏界面
    从用户界面入手

选择图形库或者其他引擎,酷跑是基于“easyx”图形库的
1)创建游戏窗口
2)设计游戏背景
a.三重背景不同的速度移动
b.循环滚动背景的实现
3)实现游戏背景
a.加载背景资源
b.渲染(实现打印图片的效果)背景知识:坐标
遇到的问题:背景图片的png格式图片出现黑色
4.实现玩家奔跑
5.实现玩家跳跃
6.实现随机小乌龟
7.创建结构体结构类型
8.使用障碍物结构体后重新初始化
9.封装后多个障碍物的显示
10.实现玩家的下蹲技能
11.添加柱子障碍物

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496


//#undef UNICODE
//#undef _UNICODE

#include <stdio.h>
#include <graphics.h>
#include <conio.h>
#include <vector> //c++ 长度可变的数组
#include "tools.h"

using namespace std; //声明命名空间
#define WIN_SCORE 10

#define WIN_WIDTH 1012 //定义宏 便于后期维护与处理
#define WIN_HEIGHT 396
#define OBSTACLE_COUNT 10


IMAGE imgBgs[3];//背景图片——创建图片数组
int bgX[3];//背景图片的X坐标(不断变化)
int bgSpeed[3] = { 1,2,4 };//控制3个背景不同速度

IMAGE imgHeros[12];//人物不断奔跑的实现
int heroX;//玩家的X坐标
int heroY;//玩家的Y坐标
int heroIndex;//玩家奔跑的图片帧序号

bool heroJump;//表示玩家正在跳跃
int jumpHeightMax;//跳跃的最大高度
int heroJumpOff;//跳跃偏移量
int update;//表示是否需要马上刷新画面

//IMAGE imgTortoise; //小乌龟
//int torToiseX; //小乌龟的水平坐标
//int torToiseY; //小乌龟的竖直坐标
//bool torToiseExist; //当前窗口是否有小乌龟

int heroBlood; //定义玩家血量
int score;

typedef enum {
TORTOISE, //乌龟 0
LION, //狮子 1
HOOK1,
HOOK2,
HOOK3,
HOOK4,
OBSTACLE_TYPE_COUNT //边界 6
}obstacle_type;

// 相当于 IMAGE obstacleImgs[3][5]
vector<vector<IMAGE>>obstacleImgs; //二维数组 存放所有障碍物的各个图片

typedef struct obstacle {
int type; //障碍物的类型
int imgIndex; //当前显示的图片的序号
int x, y; //障碍物的坐标
int speed;
int power; //杀伤力
bool exist;
bool hited; //表示是否已经发生碰撞
bool passed;//表示是否已经被通过
}obstacle_t;

obstacle_t obstacles[OBSTACLE_COUNT];
int lastObsIndex;//解决障碍物bug(柱子与狮子在一起)

IMAGE imgHeroDown[2];
bool heroDown; //表示玩家是否处于下蹲状态

IMAGE imgSZ[10];

//游戏的初始化
void init() {
//创建游戏窗口
initgraph(WIN_WIDTH, WIN_HEIGHT, EW_SHOWCONSOLE);

//加载背景资源
char name[64];
for (int i = 0; i < 3; i++)
{
//路径 "res/bg001.png" "res/bg002.png" "res/bg003.png"
sprintf(name, "res/bg%03d.png",i+1);//%03d占3位,不足3位自动补0
//#undef _UNICODE
loadimage(&imgBgs[i], name);//把3个图片加载到了图片数组的位置

bgX[i] = 0;
}

//加载Hero奔跑的图片帧素材
for (int i = 0; i < 12; i++) {
sprintf(name, "res/hero%d.png", i + 1);
loadimage(&imgHeros[i], name);
}

//设置玩家的初始位置
heroX = WIN_WIDTH * 0.5 - imgHeros[0].getwidth() * 0.5;//X坐标:屏幕宽度的一半减去人物宽度的一半
heroY = 345 - imgHeros[0].getheight();//Y坐标:脚底坐标减去人物高度
heroIndex = 0;

heroJump = false;
jumpHeightMax = 345 - imgHeros[0].getheight() - 120;
heroJumpOff = -4;

update = true;

////加载小乌龟素材
//loadimage(&imgTortoise, "res/t1.png");
//torToiseExist = false;
//torToiseY = 345 - imgTortoise.getheight() + 5;
IMAGE imgTort;
loadimage(&imgTort, "res/t1.png");
vector<IMAGE>imgTortArray;
imgTortArray.push_back(imgTort);//添加图片
obstacleImgs.push_back(imgTortArray);

IMAGE imgLion;
vector<IMAGE>imgLionArray;
for (int i = 0; i < 6; i++) {
sprintf(name, "res/p%d.png", i + 1);
loadimage(&imgLion, name);
imgLionArray.push_back(imgLion);
}
obstacleImgs.push_back(imgLionArray);

//初始化障碍物池
for (int i = 0; i < OBSTACLE_COUNT; i++) {
obstacles[i].exist = false;
}

//加载下蹲素材
loadimage(&imgHeroDown[0], "res/d1.png");
loadimage(&imgHeroDown[1], "res/d2.png");
heroDown = false;

//加载柱子图片
IMAGE imgH;
for (int i = 0; i < 4; i++) {
vector<IMAGE> imgHookArray;
sprintf(name, "res/h%d.png", i + 1);
loadimage(&imgH, name, 63, 250, true); // 图片进行缩化
imgHookArray.push_back(imgH);
obstacleImgs.push_back(imgHookArray);
}

heroBlood = 100;

//预加载音效
preLoadSound("res/hit.mp3");
//背景音乐
mciSendString("play res/bg.mp3 repeat", 0, 0, 0);

lastObsIndex = -1;
score = 0;

//加载数字图片
for (int i = 0; i < 10; i++) {
sprintf(name, "res/sz/%d.png", i);
loadimage(&imgSZ[i], name);
}
}

//随机创建障碍物
void creatObstacle() {
int i;
for (i = 0; i < OBSTACLE_COUNT; i++) {
if (obstacles[i].exist == false) {
break;
}
}
if (i >= OBSTACLE_COUNT) {
return;
}

obstacles[i].exist = true;
obstacles[i].hited = false;
obstacles[i].imgIndex = 0;
//obstacles[i].type = (obstacle_type)(rand() % OBSTACLE_TYPE_COUNT);
obstacles[i].type = (obstacle_type)(rand() % 3);

//如果上一个障碍物是柱子,下一个是狮子,判断距离,若很近,则狮子换为乌龟
if (lastObsIndex >= 0 && obstacles[lastObsIndex].type >= HOOK1 && obstacles[lastObsIndex].type <= HOOK4 && obstacles[i].type == LION && obstacles[lastObsIndex].x > WIN_WIDTH - 500)
{
obstacles[i].type == TORTOISE;
}
lastObsIndex = i;

if (obstacles[i].type == HOOK1) { //降低柱子出现的频率
obstacles[i].type += rand() % 4; //0-3
}

obstacles[i].x = WIN_WIDTH;
obstacles[i].y = 345 + 5 - obstacleImgs[obstacles[i].type][0].getheight();
if (obstacles[i].type == TORTOISE) {
obstacles[i].speed = 0;
obstacles[i].power = 5; //随意
}
else if (obstacles[i].type == LION) {
obstacles[i].speed = 1;
obstacles[i].power = 20;
}
else if (obstacles[i].type >= HOOK1 && obstacles[i].type <= HOOK4) {
obstacles[i].speed = 0;
obstacles[i].power = 20;
obstacles[i].y = 0;
}

obstacles[i].passed = false;
}

void checkHit() {
for(int i = 0; i < OBSTACLE_COUNT; i++) {
if (obstacles[i].exist && obstacles[i].hited == false) {
int a1x, a1y, a2x, a2y;
int off = 30;
if (!heroDown) { //非下蹲 奔跑 跳跃
a1x = heroX + off;
a1y = heroY + off;
a2x = heroX + imgHeros[heroIndex].getwidth() - off;
a2y = heroY + imgHeros[heroIndex].getheight();
}
else {
a1x = heroX + off;
a1y = 345 - imgHeroDown[heroIndex].getheight();
a2x = heroX + imgHeroDown[heroIndex].getwidth() - off;
a2y = 345;
}

IMAGE img = obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]; //当前障碍物类型(的第几张图片)
int b1x = obstacles[i].x + off;
int b1y = obstacles[i].y + off;
int b2x = obstacles[i].x + img.getwidth() - off;
int b2y = obstacles[i].y + img.getheight() - 10;

if (rectIntersect(a1x, a1y, a2x, a2y, b1x, b1y, b2x, b2y)) {
heroBlood -= obstacles[i].power;
printf("血量剩余 %d\n", heroBlood);
playSound("res/hit.mp3");
obstacles[i].hited = true;
}
}
}
}


//让背景动起来
void run() {
for (int i = 0; i < 3; i++) {
bgX[i] -= bgSpeed[i];//3个背景移动的速度不同
if (bgX[i] < -WIN_WIDTH) {
bgX[i] = 0;
}
}

//实现跳跃
if (heroJump)
{
if (heroY < jumpHeightMax) //达到最大跳跃高度 跳跃偏移量为正 向下跳跃
{
heroJumpOff = 4;
}

heroY += heroJumpOff;

if (heroY > 345 - imgHeros[0].getheight()) //到达地面 跳跃结束
{
heroJump = false;
heroJumpOff = -4; // 偏移量初始化
}
}
else if (heroDown) { //人物下蹲
static int count = 0;
int delays[2] = { 8,30 }; //设置下蹲的时间不一样
count++;
if (count >= delays[heroIndex]) {
count = 0;
heroIndex++;
if (heroIndex >= 2) {
heroIndex = 0;
heroDown = false;
}
}
}
else{ //不跳跃
heroIndex = (heroIndex + 1) % 12; //12张图片循环播放完成一系列动作
}

//创建障碍物
static int frameCount = 0;
static int enemyFre = 50;
frameCount++;
if (frameCount > enemyFre){
frameCount = 0;
//if (!torToiseExist) { //避免屏幕同时出现多个小乌龟
// torToiseExist = true;
// torToiseX = WIN_WIDTH;
// enemyFre=rand()%301+200; //每200-500帧随机出现一只龟
//}
enemyFre = rand() % 50 + 50;
creatObstacle();
}

//if (torToiseExist) {
// //更新小乌龟位置
// torToiseX -= bgSpeed[2];
// if (torToiseX < -imgTortoise.getwidth()) {
// torToiseExist = false;
// }
//}

//更新所有障碍物的坐标
for (int i = 0; i < OBSTACLE_COUNT; i++) {
if (obstacles[i].exist) {
obstacles[i].x -= obstacles[i].speed + bgSpeed[2];
if (obstacles[i].x < -obstacleImgs[obstacles[i].type][0].getwidth() * 2) {
obstacles[i].exist = false;
}
int len = obstacleImgs[obstacles[i].type].size();
obstacles[i].imgIndex = (obstacles[i].imgIndex + 1) % len;
}
}

//玩家和障碍物的“碰撞检测”处理
checkHit();

}

//渲染“游戏背景”
void updateBg() {
//调整背景图片位置
putimagePNG2(bgX[0], 0, &imgBgs[0]);
putimagePNG2(bgX[1], 119, &imgBgs[1]);
putimagePNG2(bgX[2], 330, &imgBgs[2]);

}

//实现跳跃
void jump() {
heroJump = true;
update = true; //未处于刷新时也能跳跃
}

void down() {
update = true;
heroDown = true;
heroIndex = 0;
}

//处理用户按键的输入
void keyEvent() {

//char c;
//scanf("%c", &c); 会直接阻塞程序的执行

if (GetAsyncKeyState(VK_UP)){ //虚拟键
jump();
/*
if(kbhit()) //kbhit()判断有无键盘输入。若有按键按下,则kbhit()返回 TRUE
{
char ch = _getch();//不需要按下回车即可直接读取
if (ch == ' ') {//按下空格跳跃
jump();
}
*/
}

else if (GetAsyncKeyState(VK_DOWN)) {
down();
}
}

void updateEnemy() {
//渲染小乌龟
/*if (torToiseExist) {
putimagePNG2(torToiseX, torToiseY, WIN_WIDTH, &imgTortoise);
}*/
for (int i = 0; i < OBSTACLE_COUNT; i++) {
if (obstacles[i].exist) {
putimagePNG2(obstacles[i].x, obstacles[i].y, WIN_WIDTH, &obstacleImgs[obstacles[i].type][obstacles[i].imgIndex]);
}
}
}

void updateHero() {
if (!heroDown) { //不处于下蹲状态——奔跑跳跃
putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);
}
else {
int y = 345 - imgHeroDown[heroIndex].getheight();
putimagePNG2(heroX, y, &imgHeroDown[heroIndex]);
}
}

void updateBloodBar()
{
drawBloodBar(10, 10, 200, 10, 2, BLUE, DARKGRAY, RED, heroBlood / 100.0);
}

void checkOver() {
if (heroBlood <= 0) {
loadimage(0, "res/over.png");
FlushBatchDraw();//刷新
mciSendString("stop res / bg.mp3", 0, 0, 0);//关掉背景音乐
system("pause");

//暂停之后,充币复活或者直接开始下一局
heroBlood = 100;
score = 0;
mciSendString("play res / bg.mp3 repeat", 0, 0, 0);
}
}

void checkScore() {
for (int i = 0; i < OBSTACLE_COUNT; i++) {
if (obstacles[i].exist && obstacles[i].passed == false &&
obstacles[i].x + obstacleImgs[obstacles[i].type][0].getwidth() < heroX && obstacles[i].hited == false)
{
score++;
obstacles[i].passed = true;
printf("score:%d\n", score);
}
}
}

void updateScore() {
char str[8];
sprintf(str, "%d", score);

int x = 20;
int y = 25;

for (int i = 0; str[i]; i++) {
int sz = str[i] - '0';
putimagePNG(x, y, &imgSZ[sz]);
x += imgSZ[sz].getwidth() + 5;
}
}

void checkWin() {
if (score >= WIN_SCORE) {
FlushBatchDraw();
mciSendString("play res/win.mp3", 0, 0, 0);
Sleep(2000);
loadimage(0, "res/win.png");
FlushBatchDraw();
mciSendString("stop res/bg.mp3", 0, 0, 0);
system("pause");

heroBlood = 100;
score = 0;
mciSendString("play res/bg.mp3 repeat", 0, 0, 0);
}
}

int main(void)
{
init();

//显示初始化面
loadimage(0, "res/over.png");
system("pause");

int timer = 0;
while (1) {
keyEvent();
timer += getDelay();//此函数返回距离上一次调用间隔的时间,第一次返回0
if (timer > 30) { //30毫秒刷新时间
timer = 0;
update = true;
}
if (update) {
update = false;
BeginBatchDraw();//这个函数用于开始批量绘图。执行后,任何绘图操作都将暂时不输出到绘图窗口上,直到执行 FlushBatchDraw 或 EndBatchDraw 才将之前的绘图输出。
updateBg();
//putimagePNG2(heroX, heroY, &imgHeros[heroIndex]);
updateHero();
updateEnemy();
updateBloodBar();
updateScore();
checkWin();
EndBatchDraw();//这个函数用于结束批量绘制,并执行未完成的绘制任务。 这两个函数主要为了消除闪烁。

checkOver();
checkScore();

run();
}


//Sleep(30); //休眠
}

system("pause");
return 0;
}

头文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
#include <stdio.h>
#include <Windows.h>
#include "tools.h"

#include <mmsystem.h>
#pragma comment(lib, "winmm.lib")


int getDelay() {
static unsigned long long lastTime = 0;
unsigned long long currentTime = GetTickCount();
if (lastTime == 0) {
lastTime = currentTime;
return 0;
}
else {
int ret = currentTime - lastTime;
lastTime = currentTime;
return ret;
}
}

// 载入PNG图并去透明部分
void putimagePNG(int picture_x, int picture_y, IMAGE* picture) //x为载入图片的X坐标,y为Y坐标
{
DWORD* dst = GetImageBuffer(); // GetImageBuffer()函数,用于获取绘图设备的显存指针,EASYX自带
DWORD* draw = GetImageBuffer();
DWORD* src = GetImageBuffer(picture); //获取picture的显存指针
int picture_width = picture->getwidth(); //获取picture的宽度,EASYX自带
int picture_height = picture->getheight(); //获取picture的高度,EASYX自带
int graphWidth = getwidth(); //获取绘图区的宽度,EASYX自带
int graphHeight = getheight(); //获取绘图区的高度,EASYX自带
int dstX = 0; //在显存里像素的角标

// 实现透明贴图 公式: Cp=αp*FP+(1-αp)*BP , 贝叶斯定理来进行点颜色的概率计算
for (int iy = 0; iy < picture_height; iy++)
{
for (int ix = 0; ix < picture_width; ix++)
{
int srcX = ix + iy * picture_width; //在显存里像素的角标
int sa = ((src[srcX] & 0xff000000) >> 24); //0xAArrggbb;AA是透明度
int sr = ((src[srcX] & 0xff0000) >> 16); //获取RGB里的R
int sg = ((src[srcX] & 0xff00) >> 8); //G
int sb = src[srcX] & 0xff; //B
if (ix >= 0 && ix <= graphWidth && iy >= 0 && iy <= graphHeight && dstX <= graphWidth * graphHeight)
{
dstX = (ix + picture_x) + (iy + picture_y) * graphWidth; //在显存里像素的角标
int dr = ((dst[dstX] & 0xff0000) >> 16);
int dg = ((dst[dstX] & 0xff00) >> 8);
int db = dst[dstX] & 0xff;
draw[dstX] = ((sr * sa / 255 + dr * (255 - sa) / 255) << 16) //公式: Cp=αp*FP+(1-αp)*BP ; αp=sa/255 , FP=sr , BP=dr
| ((sg * sa / 255 + dg * (255 - sa) / 255) << 8) //αp=sa/255 , FP=sg , BP=dg
| (sb * sa / 255 + db * (255 - sa) / 255); //αp=sa/255 , FP=sb , BP=db
}
}
}
}

// 适用于 y <0 以及x<0的任何情况
void putimagePNG2(int x, int y, IMAGE* picture) {
IMAGE imgTmp;
if (y < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, 0, -y,
picture->getwidth(), picture->getheight() + y);
SetWorkingImage();
y = 0;
picture = &imgTmp;
}

if (x < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());
SetWorkingImage();
x = 0;
picture = &imgTmp;
}

putimagePNG(x, y, picture);
}

// 适用于 y <0 以及y>0的任何情况
void putimagePNG2(int x, int y, int winWidth, IMAGE* picture) {
IMAGE imgTmp;
if (y < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, 0, -y,
picture->getwidth(), picture->getheight() + y);
SetWorkingImage();
y = 0;
picture = &imgTmp;
}

if (x < 0) {
SetWorkingImage(picture);
getimage(&imgTmp, -x, 0, picture->getwidth() + x, picture->getheight());
SetWorkingImage();
x = 0;
picture = &imgTmp;
}
else if (x >= winWidth) {
return;
}
else if (x > winWidth-picture->getwidth()) {
SetWorkingImage(picture);
getimage(&imgTmp, 0, 0, winWidth - x, picture->getheight());
SetWorkingImage();
picture = &imgTmp;
}

putimagePNG(x, y, picture);
}

//设A[x01,y01,x02,y02] B[x11,y11,x12,y12].
bool rectIntersect(int x01, int y01, int x02, int y02,
int x11, int y11, int x12, int y12)
{
int zx = abs(x01 + x02 - x11 - x12);
int x = abs(x01 - x02) + abs(x11 - x12);
int zy = abs(y01 + y02 - y11 - y12);
int y = abs(y01 - y02) + abs(y11 - y12);
return (zx <= x && zy <= y);
}

void preLoadSound(const char* name) {
char cmd[512];
sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);
mciSendString(cmd, 0, 0, 0);
sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);
mciSendString(cmd, 0, 0, 0);
}

void playSound(const char* name) {
static int index = 1;
char cmd[512];

if (index == 1) {
sprintf_s(cmd, sizeof(cmd), "play %s-1", name);
mciSendString(cmd, 0, 0, 0);
sprintf_s(cmd, sizeof(cmd), "close %s-2", name);
mciSendString(cmd, 0, 0, 0);
sprintf_s(cmd, sizeof(cmd), "open %s alias %s-2", name, name);
mciSendString(cmd, 0, 0, 0);
index++;
}
else if (index == 2) {
sprintf_s(cmd, sizeof(cmd), "play %s-2", name);
mciSendString(cmd, 0, 0, 0);
sprintf_s(cmd, sizeof(cmd), "close %s-1", name);
mciSendString(cmd, 0, 0, 0);
sprintf_s(cmd, sizeof(cmd), "open %s alias %s-1", name, name);
mciSendString(cmd, 0, 0, 0);
index = 1;
}
}

void drawBloodBar(int x, int y, int width, int height, int lineWidth, int boardColor, int emptyColor, int fillColor, float percent) {
LINESTYLE lineStyle;
getlinestyle(&lineStyle);
int lineColor = getlinecolor();
int fileColor = getfillcolor();

if (percent < 0) {
percent = 0;
}

setlinecolor(BLUE);
setlinestyle(PS_SOLID | PS_ENDCAP_ROUND, lineWidth);
setfillcolor(emptyColor);
fillrectangle(x, y, x + width, y + height);
setlinestyle(PS_SOLID | PS_ENDCAP_FLAT, 0);
setfillcolor(fillColor);
setlinecolor(fillColor);
if (percent > 0) {
fillrectangle(x + 0.5 * lineWidth, y + lineWidth * 0.5, x + width * percent, y + height - 0.5 * lineWidth);
}

setlinecolor(lineColor);
setfillcolor(fillColor);
setlinestyle(&lineStyle);
}

End!By siren~

如果想了解更深,欢迎随时访问我的博客网站https://xysiren.github.io/,这里有很多有趣的内容~