2
0
Эх сурвалжийг харах

Fixes for projectile playback. TODO: check catapult projectile

Ivan Savenko 2 жил өмнө
parent
commit
b5d1cb4996

+ 7 - 5
client/battle/CBattleAnimations.cpp

@@ -736,6 +736,7 @@ bool CShootingAnimation::init()
 	if(!attackingStack || myAnim->isDead())
 	{
 		//FIXME: how is this possible?
+		logAnim->warn("Shooting animation has not started yet but attacker is dead! Aborting...");
 		endAnim();
 		return false;
 	}
@@ -753,6 +754,7 @@ bool CShootingAnimation::init()
 	//	return false;
 
 	setAnimationGroup();
+	initializeProjectile();
 	shooting = true;
 	return true;
 }
@@ -812,7 +814,7 @@ void CShootingAnimation::initializeProjectile()
 
 void CShootingAnimation::emitProjectile()
 {
-	//owner->projectilesController->fireStackProjectile(attackingStack);
+	owner->projectilesController->emitStackProjectile(attackingStack);
 	projectileEmitted = true;
 }
 
@@ -833,17 +835,17 @@ void CShootingAnimation::nextFrame()
 		if(shooterInfo->idNumber == CreatureID::ARROW_TOWERS)
 			shooterInfo = owner->siegeController->getTurretCreature();
 
-		// animation should be paused if there is an active projectile
+		// emit projectile once animation playback reached "climax" frame
 		if ( stackAnimation(attackingStack)->getCurrentFrame() >= shooterInfo->animation.attackClimaxFrame )
 		{
-			initializeProjectile();
 			emitProjectile();
 			return;
 		}
 	}
 
+	// animation should be paused if there is an active projectile
 	if (projectileEmitted && owner->projectilesController->hasActiveProjectile(attackingStack))
-		return; // projectile in air, pause animation
+		return;
 
 
 	CAttackAnimation::nextFrame();
@@ -854,7 +856,7 @@ void CShootingAnimation::endAnim()
 	// FIXME: is this possible? Animation is over but we're yet to fire projectile?
 	if (!projectileEmitted)
 	{
-		initializeProjectile();
+		logAnim->warn("Shooting animation has finished but projectile was not emitted! Emitting it now...");
 		emitProjectile();
 	}
 

+ 25 - 21
client/battle/CBattleProjectileController.cpp

@@ -138,6 +138,7 @@ void ProjectileRay::show(std::shared_ptr<CCanvas> canvas)
 			canvas->drawLine(Point(x1 + i, y1), Point(x2 + i, y2), beginColor, endColor);
 		}
 	}
+	++step;
 }
 
 CBattleProjectileController::CBattleProjectileController(CBattleInterface * owner):
@@ -199,42 +200,43 @@ std::shared_ptr<CAnimation> CBattleProjectileController::getProjectileImage(cons
 	return projectilesCache[imageName];
 }
 
