能帮到你的话,就给个赞吧 😘
文章目录
- player.h
- player.cpp
- particle.h
- particle.cpp
player.h
#pragma once
#include <graphics.h>
#include "vector2.h"
#include "animation.h"
#include "playerID.h"
#include "platform.h"
#include "bullet.h"
#include "particle.h"extern bool isDebug;extern Atlas atlasRunEffect;
extern Atlas atlasJumpEffect;
extern Atlas atlasLandEffect;extern std::vector<Bullet*> bullets;
extern std::vector<Platform> platforms;class Player {
public:Player();
public:virtual void receiveInput(const ExMessage& msg);virtual void update(int time);virtual void render();void setId(const PlayerID& id);void setPosition(float x, float y);
public:const Vector2& getPosition() const;const Vector2& getSize() const;
public:
//攻击virtual void onAttack() = 0;virtual void onAttackEx() = 0;
protected://无敌void makeInvulnerable();public:const int getHp() const;const int getMp() const;protected:virtual void onRun(float distance); //奔跑virtual void onJump(); //跳跃virtual void onLand(); //落地void moveAndCollide(int time); //重力和碰撞protected:const float runVelocity = 0.55; //奔跑速度const float jumpVelocity = -0.85; //跳跃速度const float gravity = 1.6e-3f; //重力加速度Vector2 velocity; //玩家速度PlayerID id = P1;//HP MPint hp = 100, mp = 0;//攻击bool isCanAttck = true;Timer timerAttckCd;int attackCd = 500;bool isAttackingEx = false;//无敌IMAGE imgSketch;bool isInvulnerable = false;bool isShowSketchFram = false; //当前帧是否应该显示剪影Timer timerInvulnerable; //玩家无敌Timer timerInvulnerableBlink; //闪烁切换//粒子特效std::vector<Particle> particles;Timer timerRunEffectGeneration; //玩家跑动粒子发射器Timer timerDieEffectGeneration; //玩家死亡粒子发射器//按键信息bool isLeftKeyDown = false;bool isRightKeyDown = false;//移动信息Vector2 position; //玩家位置Vector2 size; //碰撞尺寸bool isFacingRight = true; //玩家朝向——(根据按键决定)//渲染数据Animation animationIdleLeft;Animation animationIdleRight;Animation animationRunLeft;Animation animationRunRight;Animation animationAttackExLeft;Animation animationAttackExRight;Animation animationJumpEffect; //跳跃动画Animation animationLandEffect; //落地bool isJumpEffectVisible = false; //跳跃可见bool isLandEffectVisible = false; //落地可见Vector2 positionJumpEffect;Vector2 positionLandEffect;Animation* currentAni = nullptr;};
player.cpp
#include "player.h"Player::Player() {currentAni = &animationIdleRight;timerAttckCd.setCallback([&] {isCanAttck = true;});timerAttckCd.setTimer(attackCd);timerAttckCd.setIsOneShot(true);//无敌定时器timerInvulnerable.setCallback([&] {isInvulnerable = false;});timerInvulnerable.setTimer(750);timerInvulnerable.setIsOneShot(true);//无敌动画切换timerInvulnerableBlink.setCallback([&] {isShowSketchFram = !isShowSketchFram;});timerInvulnerableBlink.setTimer(75);//粒子发射timerRunEffectGeneration.setTimer(75);timerRunEffectGeneration.setCallback([&] {Vector2 particlePosition;auto frame = atlasRunEffect.getImage(0);//粒子位于玩家水平中央particlePosition.x = position.x + (size.x - frame->getwidth()) / 2;//玩家脚底particlePosition.y = position.y + size.y - frame->getheight();particles.emplace_back(particlePosition, &atlasRunEffect, 45);});timerDieEffectGeneration.setTimer(35);timerDieEffectGeneration.setCallback([&] {Vector2 particlePosition;auto frame = atlasRunEffect.getImage(0);//粒子位于玩家水平中央particlePosition.x = position.x + (size.x - frame->getwidth()) / 2;//玩家脚底particlePosition.y = position.y + size.y - frame->getheight();particles.emplace_back(particlePosition, &atlasRunEffect, 150);});//跳跃和落地animationJumpEffect.setAtlas(&atlasJumpEffect);animationJumpEffect.setInterval(25);animationJumpEffect.setIsLoop(false);animationJumpEffect.setCallback([&] {isJumpEffectVisible = false;});animationLandEffect.setAtlas(&atlasLandEffect);animationLandEffect.setInterval(50);animationLandEffect.setIsLoop(false);animationLandEffect.setCallback([&] {isLandEffectVisible = false;});}void Player::setId(const PlayerID& id){this->id = id;
}void Player::setPosition(float x, float y){position.x = x, position.y = y;
}const Vector2& Player::getPosition() const{return position;
}const Vector2& Player::getSize() const{return size;
}void Player::makeInvulnerable(){isInvulnerable = true;timerInvulnerable.reStart();
}const int Player::getHp() const{return hp;
}const int Player::getMp() const{return mp;
}void Player::onRun(float distance){if (isAttackingEx)return;position.x += distance;timerRunEffectGeneration.resume();
}void Player::onJump(){if (velocity.y || isAttackingEx)return;//仅需更改速度即可//位置在moveAndCollide修改velocity.y += jumpVelocity;//跳跃isJumpEffectVisible = true;animationJumpEffect.reset();auto frame = animationJumpEffect.getFrame();//jump位于玩家中央positionJumpEffect.x = position.x + (size.x - frame->getwidth()) / 2;positionJumpEffect.y = position.y + size.x - frame->getheight();}void Player::onLand(){//落地isLandEffectVisible = true;animationLandEffect.reset();auto frame = animationLandEffect.getFrame();//jump位于玩家中央positionLandEffect.x = position.x + (size.x - frame->getwidth()) / 2;positionLandEffect.y = position.y + size.x - frame->getheight();
}void Player::moveAndCollide(int time){auto lastVelocityY = velocity.y;velocity.y += gravity * time;position += velocity * time;//碰撞检测//玩家与平台if (velocity.y) {for (const auto& platform : platforms) {const auto& shape = platform.shape;bool isCollideX = max(position.x + size.x, shape.right) - min(position.x, shape.left) <= shape.right - shape.left + size.x;bool isCollideY = shape.y >= position.y && shape.y <= position.y + size.y;//对玩家坐标进行修正if (isCollideX && isCollideY) {//判断上一帧玩家是否在平台之上auto deltaY = velocity.y * time;auto lastY = position.y + size.y - deltaY;if (lastY <= shape.y) {position.y = shape.y - size.y;//平台上速度为0velocity.y = 0;if (lastVelocityY)onLand();break;}}}}//玩家与子弹if (!isInvulnerable) {for (const auto& bullet : bullets) {if (!bullet->getValid() || bullet->getCollideTarget() != id)continue;if (bullet->checkCollision(position, size)) {makeInvulnerable();bullet->onCollide();bullet->setValid(false);hp -= bullet->getDamage();}}}}void Player::receiveInput(const ExMessage& msg){switch (msg.message){case WM_KEYDOWN:switch (id){case P1:switch (msg.vkcode){//'A'case 0x41:isLeftKeyDown = true;break;//'D'case 0x44:isRightKeyDown = true;break;//'W'case 0x57:onJump();break;//'J'case 0x4a:if (isCanAttck) {onAttack();isCanAttck = !isCanAttck;timerAttckCd.reStart(); }break;//'K'case 0x4b:if (mp >= 100) {onAttackEx();mp = 0;}break;default:break;}break;case P2:switch (msg.vkcode) {//<case VK_LEFT:isLeftKeyDown = true;break;//>case VK_RIGHT:isRightKeyDown = true;break;//'↑'case VK_UP:onJump();break;//'1'case 0x6e:if (isCanAttck) {onAttack();isCanAttck = !isCanAttck;timerAttckCd.reStart();}break;//'2'case 0x62:if (mp >= 100) {onAttackEx();mp = 0;}break;default:break;}break;default:break;}break;case WM_KEYUP:switch (id) {case P1:switch (msg.vkcode) {//'A'case 0x41:isLeftKeyDown = false;break;//'D'case 0x44:isRightKeyDown = false;break;default:break;}break;case P2:switch (msg.vkcode) {//<case VK_LEFT:isLeftKeyDown = false;break;//>case VK_RIGHT:isRightKeyDown = false;break;default:break;}break;default:break;}break;default:break;}}void Player::update(int time){//direction:——玩家是否按键: 0——没有按键int direction = isRightKeyDown - isLeftKeyDown;//按键if (direction) {//特殊攻击时不允许转向if(!isAttackingEx)isFacingRight = direction > 0; //根据按键判断当前朝向//根据当前朝向 选择 动画currentAni = isFacingRight ? &animationRunRight : &animationRunLeft;//水平方向移动auto distance = direction * runVelocity * time;onRun(distance);}else {currentAni = isFacingRight ? &animationIdleRight : &animationIdleLeft;timerRunEffectGeneration.pause();}if (isAttackingEx)currentAni = isFacingRight ? &animationAttackExRight : &animationAttackExLeft;//更新动画currentAni->update(time);animationJumpEffect.update(time);animationLandEffect.update(time);//更新定时器timerAttckCd.update(time);timerInvulnerable.update(time);timerInvulnerableBlink.update(time);//粒子//生成粒子timerRunEffectGeneration.update(time);if (hp <= 0)timerDieEffectGeneration.update(time);//更新粒子particles.erase(std::remove_if(particles.begin(), particles.end(), [](const Particle& particle) {return !particle.checkIsValid();}), particles.end());for (auto& particle : particles)particle.update(time);//剪影if (isShowSketchFram)sketchImage(currentAni->getFrame(), &imgSketch);//重力模拟 和 碰撞检测moveAndCollide(time);
}void Player::render(){if (isJumpEffectVisible)animationJumpEffect.render(positionJumpEffect.x, positionJumpEffect.y);if (isLandEffectVisible)animationLandEffect.render(positionLandEffect.x, positionLandEffect.y);//让粒子渲染在玩家身后for (const Particle& particle : particles)particle.render();if (hp > 0 && isInvulnerable && isShowSketchFram)putImageAlpha(position.x, position.y, &imgSketch);elsecurrentAni->render(position.x, position.y);if (isDebug) {setlinecolor(RGB(0, 125, 255));rectangle(position.x, position.y, position.x + size.x, position.y + size.y);}
}
particle.h
#pragma once#include "atlas.h"
#include "vector2.h"
#include "util.h"class Particle {public:Particle() = default;Particle(const Vector2& position, Atlas* atlas, int lifeSpan) :position(position), lifeSpan(lifeSpan),atlas(atlas) {}public:
//设置void setPosition(const Vector2& position);void setAtlas(Atlas* atlas);void setLifeSpan(int lifeSpan);//检测bool checkIsValid() const;//更新void update(int deltaT);
//渲染void render() const;private://物理Vector2 position;bool isValid = true; //粒子是否有效//渲染int timer = 0; //计时器int lifeSpan = 0; //单帧持续时间int index = 0; //当前帧Atlas* atlas = nullptr;
};
particle.cpp
#include "particle.h"void Particle::setPosition(const Vector2& position){this->position = position;
}void Particle::setAtlas(Atlas* atlas){this->atlas = atlas;
}void Particle::setLifeSpan(int lifeSpan){this->lifeSpan = lifeSpan;
}bool Particle::checkIsValid() const{return isValid;
}void Particle::update(int deltaT){timer += deltaT;if (timer >= lifeSpan) {timer = 0;index++;//粒子在播完动画后消失if (index == atlas->getSize()) {index = atlas->getSize() - 1;isValid = false;}}
}void Particle::render() const{putImageAlpha(position.x, position.y, atlas->getImage(index));
}