植物明星大乱斗15


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


文章目录

  • 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 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));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/919380.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PaddleNLP的环境配置:

PaddleNLP的环境配置&#xff1a; conda create -n paddle—test python3.9conda activate paddle—testpython -m pip install paddlepaddle-gpu2.6.1.post112 -f https://www.paddlepaddle.org.cn/whl/windows/mkl/avx/stable.html(paddle—test) (venv) PS D:\work\论文写…

【MySQL实战45讲笔记】基础篇——redo log 和 binlog

系列文章 基础篇——MySQL 的基础架构 目录 系列文章1. 重要的日志模块&#xff1a;redo log 和 binlog1.1 redo log1.2 binlog1.3 执行器和 InnoDB 引擎内部如何执行更新语句 1. 重要的日志模块&#xff1a;redo log 和 binlog 前面系统的了解了一个查询语句的执行流程&…

MATLAB常见数学运算函数

MATLAB中含有许多有用的函数,可以随时调用。 a b s abs abs函数 a b s abs abs函数在MATLAB中可以求绝对值,也可以求复数的模长:c e i l ceil ceil函数 向正无穷四舍五入(如果有小数,就向正方向进一)f l o o r floor floor函数 向负无穷四舍五入(如果有小数,就向负方向…

MySQL无开通SQL全审计下的故障分析方法

几年前MySQL数据库出现突然的从库延迟故障和CPU爆高时&#xff0c;如何排查具体原因&#xff0c;可能说已在腾讯云的MySQL库里开启了SQL全审计&#xff0c;记录了全部执行的SQL&#xff0c;再通过下面的方法就可以很容易找到原因&#xff1a; 1&#xff0c;实用QPS和TPS高的高效…

新手教学系列——善用 VSCode 工作区,让开发更高效

引言 作为一名开发者,你是否曾经在项目中频繁地切换不同文件夹,打开无数个 VSCode 窗口?特别是当你同时参与多个项目或者处理多个模块时,这种情况更是家常便饭。很快,你的任务栏上挤满了 VSCode 的小图标,切换起来手忙脚乱,工作效率直线下降。这时候,你可能会问:“有…

React(一)

文章目录 项目地址一、创建第一个react项目二、JSX语法2.1 生成列表2.2 大括号识别JS的表达式2.3 列表循环array2.4 条件判断以及假值显示2.5 复杂条件渲染2.6 事件监听和绑定2.7 使用Fregments返回多个根标签2.8 多条件渲染2.9 导出子组件 三、组件3.1 设置组件3.2 props给子组…

微服务安全Spring Security Oauth2实战_spring-security-oauth2-authorization-server

Spring Authorization Server 是什么 Spring Authorization Server 是一个框架&#xff0c;它提供了 OAuth 2.1 和 OpenID Connect 1.0 规范以及其他相关规范的实现。它建立在 Spring Security 之上&#xff0c;为构建 OpenID Connect 1.0 身份提供者和 OAuth2 授权服务器产品…

多线程-02-多线程的典型应用(异步调用和提高效率)

一、怎么理解异步和同步 从方法的角度去理解&#xff1a; 需要等待结果返回&#xff0c;才能继续运行就是同步不需要等待结果返回&#xff0c;就能继续运行就是异步 注意&#xff1a;同步在多线程中还有另外一层意思&#xff1a;是让多个线程步调一致。 同步调用 同步调用…

【数据分享】中国汽车工业年鉴(1986-2023)

本年鉴是由工业和信息化部指导&#xff0c;中国汽车技术研究中心有限公司与中国汽车工业协会联合主办。《年鉴》是全面、客观记载中国汽车工业发展与改革历程的重要文献&#xff0c;内容涵盖汽车产业政策、标准、企业、市场以及全国各省市汽车工业发展情况&#xff0c;并调查汇…

Matlab实现北方苍鹰优化算法优化随机森林算法模型 (NGO-RF)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1内容介绍 北方苍鹰优化算法&#xff08;Northern Goshawk Optimization, NGO&#xff09;是一种新颖的群智能优化算法&#xff0c;灵感源自北方苍鹰捕食时的策略。该算法通过模拟苍鹰的搜寻、接近和捕捉猎物的行为模式&am…

CentOS使用中遇到的问题及解决方法

一、CentOS 7网络配置&#xff08;安装后无法联网问题&#xff09; 现象说明 在安装CentOS系统后&#xff0c;有可能出现无法联网的问题&#xff0c;虚拟机中的网络配置并没有问题&#xff0c;而系统却无法联网,也ping不通。 原因描述 CentOS默认开机不启动网络&#xff0c;因…

QT基础 UI编辑器 QT5.12.3环境 C++环境

一、UI编辑器 注意&#xff1a;创建工程时&#xff0c;要勾上界面按钮 UI设计师界面的模块 UI编辑器会在项目构建目录中自动生成一个ui_xxx.h&#xff08;构建一次才能生成代码&#xff09;&#xff0c;来表示ui编辑器界面的代码&#xff0c;属于自动生成的&#xff0c;一定不…

数据分析-Excel基础操作

目录 周报讲解 基础概念 理解数据 筛选excel表 数据透视表 插入数据透视表 新建字段 切片器&#xff08;筛选&#xff09; 数据透视图 Excel常用函数 sum&#xff08;求和&#xff09; 1-8月GMV 1月和8月GMV sumif&#xff08;条件求和&#xff09; sumifs 日G…

OpenCV双目立体视觉重建

本篇文章主要给出使用opencv sgbm重建三维点云的代码&#xff0c;鉴于自身水平所限&#xff0c;如有错误&#xff0c;欢迎批评指正。 环境&#xff1a;vs2015 &#xff0c;opencv3.4.6&#xff0c;pcl1.8.0 原始数据使用D455采集&#xff0c;图像已做完立体校正&#xff0c;如下…

Clip结合Faiss+Flask简易版文搜图服务

一、实现 使用目录结构&#xff1a; templates ---upload.html faiss_app.py 前端代码&#xff1a;upload.html <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content&quo…

Linux驱动开发快速入门——字符设备驱动(直接操作寄存器设备树版)

Linux驱动开发快速入门——字符设备驱动 前言 笔者使用开发板型号&#xff1a;正点原子的IMX6ULL-alpha开发板。ubuntu版本为&#xff1a;20.04。写此文也是以备忘为目的。 字符设备驱动 本小结将以直接操作寄存器的方式控制一个LED灯&#xff0c;可以通过read系统调用可以…

概念解读|K8s/容器云/裸金属/云原生...这些都有什么区别?

随着容器技术的日渐成熟&#xff0c;不少企业用户都对应用系统开展了容器化改造。而在容器基础架构层面&#xff0c;很多运维人员都更熟悉虚拟化环境&#xff0c;对“容器圈”的各种概念容易混淆&#xff1a;容器就是 Kubernetes 吗&#xff1f;容器云又是什么&#xff1f;容器…

《机器人控制器设计与编程》考试试卷**********大学2024~2025学年第(1)学期

消除误解&#xff0c;课程资料逐步公开。 复习资料&#xff1a; Arduino-ESP32机器人控制器设计练习题汇总_arduino编程语言 题-CSDN博客 试卷样卷&#xff1a; 开卷考试&#xff0c;时间&#xff1a; 2024年11月16日 001 002 003 004 005 ……………………装………………………

本地音乐服务器(三)

6. 删除音乐模块设计 6.1 删除单个音乐 1. 请求响应设计 2. 开始实现 首先在musicmapper新增操作 Music findMusicById(int id);int deleteMusicById(int musicId); 其次新增相对应的.xml代码&#xff1a; <select id"findMusicById" resultType"com.exa…

如何在项目中用elementui实现分页器功能

1.在结构部分复制官网代码&#xff1a; <template> 标签: 这是 Vue 模板的根标签&#xff0c;包含所有的 HTML 元素和 Vue 组件。 <div> 标签: 这是一个普通的 HTML 元素&#xff0c;包裹了 el-pagination 组件。它没有特别的意义&#xff0c;只是为了确保 el-pagi…