-//void CBattleProjectileController::fireStackProjectile(const CStack * stack)
-//{
-//	for (auto it = projectiles.begin(); it!=projectiles.end(); ++it)
-//	{
-//		if ( !it->shotDone && it->stackID == stack->ID)
-//		{
-//			it->shotDone = true;
-//			return;
-//		}
-//	}
-//}
-
+void CBattleProjectileController::emitStackProjectile(const CStack * stack)
+{
+	for (auto projectile : projectiles)
+	{
+		if ( !projectile->playing && projectile->shooterID == stack->ID)
+		{
+			projectile->playing = true;
+			return;
+		}
+	}
+}
 
 void CBattleProjectileController::showProjectiles(std::shared_ptr<CCanvas> canvas)
 {
-	for (auto projectile : projectiles)
+	for ( auto it = projectiles.begin(); it != projectiles.end();)
 	{
+		auto projectile = *it;
 		// Check if projectile is already visible (shooter animation did the shot)
 		//if (!it->shotDone)
 		//	continue;
 
-		projectile->show(canvas);
+		if ( projectile->playing )
+			projectile->show(canvas);
 
 		// finished flying
 		if ( projectile->step > projectile->steps)
-			projectile.reset();
+			it = projectiles.erase(it);
+		else
+			it++;
 	}
-
-	boost::range::remove( projectiles, std::shared_ptr<ProjectileBase>());
 }
 
 bool CBattleProjectileController::hasActiveProjectile(const CStack * stack)
 {
 	for(auto const & instance : projectiles)
 	{
-		if(instance->shooterID == stack->getCreature()->idNumber)
+		if(instance->shooterID == stack->ID)
 		{
 			return true;
 		}
@@ -285,16 +287,16 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const
 			auto & angles = shooterInfo->animation.missleFrameAngles;
 
 			missileProjectile->animation = getProjectileImage(shooter);
-			missileProjectile->reverse  = owner->stacksController->facingRight(shooter);
-
+			missileProjectile->reverse  = !owner->stacksController->facingRight(shooter);
 
 			// only frames below maxFrame are usable: anything  higher is either no present or we don't know when it should be used
 			size_t maxFrame = std::min<size_t>(angles.size(), missileProjectile->animation->size(0));
 
 			assert(maxFrame > 0);
-			double projectileAngle = atan2(dest.y - from.y, std::abs(dest.x - from.x));
+			double projectileAngle = -atan2(dest.y - from.y, std::abs(dest.x - from.x));
 
 			// values in angles array indicate position from which this frame was rendered, in degrees.
+			// possible range is 90 ... -90, where projectile for +90 will be used for shooting upwards, +0 for shots towards right and -90 for downwards shots
 			// find frame that has closest angle to one that we need for this shot
 			int bestID = 0;
 			double bestDiff = fabs( angles[0] / 180 * M_PI - projectileAngle );
@@ -317,12 +319,14 @@ void CBattleProjectileController::createProjectile(const CStack * shooter, const
 		projectile->steps = std::round(distance / animSpeed);
 		if(projectile->steps == 0)
 			projectile->steps = 1;
+
 	}
 
 	projectile->from     = from;
 	projectile->dest     = dest;
 	projectile->shooterID = shooter->ID;
 	projectile->step     = 0;
+	projectile->playing  = false;
 
 	projectiles.push_back(projectile);
 }

+ 2 - 1
client/battle/CBattleProjectileController.h

@@ -31,6 +31,7 @@ struct ProjectileBase
 	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
 };
 
 struct ProjectileMissile : ProjectileBase
@@ -82,8 +83,8 @@ public:
 	CBattleProjectileController(CBattleInterface * owner);
 
 	void showProjectiles(std::shared_ptr<CCanvas> canvas);
-	//void fireStackProjectile(const CStack * stack);
 
 	bool hasActiveProjectile(const CStack * stack);
+	void emitStackProjectile(const CStack * stack);
 	void createProjectile(const CStack * shooter, const CStack * target, Point from, Point dest);
 };

+ 2 - 2
client/battle/CCreatureAnimation.cpp

@@ -296,13 +296,13 @@ void CCreatureAnimation::genBorderPalette(IImage::BorderPallete & target)
 	target[2] = addColors(genShadow(64),  genBorderColor(getBorderStrength(elapsedTime), border));
 }
 
-void CCreatureAnimation::nextFrame(std::shared_ptr<CCanvas> canvas, bool attacker)
+void CCreatureAnimation::nextFrame(std::shared_ptr<CCanvas> canvas, bool facingRight)
 {
 	size_t frame = static_cast<size_t>(floor(currentFrame));
 
 	std::shared_ptr<IImage> image;
 
-	if(attacker)
+	if(facingRight)
 		image = forward->getImage(frame, type);
 	else
 		image = reverse->getImage(frame, type);

+ 1 - 1
client/battle/CCreatureAnimation.h

@@ -99,7 +99,7 @@ public:
 	void setType(CCreatureAnim::EAnimType type); //sets type of animation and cleares framecount
 	CCreatureAnim::EAnimType getType() const; //returns type of animation
 
-	void nextFrame(std::shared_ptr<CCanvas> canvas, bool attacker);
+	void nextFrame(std::shared_ptr<CCanvas> canvas, bool facingRight);
 
 	// should be called every frame, return true when animation was reset to beginning
 	bool incrementFrame(float timePassed);