1

I have applied a code to 3 objects. So far this code switches three cups around so that they swap places. The code gets the start position of the cup, and then the end position of each cup. All 3 end positions are actually the start positions of the other cups, since I want them to swap to the same exact positions as the other cups. The update function makes it so that if the cup's end position (that is chosen at random) DOES NOT equal it's start position, it will move to one of the other 2 spots that were not it's start position, randomly.

I am having trouble with figuring out a couple of things and have tried a few things, but I don't think I'm getting the code right. I want to:

Make the cups randomly move to their new spot, but not move a cup to a spot that another cup is already moving to. (Currently when the animation plays, 2 cups potentially move to the same spot of the 3 spots).

I am just not sure what direction to go in. I also would like this animation to keep playing and for the cups to keep randomly swapping their spots. It would be helpful to get a point in the direction of figuring that out as well.

This is what I want the final outcome to resemble: http://i249.photobucket.com/albums/gg240/OldNewby4507/shell-game-animated.gif

Thanks in advance.

 using UnityEngine;
    using System.Collections;
    using UnityEngine;
    using System.Collections;

    public class NewBehaviourScript : MonoBehaviour
    {
        private Vector3 startPos;
        private float lerp = 0, duration = 1;
        public Vector3[] endPos = new Vector3[3];
        int index;
        Vector3 theNewPos;

        void Start ()
        {
            startPos = transform.position;
            endPos [0] = GameObject.Find ("object1").transform.position;
            endPos [1] = GameObject.Find ("object2").transform.position;
            endPos [2] = GameObject.Find ("object3").transform.position;
            index = Random.Range (0, endPos.Length);
            theNewPos = endPos[index];

        }

        void Update() {

            if (theNewPos != startPos) { 
                lerp += Time.deltaTime / duration;
                transform.position = Vector3.Lerp (startPos, theNewPos, lerp);

            }

        }
    }
Nicole Pinto
  • 364
  • 1
  • 22
  • Is the script on each object? – Chuck Savage Dec 09 '16 at 18:37
  • yes it is, the same script is on each object – Nicole Pinto Dec 09 '16 at 18:41
  • 1
    You need a script that manages the "slots" and sets the cups in motion. Movement can be done by the cups themselves but another script should manage the slots (in a list or array) to ensure that the cups all know what they are doing. For example the pseudo code might look like `clear cups from all slots and clear targets from all cups`, `loop through cups randomly and assign to the first free slot`, `tell each cup what position their target is`. In the cup script, you can just check if the target property is set, if so move towards that position. – Charleh Dec 09 '16 at 19:13
  • Thanks, I am currently working on doing something like this. Thank you for the direction! – Nicole Pinto Dec 09 '16 at 19:58

2 Answers2

1

I think you have to make code like this for your cups:

using UnityEngine;

public class Cup : MonoBehaviour
{
    public Vector3 startPos;
    private float lerp = 0, duration = 1;
    Vector3 theNewPos;

    void Awake()
    {
        startPos = transform.position;
        theNewPos = transform.position;
    }

    void Start()
    {

    }

    void Update()
    {
        float thresholdSqr = 0.01f;

        if ((theNewPos - transform.position).sqrMagnitude > thresholdSqr)
        {
            lerp += Time.deltaTime / duration;
            transform.position = Vector3.Lerp(startPos, theNewPos, lerp);
        }
        else
        {
            transform.position = theNewPos;
            startPos = transform.position;
        }
    }

    public void MoveToSpot(Vector3 pos)
    {
        theNewPos = pos;
        lerp = 0f;
    }
}

And then global gameobject Shaker with code like this:

using UnityEngine;
using System.Linq;

public class Shaker : MonoBehaviour
{    
    Cup[] cups;
    Vector3[] spots;

    void Start()
    {
        cups = GameObject.FindObjectsOfType<Cup>();
        spots = cups.Select(c => c.startPos).ToArray();
    }

    void Update()
    {

    }

