Faster Way to MoveTo

Post » Fri Nov 16, 2012 11:21 am

So I'm working on a spell that needs to PlaceAtMe between 9 and 13 identical objects and move them to a set of positions. Problem is, I've discovered that MoveTo and SetPosition are insanely slow. Calculating the positions takes almost no time at all. Positioning 9 objects during a loop, though, takes between 0.3 and 0.5 seconds. That's JUST the positioning using either MoveTo or SetPosition, not even the enabling of the objects (which is faster at 0.02 seconds for 9 objects). This is a spell, so timing is critical. 0.3 seconds is just acceptable, 0.5 completely throws things off.

Is there any faster way to position objects than SetPosition or MoveTo? Alternatively, is there a faster way to loop?

Here's a code snippet. rPosX and rPosY are Float arrays containing the pre-calculated positions. Assigning BorderPoints.Length to an int and looping on that actually cut loop time in half. The Bars are spawned with PlaceAtMe(abInitiallyDisabled = True) in an earlier loop (which is nearly instantaneous).

Float StartTime = GetCurrentRealTime()i = 0Int L = BorderPoints.LengthWhile (i < L) && !EffectOver  Bars[i].MoveTo(SpellCenter,rPosX[i] * Area,rPosY[i] * Area,-800);  Bars[i].SetScale(ScaleValue + RandomFloat(-0.1,0.1))  Bars[i].EnableNoWait(0)  i += 1EndWhileFloat EndTime = GetCurrentRealTime()Debug.Notification("Time: " + (EndTime - StartTime))

Enabling SetScale with the RandomFloat increases the loop time to nearly a full second, but I can work around that by having each Bar set its own Scale when it gets spawned.. I just need them to MoveTo faster!
User avatar
An Lor
 
Posts: 3439
Joined: Sun Feb 18, 2007 8:46 pm

Post » Fri Nov 16, 2012 8:23 pm

Do you have the placeAtMe in that same script or is it called from somewhere else? PlaceAtMe is relatively slow, while I've found moveTo to be pretty quick. (setPos too, but you have to set the angle too). Whether it's in the same script and you have a forced loop to wait for it to materialize (a while loop testing for is3DLoaded), or if your code is in an onInit or some other thing triggered by the object itself after being created.. the holdup may be coming from the placeAtMe itself.

If not, I might suggest creating the object preemptively, though disabled. Then on-demand have it materialize. This would be a last-resort workaround though.. lots more code and potential drama. AND you'd probably have to have a special type of object, since certain things cannot be moved while disabled.
User avatar
Kelvin
 
Posts: 3405
Joined: Sat Nov 17, 2007 10:22 am

Post » Fri Nov 16, 2012 7:29 am

Do you have the placeAtMe in that same script or is it called from somewhere else? PlaceAtMe is relatively slow, while I've found moveTo to be pretty quick. (setPos too, but you have to set the angle too). Whether it's in the same script and you have a forced loop to wait for it to materialize (a while loop testing for is3DLoaded), or if your code is in an onInit or some other thing triggered by the object itself after being created.. the holdup may be coming from the placeAtMe itself.

Using PlaceAtMe(abIntiallyDisabled = true) in combination with EnableNoWait(0) largely eliminates the delay associated with PlaceAtMe. If I run the loop in the code I listed after commenting out the MoveTo, the loop runs in 0.02 seconds. The delay is definitely coming from MoveTo.

If not, I might suggest creating the object preemptively, though disabled. Then on-demand have it materialize. This would be a last-resort workaround though.. lots more code and potential drama. AND you'd probably have to have a special type of object, since certain things cannot be moved while disabled.

Preloading the forms saves about 0.05 seconds in the loop, but I can't place them until the OnEffectStart event because I need the target. I haven't encountered an object that can't be moved while disabled, though translation doesn't work without the 3D loaded.

It's so aggravating. In less than 0.08 seconds I can load (disabled) all of the 9 to 13 Activators and calculate their circular placement around the target with trig functions. I can even Enable them without MoveTo and the whole thing runs in about 0.1 seconds. But the simple act of using MoveTo on even a single form takes longer than all of those operations combined.

I even tried goofy stuff like placing a temporary empty object, moving it to each (precalculated!) location and spawning the Activator there, but it's just as many MoveTo ops as before and therefore it's just as slow.

I need some way to load an object to a target location without using MoveTo.

WTB PlaceAtLocation(Float X, Float Y, Float Z) plz!
User avatar
Mr.Broom30
 
Posts: 3433
Joined: Thu Nov 08, 2007 2:05 pm

