Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
0
Question by Razorwings18 · Mar 20, 2015 at 02:19 PM · listmethodgenericsconstraintstypecasting

Can't get method using Generics to populate List

I have the following scenario:

     public class Human_Behaviour : MonoBehaviour {
     
     public static List<Human_Behaviour>[,] humanObject;
     
     /*...
     ...
     STUFF HAPPENS HERE THAT POPULATES humanObject
     ...
     ...*/
     
     static List<T> CheckCollisionsAtPoint<T>(){
         List<T> hitHuman = new List<T>();
     
         if (typeof(T) == typeof(Human_Behaviour)){
                                             hitHuman.Add(humanObject[0,0][0]);
                                         }
                                         else{
                                             hitHuman.Add(humanObject[0,0][0].gameObject);
                                         }
         return hitHuman;
       }
     }


Of course, this gives me the following errors: "Argument #1' cannot convert Human_Behaviour' expression to type T'" and "Argument #1' cannot convert UnityEngine.GameObject' expression to type T'"

I tried to add Constraints to the method declaration:

 static List<T> CheckCollisionsAtPoint<T>() where T:GameObject, Human_Behaviour{
     }

But was not allowed, since I read C# does not allow multiple inheritance.

I tried to throw a couple of Casts where I believed was reasonable, but wouldn't work either.

So, how would I get the hitHuman.Add lines to work?

WARNING: This code is an extremely simplified example, not code in use in a real application. I'm interested in whether this very particular case can be made to work.

Comment
Add comment · Show 6
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Baste · Mar 20, 2015 at 03:35 PM 0
Share

What are you trying to do? As in, what is CheckCollisionsAtPoint supposed to do?

It seems to be that you're trying to use a generic list in a context where you need actual types. I'm suspecting that what you're trying to do should be solved by method overloading, but I'll need to see code where you're using CheckCollisionsAtPoint to be sure.

avatar image NoseKills · Mar 20, 2015 at 04:05 PM 0
Share

And is humanObject supposed to be a list of arrays or an array of lists?

avatar image Razorwings18 · Mar 20, 2015 at 06:21 PM 0
Share

@Baste This is just an extremely simplified example, since I'm actually interested in this very particular form of solving the problem. The "real" code is already working, but using Generics would make it simpler to read and maintain.

@Baste @Nose$$anonymous$$ills: If you're curious, in the real case, humanObject is a matrix that divides a terrain in smaller squares (therefore the [,] need, i.e. the first 100x100 patch of terrain would be assigned [0,0]) and holds a list of all Human_Behaviour within that patch (and that's the 3rd index, and why it has to be a List)

What it does: This is a way to "virtualize" Human_Behaviour character GameObjects, where when they go offscreen, I convert their position to just numbers in a Vector3, and "move" those numbers ins$$anonymous$$d of moving the GameObject with its collider and other stuff attached. In a my mobile game with 200+ characters, this saves a cr*pload of performance.

The real "CheckCollisionsAtPoint(Vector3 point, float radius)" is used as a form of OverlapSphere that returns these "virtual" Humans (pointers to Human_Behaviour) as well as real collisions with Enabled GameObjects (containing Human_Behaviour as a Component) at that point.

So, in the "virtual" collision part of this collision check we get a Human_Behaviour, and in the "real" collision part we get a Collider (where it's easy to get a GameObject).

In several parts of the game, I need to get either Human_Behaviours or GameObjects returned from CheckCollisionsAtPoint depending on what I'll do with it next.

Since converting Human_Behaviour to GameObject wastes a little of performance (need to use, say, "human_BehaviourObject.gameObject") and converting GameObjects to Human_Behaviour wastes a lot more ("human_BehaviourObject.GetComponent"), I wanted to use Generics to avoid this conversion where it's unnecessary (since either the "virtual" or the "real" collision is certain to have the type I want).

Sorry the reply is so long... but you DID ask :) Thanks for your replies.

avatar image Baste · Mar 20, 2015 at 11:33 PM 0
Share

So, the reason I asked is because the method takes no arguments, so it doesn't make sense to have it generic unless it's in a generic class. A generic method does the same thing regardless of what class you send in, while you want two different behaviours at different points.

If you need two different behaviours from the method at different points, and you know what behaviour you need at any point, you could just make two different methods - checkVirtualCollisions and checkRealCollisions.

I might not be understanding what you're actually looking for - maybe you have a snippet of a real use case you could post?

avatar image Razorwings18 · Mar 21, 2015 at 01:11 AM 0
Share

Sorry, I should've mentioned this is just a test case from the go. I've since added a note at the end of the question.

As it is right now, the method is split into two -kind of like you mention-, the function call is overloaded, and it works. But I hate it, since using Generics should've given me the whole method, in one tidy single spot, and nicely readable at one glance.

