From 4ca22e652d97e535672b5ad375349ded825968de Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Thu, 5 Jan 2023 15:26:29 +0200 Subject: [PATCH] All projectile animations now use time-based speed --- client/battle/BattleProjectileController.cpp | 46 ++++++++++---------- client/battle/BattleProjectileController.h | 10 ++--- client/battle/CreatureAnimation.cpp | 4 +- client/battle/CreatureAnimation.h | 5 +-- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/client/battle/BattleProjectileController.cpp b/client/battle/BattleProjectileController.cpp index 651dbfd3d..571aca45a 100644 --- a/client/battle/BattleProjectileController.cpp +++ b/client/battle/BattleProjectileController.cpp @@ -53,8 +53,6 @@ void ProjectileMissile::show(Canvas & canvas) if(image) { - float progress = float(step) / steps; - Point pos { vstd::lerp(from.x, dest.x, progress) - image->width() / 2, vstd::lerp(from.y, dest.y, progress) - image->height() / 2, @@ -62,7 +60,9 @@ void ProjectileMissile::show(Canvas & canvas) canvas.draw(image, pos); } - ++step; + + float timePassed = GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; + progress += timePassed * speed; } void ProjectileAnimatedMissile::show(Canvas & canvas) @@ -82,8 +82,6 @@ void ProjectileCatapult::show(Canvas & canvas) if(image) { - float progress = float(step) / steps; - int posX = vstd::lerp(from.x, dest.x, progress); int posY = calculateCatapultParabolaY(from, dest, posX); Point pos(posX, posY); @@ -92,13 +90,13 @@ void ProjectileCatapult::show(Canvas & canvas) frameNum = (frameNum + 1) % animation->size(0); } - ++step; + + float timePassed = GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; + progress += timePassed * speed; } void ProjectileRay::show(Canvas & canvas) { - float progress = float(step) / steps; - Point curr { vstd::lerp(from.x, dest.x, progress), vstd::lerp(from.y, dest.y, progress), @@ -142,7 +140,9 @@ void ProjectileRay::show(Canvas & canvas) canvas.drawLine(Point(x1 + i, y1), Point(x2 + i, y2), beginColor, endColor); } } - ++step; + + float timePassed = GH.mainFPSmng->getElapsedMilliseconds() / 1000.f; + progress += timePassed * speed; } BattleProjectileController::BattleProjectileController(BattleInterface & owner): @@ -231,7 +231,7 @@ void BattleProjectileController::showProjectiles(Canvas & canvas) } vstd::erase_if(projectiles, [&](const std::shared_ptr & projectile){ - return projectile->step > projectile->steps; + return projectile->progress > 1.0f; }); } @@ -249,15 +249,14 @@ bool BattleProjectileController::hasActiveProjectile(const CStack * stack, bool return false; } -int BattleProjectileController::computeProjectileFlightTime( Point from, Point dest, double animSpeed) +float BattleProjectileController::computeProjectileFlightTime( Point from, Point dest, double animSpeed) { - double distanceSquared = (dest.x - from.x) * (dest.x - from.x) + (dest.y - from.y) * (dest.y - from.y); - double distance = sqrt(distanceSquared); - int steps = std::round(distance / animSpeed); + float distanceSquared = (dest.x - from.x) * (dest.x - from.x) + (dest.y - from.y) * (dest.y - from.y); + float distance = sqrt(distanceSquared); - if (steps > 0) - return steps; - return 1; + assert(distance > 1.f); + + return animSpeed / std::max( 1.f, distance); } int BattleProjectileController::computeProjectileFrameID( Point from, Point dest, const CStack * stack) @@ -297,12 +296,11 @@ void BattleProjectileController::createCatapultProjectile(const CStack * shooter catapultProjectile->animation = getProjectileImage(shooter); catapultProjectile->frameNum = 0; - catapultProjectile->step = 0; - catapultProjectile->steps = computeProjectileFlightTime(from, dest, AnimationControls::getCatapultSpeed()); + catapultProjectile->progress = 0; + catapultProjectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getCatapultSpeed()); catapultProjectile->from = from; catapultProjectile->dest = dest; catapultProjectile->shooterID = shooter->ID; - catapultProjectile->step = 0; catapultProjectile->playing = false; projectiles.push_back(std::shared_ptr(catapultProjectile)); @@ -335,11 +333,11 @@ void BattleProjectileController::createProjectile(const CStack * shooter, Point missileProjectile->frameNum = computeProjectileFrameID(from, dest, shooter); } - projectile->steps = computeProjectileFlightTime(from, dest, AnimationControls::getProjectileSpeed()); + projectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getProjectileSpeed()); projectile->from = from; projectile->dest = dest; projectile->shooterID = shooter->ID; - projectile->step = 0; + projectile->progress = 0; projectile->playing = false; projectiles.push_back(projectile); @@ -363,8 +361,8 @@ void BattleProjectileController::createSpellProjectile(const CStack * shooter, P projectile->from = from; projectile->dest = dest; projectile->shooterID = shooter ? shooter->ID : -1; - projectile->step = 0; - projectile->steps = computeProjectileFlightTime(from, dest, AnimationControls::getSpellEffectSpeed()); + projectile->progress = 0; + projectile->speed = computeProjectileFlightTime(from, dest, AnimationControls::getProjectileSpeed()); projectile->playing = false; projectiles.push_back(std::shared_ptr(projectile)); diff --git a/client/battle/BattleProjectileController.h b/client/battle/BattleProjectileController.h index 5428e5d14..8b6be2937 100644 --- a/client/battle/BattleProjectileController.h +++ b/client/battle/BattleProjectileController.h @@ -33,10 +33,10 @@ struct ProjectileBase Point from; // initial position on the screen Point dest; // target position on the screen - int step; // current step counter - int steps; // total number of steps/frames to show - int shooterID; // ID of shooter stack - bool playing; // if set to true, projectile animation is playing, e.g. flying to target + float progress; // current position of projectile on from->dest line + float speed; // how much progress is gained per second + int shooterID; // ID of shooter stack + bool playing; // if set to true, projectile animation is playing, e.g. flying to target }; /// Projectile for most shooters - render pre-selected frame moving in straight line from origin to destination @@ -97,7 +97,7 @@ class BattleProjectileController const CCreature & getShooter(const CStack * stack) const; int computeProjectileFrameID( Point from, Point dest, const CStack * stack); - int computeProjectileFlightTime( Point from, Point dest, double speed); + float computeProjectileFlightTime( Point from, Point dest, double speed); public: BattleProjectileController(BattleInterface & owner); diff --git a/client/battle/CreatureAnimation.cpp b/client/battle/CreatureAnimation.cpp index 28b4e6815..b83a4f202 100644 --- a/client/battle/CreatureAnimation.cpp +++ b/client/battle/CreatureAnimation.cpp @@ -115,12 +115,12 @@ float AnimationControls::getCreatureAnimationSpeed(const CCreature * creature, c float AnimationControls::getProjectileSpeed() { - return static_cast(settings["battle"]["animationSpeed"].Float() * 100); + return static_cast(settings["battle"]["animationSpeed"].Float() * 4000); } float AnimationControls::getCatapultSpeed() { - return static_cast(settings["battle"]["animationSpeed"].Float() * 20); + return static_cast(settings["battle"]["animationSpeed"].Float() * 1000); } float AnimationControls::getSpellEffectSpeed() diff --git a/client/battle/CreatureAnimation.h b/client/battle/CreatureAnimation.h index 8f3c46b9e..cdead9c79 100644 --- a/client/battle/CreatureAnimation.h +++ b/client/battle/CreatureAnimation.h @@ -31,11 +31,10 @@ namespace AnimationControls /// returns animation speed of specific group, taking in mind game setting (in frames per second) float getCreatureAnimationSpeed(const CCreature * creature, const CreatureAnimation * anim, ECreatureAnimType groupID); - /// returns how far projectile should move each frame - /// TODO: make it time-based + /// returns how far projectile should move per second float getProjectileSpeed(); - /// returns speed of catapult projectile + /// returns speed of catapult projectile, in pixels per second (horizontal axis only) float getCatapultSpeed(); /// returns speed of any spell effects, including any special effects like morale (in frames per second)