Post » Fri Nov 16, 2012 7:31 am

What if you have a permanent xMarker already created/placed somewhere in the world.. then have it setPos to your target spot on demand; THEN do your placeAtMe to that xMarker ref? I don't think we'll find a way to do what you want otherwise, but people have come up with stranger stuff I didn't think possible! It'd be nice to have that placeAtLoc/Pos though.

As far as moving objects while disabled.. you're correct, Activators can be movedTo AND transedTo while disabled. Once I found this out, I converted my ship's statics to Activators because otherwise it was very dramatic to get the pieces to do what I wanted otherwise.
User avatar
Roberta Obrien
 
Posts: 3499
Joined: Tue Oct 23, 2007 1:43 pm

Post » Fri Nov 16, 2012 9:30 am

It'll probably be the weekend before I can mess with this again, but I'll try some more weird tricks and see if I can get this sped up. My one hope is that it may be the OnLoad code of the Activators firing multiple times when they're moved (onLoad often fires when an object is moved, has its scale set, etc). It shouldn't be, because the activators are disabled, but that doesn't mean it isn't...

Whatever I figure out, I'll post back. I might just have to live with a spell that's only slightly less laggy than the current published version: https://www.youtube.com/watch?v=DFp8KTY4bd0
User avatar
Silencio
 
Posts: 3442
Joined: Sun Mar 18, 2007 11:30 pm

Post » Fri Nov 16, 2012 10:34 pm

It seems like your problem isn't so much the speed of the things generating but rising. Are you using SplineTranslateToRef? If not, you can pretty easily make xmarker headings above where the pillars spawn and then use that to move them up quickly. It should load much faster than what you are doing.
User avatar
Add Me
 
Posts: 3486
Joined: Thu Jul 05, 2007 8:21 am

Post » Fri Nov 16, 2012 5:29 pm

why is it necessary to placeatme on a specific location and not at their destination to begin with? cut out the middle man
User avatar
Chelsea Head
 
Posts: 3433
Joined: Thu Mar 08, 2007 6:38 am

Post » Fri Nov 16, 2012 4:01 pm

PlaceAtMe has to place it on a ref, does it not? If it's a magicEffect that basically has no target ref, then one would have to be used as a proxy (a pre-made xMarker for instance). For instance, if you wanted to spawn a new NPC when a certain NPC is hit; you COULD placeAtMe to the hit NPC, but it would spawn above it or be erratically placed. Using an xMark would give more accurate control over the spawn-site; while not using too much resources as a persistent ref (being invisible and minimal).

OnLoad events fire whenever the ref is loaded. I don't know if that is when the 3D is loaded, or the ref itself... interesting.. If it's the 3D loading that triggers the event, then anything that makes the ref 'blink' in and out would cause that (scaling, moveTo, etc). I never use onLoads because of the spurious nature - many people adjust their gridsToLoad and/or go in and out of an area rapidly... that's what causes the Wandering Bug (eg: mannequins); the fix being to make it an onCellAttach.
User avatar
Lisa
 
Posts: 3473
Joined: Thu Jul 13, 2006 3:57 am

Post » Fri Nov 16, 2012 4:26 pm

Well that's an old version in the video. In the current one, they all rise almost simultaneously and a bit faster, but there's still a 0.3 to 0.5 second delay while moving the objects.to their target locations. Since they have to be placed in a circle around the target, I have to generate the locations specific to that target, then place a pillar activator at each point in the circle. The activators are scripted to rise after being Activated by my script, which happens in a tight loop.

Everything is very fast except for the loop that does the MoveTo for each pillar; for some reason even a single MoveTo function is slower than all of the other steps I just detailed put together.

Amethyst Deceiver: I can place empty objects at the target locations and then place the activators at each point, and in fact that's what I was doing originally. That pushes the delay to the MoveTo of the borderpoints, which doesn't solve the basic problem. If you know a way to load an object at a specific location without using PlaceAtMe, please tell me!
User avatar
CArlos BArrera
 
Posts: 3470
Joined: Wed Nov 21, 2007 3:26 am

Post » Fri Nov 16, 2012 8:00 pm

ah, i see what you're saying now. you need a very specific target location in x/y/z value.

as far as i know, no matter what method of translating, there will be a slight delay when using moveto or translateto. and you said setpos also makes no difference?


how important is it to have the bars as separate objects? could it be a pre-fabricated set of bars in a single nif? that would eliminate all of your math in your script and all moveto's
User avatar
Kelsey Hall
 
