Category: Code

Code CSharp 1

The C# scripts are a wip for a level I’m working on in Unity.

InventoryItem.cs instantiates or destroys objects moving in or out of the inventory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;

// http://trinary.tech/category/mec/ more efficient coroutines documentation
using MEC;


// Eric's items inventory, controls cards behavior in inventory and instantiates or destroys world object counterparts and interacts directly with ItemsWorld script
public class InventoryItem : MonoBehaviour //, IDragHandler, IBeginDragHandler, IEndDragHandler, IDropHandler
{
    public GameObject worldCounterpart; // use prefab from project tab so that it can be instantiated and destroyed?
    private GameObject worldItem; // cloned copy of the world counterpart

    // rectangle transform of current card to send to inventory
    private RectTransform itemRectTransform;

    // get the canvas raycast
    public GameObject inventoryPanel;
    private Inventory inventory;

    // setup spawn item
    private Vector3 itemSpawnPoint;
    private Rigidbody worldItemRigidbody;
    private Vector3 keySpawnTempVar = new Vector3(-.35f, 0f, -.5f);
    private WorldInteraction worldInteraction; // get world raycast


    private bool dragStarted = false;


    private void Awake()
    {

        inventory = inventoryPanel.GetComponent<Inventory>();

        worldInteraction = Camera.main.GetComponent<WorldInteraction>();


    }

    private void Start()
    {
        //Debug.Log(deck.name);
    }

    private void Update()
    {

    }

    #region Eric's custom MEC item drag

    public void StartItemDrag(GameObject item) // this method is called from interaction.cs and Inventory.cs
    {
        // start proper raycaster, set card raycast block, start itemdrag with
        GetComponent<CanvasGroup>().blocksRaycasts = false;
        if (!dragStarted) Timing.RunCoroutine(_itemDrag(item));

    }

    IEnumerator<float> _itemDrag(GameObject item)
    {
        // itemsInWorld.inventoryCounterpart.transform.position = Input.mousePosition;
        dragStarted = true;

        while (!Input.GetMouseButtonUp(0))
        {
            //Debug.Log("Drag started");

            item.transform.position = Input.mousePosition; // transform or rectTransform?            

            yield return 0;
        }

        #region coroutine ending - sort card, spawn item, and/or send item to required item check
        // everything in this region related to setting position of world item and instantiating it may be better off in world interaction script?

        itemRectTransform = item.GetComponent<RectTransform>();

        if (inventory.lastRaycastHit != null) // still need to differentiate between items and collectibles inventory
        {
            // send card to hand
            inventory.InHand(this.gameObject, itemRectTransform);

        }
        else
        {
            // send card to deck
            inventory.InDeck(this.gameObject, itemRectTransform);


            // set spawnpoint for world counterpart
            if (!worldInteraction.hitDetected) // raycast isn't hitting something
            {
                itemSpawnPoint = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, (Camera.main.nearClipPlane + .6f))); // added .6f for approx 2 feet
                InstantiateWorldItem();
            }
            else if (worldInteraction.hitDetected && worldInteraction.worldItem != null && worldInteraction.worldItem.usable)
            { /*use the interactable object*/
                Debug.Log("Item has been dropped on usable item");

                // spawn object, set parent, set position

                // extend itemSpawnPoint later to grab the point on the new parent world item where this item should be located,
                // maybe add empty game objects called spawn points (or name spawnKey, spawnPowerCell etc) to the objects to set the position to or
                itemSpawnPoint = Vector3.zero;
                InstantiateWorldItem(worldInteraction.worldItem.transform);

                // temporary key send
                worldInteraction.worldItem.UnlockDoor(this.gameObject);
            }
            else
            {
                // get normal and adjust itemspawnpoint a few inches from it                
                itemSpawnPoint = (worldInteraction.raycastHit.normal * .127f) + worldInteraction.raycastHit.point; // .127f is five inches
                InstantiateWorldItem();
            }


        }
        #endregion


        GetComponent<CanvasGroup>().blocksRaycasts = true;
        dragStarted = false;
        //Debug.Log("done dragging card");
    }


    private void InstantiateWorldItem()
    {
        // instantiate world counterpart item
        worldItem = Instantiate(worldCounterpart, itemSpawnPoint, Quaternion.identity); // Input.mousePosition

        // set card as inventory counterpart in world item
        worldItem.GetComponent<WorldItem>().inventoryCounterpart = this.gameObject;// also temporary?
    }

    // my first overload
    private void InstantiateWorldItem(Transform newParent)
    {
        InstantiateWorldItem();

        worldItemRigidbody = worldItem.GetComponent<Rigidbody>(); // should be one so shouldn't need null check as all pickable items should be rigid bodies?
        worldItemRigidbody.isKinematic = true;
        worldItemRigidbody.detectCollisions = false; // can't pick up key again unless remove this line and set all collision shapes to trigger

        // there's a huge difference between worldInteraction.worldItem.etc vs worldItem.etc...one the world raycast just hit and one the item being spawned
        worldItem.transform.SetParent(newParent);
        worldItem.transform.localPosition = keySpawnTempVar;
    }

    #endregion

}


</center>

Code CSharp 2

Inventory.cs script controls the inventory open and close and sorting of the cards in the inventory.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
using System.Collections;
using System.Collections.Generic;
using UnityEngine.EventSystems;
using UnityEngine;
using UnityEngine.UI;

