- Home /
How to order RaycastAll by distance on IOS
Hi. I'm working on a code that selects elements, if clicked on coloured pixel. As described in one of my other question here
Here's the current code I have and it works. But the problem is that the current method of ordering RaycastAll does not work on IOS.
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
public class AlphaTest : MonoBehaviour {
private RaycastHit[] hits;
private Ray ray;
Camera myCam;
private GameObject selectedPlayer = null;
List<GameObject> disabledGameobjects = new List<GameObject>();
// Use this for initialization
void Start () {
myCam=Camera.main;
}
void Update() {
ray = myCam.ScreenPointToRay(Input.mousePosition);
//When mouse left button is pressed down | This Fires only once
if(Input.GetMouseButtonDown(0)){
hits = Physics.RaycastAll(ray).OrderBy(h=>h.distance).ToArray();//Order raycastall by hit distance
for(int i=0;i<hits.Length;i++)
{
if(hits[i].collider.tag=="Player")
{
selectedPlayer = hits[i].collider.transform.gameObject;
Renderer renderer = hits[i].collider.renderer;
MeshCollider meshCollider = hits[i].collider as MeshCollider;
if (renderer == null || renderer.sharedMaterial == null || renderer.sharedMaterial.mainTexture == null || meshCollider == null)
return;
Texture2D texture = renderer.material.mainTexture as Texture2D;
Vector2 pixelUV = hits[i].textureCoord;
pixelUV.x *= texture.width;
pixelUV.y *= texture.height;
Color pixel = texture.GetPixel((int)pixelUV.x, (int)pixelUV.y);
Debug.Log(pixel.a);
if(pixel.a < 1){
//We hit a transparent pixel
selectedPlayer.renderer.material.color = Color.black;
selectedPlayer.collider.enabled=false;
disabledGameobjects.Add(selectedPlayer);
}
else if(pixel.a >= 1){
//We did not hit a transparent pixel
selectedPlayer.renderer.material.color = Color.white;
Debug.Log(selectedPlayer.name);
return;
}
}
}
}
//While mouse left button is held down| This Fires every frame
if(Input.GetMouseButton(0)){
}
//When mouse left button is released | This Fires only once
if(Input.GetMouseButtonUp(0)){
foreach(GameObject disabledGameobject in disabledGameobjects){
disabledGameobject.collider.enabled=true;
disabledGameobject.renderer.material.color=Color.white;
}
disabledGameobjects.Clear();
}
}
}
It just gives me the following:
ExecutionEngineException: Attempting to JIT compile method 'System.Linq.OrderedEnumerable`1:GetEnumerator ()' while running with --aot-only.
I have done some research and I found that IOS dosn't like OrderBy on Arrays. So my first thought was to convert the array hits to a generic List, then order the List and then convert the ordered List back to a array.
Something Like this
hits= Physics.RaycastAll(ray);
List<RaycastHit>hitlist = new List<RaycastHit>(hits).OrderBy(h=>h.distance).ToList();
hits=hitlist.ToArray();
Which worked, but the error remained on IOS. So how can I order my raycastall by distance so that it would also work on IOS?
Actually I think the problem might not be that I'm using OrderBy. Or at least there seems to be no problems in one of my other scripts that uses Order by on gameobjects like this
GameObject[]players;
void Start () {
players= GameObject.FindGameObjectsWithTag("Player").OrderBy( go => go.name ).ToArray();
}
This seems to be fine with IOS. So I guess the problem Is that the RaycastAll array is empty by default
Answer by Hiilo · Oct 27, 2013 at 10:47 AM
I think I got it. Or at least it seems to be working and not throwing any errors on IOS. Took my time and tried out some solutions as suggested here: http://answers.unity3d.com/questions/22261/sorting-builtin-arrays.html And here's my final code:
using UnityEngine;
using System.Collections;
using System.Linq;
using System.Collections.Generic;
using System;
public class AlphaTest : MonoBehaviour {
private RaycastHit[] hits;
private Ray ray;
Camera myCam;
private GameObject selectedPlayer = null;
List<GameObject> disabledGameobjects = new List<GameObject>();
List<RaycastResult> hitList = new List<RaycastResult>();
// Use this for initialization
void Start () {
myCam=Camera.main;
}
public class RaycastResult: IComparable<RaycastResult>
{
public float distance;
public Collider collider;
public Vector2 textureCoord;
public RaycastResult(RaycastHit hit)
{
distance = hit.distance;
collider = hit.collider;
textureCoord = hit.textureCoord;
}
public int CompareTo(RaycastResult other)
{
return distance.CompareTo(other.distance);
}
}
void SortDistances()
{
hitList.Clear();
hits= Physics.RaycastAll(ray);
foreach(RaycastHit hit in hits)
{
hitList.Add(new RaycastResult(hit));
}
hitList.Sort();
}
void Update() {
ray = myCam.ScreenPointToRay(Input.mousePosition);
//When mouse left button is pressed down | This Fires only once
if(Input.GetMouseButtonDown(0)){
SortDistances();
Debug.Log("HIT-----------------------------");
foreach(RaycastHit hit in hits){
Debug.Log(hit.collider.name+""+hit.distance);
}
Debug.Log("LIST-----------------------------");
foreach(RaycastResult listItem in hitList){
Debug.Log(listItem.distance);
}
for(int i=0;i<hitList.Count;i++)
{
if(hitList[i].collider.tag=="Player")
{
selectedPlayer = hitList[i].collider.transform.gameObject;
Renderer renderer = hitList[i].collider.renderer;
MeshCollider meshCollider = hitList[i].collider as MeshCollider;
if (renderer == null || renderer.sharedMaterial == null || renderer.sharedMaterial.mainTexture == null || meshCollider == null)
return;
Texture2D texture = renderer.material.mainTexture as Texture2D;
Vector2 pixelUV = hitList[i].textureCoord;
pixelUV.x *= texture.width;
pixelUV.y *= texture.height;
Color pixel = texture.GetPixel((int)pixelUV.x, (int)pixelUV.y);
//Debug.Log(pixel.a);
if(pixel.a < 1){
//We hit a transparent pixel
selectedPlayer.renderer.material.color = Color.black;
selectedPlayer.collider.enabled=false;
disabledGameobjects.Add(selectedPlayer);
}
else if(pixel.a >= 1){
//We did not hit a transparent pixel
selectedPlayer.renderer.material.color = Color.white;
//Debug.Log(selectedPlayer.name);
return;
}
}
}
}
//While mouse left button is held down| This Fires every frame
if(Input.GetMouseButton(0)){
}
//When mouse left button is released | This Fires only once
if(Input.GetMouseButtonUp(0)){
foreach(GameObject disabledGameobject in disabledGameobjects){
disabledGameobject.collider.enabled=true;
disabledGameobject.renderer.material.color=Color.white;
}
disabledGameobjects.Clear();
}
}
}
Answer by VesuvianPrime · Oct 23, 2013 at 08:59 PM
It's ugly, but you could write your own sorting algorithm:
http://stackoverflow.com/questions/14768010/simple-bubble-sort-c-sharp
Never do the bubble sort! It costs O(N^2) and there are always intended sorting algorithms in framework! Even if you want use custom sort use Shall-algorithm or quick sort, there are lot of samples of their implementation over the internet.
Your answer
Follow this Question
Related Questions
The name 'Joystick' does not denote a valid type ('not found') 2 Answers
Why is passing this array causing some of its values to become null? 2 Answers
Unity Mono AOT iOS failure for generic method 0 Answers
Load txt file (CSV) into Generic Dictionary Javascript 1 Answer
Using Generics with arrays. 1 Answer