Jump to content

Would Appreciate Some Scripting Help; setPosition does not work after TranslateTo


ZeroCore

Recommended Posts

First, you're mixing some things in. With my code you do not need to register for updates or have anything to do with OnUpdate event at all. When you do a translation it WILL trigger either OnTranslationComplete or OnTranslationFailed once after every translation thus restarting the cycle, which is much better than trying to time an update event to move it at the right time. Your code is asking for movement from an update and then asking for it again afterwards, creating conflicting movement commands.

Second, you cannot use my recursive code when your move to start position uses a translation. When you call TranslateTo or TranslateToRef while it's already translating it will trigger OnTranslationFailed, which causes it to translate again which causes it to trigger OnTranslationFailed again and so on in a loop. That being said, I do not know if StopTranslation also causes OnTranslationFailed or OnTranslationComplete to activate (which would also cause a loop) and since it is unnecessary (I only had it in there just in case) I suggest you also remove that.

If you want to use ObjectReferences as markers with my code, then you will need to use MoveTo rather than SetPosition. MoveTo is to SetPosition, what TranslateToRef is to TranslateTo.

Try this code below and this time DO NOT use OnUpdate or RegisterForSingleUpdate at all. Note that I have also added a loop to cause the Move function to wait for the object's 3D to be loaded before doing anything, checking every 0.2 seconds so that if the Move function is called while the 3D is unloaded, it won't end the recursion that relies on translations.

Scriptname ____________ZIU3 extends ObjectReference  


ObjectReference Property XSTART  Auto  ;This is an X marker that marks where the object is supposed to start
ObjectReference Property XEND  Auto  ;Another X marker where it winds up


function Move()       ;resets the position of the object and then translates it to its destination
    While !Is3DLoaded()    ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds
        Utility.wait(0.2)
    EndWhile
    MoveTo(XSTART,0,0,0,false)
    TranslateToRef(XEND,1000.0)
EndFunction

Event OnCellLoad()      ;Starts the loop
    MoveToMyEditorLocation()   ;This is just a reset to keep tunnel pieces from going nuts and gaps from forming in the tunnel wall
    Move()
EndEvent

Event OnTranslationComplete() ;Triggers if the translation was uninterrupted
    Move()
EndEvent

Event OnTranslationFailed() ;Guaranteed to trigger if OnTranslationComplete does not
    Move()
EndEvent

EDIT: just a few changes for visibility

Edited by dalsio
Link to comment
Share on other sites

  On 9/6/2016 at 6:37 PM, dalsio said:

First, you're mixing some things in. With my code you do not need to register for updates or have anything to do with OnUpdate event at all. When you do a translation it WILL trigger either OnTranslationComplete or OnTranslationFailed once after every translation thus restarting the cycle, which is much better than trying to time an update event to move it at the right time. Your code is asking for movement from an update and then asking for it again afterwards, creating conflicting movement commands.

 

Second, you cannot use my recursive code when your move to start position uses a translation. When you call TranslateTo or TranslateToRef while it's already translating it will trigger OnTranslationFailed, which causes it to translate again which causes it to trigger OnTranslationFailed again and so on in a loop. That being said, I do not know if StopTranslation also causes OnTranslationFailed or OnTranslationComplete to activate (which would also cause a loop) and since it is unnecessary (I only had it in there just in case) I suggest you also remove that.

 

If you want to use ObjectReferences as markers with my code, then you will need to use MoveTo rather than SetPosition. MoveTo is to SetPosition, what TranslateToRef is to TranslateTo.

 

Try this code below and this time DO NOT use OnUpdate or RegisterForSingleUpdate at all. Note that I have also added a loop to cause the Move function to wait for the object's 3D to be loaded before doing anything, checking every 0.2 seconds so that if the Move function is called while the 3D is unloaded, it won't end the recursion that relies on translations.

Scriptname ____________ZIU3 extends ObjectReference  


ObjectReference Property XSTART  Auto  ;This is an X marker that marks where the object is supposed to start
ObjectReference Property XEND  Auto  ;Another X marker where it winds up


function Move()       ;resets the position of the object and then translates it to its destination
    While !Is3DLoaded()    ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds
        Utility.wait(0.2)
    EndWhile
    MoveTo(XSTART,0,0,0,false)
    TranslateToRef(XEND,1000.0)
EndFunction

Event OnCellLoad()      ;Starts the loop
    MoveToMyEditorLocation()   ;This is just a reset to keep tunnel pieces from going nuts and gaps from forming in the tunnel wall
    Move()