Posts: 3355
Joined: Sat Dec 16, 2006 8:10 pm

Post » Fri Nov 16, 2012 10:41 am

That is a solution I'm considering, but that makes scaling the cage properly to encase various creatures pretty difficult. And the breakdown animation kind of relies on having the pillars be separate.

We'll see. I'll mess with it some more and post back regardless of what I work out. Mostly I wanted to make sure there wasn't some obvious method for doing this that I was just missing.

Thanks everyone for your advice!
User avatar
Gemma Woods Illustration
 
Posts: 3356
Joined: Sun Jun 18, 2006 8:48 pm

Post » Fri Nov 16, 2012 9:14 am

and you already tried testing to see if the math calculations had noticeable impact on the total while loop execution time?

because you might get away with creating a prefab nif with set nodes where the bars should be. that way you can still call setscale on them individually and instead of using math in your moveto you can use movetonode on the custom nif

but if its the function call of moveto thats causing the delay (which i suspect may be the case), then its not going to help that much
User avatar
Dan Stevens
 
Posts: 3429
Joined: Thu Jun 14, 2007 5:00 pm

Post » Fri Nov 16, 2012 7:36 am

Okay, I think I've sped it up as much as it can be sped up. The problem seems to be two-fold:
  • MoveTo is just slow. It didn't matter WHAT object I'm using MoveTo on, it's just a slow operation, period.
  • Using MoveTo on several object in a tight loop makes it even slower for every object in the loop.
The second one is weird. If using MoveTo on N objects in a tight loop (where N is some arbitrary number) takes T seconds, you would expect that using MoveTo on N*2 objects would take T*2 seconds, right?

WRONG

It takes MUCH longer than T*2. It's more like T^2. I have no idea why this is true, but it's true.

I got the spell sped up by scattering the placement of the columns around between parts of the spell that are providing, say, dust effects or placing the stone floor. The difference is slight but noticeable and makes the spell feel much more responsive.
User avatar
Lily Evans
 
Posts: 3401
Joined: Thu Aug 31, 2006 11:10 am

Post » Fri Nov 16, 2012 6:51 am

About using a single NIF and scaling to order thing: Scaling doesn't work for collision - it's a bug in the engine I think (console scaling doesn't work either). An alternative could be to have a couple different PRE-SCALED versions (separate NIFs)... then in the script do a check for getWidth/Length on the target. I've heard they aren't the best and may have issues of their own, but at least it'd be a single mesh to transTo.

I'm surprised you got a moveTo setup to work that smoothly. Usually the problem is the fading in and out. That vid (I know you said it was an old version, and I know first-hand that Fraps vidcap slows the game WAY down), it's the hesistation before they actually start rising that you want to minimize right? Perhaps having a separate script attached to each pillar object; then when placed on their spots, each object's script would fire - moving each one up independently from the master magicEffect script.

If you DO try to use transTo instead of moveTo though, the pillars have to be Activator objects for the collision to properly move.

[EDIT: the getWidth thing was a little vague]
User avatar
Rachell Katherine
 
Posts: 3380
Joined: Wed Oct 11, 2006 5:21 pm

Post » Fri Nov 16, 2012 3:58 pm

SluckyD, that's exactly how it works :smile: Each pillar has its own script that moves it around. Take a look at the updated version:

Before breaking up the loop:
http://www.youtube.com/watch?v=0v--M2-34sM
And after (difference doesn't really show because of Fraps, but it's faster):
http://www.youtube.com/watch?v=UyAldilI8pY

As for the fading in and out, that's easy to avoid. Use PlaceAtMe with the abInitiallyDisabled = True option. Move your object, then do EnableNoWait(0). BAM! Fast placement, no fadein. Just doesn't work well in loops.
User avatar
Stephy Beck
 
Posts: 3492
Joined: Mon Apr 16, 2007 12:33 pm

Post » Fri Nov 16, 2012 11:23 am

Could you place one object with several animated parts?
User avatar
Austin England
 
Posts: 3528
Joined: Thu Oct 11, 2007 7:16 pm

Post » Fri Nov 16, 2012 8:10 pm

That would be ideal, but that would require me knowing how to create animated NIFs. Unfortunately, I have very little time for modding as it is, and definitely don't have time to go through the tortuous setup that model creation seems to require, much less learn 3DS Max or Blender. Last 3d modelling I did was in Truespace like 12 years ago :(
User avatar
Ally Chimienti
 
Posts: 3409
Joined: Fri Jan 19, 2007 6:53 am


Return to V - Skyrim