Here's the "true" code I want to use: public static List CheckCollisionsAtPoint(Vector3 point, float radius = 0) where T:$$anonymous$$onoBehaviour{ // Since humans have no colliders sometimes, this function checks if a human character is hit at POSITION. Optionally checks for collision at a certain DISTANCE radius. List hitHuman = new List();

         radius += 0.5F; // Add the character's width to the radius checked
         
         /****** FIRST, CHEC$$anonymous$$ COLLISIONS WITH INVISIBLE (VIRTUAL) OBJECTS IN humanObject $$anonymous$$ATRIX ********/
         // Based on the radius of the collision, see by how many positions in the humanObject matrix we have to extend the search
         int matrixRadius = $$anonymous$$athf.CeilToInt(radius / humanObjectTerrainDivision);
         
         // Find in which position of the humanObject matrix the center point of the collision check falls
         int[] centerPoint = WorldToHumanObjectPosition(point);
         
         // Check for hit humans in the humanObject, within matrixRadius distance from centerPoint
         for (int x = (centerPoint[0] - matrixRadius); x <= centerPoint[0] + matrixRadius; ++x){
             for (int y = (centerPoint[1] - matrixRadius); y <= centerPoint[1] + matrixRadius; ++y){
                 if ((x >= 0) && (x < humanObject.GetLength(0)) && (y >= 0) && (y < humanObject.GetLength(1))){
                     // This matrix check is within humanObject boundaries
                     if (humanObject[x,y] != null){
                         for (int i=0; i < humanObject[x,y].Count; ++i){
                             if (humanObject[x,y][i]){
                                 if (Vector3.Distance(humanObject[x,y][i].transform.position, point) < radius){
                                     // This human was hit
                                     if (typeof(T)==typeof(Human_Behaviour)){
                                         hitHuman.Add(humanObject[x,y][i]);
                                     }
                                     else{
                                         hitHuman.Add(humanObject[x,y][i].gameObject);
                                     }
                                 }
                             }
                         }
                     }
                 }
             }
         }
         
         /****** THEN, CHEC$$anonymous$$ REAL COLLISIONS WITH ACTUAL COLLIDERS IN VISIBLE OBJECTS ********/
         int character$$anonymous$$ask = 1 << GlobalCharacterData.character$$anonymous$$askPosition;
         Collider[] humanCollisions = Physics.OverlapSphere(point, radius, character$$anonymous$$ask);
         if (humanCollisions.Length > 0){
             for (int i = 0; i < humanCollisions.Length; ++i){
                 if (typeof(T)==typeof(Human_Behaviour)){
                     hitHuman.Add(humanCollisions[i].GetComponent<Human_Behaviour>());
                 }
                 else{
                     hitHuman.Add(humanCollisions[i]);
                 }
             }
         }
         
         return hitHuman;
     }

Show more comments

1 Reply

· Add your reply
  • Sort: 
avatar image
0

Answer by spiceboy9994 · Mar 20, 2015 at 11:43 PM

Can you paste the actual line that gives you the error?, you mention the error the error but not the line where the compiler or the console detects it.

Another thing:

 hitHuman.Add(humanObject[0,0][0]);

that is defined as strongly typed

 List<Human_Behaviour> hitHuman

My guess is you cannot add a strongly typed variable to a List of generic T. Have you tried this?

 hitHuman.Add((T)humanObject[0,0][0]);

Hope this helps a bit

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Razorwings18 · Mar 21, 2015 at 12:49 AM 0
Share

In lines... "hitHuman.Add(humanObject[0,0][0]);" and "hitHuman.Add(humanObject[0,0][0].gameObject);" I get the error "Argument #1' cannot convert Human_Behaviour' expression to type T'**" and "**Argument #1' cannot convert UnityEngine.GameObject' expression to type T'" ... which is quite logical, since the compiler has no idea what T will be.

So, of course, the first thing I did was try to typecast with hitHuman.Add((T)humanObject[0,0][0]); like you said, but then I get "Cannot convert type Human_Behaviour' to T'", which again, has its logic for the same reason.

In my brain, Constraints should've fixed both issues, but when I tried to add Constraints as mentioned in the Question, the error was: "The class type constraint `Human_Behaviour' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list"

...and moving Human_Behaviour to the front of the Constraints enumeration, prompted the same message but with "'GameObject' must be listed before..." ins$$anonymous$$d.

I even tried to add $$anonymous$$onoBehaviour and object as Constraints to see what that would do, but with the same result.

Thanks for your help.

avatar image spiceboy9994 · Mar 23, 2015 at 04:27 PM 0
Share

Another observation, why don't you try to get the Human_Behavior part working first before using the gameobject method. I know since the method is generic, it may work with any kind of types, but that may help you to narrow down the issue. Another thing is that I've realized your Human_Behavior class is inheriting from $$anonymous$$onoBehavior, have you changed your constraint to be

 static List<T> CheckCollisionsAtPoint<T>() where T:$$anonymous$$onoBehavior

$$anonymous$$aybe that could help you out on the Human_Behavior Part.

Or a more generic one

     static List<T> CheckCollisionsAtPoint<T>() where T:Component

That may help you with both $$anonymous$$onoBehavior and GameObject types.

Just ping me if that works...

avatar image Razorwings18 · Mar 23, 2015 at 10:12 PM 0
Share

The method already works for both Human_Behaviour and GameObject in both its "regular" form and when using Generics (by adding "where T:Human_Behaviour" or "where T:GameObject"). The problem comes when trying to accept both types.

I had already tried using $$anonymous$$onoBehaviour in the "where" clause, and on your suggestion I tried Component just for kicks, with the same result (the errors stated in my previous comments, "Cannot convert ...")

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

5 People are following this question.

avatar image avatar image avatar image avatar image avatar image

Related Questions

A node in a childnode? 1 Answer

Are generic constraints supported? 0 Answers

How to make sense of error message? 1 Answer

Implicit Downcast warning from "List.IndexOf" ...Bad? Unavoidable? 1 Answer

Is "new List ()" worse than using Clear()? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges