能帮到你的话,就给个赞吧 😘
#include <iostream>
#include <windows.h>
#include <string>
#include <graphics.h>
#include <vector>
#pragma comment(lib, "MSIMG32.LIB")class Animation {
private:std::vector<IMAGE*> imgs;int imgIndex = 0;int frameInterval = 0; //帧间隔: 两帧图片间的时间int timer = 0; //计时器: 图片播放的时间public:Animation(LPCTSTR path, int num, int frameInterval);//LPCSTR 更通用的常字符指针~Animation();
public:void play(int x, int y, int time); //time :此次播放的时间
};class Player {
private: POINT playerPos{ 500,500 }; //玩家位置const int playerSpeed = 6; //移动速度bool isLeft = false, isRight = false, //移动方向isUp = false, isDown = false; bool isFacingLeft = false; //面部朝向const int playerWidth = 80; //玩家高度const int playerHeight = 80;const int shadowWidth = 32; //玩家阴影高度private:IMAGE playerShadow;Animation* animationPlayerLeft; //玩家动画Animation* animationPlayerRight;
public:Player();~Player();
public:void processMessage(const ExMessage& msg);void move();void draw(int frameInterval);
public:int x() const { return playerPos.x; }int y() const { return playerPos.y; }
};class Enemy {
private:POINT enemyPos{ 0,0 }; //敌人位置const int enemySpeed = 2; //移动速度bool isLeft = false, isRight = false, //移动方向isUp = false, isDown = false; bool isFacingLeft = false; //面部朝向const int enemyWidth = 80; //敌人高度const int enemyHeight = 80;const int shadowWidth = 48; //敌人阴影高度private:IMAGE enemyShadow;Animation* animationEnemyLeft; //敌人动画Animation* animationEnemyRight;
public:Enemy();~Enemy();
public: void move(const Player& player);void draw(int frameInterval);
};void putImageAlpha(int x, int y, IMAGE* img); //图像绘制(透明度)
void generateEnemy(std::vector<Enemy*>& enemys);const int windowWidth = 1280;
const int windowHeight = 720;
const int frameInterval = 1000 / 120;int main() {initgraph(windowWidth, windowHeight); Player player;std::vector<Enemy*> enemys;IMAGE background; ExMessage message;bool running = true;loadimage(&background, _T("resources/img/background.png"));BeginBatchDraw();while (running) {ULONGLONG startTime = GetTickCount64();//读数据peekmessage(&message);//处理数据 player.processMessage(message);player.move();generateEnemy(enemys);for (auto& enemy : enemys)enemy->move(player);//渲染cleardevice();putimage(0, 0, &background);player.draw(frameInterval);for (auto& enemy : enemys)enemy->draw(frameInterval);FlushBatchDraw();//120刷新ULONGLONG executionTime = GetTickCount64() - startTime;if (executionTime < frameInterval)Sleep(frameInterval - executionTime);}
}Player::Player(){loadimage(&playerShadow, _T("resources/img/shadow_player.png"));animationPlayerLeft = new Animation(_T("resources/img/player_left_%d.png"), 6, 45);animationPlayerRight = new Animation(_T("resources/img/player_right_%d.png"), 6, 45);
}Player::~Player(){delete animationPlayerLeft;delete animationPlayerRight;
}void Player::processMessage(const ExMessage& msg){//判断移动方向if (msg.message == WM_KEYDOWN) {switch (msg.vkcode) {case VK_UP:isUp = true;break;case VK_DOWN:isDown = true;break;case VK_LEFT:isLeft = true;break;case VK_RIGHT:isRight = true;break;default:break;}}else if (msg.message == WM_KEYUP) {switch (msg.vkcode) {case VK_UP:isUp = false;break;case VK_DOWN:isDown = false;break;case VK_LEFT:isLeft = false;break;case VK_RIGHT:isRight = false;break;default:break;}}
}//计算移动信息
void Player::move(){// x,y 代表 向量int x = isRight - isLeft;int y = isDown - isUp;double modulus = sqrt(x * x + y * y); //向量的模if (modulus) {double vectorX = x / modulus;double vectorY = y / modulus;playerPos.x += int(playerSpeed * vectorX);playerPos.y += int(playerSpeed * vectorY);}//校准if (playerPos.x < 0) playerPos.x = 0;if (playerPos.y < 0) playerPos.y = 0;if (playerPos.x + playerWidth > windowWidth) playerPos.x = windowWidth - playerWidth;if (playerPos.y + playerHeight > windowHeight) playerPos.y = windowHeight - playerHeight;//修改面部朝向//等于0时,指向原先面部朝向if (x > 0)isFacingLeft = false;else if (x < 0)isFacingLeft = true;}void Player::draw(int frameInterval){//绘制阴影int xShadow = playerPos.x + (playerWidth - shadowWidth) / 2;int yShadow = playerPos.y + playerHeight - 8;putImageAlpha(xShadow, yShadow, &playerShadow);//绘制动画if (isFacingLeft)animationPlayerLeft->play(playerPos.x, playerPos.y, frameInterval);elseanimationPlayerRight->play(playerPos.x, playerPos.y, frameInterval);
}Enemy::Enemy(){loadimage(&enemyShadow, _T("resources/img/shadow_enemy.png"));animationEnemyLeft = new Animation(_T("resources/img/enemy_left_%d.png"), 6, 45);animationEnemyRight = new Animation(_T("resources/img/enemy_right_%d.png"), 6, 45);enum spawnEdge { up, down, left, right };spawnEdge edge = spawnEdge(rand() % 4);switch (edge){case up:enemyPos.x = rand() % windowWidth;enemyPos.y = -enemyHeight;break;case down:enemyPos.x = rand() % windowWidth;enemyPos.y = windowHeight;break;case left:enemyPos.x = -enemyWidth ;enemyPos.y = rand() % windowHeight;break;case right:enemyPos.x = windowWidth;enemyPos.y = rand() % windowHeight;break;default:break;}}Enemy::~Enemy(){delete animationEnemyLeft;delete animationEnemyRight;
}void Enemy::move(const Player& player){//怪物向玩家移动int x = player.x() - enemyPos.x;int y = player.y() - enemyPos.y;double modulus = sqrt(x * x + y * y); //向量的模if (modulus) {double vectorX = x / modulus;double vectorY = y / modulus;enemyPos.x += int(enemySpeed * vectorX);enemyPos.y += int(enemySpeed * vectorY);}//修改面部朝向if (x > 0)isFacingLeft = false;else if(x < 0)isFacingLeft = true;
}void Enemy::draw(int frameInterval){//绘制阴影int x = enemyPos.x + (enemyWidth - shadowWidth) / 2;int y = enemyPos.y + enemyHeight - 35;putImageAlpha(x, y, &enemyShadow);//等于0时,指向原先的面部朝向if (isFacingLeft)animationEnemyLeft->play(enemyPos.x, enemyPos.y, frameInterval);elseanimationEnemyRight->play(enemyPos.x, enemyPos.y, frameInterval);
}void putImageAlpha(int x, int y, IMAGE* img){int w = img->getwidth();int h = img->getheight();/*AlphaBlend: Windows GDI+ API,用于图像混合。GetImageHDC(nullptr), x, y, w, h:GetImageHDC(nullptr):获取屏幕x, y, w, h: 屏幕的位置,作为目标区域。(左上角坐标为x,y,宽为w,高为h)GetImageHDC(img), 0, 0, w, h:GetImageHDC(img):获取图像0, 0, w, h: 整个图像,作为源区域。{ AC_SRC_OVER,0,255, AC_SRC_ALPHA }: 将源图像以透明的方式覆盖到目标图像上,透明度由源图像的Alpha通道控制。AC_SRC_OVER: 源图像覆盖目标图像0,255: 参数,此处无作用AC_SRC_ALPHA: 指定源图像的Alpha通道覆盖图像的Alpha通道: 是图像的透明度通道,存储着每个像素的透明度信息*/AlphaBlend(GetImageHDC(nullptr), x, y, w, h, GetImageHDC(img), 0, 0, w, h, { AC_SRC_OVER,0,255, AC_SRC_ALPHA });
}void generateEnemy(std::vector<Enemy*>& enemys){static const int interval = 100;static int timer = 0;if (timer % interval == 0) {auto enemy = new Enemy;enemys.push_back(enemy);}timer++;timer %= interval;
}Animation::Animation(LPCTSTR path, int num, int frameInterval): frameInterval(frameInterval){TCHAR tPath[256]; // TCHAR: 更通用的字符for (int i = 0; i < num; i++) {/*将一个格式化的字符串 写入到 tPath 指向的字符数组中。格式 由 path 字符串模板决定,其中包含一些格式占位符(比如 %d、%s 等)。i 变量的值将用来替换 path 中对应的格式占位符。*/_stprintf_s(tPath, path, i);IMAGE* img = new IMAGE;loadimage(img, tPath);imgs.push_back(img);}
}Animation::~Animation(){for (int i = 0; i < imgs.size(); i++)delete imgs[i];
}void Animation::play(int x, int y, int time){putImageAlpha(x, y, imgs[imgIndex]);timer += time; //此次图片播放的时间if (timer > frameInterval) {imgIndex++;timer = 0;}imgIndex %= imgs.size();
}