// http://trinary.tech/category/mec/ more efficient coroutines documentation
using MEC;

// to use .ToList or .ToArray
using System.Linq;


// Eric's Inventory script, controls opening and closing of items and collectibles so far
public class Inventory : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler, IPointerDownHandler  // IDragHandler, IPointerUpHandler
{
    #region open/close inventory variables
    [Header("inventory open/close animation")]
    public RectTransform itemsRectTransform;
    public RectTransform itemsBackpack;
    public RectTransform collectiblesRectTransform;
    public RectTransform collectiblesBackpack;

    private CoroutineHandle openHandle;
    private CoroutineHandle closeHandle;
    private bool waiting = false;

    private bool itemsBackpackUsed = false;
    private bool itemsOpening = false;
    private bool itemsClosing = false;
    private bool itemsOpen = false;
    private bool itemsClosed = true;

    private bool collectiblesBackpackUsed = false;
    private bool collectiblesOpening = false;
    private bool collectiblesClosing = false;
    private bool collectiblesOpen = false;
    private bool collectiblesClosed = true;


    // Doesn't matter where it's at, always requires tiny bit of maths...
    private Vector3 openInventoryPosition = new Vector3(0, 100, 0);
    private Vector3 closeInventoryPosition = new Vector3(0, -100, 0);

    private float invAnimDistance; // inventory aniamtion distance

    private float openIncrement = 0f; //debug variable don't need in final
    private float closeIncrement = 0f; //debug veriable don't need in final

    public float speed = 1f;
    #endregion

    #region raycast open/close testing variables
    private GraphicRaycaster myGraphRaycast;
    private PointerEventData myPointerEventData;
    private EventSystem myEventSystem;

    [HideInInspector]
    public bool canvasRaycastRunning = false;

    [HideInInspector]
    public GameObject lastRaycastHit;
    #endregion

    #region drag item variables
    [Header("card storage areas")]
    public Transform itemsCards; // itemsPanel collectiblesPanel could probably be removed and use itemsRectTransform.gameObject collectiblesRectTransform.gameObject instead
    public GameObject collectiblesCards;
    public GameObject deck;

    //private List<Transform> itemSlots;
    private Transform[] itemSlots;
    private GameObject[] collectibleSlots;
    private InventoryItem inventoryItem;
    private Vector3 itemZeroSlot = new Vector3(0, 1600 - 64, 0); //height of slot minus half the height of card
    private Vector3 itemZeroDeck = new Vector3(0, 0, 0); //height of slot minus half the height of card
    #endregion


    private void Awake() // trying on awake as it's on this item only
    {
        // start items and collectibles closed
        itemsRectTransform.localPosition = closeInventoryPosition;
        collectiblesRectTransform.localPosition = closeInventoryPosition;

        invAnimDistance = openInventoryPosition.y - closeInventoryPosition.y; // animation distance of items and collectibles

        // graphics raycaster setup
        myGraphRaycast = GetComponent<GraphicRaycaster>();
        myEventSystem = GetComponent<EventSystem>();

        // add slots to slot list, .ToList or .ToArray requires using System.Linq
        itemSlots = itemsCards.GetComponentsInChildren<Transform>();// .ToList();
        itemSlots = itemSlots.Skip(1).ToArray(); // skips the first transform which is the parent and recreates the array

        // moved to proper method
        //for (int i = 0; i < itemSlots.Length; i++)
        //{
        //    Debug.Log("This is Stuipd!" + itemSlots[i]);
        //}
    }



    // gui debugging stuff
    private void OnGUI()
    {
        // trying to sort out these booleans
        GUI.Label(new Rect(10, 10, 300, 20), "itemsClosed = " + itemsClosed);
        GUI.Label(new Rect(10, 30, 300, 20), "itemsClosing = " + itemsClosing);
        GUI.Label(new Rect(10, 50, 300, 20), "itemsOpen = " + itemsOpen);
        GUI.Label(new Rect(10, 70, 300, 20), "itemsOpening = " + itemsOpening);

        GUI.Label(new Rect(10, 110, 300, 20), "collectiblesClosed = " + collectiblesClosed);
        GUI.Label(new Rect(10, 130, 300, 20), "collectiblesClosing = " + collectiblesClosing);
        GUI.Label(new Rect(10, 150, 300, 20), "collectiblesOpen = " + collectiblesOpen);
        GUI.Label(new Rect(10, 170, 300, 20), "collectiblesOpening = " + collectiblesOpening);

        GUI.Label(new Rect(10, 210, 300, 20), "closeIncrement = " + closeIncrement);
        GUI.Label(new Rect(10, 230, 300, 20), "openIncrement = " + openIncrement);
    }

    #region Coroutine canvas raycast start/stop
    public void OnPointerEnter(PointerEventData pointerEventData)
    {
        if (!canvasRaycastRunning) Timing.RunCoroutine(_CanvasRaycast());// start canvas raycasting if it isn't running, should stop physics raycasting
        CancelInvoke(); // prevent onpointerexit invokes from building up
    }

    IEnumerator<float> _CanvasRaycast()
    {
        canvasRaycastRunning = true;

        while (canvasRaycastRunning) // onPointerExit switches this to false
        {
            myPointerEventData = new PointerEventData(myEventSystem);
            myPointerEventData.position = Input.mousePosition;

            List<RaycastResult> results = new List<RaycastResult>();

            myGraphRaycast.Raycast(myPointerEventData, results); // requires graphicraycaster component added to the object, event data doesn't seem to need to be added?

            MyRaycastResults(results); // this function is probably not necessary

            yield return 0;
        }
    }


    private void MyRaycastResults(List<RaycastResult> results)
    {
        foreach (RaycastResult result in results)
        {

            //Debug.Log("Hit " + result.gameObject.name);
            lastRaycastHit = result.gameObject;

            if (lastRaycastHit.name == itemsBackpack.name || lastRaycastHit.name == collectiblesBackpack.name
                || lastRaycastHit.name == itemsRectTransform.name || lastRaycastHit.name == collectiblesRectTransform.name)
            { OpenInventory(); }

            // yield return 0; // would use this if the for each were in a coroutine, this would also cause the items to cycle 60 items per second
        }
    }

    #endregion

    #region open/close inventory
    private void OpenInventory()// public void OnPointerEnter(PointerEventData pointerEventData)
    {
        // set this condition to raycast instead of pointer enter, that way if the backpacks are overlaying other interface components this condition can still resolve to true
        if (lastRaycastHit.name == itemsBackpack.name) // old pointerEventData.pointerEnter.name == itemsBackpack.name
        {
            collectiblesBackpackUsed = false;

            if (!itemsBackpackUsed && !itemsOpening && !itemsOpen)
            {
                itemsBackpackUsed = true;
                Timing.KillCoroutines(openHandle);

                if (itemsClosing)
                {
                    waiting = false;
                    Timing.KillCoroutines(closeHandle);
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(itemsRectTransform));
                }

                else if (itemsClosed && collectiblesClosed)
                {
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(itemsRectTransform));
                }

                else if (collectiblesOpen)
                {
                    waiting = true;
                    closeHandle = Timing.RunCoroutine(_LerpInventoryClose(collectiblesRectTransform));
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(itemsRectTransform));
                }

