Jump to content

Photo

Parabolic Motion Along Z Axis


  • Please log in to reply
8 replies to this topic

#1 Lejes

Lejes

    Seeker of Runes

  • Members
  • Location:Flying High Above Monsteropolis

Posted 15 May 2014 - 09:05 PM

So, I have a problem. I want a spawned LWeapon, with an initial Z axis velocity (Jump) to travel to an arbitrary, fixed point along a parabolic path. i.e. Z must be 0 when its X and Y reach the fixed point. The X and Y velocities (the LWeapon's Step) are constant. Normally the equation D(t) = at^2 + vt + d0 could solve this, but there's a big issue. I don't know how any of the units in ZC relate. I tried to estimate it, but it ended poorly. I might also be running into floating point numbers getting truncated somewhere. Here's the script:

ffc script ThrowBomb
{
	void run()
	{
		lweapon weapon;
		lweapon weapon_blast;
		int BCounter = 0;
		int target_counter = 0;
		npc target;
		
		float dist;
		float step;
		float v_adjust = 15972;
		
		while (true)
		{
			for (int i = 1; i <= Screen->NumNPCs(); i++)
			{
				target_counter++;
			}
				
			if (!Link->InputB && BCounter < 40)
			{
				weapon = NextToLink(LW_BOMB, 0, 0);
				weapon->Z = 1;
				weapon->Jump = 3;
				weapon->Dir = Link->Dir;
				weapon->Step = 200;
				break;
			}
			if (!Link->InputB && BCounter >= 40 && target_counter != 0)
			{
				target = Screen->LoadNPC(Rand(1, target_counter));
				weapon = NextToLink(LW_BOMB, 0, 0);
				weapon->Z = 1;
				
				// Calculating the Z axis velocity
				dist = Distance (Link->X, Link->Y, target->X, target->Y);
				step = 200;
				weapon->Jump = (-1 - GRAVITY_ACCEL * Pow((dist / (step / 100)), 2)) / ((v_adjust / 100000) * (dist / (step/100)));
				
				weapon->Angular = true;
				weapon->Angle = RadianAngle(Link->X, Link->Y, target->X, target->Y);
				weapon->Step = step;
				break;
			}
			
			if (Link->InputB)
			{
				BCounter++;
			}
			target_counter = 0;
			Waitframe();
		}
		
		while (weapon->isValid())
		{
			if (weapon->Z <= 0)
			{
				weapon_blast = Screen->CreateLWeapon(LW_BOMBBLAST);
				weapon_blast->X = weapon->X;
				weapon_blast->Y = weapon->Y;
				weapon_blast->Damage = 8;
				weapon->DeadState = WDS_DEAD;
			}
			
			Waitframe();
		}
	}
}

If anyone could help with unit conversions between Step, Jump, and Gravity, or how to get numbers to stop being truncated, I would be grateful.



#2 Moosh

Moosh

    The Mush

  • Moderators

Posted 15 May 2014 - 09:29 PM

I believe jump is decreased by gravity every frame but for any frame that it exceeds terminal velocity it uses that instead. Step is measured in 100ths of a pixel per frame so a step speed of 100 will travel one pixel in one frame.



#3 anikom15

anikom15

    Dictator

  • Banned
  • Real Name:Westley
  • Location:California, United States

Posted 15 May 2014 - 09:34 PM

Why don't you just use the direct formula for velocity under constant acceleration, a*t? Also, the function for distance is s0 + v0*t + (1/2)*a*t^2. You forgot the 1/2.

How is terminal velocity calculated? Isn't terminal velocity dependant on the cross-sectional surface area of an object (and therefore arbitrary)?

EDIT: actually, the easiest thing to do would be to use the gravity constant directly to get the change in velocity.

Edited by anikom15, 15 May 2014 - 09:57 PM.


#4 Lejes

Lejes

    Seeker of Runes

  • Members
  • Location:Flying High Above Monsteropolis

Posted 15 May 2014 - 10:50 PM

v(t) = at + v0 isn't much use to me. I don't know v0. You're right about me forgetting the 1/2, though. I'm not sure what you mean by using the gravity constant directly?



#5 anikom15

anikom15

    Dictator

  • Banned
  • Real Name:Westley
  • Location:California, United States

Posted 15 May 2014 - 11:02 PM

You store velocity in some variable and subtract g from it each frame (acceleration is the change of velocity). You'll need g to be in the appropriate units of course.

If you don't know v0, how can you use D(t)? If you really don't know v0, the only equation you can use is a(t) = g.

#6 Lejes

Lejes

    Seeker of Runes

  • Members
  • Location:Flying High Above Monsteropolis

Posted 15 May 2014 - 11:19 PM

I can use D(t) = (1/2)at^2 + v0t + d0 because I know every variable other than v0. a is 0.16 by default, t is (distance from enemy)/(step), multiplied by some conversion factor, d0 is whatever I set it to be, and D(t) will be 0 at the point of interest. If it wasn't clear from the original post, I want Link to toss a bomb into the air, and for that bomb to land on an enemy. Actually, I should just look through ghost.zh and see how it manages it. I'll do that tomorrow.



#7 anikom15

anikom15

    Dictator

  • Banned
  • Real Name:Westley
  • Location:California, United States

Posted 16 May 2014 - 12:27 AM

Oh, so you want the initial velocity to be that required to get the bomb to reach its target? Makes sense.

#8 Lejes

Lejes

    Seeker of Runes

  • Members
  • Location:Flying High Above Monsteropolis

Posted 16 May 2014 - 09:06 PM

So in case anyone was curious, here's how ghost.zh does the hurl-junk-at-Link trick.

float time=Distance(wpn->X, wpn->Y, Link->X, Link->Y)/(wpn->Step/100);
wpn->Misc[__EWI_MOVEMENT_ARG]=GH_GRAVITY*time/2;

wpn->Misc[__EWI_MOVEMENT_ARG] is just the value the header uses for initial upward velocity, and GH_GRAVITY is 0.16 by default. This is a lot simpler than whatever I was trying.



#9 Saffith

Saffith

    IPv7 user

  • Members

Posted 16 May 2014 - 09:39 PM

That's a very rough approximation, though. It works pretty well at short range, but the farther away Link is, the less accurate it gets.

In the Twin Amoeba script, I did this:
// Jump
do
{
	// Get the current positions of the two slimes
	startX=startSlime->X;
	startY=startSlime->Y;
	targetX=destSlime->X;
	targetY=destSlime->Y;
	
	// Move toward one
	angle=Angle(Ghost_X, Ghost_Y, targetX, targetY);
	Ghost_X+=VectorX(TWA_JUMP_SPEED, angle);
	Ghost_Y+=VectorY(TWA_JUMP_SPEED, angle);
	
	// Set height based on how much of the total distance has been covered
	totalDist=Distance(startX, startY, targetX, targetY);
	currentDist=Distance(Ghost_X, Ghost_Y, targetX, targetY);
	Ghost_Z=totalDist/2*Sin(currentDist/totalDist*180);
	
	TwAWaitframe(this, ghost, startSlime, destSlime);
} while(currentDist>1);
It totally disregards gravity and terminal velocity, and it can even change direction slightly in midair, but it works well enough.


1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users