个人作品

合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下

贪婪球 2.0(by 奶酪) 铜牌收录

贪婪球第一版在这里:https://codebus.cn/contributor/post/greedy-ball

2.0 版本相对第一版做了如下修改:

  1. 视野缩放,会随着体积增大视野变大,解决一代玩家球过大挡住屏幕现象
  2. 增加高杀伤力毒圈,解决满地图跑问题
  3. 提高敌人 AI 智商,会主动吃食物
  4. 修复若干已知 bug
  5. 扩大了游戏区域
  6. 全部用 c++ 重写

执行效果如下:

完整的源代码如下:

///////////////////////////////////////////////////
// 程序名称:贪婪球 2.0
// 编译环境:Microsoft Visual studio 2017,EasyX 2018春分版
// 作  者:奶酪
// 邮  箱:2190038793@qq.com
// 发布日期:2019-6-24
// 最后修改:2019-8-8
//
#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <math.h>


const int WIDTH = 1024;			// 屏幕宽1024
const int HEIGHT = 768;			// 屏幕高576
const int MAPW = (WIDTH * 4);	// 地图宽
const int MAPH = (HEIGHT * 4);	// 地图高
const int AINUM = 300;			// AI 数量
const int FNUM = 500;			// FOOD 数量
const int IMGNUM = 10;
const double PI = 3.1415926;
#define DISTANCE(x1, y1, x2, y2)	(sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)))

void set();
void delay(DWORD ms);
void start();
void Draw();
void run();

// 玩家 敌人 食物 之父
class Ball
{
public:
	bool		life;		// 是否被吃 活 1,死 0
	COLORREF	color;		// 颜色
	float		x;			// 坐标
	float		y;

	Ball();
	~Ball();
	virtual void draw() {};
};

// 玩家与敌人(戏称怪物) 继承Ball
class Monster :public Ball
{
public:
	float r;		// 半径
	Monster();
	~Monster();
	void draw();
	void move();	// ai控制
	void control();	// 玩家控制
	void eat(Monster& compare);
	void lostweight();
};

// 食物 继承Ball
class Food :public Ball
{
public:
	char shape;

	Food();
	~Food();
	void draw();
	void newfood();
	void eaten(Monster& compare);
	void lostweight();
};

Food* food = new Food[FNUM];
Monster* ai = new Monster[AINUM];
Monster* player = new Monster;
IMAGE		Map(MAPW, MAPH);
float lx = 0, ly = 0, rx = MAPW, ry = MAPH - 100;				// 毒的位置


int main()
{
	initgraph(WIDTH, HEIGHT);
	set();
	start();
	BeginBatchDraw();
	while (true)
	{
		Draw();
		run();
		FlushBatchDraw();	// 显示缓存的绘制内容
		delay(10);			// 绝对延迟
	}

	closegraph();
}

void set()
{
	srand((unsigned)time(NULL));		// 随机数
	SetWorkingImage(&Map);
	setbkcolor(WHITE);					// 白色背景
	cleardevice();						// 初始化背景
	SetWorkingImage();

	// 赋随机值
	player->x = (float)(rand() % MAPW);
	player->y = (float)(rand() % MAPH);
	player->color = RGB(rand() % 256, rand() % 256, rand() % 256);		// 随机颜色
	for (int i = 0; i < AINUM; i++)
	{
		ai[i].x = (float)(rand() % MAPW);
		ai[i].y = (float)(rand() % MAPH);
		ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);	// 随机颜色
	}
	for (int i = 0; i < FNUM; i++)
	{
		food[i].x = (float)(rand() % MAPW);
		food[i].y = (float)(rand() % MAPH);
		food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);	// 随机颜色
	}
}