                else if (collectiblesOpening)
                {
                    waiting = true;
                    closeHandle = Timing.RunCoroutine(_LerpInventoryClose(collectiblesRectTransform));
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(itemsRectTransform));
                }

                // at face value it would seem this isn't need but if it's closing after invoke time period then still need this
                else if (collectiblesClosing)
                {
                    waiting = true;
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(itemsRectTransform));
                }
            }
        }

        if (lastRaycastHit.name == collectiblesBackpack.name) //  ||
        {
            itemsBackpackUsed = false;

            if (!collectiblesBackpackUsed && !collectiblesOpening && !collectiblesOpen)
            {
                collectiblesBackpackUsed = true;
                Timing.KillCoroutines(openHandle);

                if (collectiblesClosing)
                {
                    waiting = false;
                    Timing.KillCoroutines(closeHandle);
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(collectiblesRectTransform));
                }

                // set bools, start opening items
                else if (itemsClosed && collectiblesClosed)
                {
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(collectiblesRectTransform));
                }

                else if (itemsOpen)
                {
                    waiting = true;
                    closeHandle = Timing.RunCoroutine(_LerpInventoryClose(itemsRectTransform));
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(collectiblesRectTransform));
                }

                else if (itemsOpening)
                {
                    waiting = true;
                    closeHandle = Timing.RunCoroutine(_LerpInventoryClose(itemsRectTransform));
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(collectiblesRectTransform));
                }

                // at face value it would seem this isn't need but if it's closing after invoke time period then still need this
                else if (itemsClosing)
                {
                    waiting = true;
                    openHandle = Timing.RunCoroutine(_LerpInventoryOpen(collectiblesRectTransform));
                }
            }
        }
    }


    public void OnPointerExit(PointerEventData pointerEventData)
    {
        // stop canvas raycast, also stop when F key is released
        canvasRaycastRunning = false;
        lastRaycastHit = null;
        //Debug.Log(lastRaycastHit.name);
        //Debug.Log(itemsRectTransform.name);

        Invoke("CloseInventory", 5);
    }


    private void CloseInventory()
    {
        itemsBackpackUsed = false;
        collectiblesBackpackUsed = false;

        if (itemsOpen) closeHandle = Timing.RunCoroutine(_LerpInventoryClose(itemsRectTransform));
        if (collectiblesOpen) closeHandle = Timing.RunCoroutine(_LerpInventoryClose(collectiblesRectTransform));
    }
    #endregion

    #region coroutine lerp items collectibles panels
    IEnumerator<float> _LerpInventoryClose(RectTransform currentRectTransform) // send parameters in for whatever needs to be closed
    {
        if (currentRectTransform.name == itemsRectTransform.name) { itemsClosing = true; itemsClosed = false; itemsOpening = false; itemsOpen = false; }
        if (currentRectTransform.name == collectiblesRectTransform.name) { collectiblesClosing = true; collectiblesClosed = false; collectiblesOpening = false; collectiblesOpen = false; }

        float percentClosed = 0f;
        float percentClosedSqr;

        while (percentClosed < 1) // While not closed
        {
            openIncrement = invAnimDistance - closeIncrement;

            percentClosed = (closeIncrement / invAnimDistance);

            // https://stackoverflow.com/questions/13462001/ease-in-and-ease-out-animation-formula, parametric function
            percentClosedSqr = percentClosed * percentClosed;
            percentClosed = percentClosedSqr / (2f * (percentClosedSqr - percentClosed) + 1f);

            currentRectTransform.localPosition = Vector3.Lerp(openInventoryPosition, closeInventoryPosition, percentClosed);

            closeIncrement = Time.deltaTime * speed + closeIncrement; // put this at the end so that the first frame is 0 lerp

            if (closeIncrement >= invAnimDistance)
            {
                openIncrement = 0f;
                percentClosed = 1f; // prevents bounceback
                waiting = false;

                if (currentRectTransform.name == itemsRectTransform.name) { itemsClosing = false; itemsClosed = true; itemsOpening = false; itemsOpen = false; }
                if (currentRectTransform.name == collectiblesRectTransform.name) { collectiblesClosing = false; collectiblesClosed = true; collectiblesOpening = false; collectiblesOpen = false; }
            }

            yield return 0;
        }
    }

    IEnumerator<float> _LerpInventoryOpen(RectTransform currentRectTransform)
    {
        // wait until other is closed
        while (waiting) yield return Timing.WaitUntilDone(closeHandle);

        if (currentRectTransform.name == itemsRectTransform.name) { itemsClosing = false; itemsClosed = false; itemsOpening = true; itemsOpen = false; }
        if (currentRectTransform.name == collectiblesRectTransform.name) { collectiblesClosing = false; collectiblesClosed = false; collectiblesOpening = true; collectiblesOpen = false; }

        float percentOpen = 0f;
        float percentOpenSqr;

        while (percentOpen < 1) // While not closed
        {
            closeIncrement = invAnimDistance - openIncrement;

            percentOpen = (openIncrement / invAnimDistance);

            // https://stackoverflow.com/questions/13462001/ease-in-and-ease-out-animation-formula, parametric function
            percentOpenSqr = percentOpen * percentOpen;
            percentOpen = percentOpenSqr / (2f * (percentOpenSqr - percentOpen) + 1f);

            currentRectTransform.localPosition = Vector3.Lerp(closeInventoryPosition, openInventoryPosition, percentOpen);

            openIncrement = Time.deltaTime * speed + openIncrement; // put this at the end so that the first frame is 0 lerp

            if (openIncrement >= invAnimDistance)
            {
                closeIncrement = 0f;
                percentOpen = 1f; // prevents bounceback

                if (currentRectTransform.name == itemsRectTransform.name) { itemsClosing = false; itemsClosed = false; itemsOpening = false; itemsOpen = true; }
                if (currentRectTransform.name == collectiblesRectTransform.name) { collectiblesClosing = false; collectiblesClosed = false; collectiblesOpening = false; collectiblesOpen = true; }
            }

            yield return 0;
        }
    }

    IEnumerator<float> _WaitUntilDone() // not sure how to do this yet
    {
        yield return 0;
    }
    #endregion

    #region start item drag and slot sorting

    public void OnPointerDown(PointerEventData pointerEventData) // OnPointerDown over OnDrag so only send one start item drag
    {
        //Debug.Log(pointerEventData.pointerEnter.name + " is being dragged by OnPointerDown");

        inventoryItem = pointerEventData.pointerEnter.GetComponent<InventoryItem>();

        if (inventoryItem != null)
        {
            //Debug.Log("found InvenotryItem script");
            inventoryItem.StartItemDrag(inventoryItem.gameObject);
        }
    }

    public void SlotSort(GameObject item)
    {
        // sort slots
    }


    #endregion

    #region world, hand, deck
    public void InWorld()
    {
        // objects in world
    }

    public void InHand(GameObject item, RectTransform itemRectTransform)
    {
        //item.transform.SetParent(slot01.transform);

        for (int i = 0; i < itemSlots.Length; i++)
        {
            Debug.Log("This is Stuipd!" + itemSlots[i]);
            if (itemSlots[i].childCount == 0)
            {
                item.transform.SetParent(itemSlots[i]);
                break;
            }
        }
        itemRectTransform.localPosition = itemZeroSlot;
    }

    public void InDeck(GameObject item, RectTransform itemRectTransform)
    {
        item.transform.SetParent(deck.transform);
        itemRectTransform.localPosition = itemZeroDeck;
    }
    #endregion



}

Code CSharp 3

WorldItem.cs is for objects that can be interacted with in the world. There’s not much to this script yet but it’s intended to control the function of elevators, keypads, power supply, circuit breaker, doors and other objects.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

// Eric's item's in the world script, interacts directy with ItemsInventory script?? Physics Raycasting will be handled in interactions script
public class WorldItem : MonoBehaviour
{

    public enum UsableTypes { Door = 1, Elevator, Fusebox, Keypad, TV, Computer, CassettePlayer, PowerSupply };

    [Header("Pickable item variables")]
    public bool pickable = false;
    public GameObject inventoryCounterpart; // actual card, not from project window, as none of the cards get instantiated or destroyed just pulled and put from the deck


    [Header("Usable item variables")]
    public bool usable = false;
    public UsableTypes usableType;
    public List<GameObject> requiredItems;


    // items setup variables
    private HingeJoint myHingeJoint;
    private JointSpring mySpring;

    // temp door testing remember to remove from custom inspector
    public bool locked = true;

    // instead of onmouseover use a while getting hit by raycast so the only time this script is running is while getting hit otherwise it might be listening all the time for a hit.