EndEvent

Event OnTranslationComplete() ;Triggers if the translation was uninterrupted
    Move()
EndEvent

Event OnTranslationFailed() ;Guaranteed to trigger if OnTranslationComplete does not
    Move()
EndEvent

EDIT: just a few changes for visibility

I used your script, exactly as you have it here, but the problem still persists; the objects that this script is attached to go backwards to the XMarker that fills the "XEND" property, but they will not return to the start position. MoveTo still fails to trigger.

Link to comment
Share on other sites

Hmm, do two things:

 

1. in my code, add Utility.wait(0.1) before and after MoveTo() like this:

Utility.wait(0.1)
MoveTo(XSTART, 0, 0, 0, false)
Utility.wait(0.1)
TranslateToRef(XEND, 1000.0)

and see if that works. I doubt it will but what the hey.

 

If that fails, do me a favor and add at the end of your Move() function a debug.notification() containing the position of XSTART and XEND like this:

MoveTo(XSTART,0,0,0,false)
TranslateToRef(XEND,1000.0)
Debug.notification("Start position: "+XSTART.x+","+XSTART.y+","+XSTART.z+"  End position: "+XEND.x+","+XEND.y+","+XEND.z)

and tell me what pops up in the upper-left corner (or wherever game notifications appear on your screen).

 

If it only displays one notification and stops, then it isn't looping properly for some reason. If it doesn't display the notification at all, then it isn't getting past the TranslateToRef line in the code. If it keeps repeating the positions in the notification every so often (the time it would take for the wall to translate normally) then the code is looping, but not moving right. If the code is looping and the notification says that the position of XSTART is the same as the position of XEND then something is moving XSTART to the same location as XEND. If, however, XSTART and XEND are in fact different locations, then MoveTo() is in fact being called on a location that is not the same as the end location but for some reason is failing.

Edited by dalsio
Link to comment
Share on other sites

  On 9/6/2016 at 11:08 PM, dalsio said:

Hmm, do two things:

 

1. in my code, add Utility.wait(0.1) before and after MoveTo() like this:

Utility.wait(0.1)
MoveTo(XSTART, 0, 0, 0, false)
Utility.wait(0.1)
TranslateToRef(XEND, 1000.0)

and see if that works. I doubt it will but what the hey.

 

If that fails, do me a favor and add at the end of your Move() function a debug.notification() containing the position of XSTART and XEND like this:

MoveTo(XSTART,0,0,0,false)
TranslateToRef(XEND,1000.0)
Debug.notification("Start position: "+XSTART.x+","+XSTART.y+","+XSTART.z+"  End position: "+XEND.x+","+XEND.y+","+XEND.z)

and tell me what pops up in the upper-left corner (or wherever game notifications appear on your screen).

 

If it only displays one notification and stops, then it isn't looping properly for some reason. If it doesn't display the notification at all, then it isn't getting past the TranslateToRef line in the code. If it keeps repeating the positions in the notification every so often (the time it would take for the wall to translate normally) then the code is looping, but not moving right. If the code is looping and the notification says that the position of XSTART is the same as the position of XEND then something is moving XSTART to the same location as XEND. If, however, XSTART and XEND are in fact different locations, then MoveTo() is in fact being called on a location that is not the same as the end location but for some reason is failing.

The debug message kept popping up again and again, and the numbers were consistent each time. The X markers stayed in place, did not move, and were exactly where I placed them (I wrote the coordinates down).

 

This only means one thing; SetPosition and MoveTo aren't working.

Link to comment
Share on other sites

  On 9/7/2016 at 2:42 AM, ZeroCore said:

 

This only means one thing; SetPosition and MoveTo aren't working.

 

 

Indeed. If Start and end objects are at different positions and it wasn't working as intended, then MoveTo is failing.

 

I looked up the reference of MoveTo and I have some ideas. Without that, I'd have to rewrite my previous code quite a bit to accommodate using TranslateToRef() at high speed in place of MoveTo. But first, try this:

 

First, double check that your wall isn't a type of flora object. For some reason MoveTo() fails specifically when called on Flora (probably not relevant, but I figured I would ask). Otherwise:

 

Place DisableNoWait() before the MoveTo function and EnableNoWait() after it like this:

DisableNoWait()
MoveTo(XSTART,0,0,0,false)
EnableNoWait()

It seems MoveTo() has problems functioning on actors at certain times and this is supposed to fix it. Maybe it's failing for non-actors as well.

 