// 绘制游戏
void Draw()
{
	SetWorkingImage(&Map);
	cleardevice();
	for (int i = 0; i < FNUM; i++)
		food[i].draw();
	for (int i = 0; i < AINUM; i++)
		ai[i].draw();
	player->draw();

	setlinestyle(PS_SOLID | PS_JOIN_BEVEL, 20);	// 改笔的颜色、状态
	setlinecolor(RGB(0, 100, 0));
	line((int)lx - 20, (int)ly - 20, (int)lx - 20, (int)ry + 20);	// 左竖
	line((int)lx - 20, (int)ly - 20, (int)rx + 20, (int)ly - 20);	// 上横
	line((int)lx - 20, (int)ry + 20, (int)rx + 20, (int)ry + 20);	// 下横
	line((int)rx + 20, (int)ly - 20, (int)rx + 20, (int)ry + 20);	// 右竖
	setlinestyle(PS_NULL);

	IMAGE map2;
	const float asptime = 1;
	getimage(&map2, (int)(player->x - WIDTH * .5 - player->r * asptime), (int)(player->y - HEIGHT * .5 - player->r * asptime),
		(int)(WIDTH + player->r * asptime * 2), (int)(HEIGHT + player->r * asptime * 2));
	float aspx = WIDTH / (WIDTH + player->r * 2);
	float aspy = HEIGHT / (HEIGHT + player->r * 2);
	SetWorkingImage();
	setaspectratio(aspx, aspy);
	putimage(0, 0, &map2);

	const int mapw = 180;
	const int maph = 130;
	IMAGE map((int)(mapw / aspx), (int)(maph / aspy));			// 小地图
	SetWorkingImage(&map);
	setbkcolor(RGB(120, 165, 209));	// 浅灰色背景
	cleardevice();

	for (int i = 0; i < AINUM; i++)	// 画 AI
	{
		if (ai[i].life == 0) continue;
		setfillcolor(ai[i].color);
		fillcircle((int)(ai[i].x * mapw / WIDTH / 4 / aspx), (int)(ai[i].y * maph / HEIGHT / 4 / aspy),
			int(((ai[i].r * 2) / (aspx + aspy)) / ((MAPH / HEIGHT) * (MAPH / HEIGHT)) - 0.5));
	}

	setfillcolor(player->color);		// 画玩家
	fillcircle((int)(player->x * mapw / WIDTH / 4 / aspx), (int)(player->y * maph / HEIGHT / 4 / aspy),
		int(((player->r * 2) / (aspx + aspy)) / ((MAPH / HEIGHT) * (MAPH / HEIGHT) - 0.5)));

	SetWorkingImage();
	putimage((int)(WIDTH - map.getwidth() + player->r * asptime * 2), 0, &map);
	setlinecolor(LIGHTGRAY);	// 改笔颜色   状态
	setlinestyle(PS_SOLID | PS_JOIN_BEVEL, (int)(3 / aspx));
	line(map2.getwidth() - map.getwidth(), 0, map2.getwidth() - map.getwidth(), map.getheight());
	line(map2.getwidth() - map.getwidth(), map.getheight(), map2.getwidth(), map.getheight());

	setlinestyle(PS_NULL);		// 恢复笔
	settextstyle((int)(40 / (aspx + aspy)), 0, _T("宋体"));
	TCHAR str[16];
	_stprintf_s(str, _T("质量:%.1f kg"), (float)(player->r * player->r * PI / 300));
	settextcolor(BLUE);			// 改字体
	outtextxy(0, 0, str);

}