    private void Awake()
    {
        // set up all items according to type, add all spawnpoints on usable items to list
        myHingeJoint = this.GetComponent<HingeJoint>();

        if (GetComponent<HingeJoint>() != null)
        {
            //Debug.Log("my hinge joint isn't null");
            //mySpring = myHingeJoint.spring;
            mySpring = GetComponent<HingeJoint>().spring;


        } // must be a door?   use enum instead of checking if it has a hinge

        Debug.Log("The first required item is" + requiredItems[0]);
    }


    private void Start()
    {
        //Debug.Log(name + " has been created" + " and pickable = " + pickable);
    }

    public void ContextMenu()
    {
        // receive right click activation from world interactions script, not sure why at the moment but kinda makes sense as inventory and interactions mostly track input
        // with less tracked in items scripts

        // rightclick context menu? Bools for the script will allow every object with this script to have different
        // context menu options which will allow each option to run it's equivalent script with itself(this/raycastresults/whatever) as the input
    }

    // overload use for different world item types?
    public void Use()
    {
        //Debug.Log("world item has been used");
        if (!locked)
        {
            if (myHingeJoint != null)
            {

                mySpring.targetPosition = 80f;
                myHingeJoint.spring = mySpring; // argh, all night to find out that I have to take it out save a variable then save the variable back into it

                //Debug.Log("setting target position on jointspring variable to " + mySpring.targetPosition);
                //Debug.Log("target position for hingejoint " + myHingeJoint.spring.targetPosition);
            }
        }

        // send item type from world interaction to set conditions and determine how use should work

        // if doesn't have required items post message to screen "door is locked" or appropriate message



        // if door unlocked and mouse drag detected then use transform.lookat on an empty gameobject and upvector with:
        // Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, Camera.main.nearClipPlane))
        // and match target position under hinge joint, spring for door with empty gameobject



        // if mouse not dragged then default open door, set target position to open, 80 degrees? Animation and OnOff anim boolean is not needed using this technique
        // Be aware that taget position number doesn't guarantee y rotation on door transform, alter spring, drag, and rigid body mass until you get the effect you want
    }

    // temporary door lock method, goes with the temp lock variables
    public void UnlockDoor(GameObject redKey)
    {
        if (redKey == requiredItems[0]) { locked = false; }
    }
}










#region custom inspector
// I wonder if this will error on game build? Does a class that inherits editor need to be separated from classes that get built into the game?
//[CanEditMultipleObjects]
[CustomEditor(typeof(WorldItem))]
public class WorldItemEditor : Editor
{
    SerializedProperty usableType; // WorldItem.usableType?? if this script doesn't modify the list and enum properly then there's probably a targeting issue
    SerializedProperty requiredItems;


    private void OnEnable()
    {
        requiredItems = serializedObject.FindProperty("requiredItems");
    }


    override public void OnInspectorGUI()
    {

        WorldItem worldItem = target as WorldItem;

        // temporary door variables
        worldItem.locked = EditorGUILayout.Toggle("doorLocked", worldItem.locked);


        //EditorGUILayout.LabelField("Pickable ", EditorStyles.boldLabel);
        worldItem.pickable = EditorGUILayout.Toggle("Pickable", worldItem.pickable);
        using (new EditorGUI.DisabledScope(!worldItem.pickable))
        {
            worldItem.inventoryCounterpart = (GameObject)EditorGUILayout.ObjectField("Inventory Counterpart", worldItem.inventoryCounterpart, typeof(GameObject), true);
        }


        EditorGUILayout.LabelField(" ", EditorStyles.boldLabel); // just a line spacer
        worldItem.usable = EditorGUILayout.Toggle("Usable", worldItem.usable);
        using (new EditorGUI.DisabledScope(!worldItem.usable))
        {
            // https://answers.unity.com/questions/26207/how-can-i-recreate-the-array-inspector-element-for.html

            serializedObject.Update();

            //EditorGUIUtility.LookLikeInspector(); // deprecated, url above has a reply with an "alternative"
            usableType = serializedObject.FindProperty("usableType"); // WorldItem.usableType?? read SerializedProperty usableType; above
            requiredItems = serializedObject.FindProperty("requiredItems");

            EditorGUI.BeginChangeCheck();

            EditorGUILayout.PropertyField(usableType, true);
            EditorGUILayout.PropertyField(requiredItems, true);

            if (EditorGUI.EndChangeCheck())
                serializedObject.ApplyModifiedProperties();

            //EditorGUIUtility.LookLikeControls(); // deprectaed


            //EditorGUILayout.PropertyField(requiredItems, new GUIContent("requiredItems")); //worldItem.requiredItems =
        }
    }
}
#endregion

Code CSharp 4

WorldInteraction.cs detects interactions and then decides where to send the object, to inventory or to worlditem script.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

// http://trinary.tech/category/mec/ more efficient coroutines documentation
using MEC;


// Eric's interaction script will handle raycasting for world objects, Inventory is kind of the UI counterpart. So inventory to itemsinventory as interaction to itemsinworld?
// this script will handle dragging in 3d, right click context menu, updating information in inventory.
// add zoom to mouse wheel and depth of field surroundings. Only zoom on interactable objects, when mouseoff then return zoom to normal after a second.
public class WorldInteraction : MonoBehaviour
{
    #region variables to check if item is pickable
    public Inventory inventoryPanel;
    private GameObject item;
    private GameObject inventoryItem; //InventoryItem
    [HideInInspector]
    public WorldItem worldItem;
    private bool itemDragCheckRunning = false;
    // private GameObject inventoryCounterpart;
    #endregion

