自学内容网 自学内容网

植物明星大乱斗15


能帮到你的话,就给个赞吧 😘


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 MP
int 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;

//平台上速度为0
velocity.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);
else
currentAni->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));
}


原文地址:https://blog.csdn.net/qq_42863961/article/details/143841245

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!