Have an idea, need help implementing it.

Post » Thu Feb 28, 2013 2:43 pm

So, I had this idea for a useful script that would determine the location where an arrow has impacted an actor.

My idea is to utilize basic dymanics equations to create a formula which will utilize easily obtained information.

The equation of motion in one dimension with constant acceleration (note that if acceleration due to gravity in skyrim has a "cap" in that it drops to zero at some point, or varies at all, I am in deep trouble seeing as integrating is not the easiest thing to do in papyrus.) is defined as:

Rt = Ro + Vo * T + 0.5 * A * T^2


So I though, okay, well we can easily obtain the angles that the player is facing the moment the bow is fired, along with his position and thus roughly the point of origin on the projectile. We can find the velocity in the projectile forms for all arrows and they all appear to be at 3600 by default. Additionally, we can easily find the time the arrow is fired, and as long as it actually hits something that a magic effect can be applied to, we can register an onhit event and record the time the arrow landed. With this information, we should be able to locate an X Y and Z coordinates in space exactly where the arrow struck the enemy, and then use this information to do any number of things including some form of accurate locational damage that actually looks at where the target's body parts are in relation to the arrow sticking out of them rather than relying on where the shooter is looking the moment the arrow strikes.

Additionally, this could work without modifying any arrow or ammo forms and be compatible with all mods that introduce new arrows.

But, there were a few problems that I am stuggling with.



First off, I set up a quest. This quest throws the player into an alias so that I can give him an ability, upon which I attached a script with an OnPlayerBowShot event. Alternatively, you could probably register for an animation event OnInit() that corresponds with an arrow being fired if this event doesn't work with crossbows, but the nice thing about OnPlayerBowShot is that it returns the draw strength of the bow. This is important, because it effects the trajectory.


So now that we have that script, we can find the angles, position, and time the arrow was fired at. Then we can report them to a script on the quest I created to store them. Now that those are stored, we need to register the time that the arrow hits the actor to actually calculate the final positions of the arrow, and hopefully get it right.


Now looking at the equations, we can establish a motion equation for each direction, X, Y, and Z.
The Z direction, being up and down, is the only direction that experiences acceleration to my knowledge, unless there is wind resistance or some crap in Skyrim, which I doubt. So the X and Y equations of motion become:

Xpos = Xinit + Vxinit * Time
and
Ypos = Yinit + Vyinit * Time
, where Xpos and Ypos are the final positions we are looking for, Xinit and Yinit are the initial X and Y positions, the ones we got right when the player fired the bow, and Time is the time elapsed from the moment the arrow was fired and the moment it hit the target. Vxinit and Vyinit are a little more difficult. Those are the components of the initial velocity in the X and Y directions. We can calculate those once we have the Z component, which is easier to calculate.

The Z direction is the direction that gravity acts in. As such, the motion equation becomes
Zpos = Zinit + Vzinit * Time + 0.5 * Grav * Time^2

This is obviously a little more complex. The new variable here, Grav, is the acceleration due to gravity. This one is a bit of a mystery. In the projectile forms, it is listed as 0.35. No units are given. So I assume this is a percentage of the maximum gravity experienced by any object in the game. But what is that value, and what units does it have so I can use it in this equation?

So I set about creating an Accelerometer to determine this value. I made a spell which causes an arrow to drop in free fall, with zero initial velocity, and record the distance traveled and the start and end times when it hit the ground. The arrow had 0.35 gravity, whatever that means. I applied these distances and time elapsed along with the information that initial velocity was zero, to the equation:
Grav = (2* (Zpos - Zinit)) / (T^2)
which is just rearranged from the equation above.

Almost every time I ran the test, I got a value around 233. Sometimes I got anomalies. But it was fairly consistent The problem is, experimental error will lend to a number which is inexact, and as such, will effect the accuracy of our determination of the arrow's position in our ultimate goal. Remember, we are trying to figure out where in space we achieved a hit with our arrow without actually looking at the arrow itself, because doing so would make our mod extremely incompatible with other mods.



So, we have a rough estimate for the amount of gravity experienced by an arrow in flight. Now we need a little trig to get the velocity components and we should be good to go.

Lumping the X and Y directions into one dimension in the direction of the velocity vector component in those two directions yields a two dimensional vector. The XY, Z plane. We can use simple sin and cos to break our vector apart to get the magnitude of the velocity in the Z direction. But first, we must remember that in skyrim, arrows are not shot directly though the crosshairs, without editing the INI, they are given a slight upward angle, as if the crosshair is not zeroed at point blank but rather at 10 meters or so. This means we must first fetch this angle from the INI file using the utility.GetINIFloat() function. Then, we must add this to the player's angle around the X axis at the time of firing the bow. But again, we must remember that this angle is inverted when retrieved with the GetAngleX() function, when the player looks up, it goes negative, and goes positive when the player looks down, contrary to intuition. So we multiply GetAngleX() by negative one and add Utility.GetINIFloat() to retrieve the aditional firing angle. Now we take the Sin of this value, and multiply it by our arrow speed, which is 3600 according to the form (we just hope these units actually work out, which they dont).

Now, we have a value for Vzo. We need to find Vxo and Vyo. Since we broke our 3600 into a Z component, we are left with an XY component we can use and break it apart further. So we take Cos of the value above, retrieved from the GetAngleX() function and GetINIFloat() function. That yields the magnitude of our velocity in the XY plane, or horizontal plane. We need the direction too, to get the components. I could be wrong, but this is what I think we should do. Take the angle around the Z axis which is the angle that the player is turned, and multiply the magnitude we just got times the SIN of that angle around the Z axis to yield the Y compenent, and COS to yield the X component.

The end result looks like this.

Xpos = Xinit + Vxinit * Time
Ypos = Yinit + Vyinit * Time
Zpos = Zinit + Vzinit * Time + 0.5 * Grav * Time^2


Where:

Vxinit = ((ArrowVelocity * Cos(Utility.GetINIFloat("f1PArrowTiltUpAngle") + (-1 * Game.GetPlayer().GetAngleX())) * Cos(Game.GetPlayer().GetAngleZ())
Vyinit = (ArrowVelocity * Cos(Utility.GetINIFloat("f1PArrowTiltUpAngle") + (-1 * Game.GetPlayer().GetAngleX())) * Sin(Game.GetPlayer().GetAngleZ())
Vzinit = (ArrowVelocity * Sin(Utility.GetINIFloat("f1PArrowTiltUpAngle") + (-1 * Game.GetPlayer().GetAngleX()))


All taken at the time the arrow was fired with ArrowVelocity being the velocity of the arrow taken from the projectile form multiplied by afPower returned from the event OnPlayerBowShot(), additionally:

Time = TimeHit - TimeShot



Now onto the questions.

1) Is my math even remotely correct?

2) Is it possible to do this another way, using a script to fire a projectile right when an arrow is fired that mimicks the trajectory of the arrow? Possibly only with a full power bow draw to avoid that problem? I can't seem to get "Cast()" to work on the player to do this, and even then, we would encounter problems with the INI setting mentioned above which makes arrows, but not spells, fire at a slight upwards angle. Perhaps using an activator placed using trig to acquire this angle and firing the projectile from the player towards the activator would work, but would introduce timing problems.

3) Does anyone know the exact value in units/(s^2) of the acceleration due to gravity in this game?
User avatar
Ezekiel Macallister
 
Posts: 3493
Joined: Fri Jun 22, 2007 12:08 pm

Return to V - Skyrim