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
1
Question by Sendatsu_Yoshimitsu · Dec 19, 2014 at 03:37 AM · c#listsimulation

Fast way to find a specific myClass across many List?

I have a simulation class which contains a list for each Room in the game, and each Room has a list of each NPC in that room. When the player enters a room every NPC the simulation says is in that room gets an instantiated model which is given a reference to that NPC's CharacterSheet class in the simulation, so that anything that happens to the spawned character can be added to their local CharacterSheet. When the NPC despawns, I would like to re-locate the position of its CharacterSheet in the simulator, and set the simulator's sheet equal to the local NPC's sheet, effectively applying any changes that occurred (injuries, item acquisitions) while the NPC was spawned.

Is there a simple, fast way to do this I'm not thinking of? What I'm doing right now is giving each NPC a unique ID number in their CharacterSheet, and iterating through each Room until I find a character whose ID matches the one of the NPC I'm trying to despawn, but this is heinously slow already, and if I'm having to do it 10-20 times every time the PC enters a room, things would slow to a crawl.

Comment
Add comment
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

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by Bunny83 · Dec 19, 2014 at 04:42 AM

Uhm, why don't you hold a reference to your simulation class in a script attached to your character object? If your simulation class holds your actual values, why do you use a local CharacterSheet in the first place? When you create the visual representation of your NPC, you could simply assign it the reference to the simulation class instance that represents that NPC logically.

edit
In reply to @BoredMormon's comment:

Classes are passed by reference

Unfortunately "passing" the wrong terminology :) A lot people mix up those terms and concepts and in the end most think they understood how it works but actually got it wrong.

When you assign or pass a variable to another variable or to a method it's always "passed by value". The only exceptions are "ref" and "out" parameters of methods.

When you assign a variable to another variable you copy the content of the variable into the other variable. For method parameters it's exactly the same. What most people seem to struggle with is that the content of a variable can be a reference. That's the case for all reference-types. Reference-types aren't stored on the stack like local variables. You actually never get direct access to the content of a reference type (like a class instance) since you only can access this data indirectly by using a reference to that object.

Short example:

 public class SomeClass
 {
     public int i = 0;
 }
 
 
 //...
 SomeClass CreateObject()
 {
     SomeClass myVariable = new SomeClass();  // (1)
     SomeClass myOtherVariable = myVariable;  // (2)
     myOtherVariable.i = 42;                  // (3)
     return myVariable;                       // (4)
 }
 
 // ...
 
 SomeClass a = CreateObject();                // (5)
 SomeClass b = a;                             // (6)
 a = new SomeClass();                         // (7)


Inside the CreateObject method there are two local variables "myVariable" and "myOtherVariable". At (1) we create a new instance of our "SomeClass" class. The new operator however does not return the object that is created, but a reference to that object. That reference is copied into "myVariable". You can now use this variable to indirectly use that object that is referenced.

At (2) we copy the content of myVariable to myOtherVariable. Both variables now contains the same reference. At (3) we use our copy of the reference to indirectly access our object on the heap and change it's variable "i" to 42.