    [HideInInspector] public RaycastHit raycastHit;
    private Ray ray;
    //[HideInInspector] public Vector3 itemSpawnPoint;
    [HideInInspector] public bool hitDetected;

    #region watch for mouse drag
    private CoroutineHandle pauseHandle;
    private Vector3 mousePositionSaved;// = new Vector3(0, 0, 0);
    #endregion


    private void Awake()
    {
        // drag coroutine preparation
        mousePositionSaved = Input.mousePosition;
    }

    private void Start()
    {

    }

    private void Update()
    {
        // while mouse is over inventory prevent raycasting, set up toggle so you can hold f or click to toggle
        if (Input.GetKey(KeyCode.F))
        {
            // Debug.Log(inventoryPanel.canvasRaycastRunning);            

            if (!inventoryPanel.canvasRaycastRunning)
            {
                ray = Camera.main.ScreenPointToRay(Input.mousePosition);


                if (Physics.Raycast(ray.origin, ray.direction, out raycastHit, 2)) // not Mathf.Infinity please, about arms length or 6 ft to be able to grab at feet? 1.8288
                {
                    // Debug.Log("Did Hit: " + hit.collider + "\n" + hit.collider + " is tagged: " + hit.collider.tag);
                    hitDetected = true;


                    if (!itemDragCheckRunning)
                    {
                        // in fact just wrap everything that a raycast can allow to happen nicely in drag item check
                        item = raycastHit.transform.gameObject; // if this isn't also in the dragcheckrunning then if the raycast hits something else it will be deleted, lol
                        worldItem = item.GetComponent<WorldItem>(); // this causes null error on line 112 if mouse drag causes raycast to hit another item before swapping to card drag


                        if (worldItem != null && worldItem.pickable)
                        {
                            // Debug.Log("Item is pick up able " + itemsInWorld.pickable);

                            if (Input.GetMouseButtonDown(0))
                            {
                                //Debug.Log("mouse has been clicked on a pickable item and mouse position is" + Input.mousePosition);                            

                                mousePositionSaved = Input.mousePosition;
                                Timing.RunCoroutine(_ItemDragCheck());

                            }
                        }
                        // get enum type to determine how to use Use(), overload, send enum type, send something else, idk yet
                        // or maybe different methods in world item for each enum type UseDoor, UseElevator, UseCassettePlayer etc
                        if (worldItem != null && worldItem.usable)
                        {
                            Debug.Log("world item is usable, it's probably a door");

                            if (Input.GetMouseButtonDown(0))
                            {
                                // run world item use and send item type to set use conditions to for proper object. Door, keypad
                                worldItem.Use(); // for now all doing is setting door open closem use
                            }
                        }
                    }
                }

                if (!Physics.Raycast(ray.origin, ray.direction, out raycastHit, 2)) { hitDetected = false; }
            }
        }
    }

