SHOW:
|
|
- or go back to the newest paste.
1 | - | /* Check out our new 2D point and click adventure at */ |
1 | + | using UnityEngine; |
2 | - | /* http://www.NotQuiteBlackandWhite.com */ |
2 | + | using System; |
3 | ||
4 | - | /* |
4 | + | public class SmartInput : MonoBehaviour |
5 | - | "FrontmostSpriteClicker" for Unity |
5 | + | |
6 | // Fixed size array for hit testing to avoid repeated memory allocation | |
7 | - | Attaching this script to the game camera will allow any 2D sprite that has a collider attached to receive clicks. |
7 | + | // If you might have more than 10 overlapping colliders, you may need to increase array size |
8 | - | It will ignore anything beneath the frontmost sprite i.e a sprite in a lower sorting layer or in a |
8 | + | Collider2D[] Hits = new Collider2D[10]; |
9 | - | lower sorting order in the same layer. |
9 | + | |
10 | void Update() | |
11 | - | This script requires that any sprite you want to be clickable has a script attached |
11 | + | { |
12 | - | that has a function called OnLeftClick, and one called OnRightClick. |
12 | + | // Get all 2D colliders under the mouse/finger |
13 | Vector3 v3 = Camera.main.ScreenToWorldPoint(Input.mousePosition); | |
14 | - | NOTE 1: Works with 2D colliders only but more code could be added to take into account 3D objects and Z depth. |
14 | + | int hitCount = Physics2D.OverlapPointNonAlloc(new Vector2(v3.x, v3.y), Hits); |
15 | - | NOTE 2: Works only with an orthographic camera. |
15 | + | |
16 | - | NOTE 3: Currently uses Camera.main, change this if the camera you are using is not tagged "MainCamera". |
16 | + | // If none, do nothing. |
17 | - | NOTE 4: No effort has been made to optimise this script, it can almost definitely be improved upon. |
17 | + | if (hitCount == 0) |
18 | return; | |
19 | - | Please get in touch with us if there's any issues with the script or if you have any questions. |
19 | + | |
20 | - | */ |
20 | + | // This will be set to front-most collider |
21 | Collider2D frontMostHit = null; | |
22 | - | #pragma strict |
22 | + | |
23 | // Keep track of highest sort order found so far | |
24 | - | private var leftClickedObject : GameObject; |
24 | + | uint highestSortOrder = 0; |
25 | - | private var rightClickedObject : GameObject; |
25 | + | |
26 | - | private var frontmostRaycastHit : RaycastHit2D; |
26 | + | // For each collider hit... |
27 | for(int x=0;x<hitCount;x++) | |
28 | - | // It's necessary to access the SpriteRenderer of a game object to be able to access its sorting layer ID |
28 | + | { |
29 | - | // and sorting order ("Order in Layer" in the inspector) |
29 | + | Collider2D hit = Hits[x]; |
30 | - | private var spriteRenderer : SpriteRenderer; |
30 | + | |
31 | // Get sprite render | |
32 | - | function Update () |
32 | + | SpriteRenderer sr = hit.GetComponent<SpriteRenderer>(); |
33 | ||
34 | - | // If the left mouse button is clicked anywhere... |
34 | + | // Convert sorting order to unsigned value by adding the minimum (negative) value it can possibly have |
35 | - | if (Input.GetMouseButtonDown(0)) |
35 | + | uint uSortingOrder = (uint)(sr.sortingOrder + short.MinValue); |
36 | - | { |
36 | + | |
37 | - | // frontmostRaycastHit stores information about the RaycastHit2D that is returned by GetFrontmostRaycastHit() |
37 | + | // In my game I use 3 sorting layers, you will need to adjust this. SortingLayerOrder needs to have |
38 | - | frontmostRaycastHit = GetFrontmostRaycastHit(); |
38 | + | // a value of 0 for your first layer, 1 for second, 2 for third, and so on. This code |
39 | uint sortingLayerOrder; | |
40 | - | // If frontmostRaycastHit is true, i,e the user hasn't clicked on nothing, i.e GetFrontmostRaycastHit() didn't return nothing... |
40 | + | if (sr.sortingLayerID == 0) // Default |
41 | - | if (frontmostRaycastHit) |
41 | + | sortingLayerOrder = 1; |
42 | - | { |
42 | + | else if (sr.sortingLayerID == 1) // Background |
43 | - | // Assigns the game object that the collider that has been clicked on to leftClickedObject. |
43 | + | sortingLayerOrder = 0; |
44 | - | leftClickedObject = frontmostRaycastHit.collider.gameObject; |
44 | + | else |
45 | - | |
45 | + | { |
46 | - | // Sends the frontmostRaycast to a function called OnLeftClick in a script attached to whatever the leftClickedObject is. |
46 | + | if (sr.sortingLayerID != 2) // Foreground |
47 | - | leftClickedObject.SendMessage("OnLeftClick", frontmostRaycastHit, SendMessageOptions.DontRequireReceiver); |
47 | + | throw new Exception("You updated sorting layers but forgot to update this code!"); |
48 | - | } |
48 | + | sortingLayerOrder = 2; |
49 | - | } |
49 | + | } |
50 | - | // If the right mouse button is clicked anywhere... |
50 | + | |
51 | - | else if (Input.GetMouseButtonDown(1)) |
51 | + | // Assign base value for layer based on layer order |
52 | - | { |
52 | + | // 1st layer = 0 to 65535 |
53 | - | // frontmostRaycastHit stores information about the RaycastHit2D that is returned by GetFrontmostRaycastHit() |
53 | + | // 2nd layer = 65536 to 131,070 |
54 | - | frontmostRaycastHit = GetFrontmostRaycastHit(); |
54 | + | // 3rd layer = 131,070 to 196,605 |
55 | // Each value increases by ushort.MaxValue to ensure that the highest value in a prior layer can never be | |
56 | - | // If frontmostRaycastHit is true, i,e the user hasn't clicked on nothing, i.e GetFrontmostRaycastHit() didn't return nothing... |
56 | + | // greater than the lowest value in the next layer. |
57 | - | if (frontmostRaycastHit) |
57 | + | uint sortingLayerBase = sortingLayerOrder * ushort.MaxValue; |
58 | - | { |
58 | + | |
59 | - | // Assigns the game object that the collider that has been clicked on to rightClickedObject. |
59 | + | // Actual sort order is layer base value + object order |
60 | - | rightClickedObject = frontmostRaycastHit.collider.gameObject; |
60 | + | uint sortOrder = sortingLayerBase + uSortingOrder; |
61 | - | |
61 | + | |
62 | - | // Sends the frontmostRaycast to a function called OnLeftClick in a script attached to whatever the rightClickedObject is. |
62 | + | // If sort order is same (mostly to ensure we always have something) or higher than our highest so far... |
63 | - | rightClickedObject.SendMessage("OnRightClick", frontmostRaycastHit, SendMessageOptions.DontRequireReceiver); |
63 | + | if (sortOrder >= highestSortOrder) |
64 | - | } |
64 | + | { |
65 | - | } |
65 | + | // Save new high value |
66 | - | } |
66 | + | highestSortOrder = sortOrder; |
67 | ||
68 | - | function GetFrontmostRaycastHit(): RaycastHit2D |
68 | + | // This hit is our current front-most collider |
69 | frontMostHit = hit; | |
70 | - | // Store the point where the user has clicked as a Vector3. |
70 | + | } |
71 | - | var clickPosition : Vector3 = Camera.main.ScreenToWorldPoint(Input.mousePosition); |
71 | + | } |
72 | - | // Retrieve all raycast hits from the click position (to the same click position - more a dot than a ray) and store them in an array called "hits". |
72 | + | |
73 | - | var hits : RaycastHit2D[] = Physics2D.LinecastAll (clickPosition, clickPosition); |
73 | + | // If left mouse or finger just went down between last frame and this one... |
74 | if (Input.GetMouseButtonDown(0)) | |
75 | - | // If the raycast hits something... |
75 | + | { |
76 | - | if (hits.length != 0) |
76 | + | // Fire OnLeftDown event if this object has one |
77 | - | { |
77 | + | frontMostHit.SendMessage("OnLeftDown", SendMessageOptions.DontRequireReceiver); |
78 | - | // A variable that will store the frontmost sorting layer that contains an object that has been clicked on as an int. |
78 | + | } |
79 | - | var topSortingLayer : int = 0; |
79 | + | |
80 | - | // A variable that will store the index of the top sorting layer as an int. |
80 | + | // If left mouse or finger is down... |
81 | - | var indexOfTopSortingLayer : int; |
81 | + | if (Input.GetMouseButton(0)) |
82 | - | // An array that stores the IDs of all the sorting layers that contain a sprite in the path of the linecast. |
82 | + | { |
83 | - | var sortingLayerIDArray : int[] = new int[hits.length]; |
83 | + | // Fire OnLeftHoverDown event if this object has one |
84 | - | // An array that stores the sorting orders of each sprite that has been hit by the linecast |
84 | + | frontMostHit.SendMessage("OnLeftHoverDown", SendMessageOptions.DontRequireReceiver); |
85 | - | var sortingOrderArray : int[] = new int[hits.length]; |
85 | + | } |
86 | - | // An array that stores the sorting order number of the frontmost sprite that has been clicked. |
86 | + | |
87 | - | var topSortingOrder : int = 0; |
87 | + | // Always fire OnHover if this object has one |
88 | - | // A variable that will store the index in the sortingOrderArray where topSortingOrder is. This index used with the hits array will give us our frontmost clicked sprite. |
88 | + | frontMostHit.SendMessage("OnHover", SendMessageOptions.DontRequireReceiver); |
89 | - | var indexOfTopSortingOrder : int; |
89 | + | } |
90 | } |