https://live.csdn.net/v/385490
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#pragma comment(lib,"winmm.lib")
//所需要的库引入
#define WIN_WIDTH 1024
#define WIN_HEIGHT 640
#define MAP_WIDTH (WIN_WIDTH*5)
#define MAP_HEIGHT (WIN_HEIGHT*5)
#define FOOD_NUM 1000
#define AI_NUM 500
int main() {
initgraph(WIN_WIDTH, WIN_HEIGHT);//初始化界面
gameinit();
while (true) {
aimove();
gamedraw();
eatfood();
playercontroller(10);
}
/*getchar();*/
return 0;
}
struct ball
{
int x;
int y;
int r;
bool flag;
DWORD color;
}player,food[FOOD_NUM],ai[AI_NUM];
void Chase(struct ball* chase,struct ball run)
{
chase->x < run.x ? chase->x += 2 : chase->x -= 2;
chase->y < run.y ? chase->y += 2 : chase->y -= 2;
}
void aimove()
{
for (int i = 0; i < AI_NUM; i++)
{
if (ai[i].flag)
{
Chase(&ai[i], player);
}
}
}
ai
数组。flag
是否为真(即激活状态)。Chase
函数,将 ai[i]
(追击者的位置)和 player
(目标的位置)作为参数传递给 Chase
。chase->x
(追击者的横坐标)小于 run.x
(目标的横坐标),则将 chase->x
增加 2。chase->x
不小于 run.x
),将 chase->x
减少 2。y
,如果 chase->y
小于 run.y
,则 chase->y
增加 2;否则 chase->y
减少 2#include // 引入INT_MAX以确保不会除以零
void Chase(struct ball* chase, struct ball run) {
int dx = run.x - chase->x; // 计算目标和追击者之间的横坐标差
int dy = run.y - chase->y; // 计算目标和追击者之间的纵坐标差
// 确保不会除以零
if (dx == 0 && dy == 0) {
return;
}
// 限制移动速度
int max_speed = 5; // 假设最大移动速度为5
int speed = fmin(abs(dx), abs(dy)) * (dx < 0 ? -1 : 1); // 计算实际移动速度
speed = fmin(speed, max_speed); // 限制速度不超过最大值
// 更新追击者的位置
if (dx < 0) {
chase->x += speed;
} else if (dx > 0) {
chase->x -= speed;
}
if (dy < 0) {
chase->y += speed;
} else if (dy > 0) {
chase->y -= speed;
}
// 确保移动后的位置不会超出边界
int max_x = INT_MAX; // 假设横坐标的最大值
int max_y = INT_MAX; // 假设纵坐标的最大值
int min_x = INT_MIN; // 假设横坐标的最小值
int min_y = INT_MIN; // 假设纵坐标的最大值
chase->x = fmin(fmax(chase->x, min_x), max_x);
chase->y = fmin(fmax(chase->y, min_y), max_y);
}
void aimove() {
for (int i = 0; i < AI_NUM; i++) {
if (ai[i].flag) {
Chase(&ai[i], player);
// 这里可以添加其他逻辑,例如检查玩家是否在AI的视野范围内
}
}
}
IMAGE map(MAP_WIDTH, MAP_HEIGHT);
POINT cameraPos;
void CameraUpdate()
{
cameraPos.x = player.x - WIN_WIDTH / 2;
cameraPos.y = player.y - WIN_HEIGHT / 2;
if (cameraPos.x < 0) cameraPos.x = 0;
if (cameraPos.y < 0) cameraPos.y = 0;
if (cameraPos.x > MAP_WIDTH - WIN_WIDTH) cameraPos.x = MAP_WIDTH - WIN_WIDTH;
if (cameraPos.y > MAP_HEIGHT - WIN_HEIGHT) cameraPos.y = MAP_HEIGHT - WIN_HEIGHT;
}
void gamedraw() {
BeginBatchDraw();
SetWorkingImage(&map);//设置图像
setbkcolor(WHITE);//设置背景颜色
cleardevice();
//准备工作
//绘制图像
//1.食物圆
for (int i = 0; i< FOOD_NUM; i++) {
if (food[i].flag) {
setfillcolor(food[i].color);
solidcircle(food[i].x, food[i].y, food[i].r);
}
}
//2.ai圆
for (int i = 0; i < AI_NUM; i++)
{
if (ai[i].flag)
{
setfillcolor(ai[i].color);
solidcircle(ai[i].x, ai[i].y, ai[i].r);
}
}
//3.玩儿家圆
if (player.flag)
{
setfillcolor(player.color);
solidcircle(player.x, player.y, player.r);
settextcolor(BLACK);
setbkmode(TRANSPARENT);
// 确保文件编码支持中文,并且项目设置使用MBCS
outtextxy(player.x, player.y, "百年好合");
}
//显示页面
SetWorkingImage();
CameraUpdate();
putimage(0, 0, WIN_WIDTH, WIN_HEIGHT, &map, cameraPos.x, cameraPos.y);
EndBatchDraw();
}
BeginBatchDraw();
: 开始批处理绘图,这通常意味着接下来所有的绘图操作都将被累积起来,直到EndBatchDraw
被调用时一次性渲染到屏幕上。
SetWorkingImage(&map);
: 设置当前工作图像为map
,这通常是游戏中的地图或者背景图像
setbkcolor(WHITE);
: 设置背景颜色为白色。
cleardevice();
: 清除设备,通常是清除屏幕,使其变为背景颜色。
现在整个画面已经布局好 但是静态的 需要令其动起来
double DisTance(struct ball b1, struct ball b2)
{
return sqrt((double)(b1.x - b2.x) * (b1.x - b2.x) + (b1.y - b2.y) * (b1.y - b2.y));
}
void eatfood() {
//吃食物的逻辑 : 遇见食物就圆扩大
for (int i = 0; i < FOOD_NUM; i++)
{
if (food[i].flag && DisTance(player, food[i]) < player.r)
{
food[i].flag = false;
player.r += food[i].r / 4;
}
}
}
DisTance
DisTance
函数计算两个球体之间的欧几里得距离。这个函数对于游戏中的碰撞检测非常有用,比如判断玩家控制的球体是否接触到食物。函数的逻辑如下:
ball
类型的参数 b1
和 b2
,代表两个球体的位置。eatfood
函数处理玩家球体吃食物的逻辑。当玩家球体接触到食物时,球体会变大。函数的逻辑如下:food
数组,该数组包含多个食物元素。food[i].flag
为 true
)以及玩家球体与食物之间的距离是否小于玩家球体的半径(player.r
)。flag
设置为 false
,表示食物已被吃掉。food[i].r / 4
)。这表示玩家球体在吃到食物后会变大。void playercontroller(int speed) {
//根据按键玩家控制移动
if (GetAsyncKeyState(VK_UP) && player.y - player.r >= 0)
{
player.y -= speed;
}
if (GetAsyncKeyState(VK_DOWN) && player.y + player.r < MAP_HEIGHT)
{
player.y += speed;
}
if (GetAsyncKeyState(VK_LEFT) && player.x - player.r >= 0)
{
player.x -= speed;
}
if (GetAsyncKeyState(VK_RIGHT) && player.x + player.r < MAP_WIDTH)
{
player.x += speed;
}
}
使用了 GetAsyncKeyState
函数来检测按键的状态
if (GetAsyncKeyState(VK_UP) && player.y - player.r >= 0)
: 这行代码检查 ‘上’ 箭头键是否被按下,并且玩家的当前位置的 y 坐标减去其半径是否大于或等于 0。如果这两个条件都为真,意味着玩家不在屏幕底部,可以向上移动。
player.y -= speed;
: 如果 ‘上’ 箭头键被按下,并且玩家不在屏幕底部,玩家的 y 坐标会减去速度值,这样玩家就会在游戏世界中向上移动。
if (GetAsyncKeyState(VK_UP) && player.y - player.r >= 0)
: 这行代码检查 ‘上’ 箭头键是否被按下,并且玩家的当前位置的 y 坐标减去其半径是否大于或等于 0。如果这两个条件都为真,意味着玩家不在屏幕底部,可以向上移动。
player.y -= speed;
: 如果 ‘上’ 箭头键被按下,并且玩家不在屏幕底部,玩家的 y 坐标会减去速度值,这样玩家就会在游戏世界中向上移动。。。。。。。。。。
补充:
`CameraUpdate` 函数是用于更新游戏相机位置的函数。相机在游戏中的作用是让玩家能够看到游戏世界的一部分,通常是一个窗口(视口)。这个函数确保相机的位置始终在游戏世界的可视区域内。
以下是 `CameraUpdate` 函数的原理和逻辑:
1. `cameraPos.x = player.x - WIN_WIDTH / 2;`:计算相机在 x 轴的位置。相机的 x 坐标是玩家的 x 坐标减去屏幕宽度的一半。这样,相机就会在玩家正中间的位置。
2. `cameraPos.y = player.y - WIN_HEIGHT / 2;`:计算相机在 y 轴的位置。相机的 y 坐标是玩家的 y 坐标减去屏幕高度的一半。这样,相机就会在玩家正中间的位置。
3. `if (cameraPos.x < 0) cameraPos.x = 0;`:如果相机的位置在 x 轴上小于 0,则将相机的位置设置为 0。这意味着相机不能移动到游戏世界的左侧边界之外。
4. `if (cameraPos.y < 0) cameraPos.y = 0;`:如果相机的位置在 y 轴上小于 0,则将相机的位置设置为 0。这意味着相机不能移动到游戏世界的顶部边界之外。
5. `if (cameraPos.x > MAP_WIDTH - WIN_WIDTH) cameraPos.x = MAP_WIDTH - WIN_WIDTH;`:如果相机的位置在 x 轴上大于游戏世界的宽度减去屏幕宽度,则将相机的位置设置为游戏世界的右侧边界。
6. `if (cameraPos.y > MAP_HEIGHT - WIN_HEIGHT) cameraPos.y = MAP_HEIGHT - WIN_HEIGHT;`:如果相机的位置在 y 轴上大于游戏世界的高度减去屏幕高度,则将相机的位置设置为游戏世界的底部边界。
通过这些逻辑,`CameraUpdate` 函数确保相机始终在游戏世界的可视区域内,无论玩家在游戏世界中如何移动。这对于保持玩家在屏幕上的中心位置并显示游戏世界的重要部分非常重要。
//#include "contains.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#pragma comment(lib,"winmm.lib")
#define WIN_WIDTH 1024
#define WIN_HEIGHT 640
#define MAP_WIDTH (WIN_WIDTH*5)
#define MAP_HEIGHT (WIN_HEIGHT*5)
#define FOOD_NUM 1000
#define AI_NUM 500
struct ball
{
int x;
int y;
int r;
bool flag;
DWORD color;
}player,food[FOOD_NUM],ai[AI_NUM];
/*结构体定*/
IMAGE map(MAP_WIDTH, MAP_HEIGHT);
POINT cameraPos;
void PlayBackgroundMusic() {
// 使用相对路径打开音频文件,假设音频文件名为"example.mp3"
if (mciSendString("open mus.mp3 alias BGM", NULL, 0, NULL) != 0) {
std::cerr << "Failed to open the audio file." << std::endl;
return;
}
// 播放音频并设置为循环播放
if (mciSendString("play BGM repeat", NULL, 0, NULL) != 0) {
std::cerr << "Failed to play the audio." << std::endl;
mciSendString("close BGM", NULL, 0, NULL); // 如果播放失败,关闭文件
return;
}
}
void gameinit() {
PlayBackgroundMusic();
//bgm
//随机种子
srand((unsigned)time(NULL));
//角色
player.x = rand() % MAP_WIDTH;
player.y = rand() % MAP_HEIGHT;
player.r = 15;
player.flag = true;
player.color = RGB(rand() % 256, rand() % 256, rand() % 256);
//食物
for (int i = 0; i < FOOD_NUM; i++)
{
food[i].x = rand() % MAP_WIDTH;
food[i].y = rand() % MAP_HEIGHT;
food[i].r = rand() % 5 + 1;
food[i].flag = true;
food[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
}
//自由移动者
for (int i = 0; i < AI_NUM; i++)
{
ai[i].x = rand() % MAP_WIDTH;
ai[i].y = rand() % MAP_HEIGHT;
ai[i].r = rand() % 15 + 1;
ai[i].flag = true;
ai[i].color = RGB(rand() % 256, rand() % 256, rand() % 256);
}
}
void Chase(struct ball* chase,struct ball run)
{
chase->x < run.x ? chase->x += 2 : chase->x -= 2;
chase->y < run.y ? chase->y += 2 : chase->y -= 2;
}
void aimove()
{
for (int i = 0; i < AI_NUM; i++)
{
if (ai[i].flag)
{
Chase(&ai[i], player);
}
}
}
void CameraUpdate()
{
cameraPos.x = player.x - WIN_WIDTH / 2;
cameraPos.y = player.y - WIN_HEIGHT / 2;
if (cameraPos.x < 0) cameraPos.x = 0;
if (cameraPos.y < 0) cameraPos.y = 0;
if (cameraPos.x > MAP_WIDTH - WIN_WIDTH) cameraPos.x = MAP_WIDTH - WIN_WIDTH;
if (cameraPos.y > MAP_HEIGHT - WIN_HEIGHT) cameraPos.y = MAP_HEIGHT - WIN_HEIGHT;
}
void gamedraw() {
BeginBatchDraw();
SetWorkingImage(&map);//设置图像
setbkcolor(WHITE);//设置背景颜色
cleardevice();
//准备工作
//绘制图像
//1.食物圆
for (int i = 0; i< FOOD_NUM; i++) {
if (food[i].flag) {
setfillcolor(food[i].color);
solidcircle(food[i].x, food[i].y, food[i].r);
}
}
//2.ai圆
for (int i = 0; i < AI_NUM; i++)
{
if (ai[i].flag)
{
setfillcolor(ai[i].color);
solidcircle(ai[i].x, ai[i].y, ai[i].r);
}
}
//3.玩儿家圆
if (player.flag)
{
setfillcolor(player.color);
solidcircle(player.x, player.y, player.r);
settextcolor(BLACK);
setbkmode(TRANSPARENT);
// 确保文件编码支持中文,并且项目设置使用MBCS
outtextxy(player.x, player.y, "百年好合");
}
//显示页面
SetWorkingImage();
CameraUpdate();
putimage(0, 0, WIN_WIDTH, WIN_HEIGHT, &map, cameraPos.x, cameraPos.y);
EndBatchDraw();
}
double DisTance(struct ball b1, struct ball b2)
{
return sqrt((double)(b1.x - b2.x) * (b1.x - b2.x) + (b1.y - b2.y) * (b1.y - b2.y));
}
void eatfood() {
//吃食物的逻辑 : 遇见食物就圆扩大
for (int i = 0; i < FOOD_NUM; i++)
{
if (food[i].flag && DisTance(player, food[i]) < player.r)
{
food[i].flag = false;
player.r += food[i].r / 4;
}
}
}
void playercontroller(int speed) {
//根据按键玩家控制移动
if (GetAsyncKeyState(VK_UP) && player.y - player.r >= 0)
{
player.y -= speed;
}
if (GetAsyncKeyState(VK_DOWN) && player.y + player.r < MAP_HEIGHT)
{
player.y += speed;
}
if (GetAsyncKeyState(VK_LEFT) && player.x - player.r >= 0)
{
player.x -= speed;
}
if (GetAsyncKeyState(VK_RIGHT) && player.x + player.r < MAP_WIDTH)
{
player.x += speed;
}
}
int main() {
initgraph(WIN_WIDTH, WIN_HEIGHT);//初始化界面
gameinit();
while (true) {
aimove();
gamedraw();
eatfood();
playercontroller(10);
}
/*getchar();*/
return 0;
}
总结:至此简单实现的游戏完结,主要在于理清思路,拿此训练思维,孰能生巧。至于高级低级全看个人,随之成长日趋强键。