能帮到你的话,就给个赞吧 😘
#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; //帧间隔ms: 两帧动画间的时间
int timer = 0; //计时器: 本张动画已经播放的时间
public:
Animation(LPCTSTR path, int num, int frameInterval);//LPCSTR 更通用的常字符指针
~Animation();
public:
//播放一张动画
void play(int x, int y, int playTime); //playTime :本张动画播放的时间
};
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);
else
animationPlayerRight->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);
else
animationEnemyRight->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 playTime) {
if (timer > frameInterval) {
imgIndex++;
imgIndex %= imgs.size();
timer = 0;
}
putImageAlpha(x, y, imgs[imgIndex]);
timer += playTime;
}