I'll start rewriting the code to use TranslateToRef instead of MoveTo in a minute and post it down below in case the above fails.

Edited by dalsio
Link to comment
Share on other sites

If my above method fails, try this:

Scriptname ____________ZIU3 extends ObjectReference 

ObjectReference Property XSTART  Auto  ;This is an X marker that marks where the object is supposed to start
ObjectReference Property XEND  Auto  ;Another X marker where it winds up

bool ResetNextTranslation = false

Function Move()       ;Translates the object to the destination
    While !Is3DLoaded()    ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds
        Utility.wait(0.2)
    EndWhile
    ResetNextTranslation = true
    TranslateToRef(XEND, 1000)
EndFunction

Function ResetPosition()    ;Resets the position of the object
    While !Is3DLoaded()    ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds, then resets
        Utility.wait(0.2)
    EndWhile
    ResetNextTranslation = false
    TranslateToRef(XSTART, 1000000)
Endfunction

Event OnCellLoad()      ;Starts the loop
    MoveToMyEditorLocation()   ;This is just a reset to keep tunnel pieces from going nuts and gaps from forming in the tunnel wall
    Move()
EndEvent

Event OnTranslationComplete() ;Triggers if the translation was uninterrupted
    if ResetNextTranslation
        ResetPosition()
    else
        Move()
    endif
EndEvent

Event OnTranslationFailed() ;triggers if OnTranslationComplete doesnt
    if ResetNextTranslation
        ResetPosition()
    else
        Move()
    endif
EndEvent
Edited by dalsio
Link to comment
Share on other sites

  On 9/7/2016 at 5:35 AM, dalsio said:

 

If my above method fails, try this:

Scriptname ____________ZIU3 extends ObjectReference 

ObjectReference Property XSTART  Auto  ;This is an X marker that marks where the object is supposed to start
ObjectReference Property XEND  Auto  ;Another X marker where it winds up

bool ResetNextTranslation = false

Function Move()       ;Translates the object to the destination
    While !Is3DLoaded()    ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds
        Utility.wait(0.2)
    EndWhile
    ResetNextTranslation = true
    TranslateToRef(XEND, 1000)
EndFunction

Function ResetPosition()    ;Resets the position of the object
    While !Is3DLoaded()    ;causes the script to wait for Is3DLoaded() to be true, checking every .2 seconds, then resets
        Utility.wait(0.2)
    EndWhile
    ResetNextTranslation = false
    TranslateToRef(XSTART, 1000000)
Endfunction

Event OnCellLoad()      ;Starts the loop
    MoveToMyEditorLocation()   ;This is just a reset to keep tunnel pieces from going nuts and gaps from forming in the tunnel wall
    Move()
EndEvent

Event OnTranslationComplete() ;Triggers if the translation was uninterrupted
    if ResetNextTranslation
        ResetPosition()
    else
        Move()
    endif
EndEvent

Event OnTranslationFailed() ;triggers if OnTranslationComplete doesnt
    if ResetNextTranslation
        ResetPosition()
    else
        Move()
    endif
EndEvent

 

 

This last part works, and I see how it does too. It has a bool that functions as a switch, or a check rather, to keep the one function from triggering when the other one plays.

 

This is working great, and thanks for all the help.

 

Unfortunately this has spawned yet another problem; the sections of the tunnels and rails are moving out of sync with one another, creating gaps in the tunnel that are quite noticeable when the player is riding the train.

 

I'm thinking that I should put the movement script on only a few sections of tunnel and rail, and then write another script to have the other sections of rail and tunnel use "SetPosition" or some variant of it, to constantly update their position to one of the actual "mover" tunnel bits or rails that have your script attached to them.

 

The issue is that I'm not sure if their 3D data will stay loaded when using SetPosition. For some reason, I doubt it.

 

Getting the bits moving was the first part, which is now done thanks to you, but now the second part comes up; keeping each and every section of tunnel and rail where it's supposed to be.

Link to comment
Share on other sites

Imo for it to be synced a single script should do all the moving and do it in a multithreaded way so all pieces move simultaneously. Different scripts syncing would be a matter of luck, if for any reason one of them takes longer to run, starts little later or gets into the Is3DLoaded loop you get a gap.

http://www.creationkit.com/index.php?title=Creating_Multithreaded_Skyrim_Mods.

 

Other than that you may be able to hide the gaps by making the pieces overlap a bit so there is some "gap-tolerance" you'll see a seam but it's probably less visible than a gap.

 