At (4) we return the value of myVariable, which is the reference to our class instance .At (5) we receive the copy of that reference and copy it into the variable "a". At the same time the variables myVariable and myOtherVariable go out of scope and extent (since we've left the method). Those variables don't exist anymore. However our class instance still exists since we still have a copy of the reference stored in "a". At (6) we again copy the content of the variable "a" to the variable "b". Now at (7) when we overwrite the content of our variable "a" with a reference to a new instance we just created, the content of the variable "b" will stay the same since it's an independet copy of the reference to our first object. When now reading "b.i" it would return "42" while "a.i" now returns "0" since the reference stored in "a" references the new object.

A struct on the other hand is a value type. The whole struct is actually stored directly in a variable as one big value / content. Vector3 for example is a struct and therefore value type. Let's do something similar to what we just did with a class:

 Vector3 v1 = new Vector3(1,2,3);     // (1)
 Vector3 v2 = v1;                     // (2)
 v2.x = 42;                           // (3)
 Debug.Log(v1);                       // (4)

At (1) we initialize our v1 variable with a Vector(1,2,3) unlike classes structs are stored directly inside the variable. So the content of v1 is a Vector(1,2,3) and not a reference to some place on the heap. At (2) we again copy the content of the variable into our second variable "v2". Now if we change the value of the "x" member of our v2 variable we directly modify the value which is stored inside v2. That means the content of v1 is not modified which you can prove at (4) since it would print (1,2,3).

So as said variable assignment or passing of a variable to a method will always copy the content of a variable. Now the exceptional case, the ref keyword. The ref keyword allows you to pass a variable by reference and not by value as usual. The point of this is that inside of that method you can actually directly modify the content of the variable. I've often read a statement like: "it makes no sense to pass a variable of a reference type by reference since you already can modify the object the reference references". It's true that you can modify the object behind the reference, but that's not the point of the ref keyword. The ref keyword allows you to modify the content of a variable. Again, the content of a reference-type variable is the reference, not the object behind the reference.

Example:

 void DoMagic(ref SomeClass aObj)
 {
     aObj.i = 111;            (4)
     aObj = new SomeClass();  (5)
     aObj.i = 222;            (6)
 }
 //...
 SomeClass a = SomeClass();   (1)
 SomeClass b = a;             (2)
 DoMagic(ref a);              (3)
 Debug.Log("a.i == " + a.i);  (7)
 Debug.Log("b.i == " + b.i);  (8)

At (1) we create a new instance of our class and store the reference in variable "a". At (2) we create a copy of the reference in "b". Just to recap, both variables no point to the same object. At (3) we call our method "DoMagic" and pass the variable a by reference. Since the parameter is a ref-parameter we have to pass the variable like this.

Inside DoMagic at (4) we set the "i" variable of the object behind the reference to "111". At (5) we overwrite the content of aObj with a new instance. Since aObj is a reference to the variable "a" we directly replace the content of the variable "a" outside of the method. At (6) we set the "i" variable of our new object to "222". At (7) and (8)you can observe that it will print:

 "a.i == 222"
 "b.i == 111"

As you can see DoMagic hasn't only changed the content of the variable "i" in our first object (where we still have a reference stored in "b"), but also replaced the reference that was stored in "a" with a new object.

If you would do the same without the ref keyword, your Debug logs would print:

 "a.i == 111"
 "b.i == 111"

That's because if "aObj" is not a ref-parameter it's an ordinary local variable of our method. You can use it at (4) to set the value of "i", just like in the other example. However, at (5) you would only overwrite the content of the local variable which at the moment hold a copy of the reference to our first object. That wouldn't affect the variable "a" outside of the method since the content of a has been copied inthe aObj. When DoMagic is done and returns to the main program the newly created class instance (with i set to "222") is now marked for garbage collection since there is no reference left to that object.

Just as final note: You may ask yourself "How are ref parameters actually implemented in C#", the answer is: by cheating :D. Usually pointers (not references, actual pointers) aren't allowed in the managed environment. You usually have to use an unsafe context to mess around with pointers. However in this special case the compiler actually creates a pointer to the memory location where the variable is stored and passes that pointer (of course, by value, the address value) to the method. When using the "aObj" variable inside the method you working indirectly with the variable "a" through a pointer.

If you like reading great analogies you have to read this one by Eric Lippert (he's one of the people who designed the C# language and has written major parts of microsofts C# compiler). Even this question was about C++ it applies to almost any language which has pointers.

Comment
Add comment · Show 4 · 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 Sendatsu_Yoshimitsu · Dec 19, 2014 at 05:02 AM 0
Share

Here's where I'm unclear: if on the spawned NPC I give him a variable of type CharacterSheet, and set it equal to the sheet in the simulation, won't that create a new instance of the sheet, not a reference to the original one?

avatar image Sendatsu_Yoshimitsu · Dec 19, 2014 at 01:46 PM 0
Share

Just verified for myself that it works by reference, not copying- thank you! :)

avatar image Kiwasi · Dec 19, 2014 at 02:20 PM 0
Share

For clarification

  • Classes are passed by reference

  • Structs and primitives are passed by value

So as long as CharacterSheet is a class you can pass it around as much as you like, and still be playing with the original.

avatar image Bunny83 · Dec 19, 2014 at 04:39 PM 0
Share

@Bored$$anonymous$$ormon: Hmm i wanted to write a short reply, but it somehow got 2500 characters beyond the comment limit ^^

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

28 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

C# Randomly Adding Elements from stringListA to stringListB 1 Answer

C# Adding Multiple Elements to a List on One Line 5 Answers

Confused about copying Lists! 1 Answer

List of C# scripting definitions 1 Answer

Best way to add specific child objects to a list. 1 Answer


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