// 运行游戏
void run()
{
	if (player->r <= 0)	player->life = false;

	if (!player->life)	// 判定游戏是否接束
	{
		HWND hwnd = GetHWnd();
		MessageBox(hwnd, _T("呼呼!你被吃了!"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION);	// 结束
		closegraph();
		exit(0);
	}
	int eaten = 0;
	for (int i = 0; i < AINUM; i++)
		if (ai[i].life == 0)
			eaten++;
	if (eaten >= AINUM)	// 是否吃掉所有 AI
	{
		HWND hwnd = GetHWnd();
		MessageBox(hwnd, _T("敌人已消灭!恭喜过关!"), _T("游戏结束"), MB_OK | MB_ICONEXCLAMATION);	// 结束
		closegraph();
		exit(0);
	}

	// 玩家
	player->control();
	player->lostweight();

	// ai
	for (int i = 0; i < AINUM; i++)
	{
		if (ai[i].r <= 0)	ai[i].life = false;
		if (ai[i].life)
		{
			ai[i].lostweight();
			ai[i].move();
			player->eat(ai[i]);
			ai[i].eat(*player);
			for (int j = 0; j < AINUM; j++)
			{
				if (ai[j].life)
				{
					if (i == j) continue;
					ai[i].eat(ai[j]);
					ai[j].eat(ai[i]);
				}
			}
		}
	}

	// 食物
	for (int i = 0; i < FNUM; i++)
	{
		food[i].newfood();
		food[i].eaten(*player);
		food[i].lostweight();

		for (int j = 0; j < AINUM; j++)
			food[i].eaten(ai[j]);
	}

	// 毒圈
	lx += 0.35f;
	ly += 0.3f;
	rx -= 0.35f;
	ry -= 0.3f;
}

void delay(DWORD ms)
{
	static DWORD oldtime = GetTickCount();

	if (GetTickCount() - oldtime < ms)
		Sleep(1);
	oldtime = GetTickCount();
}

void start()
{
	setbkcolor(WHITE);		// 白色背景
	cleardevice();			// 初始化背景
	settextcolor(RED);		// 改字体
	setbkmode(TRANSPARENT);
	settextstyle(128, 0, _T("宋体"));
	outtextxy(320, 40, _T("贪婪球"));
	settextstyle(32, 0, _T("宋体"));
	outtextxy(740, 135, _T("Ver 2.0"));
	settextcolor(BLUE);		// 改字体
	outtextxy(304, 240, _T("W上移 S下移 A左移 D右移"));
	outtextxy(112, 340, _T("躲避大球   追补小球   贪吃食物   增强实力"));
	settextcolor(BLACK);	//改字体
	settextstyle(32, 0, _T("宋体"));
	outtextxy(384, 500, _T("按任意键开始游戏"));
	settextstyle(20, 0, _T("宋体"));
	outtextxy(810, 10, _T("作者 QQ: 2190038793"));
	_getch();
}

// 大球的函数
Ball::Ball()
{
	life = 1;
}

Ball::~Ball() {}

// 食物的函数
Food::Food()
{
	shape = rand() % 10 + 1;
}

Food::~Food() {}

void Food::draw()
{
	if (life == 0) return;
	setfillcolor(color);
	switch (shape)		// 形状
	{
	case 1:		solidellipse((int)x, (int)y, (int)x + 2, (int)y + 4);				break;
	case 2:		solidellipse((int)x, (int)y, (int)x + 4, (int)y + 2);				break;
	case 3:		solidrectangle((int)x, (int)y, (int)x + 4, (int)y + 2);				break;
	case 4:		solidrectangle((int)x, (int)y, (int)x + 2, (int)y + 4);				break;
	case 5:		solidroundrect((int)x, (int)y, (int)x + 2, (int)y + 4, 2, 2);		break;
	case 6:		solidroundrect((int)x, (int)y, (int)x + 4, (int)y + 2, 2, 2);		break;
	case 7:		solidroundrect((int)x, (int)y, (int)x + 4, (int)y + 2, 4, 2);		break;
	case 8:		solidroundrect((int)x, (int)y, (int)x + 4, (int)y + 2, 2, 4);		break;
	case 9:		solidroundrect((int)x, (int)y, (int)x + 4, (int)y + 2, 1, 1);		break;
	case 10:	fillcircle((int)x, (int)y, 3);										break;
	}
}

void Food::newfood()
{
	if (!life)
	{
		life = 1;
		color = RGB(rand() % 256, rand() % 256, rand() % 256);
		x = (float)(rand() % MAPW);
		y = (float)(rand() % MAPH);
		shape = rand() % 10 + 1;
	}
}

void Food::eaten(Monster& compare)
{
	if (!life)	return;
	if (DISTANCE(compare.x, compare.y, x, y) < compare.r)
	{
		compare.r = (float)sqrt(compare.r * compare.r + 16);
		life = 0;				// 食物被吃
	}
}

void Food::lostweight()
{
	if (x > rx || x < lx || y < ly || y >ry)
		life = 0;
}

// 怪物的函数
Monster::Monster()
{
	r = 10.0f + rand() % 5;
}

Monster::~Monster() {}

void Monster::draw()
{
	if (life == 0) return;
	setfillcolor(color);		// 画怪物
	fillcircle((int)x, (int)y, int(r + 0.5));
}

void Monster::move()
{
	if (life == 0)	return;
	double min_DISTANCE1 = 15000000;
	double min_DISTANCE2 = 15000000;
	int min1 = -1, min2 = -1, k, q;
	for (k = 0; k < AINUM; k++)		// AI 靠近 AI
	{
		if ((r > ai[k].r + 3) && (ai[k].life == 1))
		{
			if (DISTANCE(x, ai[k].x, y, ai[k].y) < min_DISTANCE1)
			{
				min_DISTANCE1 = DISTANCE(x, ai[k].x, y, ai[k].y);
				min1 = k;
			}
		}
	}
	for (q = 0; q < FNUM; q++)		// AI 靠近 食物
	{
		if (food[q].life == 1)
		{
			if (DISTANCE(x, food[q].x, y, food[q].y) < min_DISTANCE2)
			{
				min_DISTANCE2 = DISTANCE(x, food[q].x, y, food[q].y);
				min2 = q;
			}
		}
	}
	if (x > rx - 20) x--;
	if (x < lx + 20) x++;
	if (y > ry - 20) y--;
	if (y < ly + 20) y++;

	if (min_DISTANCE1 > min_DISTANCE2) // 食物近
	{
		if (rand() % 5 > 3)	return;
		if (rand() % 2)
		{
			if (x > food[min2].x)	x--;
			else x++;
		}
		else
		{
			if (y > food[min2].y)	y--;
			else y++;
		}
	}
	else
	{
		if (rand() % 5 > 3)	return;
		if (rand() % 2)
		{
			if (x < ai[min1].x) x++;
			else x--;
		}
		else
		{
			if (y < ai[min1].y) y++;
			else y--;
		}
	}
}

// 移动控制函数
void Monster::control()
{
	if (!life)	return;
	// 先凑合着
	if (GetAsyncKeyState(65) & 0x8000)  player->x -= 2;	// 左边
	if (GetAsyncKeyState(87) & 0x8000)  player->y -= 2;	// 上面
	if (GetAsyncKeyState(83) & 0x8000)  player->y += 2;	// 下面
	if (GetAsyncKeyState(68) & 0x8000)  player->x += 2;	// 右边

	// if (GetAsyncKeyState(VK_SPACE) & 0x8000)  player->r += 5;	// 作弊调试 记得  记得 记得删
}

void Monster::eat(Monster& compare)
{
	if (r > compare.r)
	{
		if (DISTANCE(x, y, compare.x, compare.y) < 4 / 5.0 * r + compare.r)
		{
			r = (float)sqrt(r * r + compare.r * compare.r);
			compare.life = 0;
			compare.r = 0;
		}
	}
}

void Monster::lostweight()
{
	if (r * r * PI > 120000)
		r -= 1 / r;
	if (x > (rx - r) || x - r < lx || y - r < ly || y >(ry - r))
		r -= 1.f;
}

作者:奶酪
QQ:2190038793
邮箱:2190038793@qq.com

评论 (7) -

  • 作者您好,我想问一下关于地图大小根据玩家大小而缩放的功能代码是怎么实现的呢?初学者不是很多可能问题太傻了
  • 完整项目吗,很多函数没有
  • 你好,我想问一下,在改背景图片之后,移动的时候一直出现一些蓝色的线条是怎么回事呢
  • 错误  1  error C2664: “int swprintf_s(wchar_t *,size_t,const wchar_t *,...)”: 无法将参数 1 从“TCHAR [16]”转换为“wchar_t *”  
      2  IntelliSense:  没有与参数列表匹配的 重载函数 "swprintf_s" 实例
                参数类型为:  (TCHAR [16], const char [13], float)  怎么解决

添加评论