Search Unity

Aligning moving objects

Discussion in 'Editor & General Support' started by MattBradley, Nov 8, 2013.

  1. MattBradley

    MattBradley

    Joined:
    Nov 8, 2013
    Posts:
    11
    Hello there,

    I've just started my first proper project in Unity using playMaker and I have to say it's pretty great so far! :)

    I'm having a little bit of trouble aligning moving objects, however. I'm making a kind of endless runner/rhythm action game where prefab sections of the game environment are being spawned (or moved, I've tried both) in front of the player. The player stays still while the prefab sections move, kind of like a conveyer belt.

    The problem is when I spawn or move the prefab sections they have a tendency to be just slightly behind the desired location, maybe 1 to 2 units out. I wouldn't normally consider this an issue, I'd just bump the spawn point forwards a few units to compensate. However because this is a rhythm action game the prefabs need to come in at exactly the right place or the audio will be off.

    I've investigated a number of different approaches with no luck.

    The issue lies in the prefab section moving as the next one is spawned. In the moment it takes for the CPU to figure out the place it should spawn and it actually spawning a slight misalignment is created. It's compounded by framerate and the speed at which the prefabs move (less frames, or quicker movement = bigger gaps).

    Does anyone have a technique for solving a problem like this in playMaker/unity?
     
  2. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    I've been doing something similar myself, but without having to synchronize the prefab sections with actual audio. I'm using my own scripts to handle the placement/spawning instead of PM - I'd be willing to bet that's where you're losing sync since, if I remember, PM needs a new frame update in order for it to tick the state machine.

    How are you determining where the section needs to spawn and how are you actually spawning the section in? You'll probably need to write a custom PM action that'll do both at once and be completely in sync.
     
  3. MattBradley

    MattBradley

    Joined:
    Nov 8, 2013
    Posts:
    11
    Hey Thanks for replying. It makes sense then if PM does require a new frame.

    I have tried a few methods of spawning. What I'd like to do is spawn the next prefab in at a helper that's a child of the previously spawned prefab. I have tried creating the object and destroying it (which I understand can be expensive), and also just having the prefab loaded in and moving it when required.

    I was thinking maybe I could make the newly spawned prefab a child of the one that goes before it? The problem then I guess would be making sure it maintains it's movement once I detach it.

    How would you suggest I go about writing a custom PM action that syncs things up?
     
  4. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Its difficult determining what the issue and best solution might be while hovering about the conceptual, I'm pretty sure the problem isn't so much in any of your concepts, but rather hidden in the details of the implementation of that concept.

    What I mean is: Yeah you could have a helper child determine what position the next prefab should spawn in, and you could parent that prefab to the previously spawned section. Or you could come up with other approaches that would be perfectly valid - but still end up not addressing the issue.

    Just a stab in the dark on my part but I want to say that the problem is that you're determining the position you need to spawn the next section in on one state, but then instantiating the section using that position in another state that you trigger maybe on the next frame (when that position is no longer valid)? Can you post a pic of the state machine with the relevant state(s) actions?

    Once we determine the issue we can go about implementing a solution. A custom action may or may not be necessary - they aren't too difficult to implement (unless you have no experience programming at all, but I can help if that's the case). You can look at existing actions as a template and do a little research online to get there.

    I'm interested in this - keep us posted, aye?
     
  5. MattBradley

    MattBradley

    Joined:
    Nov 8, 2013
    Posts:
    11
    Yea I think you're right. I don't fully understand Unity and playMaker just yet so I have been trying various different ideas to learn about what does and doesn't work. I used to work a lot with CryEngine which had a lot of quirks, my experience with that when trying to fix something particularly tricky was to try as many approaches as possible until I found one that worked, you'd be surprised how often a new concept can solve things with it! Obviously that's not ideal though.

    I've just set up a quick example of the setup where I know it's not working correctly...

    - Setup FSM spawns in 3 prefabs at 0,0,0/0,0,240/0,0,480 (prefabs are 240 units long)
    $FSMSetup01.jpg

    - On spawning each prefab has an FSM action that moves it to 0,0,-240
    $FSMSetup02.jpg

    - When 0,0,-240 is reached an event is fired to the spawn manager FSM and the prefab destroys itself
    $FSMSetup03.jpg

    - Once despawned another prefab is spawned is the spawn manager FSM at the child of the prefab that went before
    $FSMSetup04.jpg

    Right now I'm using 'Create Object' and 'Destroy' but I'll be replacing that with a pool manager once I figure out how to squash this bug.

    I'm interested in this too! Thanks for offering your support :D
     
  6. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Thanks for the info!
    Well, the good news is that there's no delay between the event sent when a section is destroyed and the event received where the new section is instantiated. It looks to me that it is in fact being created in the correct position.

    The bad news is that a newly created section's ITween component doesn't actually get its Update method called until the next frame, after which existing sections would've already moved away a bit from the location that the new section was spawned in. I don't know if ITween tries to compensate for this somehow, I kinda doubt it, but I believe this is where your levels are getting out of sync. The faster sections are moving, or the longer a hiccup that happens between the frame that a section gets created and the next frame, the greater distance existing sections will gain on the newly created section in that gap.

    In retrospect I think a better design would be to have 1 component moving the whole chain once every frame (which I think was what you were starting to consider) instead of multiple components that each move their respective sections independently. I could think of a couple of ways of doing this directly in a script, but I'm guessing you'd be wanting to implement it in PM?

    [EDIT]
    Best I can come up with is having each instance of a section's FSM maintain a reference to the section in front of and behind it. Every frame it would check if there's one in front (as in "approaching the player first") and if there is: do nothing. If there isn't then it's at the "head of the pack" and should move according to whatever velocity you have set, then send an event to the section behind it which, when received, will simply set it's position to have it match whatever position relative to the section in front of it would be correct (like an anchor child object on the section). It then sends that same event down the line to the next section until you reach the end and there is no other section behind it being referenced.

    You'll probably have to use a simple Translate action instead of ITween for the movement and will have to manually check a section's position using GetVector3XYZ to get, say, the x component if that's the axis your sections are moving in, along with FloatCompare to trigger its demise. When a section gets destroyed you need to ensure that the section behind it has first moved for that frame and has started the chained event to update the other sections. Thereafter it'll be referencing null in front and be considered at the head of the chain - it'll fall to the previous logic to have it move until it dies.

    Heh - Now I really wanna see that working.
     
    Last edited: Nov 12, 2013
  7. MattBradley

    MattBradley

    Joined:
    Nov 8, 2013
    Posts:
    11
    Thanks for replying Roland. I think what you're describing with the itween update coming in the next frame makes sense. I'm still no closer to fixing it though even with that knowledge!

    I've tried to figure out the method you suggest but I can't quite understand it. I think I've been looking at doing it in a certain way for so long that it makes it difficult to determine how else I might do it.

    Is there any way you might be able to explain it a little bit more clearly for me?

    Thanks again, I really appreciate your time :)
     
  8. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Sure - The basic idea is that instead of having each section moving independently and potentially out of sync, we only move the leading section once each frame and update all following sections down the line, ensuring that all sections are always exactly where they need to be relative to each other every frame.

    So, an implementation of what I'm suggesting came out looking like this for me (I haven't used PM in a while so you might be able to trim/optimize it better):

    $runner-FSM.jpg

    The gray states are what initialize a section's Leader and Follower references (along with the Leader's Anchor object) which make up the chain. The green states are what check for and move the leading section of the chain (note the use of Translate instead of ITween), checking its position for possible destruction and spawning of a new section, and sending the event to set a follower's position to its Anchor reference down the chain.

    Let me know if you'd like more details!
     
    Last edited: Nov 13, 2013
  9. MattBradley

    MattBradley

    Joined:
    Nov 8, 2013
    Posts:
    11
    Thanks very much Roland. Using the principle of just one section moving and having the others align to it has worked :D

    I've done it slightly differently to your setup by making the following section a child of the leader but the idea is the same. For the moment I have it working with two sections but I believe I could add another if I need it. It does seem to get a little more complicated when you add a further section, though!

    I just want to say thank you very much for helping me out with this. I was starting to go a bit crazy!
     
  10. Roland1234

    Roland1234

    Joined:
    Nov 21, 2012
    Posts:
    190
    Absolutely - be sure and let me know if you come across something else starts threatening your sanity.
    I'd be interested in knowing how your project develops over time as well. If you ever start a venue for posting updates or anything make sure and tell me, aye?
     
  11. MattBradley

    MattBradley

    Joined:
    Nov 8, 2013
    Posts:
    11