    void Shake()
    {
        int[] newIndices = Enumerable.Repeat(-1, cups.Length).ToArray();

        for (int i = 0; i < cups.Length; i++) //there could be another random sort algorithm, for example to make that every cup would move to another spot.
        {
            int free = cups.Length - i;
            int j = Random.Range(0, free);

            for (int k = j; k < cups.Length; k++)
            {
                if (newIndices[k] == -1)
                {
                    newIndices[k] = i;
                    break;
                }
            }
        }

        for (int i = 0; i < cups.Length; i++)
        {
            cups[i].MoveToSpot(spots[newIndices[i]]);
        }
    }
}
mcpiroman
  • 175
  • 2
  • 11
  • Thank you! I am going to try this. Where/or what object would I attach the global game object Shaker script too? – Nicole Pinto Dec 09 '16 at 19:57
  • Also when you introduce the "Cups " with the line " Cups[] cups; ", I'm getting an error that says "The type or namespace name `Cups' could not be found. Are you missing a using directive or an assembly reference?" – Nicole Pinto Dec 09 '16 at 20:05
  • Nicole change Cups to Tests – Chuck Savage Dec 09 '16 at 20:10
  • Thank you! Would I attach the Shaker script to the cups as well, or would I put that script somewhere else? – Nicole Pinto Dec 09 '16 at 20:11
  • Add it to the camera or something that isn't a part of the cups. Or you can add an empty object and name it Shaker, and add it to that. – Chuck Savage Dec 09 '16 at 20:12
  • I modified the method MoveToSpot to reset the lerp counter. – Chuck Savage Dec 09 '16 at 20:14
  • Great...one last thing I'm also getting this error "The name `Enumerable' does not exist in the current context" . Sorry to ask so much – Nicole Pinto Dec 09 '16 at 20:14
  • Ops, sorry, my bad, I forgot to change everything as I do it with diffrent names. Make a empty game object anywhere (well it should be high in hierarchy as it's something global and static) and attach this script to it. – mcpiroman Dec 09 '16 at 20:15
  • No problem, add 'using System.Linq;' at beginning as in code I wrote. – mcpiroman Dec 09 '16 at 20:17
  • I'm pretty sur eI've done everything right, but I think that there might be something wrong with algorithm, as when I press play the cups move at random for the first transformation, but then I'll find one or two of them disappear and I realized they were moving a far distance away in the space of my game. This might be to do with the script checking if there's a spot for them, but if there isn't they break away? Because of this, it's not repeating and constantly switching around either, it stops after the first movement. – Nicole Pinto Dec 09 '16 at 20:31
  • Interesting, i'll check what's wrong, but for me it worked well (except that the spots are really offtent the same so there's no movement for cups (that could be since I wrote this algorithm just for now)). Do you call the 'Shake' function only at start or etiher after that? – mcpiroman Dec 09 '16 at 20:41
  • I called it exactly where you called it in your code... I've got just 3 cups , so 3 spots..On some plays even all 3 disappear, I'm think they're movement is getting cancelled out somehow because they're all trying to move to the same spot or something on some plays – Nicole Pinto Dec 09 '16 at 20:47
  • Is there a way I can make it so the spots are never the same, so there's always movement? I think that might be the issue, there's no movement so they mess up. – Nicole Pinto Dec 09 '16 at 20:49
  • Yeah, there were problems with movement, but I fixed them, now it should work. About algorithm, I'll think about it – mcpiroman Dec 09 '16 at 20:58
  • I tweaked some stuff around, but I've got it. Thanks for your help so much! – Nicole Pinto Dec 09 '16 at 20:59
1

If you are adding this script to each of the objects, do the following. This only requires one script, and it is added to each of the cup objects.

using UnityEngine;
using System.Collections.Generic;
using System.Linq;

public class rotateCups : MonoBehaviour
{
    private float lerp = 0f, speed = 5f;
    static List<Vector3> listOfCupPositions, shuffleList;
    Vector3 theNewPos, startPos;
    readonly int shuffleSpeed = 100;
    int shuffle = 0;

    void Start()
    {
        if (null == listOfCupPositions)
        {
            // These lists are global to each cup
            listOfCupPositions = new List<Vector3>();
            shuffleList = new List<Vector3>();
        }
        theNewPos = startPos = transform.position;
        listOfCupPositions.Add(theNewPos); // Add this cup to the main list
    }

    void Update()
    {
        if (startPos != theNewPos)
        {
            lerp += Time.deltaTime * speed;
            lerp = Mathf.Clamp(lerp, 0f, 1f); // keep lerp between the values 0..1
            transform.position = Vector3.Lerp(startPos, theNewPos, lerp);
            if (lerp >= 1f)
            {
                startPos = theNewPos;
                lerp = 0f;
            }
        }
    }

    void LateUpdate()
    {
        if (--shuffle <= 0)
        { 
            // Shuffle the cups
            shuffle = shuffleSpeed;
            if (0 == shuffleList.Count)
                shuffleList = listOfCupPositions.ToList(); // refresh shuffle positions

            // Loop until we get a position this cup isn't, 
            // or unless there's only one spot left in shuffle list, 
            // use it (ie don't move this cup this round)
            int index;
            do
            {
                index = Random.Range(0, shuffleList.Count);
            } while (startPos == shuffleList[index] && shuffleList.Count > 1);

            // give this cup a new position
            theNewPos = shuffleList[index];
            shuffleList.RemoveAt(index); // remove position from shuffle list so it isn't duplicated to another cup
        }
    }
}

This is a fun little thing to watch in action. To test this, I added a cube, capsule and a sphere, moved them to 3 separate spots, added the script to each, and then with the camera selected, did a ctrl+shift+F to give it the same view point as my editor window, (save the scene first just in case), then run it.

Chuck Savage
  • 11,775
  • 6
  • 49
  • 69
  • Just for learning purposes, what were the things you added here. It's a little different from my original code and I'm not familiar with things like Mathf.Clamp or creating a static List..is this the same as creating an array? It all seems very efficiently done! – Nicole Pinto Dec 09 '16 at 21:02
  • static objects are available in each object, and there is only one of them. So each of the lists are available to each cup. but the lists are global to them all. – Chuck Savage Dec 09 '16 at 21:03
  • `Math.Clamp` restricts a value in a range. Lerp can only have the values between 0 and 1, so I restricted that to be sure. – Chuck Savage Dec 09 '16 at 21:04
  • Lists are dynamic arrays, so we can have any number of items, and they can be added to and subtracted from. Like the 2nd list has each position removed after it is used. – Chuck Savage Dec 09 '16 at 21:09
  • So List 1 is a list of the New Positions that can be used and list 2 is a list of the positions just used? – Nicole Pinto Dec 09 '16 at 21:20
  • List 1 (now list of cup positions) is all the cup positions, never modified after cups are added. List 2 (shuffle list) is a temporary list that we randomly pick a new position from (then remove it from the list, so we don't duplicate that position to another cup). Once the List 2 (shuffle list) is empty, we load it up with all of List 1's positions again. We use `.ToList()` so we get a new list of the same positions. We protect List 1, so it keeps our positions, and it never gets modified. – Chuck Savage Dec 09 '16 at 21:28
  • You could make `speed` a public variable, then each cup could move at different speeds, set using the inspector. – Chuck Savage Dec 09 '16 at 21:37
  • That makes a lot of sense. You've been a lot of help, thank you! – Nicole Pinto Dec 09 '16 at 21:59