    IEnumerator<float> _ItemDragCheck()
    {
        //Debug.Log("Item drag check is trying to start");
        itemDragCheckRunning = true;

        while (!Input.GetMouseButtonUp(0))
        {
            //Debug.Log("Item drag check started");

            if (Input.mousePosition != mousePositionSaved)
            {
                //Debug.Log("mouse has been dragged on pickable item");
                //Debug.Log(itemsInWorld.inventoryCounterpart);                

                // pull card from deck, set to mouse position, destroy object
                inventoryItem = worldItem.inventoryCounterpart.gameObject; // null exception comes on this line when the mouse raycast is moved away from the object too fast raycasting onto the wrong surface
                inventoryItem.GetComponent<InventoryItem>().StartItemDrag(inventoryItem);

                Destroy(item);

                itemDragCheckRunning = false;

                break;
            }

            yield return 0f;
        }
    }

Code CG/HLSL 1

CG/HLSL Distort_Modified.cginc is a modified part of the open source Alloy shader for Unity game engine. I added the option to blur the refraction of light through a transparent surface. I added lines 83 through 122 from a simple blur algorithm and modified other parts of the code to integrate the effect into the shader.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/////////////////////////////////////////////////////////////////////////////////
/// @file Distort.cginc
/// @brief Forward distort pass vertex & fragment shaders.
/////////////////////////////////////////////////////////////////////////////////

#ifndef ALLOY_SHADERS_FORWARD_DISTORT_CGINC
#define ALLOY_SHADERS_FORWARD_DISTORT_CGINC

#define A_TEXEL_SIZE(a) a##_TexelSize

#ifndef A_DISTORT_TEXTURE
    #define A_DISTORT_TEXTURE _GrabTexture
#endif

#define A_DISTORT_TEXTURE_TEXEL_SIZE A_TEXEL_SIZE(A_DISTORT_TEXTURE)

#define A_BASE_PASS
#define A_TESSELLATION_PASS
#define A_INSTANCING_PASS
#define A_NORMAL_MAPPED_PASS
#define A_PARALLAX_MAPPED_PASS
#define A_VOLUMETRIC_PASS
#define A_CROSSFADE_PASS

#define A_FORWARD_TEXCOORD0 float3 normalProjection : TEXCOORD0;
#define A_FORWARD_TEXCOORD1 float4 grabUv : TEXCOORD1;

#include "Assets/Alloy/Shaders/Framework/Forward.cginc"

/// Grab texture containing copy of the back buffer.
sampler2D A_DISTORT_TEXTURE;

/// Grab texture dimension info.
/// (x: 1 / width, y: 1 / height, z: width, w: height).
float4 A_DISTORT_TEXTURE_TEXEL_SIZE;

/// Weight of the distortion effect.
/// Expects values in the range [0,1].
float _DistortWeight;

/// Strength of the distortion effect.
/// Expects values in the range [0,128].
float _DistortIntensity;

/// Mesh normals influence on distortion.
/// Expects values in the range [0,1].
float _DistortGeoWeight;

///
///Eric's variables
float _RefractionBlur;
float _RefractionBrightness;


void aMainVertexShader(
    AVertexInput v,
    out AFragmentInput o)
{
    aForwardVertexShader(v, o);
    o.normalProjection = mul((float3x3)UNITY_MATRIX_MVP, v.normal);
    o.grabUv = ComputeGrabScreenPos(o.pos);
    o.grabUv.z = UNITY_Z_0_FAR_FROM_CLIPSPACE(o.grabUv.z);
}

half4 aMainFragmentShader(
    AFragmentInput i
    A_FACING_SIGN_PARAM) : SV_Target
{
    // Transfer instancing and stereo IDs.
    ASurface s = aForwardSurface(i, A_FACING_SIGN);

    // Mesh normals distortion.
    // cf http://wiki.unity3d.com/index.php?title=Refraction
    float3 bump = s.normalTangent + i.normalProjection * abs(i.normalProjection);
    float2 offset = A_DISTORT_TEXTURE_TEXEL_SIZE.xy * lerp(s.normalTangent, bump, _DistortGeoWeight).xy;

    i.grabUv.xy += offset * (i.grabUv.z * _DistortWeight * _DistortIntensity);
   
    // Sample and combine textures.
    half3 refr = tex2Dproj(A_DISTORT_TEXTURE, UNITY_PROJ_COORD(i.grabUv)).rgb;
    //return aForwardColor(s, s.baseColor * refr);

    // ew added and modified code
    i.grabUv.y = i.grabUv.y * -1; // blur code below has the image upside down     

    float2 screenPos = i.grabUv.xy / (i.grabUv.w * .5); // original: float2 screenPos = i.screenPos.xy / i.screenPos.w;
    float depth = _RefractionBlur * 0.0005;

    screenPos.x = (screenPos.x) * 0.5; // original: screenPos.x = (screenPos.x + 1) * 0.5;

    screenPos.y = 1 - (screenPos.y + 2) * 0.5; // original: screenPos.y = 1 - (screenPos.y + 1) * 0.5;

    half3 sum = half3(0.0h, 0.0h, 0.0h); // original: half4 sum = half4(0.0h, 0.0h, 0.0h, 0.0h);
    sum += tex2D(_GrabTexture, float2(screenPos.x - 5.0 * depth, screenPos.y + 5.0 * depth)) * 0.025;
    sum += tex2D(_GrabTexture, float2(screenPos.x + 5.0 * depth, screenPos.y - 5.0 * depth)) * 0.025;

    sum += tex2D(_GrabTexture, float2(screenPos.x - 4.0 * depth, screenPos.y + 4.0 * depth)) * 0.05;
    sum += tex2D(_GrabTexture, float2(screenPos.x + 4.0 * depth, screenPos.y - 4.0 * depth)) * 0.05;

    sum += tex2D(_GrabTexture, float2(screenPos.x - 3.0 * depth, screenPos.y + 3.0 * depth)) * 0.09;
    sum += tex2D(_GrabTexture, float2(screenPos.x + 3.0 * depth, screenPos.y - 3.0 * depth)) * 0.09;

    sum += tex2D(_GrabTexture, float2(screenPos.x - 2.0 * depth, screenPos.y + 2.0 * depth)) * 0.12;
    sum += tex2D(_GrabTexture, float2(screenPos.x + 2.0 * depth, screenPos.y - 2.0 * depth)) * 0.12;

    sum += tex2D(_GrabTexture, float2(screenPos.x - 1.0 * depth, screenPos.y + 1.0 * depth)) *  0.15;
    sum += tex2D(_GrabTexture, float2(screenPos.x + 1.0 * depth, screenPos.y - 1.0 * depth)) *  0.15;

    sum += tex2D(_GrabTexture, screenPos - 5.0 * depth) * 0.025;
    sum += tex2D(_GrabTexture, screenPos - 4.0 * depth) * 0.05;
    sum += tex2D(_GrabTexture, screenPos - 3.0 * depth) * 0.09;
    sum += tex2D(_GrabTexture, screenPos - 2.0 * depth) * 0.12;
    sum += tex2D(_GrabTexture, screenPos - 1.0 * depth) * 0.15;
    sum += tex2D(_GrabTexture, screenPos) * 0.16;
    sum += tex2D(_GrabTexture, screenPos + 5.0 * depth) * 0.15;
    sum += tex2D(_GrabTexture, screenPos + 4.0 * depth) * 0.12;
    sum += tex2D(_GrabTexture, screenPos + 3.0 * depth) * 0.09;
    sum += tex2D(_GrabTexture, screenPos + 2.0 * depth) * 0.05;
    sum += tex2D(_GrabTexture, screenPos + 1.0 * depth) * 0.025;

    // return sum / 2;
    // ew added and modified code

    return aForwardColor(s, s.baseColor * (sum * _RefractionBrightness));
}

#endif // ALLOY_SHADERS_FORWARD_DISTORT_CGINC

Code Python 1

Python script toolReset.py for Modo is for resetting tools so you don’t have to manually zero out fields, options, and toolpipe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# python
# toolReset, reset any active tool with one script. current active tool detected with lx.test
# some tools can be reset using the pipeline, others might need manual resetting of all values

# Modo check
# These all return 1 or 0 based on the first item in the list and if Modo is in that mode. For instance testPoly, first item is polygon if Modo is in Polygons then it will return 1.
testPoly = lx.eval ("select.typeFrom polygon;edge;vertex;item;pivot;center;ptag ?")
testEdge = lx.eval ("select.typeFrom edge;vertex;polygon;item;pivot;center;ptag ?")
testVert = lx.eval ("select.typeFrom vertex;edge;polygon;item;pivot;center;ptag ?")

testItem = lx.eval ("select.typeFrom item;pivot;center;edge;polygon;vertex;ptag ?")
testMat = lx.eval ("select.typeFrom ptag;item;pivot;center;edge;polygon;vertex ?")
testPivot = lx.eval ("select.typeFrom pivot;center;item;edge;polygon;vertex;ptag ?")
testCenter = lx.eval ("select.typeFrom center;pivot;item;edge;polygon;vertex;ptag ?")

if testPoly or testEdge or testVert == 1:
    mode = "modePoly"
elif testItem or testMat or testPivot or testCenter == 1:
    mode = "modeItem"

def resetMirror():
    lx.eval("tool.reset gen.mirror")   
    if mode == "modePoly":
        lx.eval("tool.reset effector.clone") # instead of using try/except, check the mode and run the right command
        lx.eval("tool.attr effector.clone flip true")
        lx.eval("tool.attr effector.clone merge true")
    elif mode == "modeItem":
        lx.eval("tool.reset effector.item")

def anotherTool():
    return # return not needed after method/function is setup with reset commands

# probably have to test for any tool that I want reset
if lx.test( "tool.set *.mirror on" ) == True:
    resetMirror()
    lx.out("Mirror tool reset")
# elif lx.test("other tools") == True:
    # anotherToolReset()
    # lx.out("Other Tool reset")
else:
    lx.out("No tool active, or tool isn't set up for reset. Check EW_toolReset")
    print ("No tool active, or tool isn't set up for reset. Check EW_toolReset")

Code Perl 1

Perl script detach_all.pl for Modo takes a multi-part object and splits all the contiguous geometry into their own layers. Good for vehicle models, architectural models or physics simulations preparation or anything that you don’t want to copy and paste into new layers hundreds of times.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# perl script for Modo: split mesh into layers

$layerID = lxq("query layerservice layer.ID ? main");
$sceneID = lxq("query sceneservice selection ? locator");

if ($layerID eq $sceneID) {

    # lxmonInit(100); #add zeros to increase bar accuracy.  Match $barstep.

    $origName = lxq("query layerservice layer.name ? main");

    lx("layer.setVisibility "$origName" false");
    lx("item.duplicate");
    lx("select.type polygon");

    $tempIndex = lxq("query layerservice layer.index ? main");
    $tempPolysAll = lxq("query layerservice poly.N ? all");
    $tempPolys = $tempPolysAll;

    lx("item.create groupLocator "detach all $origName"");
    $groupID = lxq("query sceneservice selection ? locator");

    while ($tempPolys != 0) {
   
        lx("select.drop item");
        lx("select.layer $tempIndex");
        lx("select.element $tempIndex polygon add 1");
        lx("select.polygonConnect");
       
        lxq("query layerservice layer.index ? main");
        $PolysSelected = lxq("query layerservice poly.N ? selected");
       
        lx("select.cut");
       
        lxq("query layerservice layer.index ? main");
        $tempPolys = lxq("query layerservice poly.N ? all");
       
        lx("item.create mesh "$origName part"");
        lx("select.paste");

        $childID = lxq("query layerservice layer.ID ? main");

        lx(qq(item.parent "$childID" "$groupID"));
       
        # comment out here through dialog for math check for script to work without loading bar.  Also comment out lxmoninit
        # currently a bug in Modo causes the loading bar to crash the software.
       
        # $barStep = $PolysSelected / $tempPolysAll * 100; #add zeros to increase bar accuracy.  Match lxmonInit
        # $barStepAdd = $barStepAdd + $barStep; #temporary checking math goes with dialog below
       
        # lxmonStep($barStep);
       
        # if( !lxmonStep ) {
            # die( "User Abort" );
        # }
       
        #math check dialog, remove after testing.  Do not run large objects without commenting out.
        # lx("dialog.setup info");
        # lx("dialog.title "Detach All"");
        # lx("dialog.msg "Step: $barStep Percent: $barStepAdd"");
        # lx("dialog.open");       
    }
   
    lx("select.layer $tempIndex");
    lx("delete");  
   
}

else {
   
        lx("dialog.setup info");
    lx("dialog.title "Detach All"");
    lx("dialog.msg "Select mesh layer"");
    lx("dialog.open"); 

}  
   
# lxmonInit(100);
# lxmonStep();