As a side note, there are other ways to achieve the whole effect, i think animated textures is a very clean alternative: http://www.nexusmods.com/skyrim/mods/47104/?. Or animated meshes.

Link to comment
Share on other sites

  On 9/7/2016 at 10:25 AM, FrankFamily said:

Imo for it to be synced a single script should do all the moving and do it in a multithreaded way so all pieces move simultaneously. Different scripts syncing would be a matter of luck, if for any reason one of them takes longer to run, starts little later or gets into the Is3DLoaded loop you get a gap.

http://www.creationkit.com/index.php?title=Creating_Multithreaded_Skyrim_Mods.

 

Other than that you may be able to hide the gaps by making the pieces overlap a bit so there is some "gap-tolerance" you'll see a seam but it's probably less visible than a gap.

 

As a side note, there are other ways to achieve the whole effect, i think animated textures is a very clean alternative: http://www.nexusmods.com/skyrim/mods/47104/?. Or animated meshes.

Could I perhaps have an activator or other object holding the script, and then add object reference properties to the script?

 

Each object I want to move would be linked to an object reference, and then I could just call the function on all of them, all the while though each and every object would be operating under the same instance of the same script.

 

Would that work?

 

I've tried learning how to do animated textures, as well as meshes and textures in general but I was never able to learn it since no one ever wanted to really teach me, and I had a hard time trying to learn the tutorials on my own since they all assumed that you had a comprehensive understanding of both Blender 2.49b and NifSkope, which I didn't have.

 

And even trying to first learn Blender and NifSkope was something I couldn't get down on my own because the tutorials on Youtube aren't comprehensive enough, and they don't link to the tutorials that well (IE, they show you something really basic about the program, but not the specific ins and outs of how you can relate that knowledge to meshes and textures you're trying to make for Skyrim).

 

And no actual member of any forum is willing to teach me how to do this, or even give a basic run-down of it to me (they just don't want to).

 

Personally if someone would teach me how to do this, I'd be very grateful to them, would give them top-billing (mention their name first in the credits of) the first mod I made with custom textures and meshes, and would also then make a full, comprehensive tutorial of my own showing you how to do all of that all in one go (giving them credit for that too).

 

But again, so far no one wants to help on that front.

 

I'm better at learning code on my own than the ins and outs of 3D modelling (and I still sometimes need help learning code, like right now).

Edited by ZeroCore
Link to comment
Share on other sites

Multi-threading inherently introduces de-synchronization, not fixes it. To synchronize different objects would necessitate staying on one thread.

In regards to animations and such, I would say that it would be more elegant, less cpu intensive, and more seamless. However, that would in fact require a lot of knowledge about animations/models and it's not as controllable through scripts (obviously scripts are easier to control with scripts :tongue:).

I would teach you how to do that, if I knew how. While I have a fairly firm grasp of Nifskope and textures, and I know how to make models in blender and the basics of exporting them to skyrim, I don't really know much more than that.

 

What I do know is programming, so I'll do my best to help you with what I'm most familiar with:

If the walls are all premade (none being spawned in that need to be moved, which is fine but requires a bit more code) the easiest method of handling this is to have a script tied to a marker or off-screen object to act as a sort of "main control". Then, pass into it's script all the other wall objects (or an array depending on how many there are) as a property and move the marker with the walls as if it were one of them. Then, using it's translation events as the trigger for all of them, create a loop to tell each wall in rapid succession to move or reset.

I'm making the assumption that when the marker or hidden object has it's 3D loaded, all of the walls will (which they should, if they're in the same cell). If not, that would require some workarounds because if one wall is loaded while another is not, that would cause a desync. Thus with the code below, if the control object does not have it's 3D loaded then the walls will not move.

You can of course use one array, but I recommend two in order to keep them from getting mixed up. You'll also need an array of markers each acting as a start and end point to their respective walls; that is, if you continue to control them through placed markers and TranslateToRef. I highly recommend either placing the markers in very specific coordinates (setting their position manually in the editor so that they line up exactly with each other) or use a coordinate-based system and TranslateTo instead. This will help with the look and synchronization since while the code will still work, if the distances each wall moves are not identical or they and their markers aren't perfectly lined up on two axes, it might make them look strange. Further, using a coordinate system where the travel distances are identical can eliminate the need for using the many arrays that you see here, and instead replace them with one variable and a bit of math.

I'll give you this code using markers, but let me know if you want help shifting to using coordinates instead. Attach this to your "control" object:

  Reveal hidden contents

 

Edited by dalsio
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...