Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Motion Controller

Discussion in 'Assets and Asset Store' started by Tryz, Feb 21, 2014.

  1. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    TY Both and good advice :)

    OK I substituted the new TPose that comes with UMA 2.7 as suggested by kenamis above and it's a huge improvement (in my eyes) to the basic character.

    OK, I'll go on and do some basics parts now with other things such as Inventory pro integration (which I know is going to be interesting with weapons and displaying the correct ones, although the video by Secret Anorak I know works with clothing) etc etc.

    2 quick questions though...
    1) Any ideas on the jump issue with the fact it works in the editor but not in build.
    2) Would Bone Controller even work on UMA characters in the same way since theres no actual avatar to look at in the editor window, or could you do it in pause mode in play with a UMA character that has been through bone builder?

    Thanks again. Onward and Upward.

    M
     
  2. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,676
    Yes, BC should work on UMAs because they are existing characters at the time the IK occurs.

    There could possibly be tricky bits in setup, for the usual reason (plugin expects a character skeleton in editor).
     
    Tryz likes this.
  3. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    From my (brief) tests, Bone Builder resolves the tricky bits of getting Bone Controller setup. I used to configure everything in script, but I was able to get rid of all of that.
     
    Tryz, MaliceA4Thought and hopeful like this.
  4. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    @moria15 , I'm going through the posts and it loos like @TeagansDad and @hopeful have covered everything. These guys have official ootii super hero capes. So, you can absolutely trust what they say. :D

    Is this still an issue?

    I'm wondering if your gravity setting or world scale may be different than the default. The jumps should disable ground-locking automatically.

    I can't think of any reason they would act different between editor and build. What's your frame-rate in each?
     
    Last edited: Jan 31, 2018
    TeagansDad likes this.
  5. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    There shouldn't be an issue duplicating the ladder. Just make sure that the duplicate is set to the layer you're using in the Climb Ladder motion.

    When you set the ladder's layer, you can also set the character to collide with that layer. On the Actor Controller, simply add the layer to the "Collision Layers" property.

    The Climb Layer motion really doesn't care about the true shape of the ladder (ie rungs and rails). It's just recognizing a box collider and allowing you to animate up and down. The animation looks like you're climbing the ladder.

    There's nothing that officially says "your character is 6' tall". That said, you could use my Basic Attributes component and add a float attribute called "Height" and use that.

    That variable shouldn't be exposed. That was an old value that isn't used.

    The Basic Interaction motion is the starting point and it looks for an Interactable Core that is near by. The motion then calls the core's OnActivate() function when it's time to activate.

    Yes. Add your animations to BasicInteraction-SM. Then, set that form on Interactable Core. That's how the motion knows which animation to use.

    You can certainly create your own "interaction" motion if there's more things you want to do. For example, you could inherit from mine and do an inventory check to make sure you have the key to open the chest.
     
  6. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Hey @zeb33 , How are you doing with this?

    I'm not sure what OnUp() does. I'm guessing that's from Easy Touch.

    I would expect the looping to end because it would go the number of frames the button is down when not using an "IsJustPressed" kind of function.

    Please let me know if you need more help. Sorry for the delay. :(
     
  7. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Greetings and welcome back :) Hope you are feeling better :)

    I trust everything that @TeagansDad and @hopeful say, they have helped a great deal and deserve medals :)

    OK.. what you said triggered some playing at my end.

    I am doing all this testing in a small demo scene and am running at ultra with V-sync off so was getting 400FPS+ in both editor and runtime.

    I turned V-sync back on and locked it at 60FPS and the jumps started working again in the build version.. so that's solved :)

    As usual, I have 2 more questions that have been bugging me a little, but not worth fussing about till now :)

    1) I have the targetting turned on by default and am using the targetting reticule. When using the bow... releasing the right mouse button turns the reticule off and even though I have looked in a lot of scripts regarding the archery, I've missed the turning off the reticule.. if you could give me a pointer that would be great as I want that reticule to stay onscreen always.

    I can always write a simple script that watches it and if it's off turn it back on.. that's what I am doing now, but stopping it turning off would be preferable.

    2) Spell casting. Am using some of the extra spells from the Realistic effects pack.. (awesome) as per your vault item and with all the camera shakes set off. Now.. before I installed Archery, the fire dragon spell was started by pressing the button and then you clicked on the ground to generate the second part of the spell. Where you targetted there was a shadow on the ground you could position the spell to fire at. After installing Archery, that shadow never appears and the spell cannot be completed. Spells which are just fire and forget without needing a target such as firering or similar work fine, but any spell that requires a target area such as FireDragon, Teleport or Firewall start but then die because there is no target.

    Any ideas on both the above would be wonderful ty and then I believe I have a great working prefab of a UMA player character with most packs installed :) (Yes I expect I will get to shooter and swimming later, but they are not as important right now)

    Regards

    M
     
    Last edited: Jan 31, 2018
  8. francescobr

    francescobr

    Joined:
    Apr 2, 2017
    Posts:
    45
    Having ladders that did not work on their own layers did solve the climbing not happening or happening like an obstacle climb. Anyway I still cannot make it climb inclined ladders. And I cannot have only ladders perfectly perpendicular to the ground. Any advice?

    I think you misunderstood what I meant. I meant : how can I know how much tall my player model is? Is there any way for unity to tell me "this mesh is 2 units tall"? It's kind of a noob question I know...


    That's a real good advice, I'll do locked chests like that, thank you :)
     
  9. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Ladders need to be perpendicular to the ground or close enough that the raycasts can hit them. You could use my ClimbLadders.cs as a base and create a custom motion that supports tilted ladders, but that's not what it does out-of-the-box.

    Oh... I'm not sure. You may have to Google that.

    NP. :)
     
  10. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    I think you can do this with the bounds command....

    http://unity3d.com/support/documentation/ScriptReference/Renderer-bounds.html
    http://unity3d.com/support/documentation/ScriptReference/Bounds.html
    http://unity3d.com/support/documentation/ScriptReference/Bounds-size.html

    M
     
    Tryz likes this.
  11. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Agreed! :D

    My jumps should be frame-rate independent (if I remember correctly). I'll try v-sync off and let you know what I find. But, this is a good starting point.

    On the Basic Ranged Attack motion is a property called "Manage Reticle". Uncheck that and archery won't turn it on or off.

    Let me test this and I'll get back with you. I've not seen that, but it may be something I missed.
     
    MaliceA4Thought likes this.
  12. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    TY, I'll work through this lot... if you need it, as always, a small (in unity terms) project can be sent :)

    M
     
  13. francescobr

    francescobr

    Joined:
    Apr 2, 2017
    Posts:
    45
    Tryz likes this.
  14. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    I found out what's going on with that.

    In the Actor Core is a setting called Skin Width:



    If the ground is within the "Skin Width", I force the character to the ground. This helps with things like ramps and determining if you've landed. It's like "Force Grounding", but used after distance tests.

    When the frame rate is super high, the movement is super small. At a frame rate of 600, the jump was just barely moving you up vertically (in a single frame) which was smaller than the default Skin Width. So, I'd force you to the ground. By changing the Skin Width to 0.001, I was able to jump since the high frame rate movement (per frame) now exceeded the Skin Width.

    Removing V-sync also helped because your frame rate was no longer super high. That meant the normal movement was larger (each frame) and exceeded the default Skin Width.

    It's tricky, but I hope that makes sense.
     
    hopeful and MaliceA4Thought like this.
  15. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Awesome, yes I understand... and went into project, modified the skinwidth and removed the V-Blank and running at 400+FPS I have the jumps back in build :)

    TY :)
    M
     
    hopeful likes this.
  16. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    Just something I've been working on...

     
    Warspawn, Tryz and MaliceA4Thought like this.
  17. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Nice :) I can see that you are using Inventory pro (I think).. is that a UMA character or something else?

    If UMA, I may have some questions for you about dynamically adding weapons to the character or if you know of a video, I would appreciate it's source :) I am starting to think I am going to have to make some new slots and recipies.

    This is as far as I have got with MC/UMA/IPro with all the help you guys have given me so far. I have swords, archery and spellcasting in with UMA clothing swappable in Inventory Pro so far and the health is linked between IPro and MC.

    WIP.jpg

    Regards

    M
     
    Tryz likes this.
  18. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    @moria15 - I'm using a Fuse character for the moment. I hadn't worked on this project for a couple of months and I wanted a clean setup with 2017.3, so I created a new project and started bringing pieces one one at a time, making any fixes or tweaks necessary. I rewrote my InventoryProSource and InventoryProAttributeSource for example.

    Anyway, I already have UMA working (equipping weapons and wardrobe items)... I just haven't brought them in yet, as I wanted to get the basics polished up a bit first.

    This one uses Inventory Pro and my own extension to BasicInventory; when I equip the sword and shield in the Inv Pro UI (for example), they are attached to the character's belt and back. When I press Tab, the character draws (or stores) his weapons. This works with UMA characters too.
     
    MaliceA4Thought and Tryz like this.
  19. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    That was pretty much the way I was thinking of it... when the weapon changes on the inv pro character inventory, send a message to the MC inventory to place the details in the Instance and Resource path of the new weapon and then let MC work as normal letting the MC inventory swap the display item and therefore the owned weapon.

    The only Issue I see with that is keeping the two inventories in sync, but if both have the models etc in the single resource directory then it should be fairly easy to do.

    What I haven't done yet is add the Instance to the UMA character as there is no character in the Scene screen.. I have used Bone Builder so I think I can just add them to an appropriate bone.. will try that tomorrow :)

    M
     
  20. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    @moria15 - I wrote a class that inherits from BasicInventoryItem but includes additional properties to assist with linking everything together. I grab the item instance from the Inventory Pro item when it is equipped and set that on the ootii side.

    I've also got a number of data classes (as ScriptableObjects) which include all of the info such as Equip/Store motions, Motion Form, Attack Styles, equip/stored slots, whether the weapon is used in the primary or off hand, etc. I name these "Equipment Classes" the same as the Inv Pro Equipment Type, so all I need to do is query my own (simple) database for the correct Equipment Class, and then I've got everything I need. I don't have any custom Item Stats in Inv Pro for this purpose.

    Of course I'll share it.
     
    tchris, Tryz and MaliceA4Thought like this.
  21. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Sounds awesome.. I'll have a play first because it will be good learning for me, but if all else fails, I'll shout :)

    Thanks for the offer :)

    M
     
    TeagansDad and Tryz like this.
  22. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    101
    Hi there,


    I recently purchased motion controller and spells pack and was wondering if you are able
    to make those spells gamepad friendly? I’m currently not able to complete the cast even with
    the mouse. I guess the options would be to either make the spells cast a certain distance ahead of
    facing direction, or to have a ring graphic that becomes active on cast and can be positioned with
    the analog stick. I'm also using the rewired Input source.

    Please let me know your thoughts on this and thanks for all of your hard work.
     
  23. haywirephoenix

    haywirephoenix

    Joined:
    May 17, 2017
    Posts:
    101
    p.s: Spell editor is empty in every one there appears to be no nodes, is this a bug?
     
  24. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Hey @haywirephoenix ,

    They do work with gamepads as well. I just responded to the email you sent.
     
  25. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Morning :)

    Am trying to fire a trigger with my character... and it's not firing.

    If I add a rigidbody to my char then it fires fine, but the camera bounces up and down unless I set it to Kinematic. Having done that and setting Mass to 0.1 Darg and Angular Drag to 0 it works fine.

    Collisions are enabled in character in MC and collision layers are setup but it still won't fire the trigger.
    .
    Body Capsule is also setup to use Unity Colliders and enabled in all cases

    Am Using a UMA char, but it just struck me as odd.. am I missing something simple? (probably)

    M
     
  26. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    I just did a fresh install with Unity 5.6 and Unity 2017.3 and I'm seeing the spells as expected.






    No one else has reported an issue. So, I'm not sure why you're not seeing the contents of a spell.

    What OS and what version of Unity are you using?

    What if you import into a new project with only the Motion Controller and Spell Casting Motion Pack (no other assets)?
     
  27. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    For Unity to fire a trigger, a rigidbody must be in the mix (on the character or on the trigger). This follows Unity's collision matrix: https://docs.unity3d.com/Manual/CollidersOverview.html

    You can add a rigidbody to the character, but (as you found) you have to set it to Is Kinematic and disable gravity. Otherwise you have two components trying to control the character (the MC and the rigidbody).

    You also have to make sure you have a true Unity collider on your character as Unity doesn't care about my Body Shapes. You can add your own or check the "Use Unity Colliders" checkbox on the body shapes and I'll create them for you automatically.

    I hope that helps.
     
    TeagansDad and MaliceA4Thought like this.
  28. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,676
    Not sure if this is influencing you or not, but UMA makes a capsule collider for each character unless you tell it not to.
     
    Tryz likes this.
  29. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Yeah, I went through all the colliders and double checkd. Since MC adds one as well though, I may remove the UMA one.

    Solved it by putting a kinematic rigidbody on the trigger at this stage and all is working fine.

    I will prolly move it to the char though since without that to make it easier for combat etc.

    M
     
    Tryz likes this.
  30. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    OK whole new topic.

    Character health :)

    I have an attribute in MC called Health and, because I am using Inventory Pro, a health Stat. Now I want the Inventory pro one to be the master as it's easier to setup items to affect it and I don't want to try and have to balance the two.

    Now, if I have got it right from watching the videos, the Basic Damage reactor watches for Damage messages to the Actor and then looks in the Actor core for a "Health" attribute and subtracts the value in the Damage message.

    So in theory, if i swap the Damage reactor to look instead at the Inventory Pro Health Stat, rather than the Actor Core health Stat, then the update to the damage should be sent there instead?

    Now in the BasicDamageReactor theres a lot of (to me) complex code that is based on other components but in Activate() this bit...

    Code (CSharp):
    1.             if (mActorCore.AttributeSource != null)
    2.             {
    3.                 lRemainingHealth = mActorCore.AttributeSource.GetAttributeValue<float>(HealthID) - ((DamageMessage)mMessage).Damage;
    4.                 mActorCore.AttributeSource.SetAttributeValue(HealthID, lRemainingHealth);
    5.             }
    seems to handle the damage.. is that where I should be looking to send it to the Inventory Pro section instead by looking for the IPro stat and if that's not null send it to the Ipro stat?

    Regards

    M
     
  31. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    The problem with just directing to the Inv Pro stat in the Damage Reactor is that other components use the IAttributeSource interface to check the current "Health" and in those cases won't be getting the correct value.

    I've written up an InventoryProAttributeSource component that inherits from BasicAttributes (and thus implements IAttributeSource).

    It's possible to write a simple(ish) component that just implements IAttributeSource and gets/sets values in Inventory Pro. However, because IAttributeSource uses .NET generics for its GetAttributeValue and SetAttributeValue methods and Inventory Pro's stats use float values, we're likely to have situations where other components in the ootii suite of products using IAttributeSource to access attribute types that are not supported by Inventory Pro.

    Thus, my version essentially wraps around those methods of BasicAttributes. If you're calling IAttributeSource.GetAttributeType<float>(), then I first check to see if Inventory Pro has a stat with that name in its StatCollection. If so, then I grab the value from Inv Pro; if not, then I pass it on to the base class (BasicAttributes) to check if it has an attribute with that name. And the same for IAttributeSource.SetAttributeType<float>().

    I made sure to support stat categories as well. If you just specify a stat name such as "Health," then it will get the stat Default_Health. If you have a skill named "Archery" in the category "Skills" then you'd need to call IAttributeSource.GetAttributeType<float>("Skills_Archery").

    Code (CSharp):
    1. using System;
    2. using com.ootii.Actors.Attributes;
    3. using Devdog.InventoryPro;
    4. using UnityEngine;
    5.  
    6. namespace CodexFramework.Integrations.Inventory_Pro
    7. {
    8.     public class InventoryProAttributeSource : BasicAttributes
    9.     {
    10.         /// <summary>
    11.         /// The Inventory Pro "InventoryPlayer" component
    12.         /// </summary>
    13.         public InventoryPlayer _InventoryPlayer;
    14.  
    15.         [Tooltip("Category to use when searching for Inventory Pro stat")]
    16.         [SerializeField]
    17.         protected string _statCategory = "Default";
    18.         public string StatCategory
    19.         {
    20.             get { return _statCategory; }
    21.             set { _statCategory = value; }
    22.         }
    23.  
    24.         [Tooltip("Separator used when specifying an Inventory Pro stat outside the Default category (e.g. 'Skill_Melee' or 'Resistance_Magic'")]
    25.         [SerializeField]
    26.         protected string _separator = "_";
    27.         public string Separator
    28.         {
    29.             get { return _separator; }
    30.             set { _separator = value; }
    31.         }
    32.  
    33.         // Has the component been initialized?
    34.         protected bool mIsInitialized = false;
    35.  
    36.         // For caching the default Category, in case we change it at runtime
    37.         protected string mDefaultStatCategory;    
    38.  
    39.         protected virtual void Start()
    40.         {
    41.             mDefaultStatCategory = _statCategory;
    42.  
    43.             if (_InventoryPlayer == null)
    44.             {
    45.                 _InventoryPlayer = GetComponent<InventoryPlayer>();
    46.             }
    47.  
    48.             mIsInitialized = _InventoryPlayer != null;
    49.         }
    50.  
    51.         public override bool AttributeExists(string rID)
    52.         {
    53.             bool lExists = false;
    54.  
    55.             // Check Inventory Pro stats first
    56.             if (mIsInitialized)
    57.             {                            
    58.                 lExists = (GetStat(rID) != null);
    59.             }
    60.  
    61.             if (!lExists)
    62.             {
    63.                 lExists = base.AttributeExists(rID);
    64.             }
    65.  
    66.             return lExists;
    67.         }
    68.  
    69.         public override Type GetAttributeType(string rID)
    70.         {
    71.             if (mIsInitialized)
    72.             {
    73.                 var stat = GetStat(rID);
    74.                 if (stat != null) { return typeof (float); }
    75.             }
    76.  
    77.             return base.GetAttributeType(rID);
    78.         }
    79.  
    80.         public override T GetAttributeValue<T>(string rID, T rDefault = default(T))
    81.         {
    82.             if (mIsInitialized && typeof(T) == typeof(float))
    83.             {
    84.                 var stat = GetStat(rID);
    85.                 if (stat == null)
    86.                 {
    87.                     return base.GetAttributeValue(rID, rDefault);
    88.                 }
    89.              
    90.                 return (T)(object)stat.currentValue;              
    91.             }
    92.             return base.GetAttributeValue(rID, rDefault);
    93.         }
    94.  
    95.         public override void SetAttributeValue<T>(string rID, T rValue)
    96.         {
    97.             if (mIsInitialized && typeof(T) == typeof(float))
    98.             {
    99.                 var stat = GetStat(rID);
    100.                 if (stat == null)
    101.                 {
    102.                     base.SetAttributeValue(rID, rValue);                  
    103.                 }
    104.                 else
    105.                 {
    106.                     stat.SetCurrentValueRaw(Convert.ToSingle(rValue));
    107.                 }
    108.             }          
    109.         }
    110.  
    111.         protected IStat GetStat(string rID)
    112.         {
    113.             if (rID.Contains(_separator))
    114.             {
    115.                 var values = rID.Split(_separator.ToCharArray());
    116.                 if (values.Length > 1)
    117.                 {
    118.                     return _InventoryPlayer.stats.Get(values[0], values[1]);
    119.                 }
    120.             }
    121.  
    122.             return _InventoryPlayer.stats.Get(_statCategory, rID);
    123.         }
    124.     }
    125. }
    126.  
    EDIT: to be able to add and edit attributes in the Inspector, you'll need the custom Editor script as well. However, the bulk of it is copied-and-pasted from BasicAttributesEditor (as there are too many private fields and methods in it to just inherit from it). If @Tryz is okay with it, I'll paste the Editor script here as well. Otherwise, I'll send it to you via PM.
     
    Tryz and MaliceA4Thought like this.
  32. hopeful

    hopeful

    Joined:
    Nov 20, 2013
    Posts:
    5,676
    Or, if it is suitable, would this be a good example to include in the ootii Vault?
     
    Tryz and MaliceA4Thought like this.
  33. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406

    I think this would be an excellent example to add to the vault with details of where to put the scripts and what is needed to access them for future reference as part of the IPro vault setups.

    In the Interim.. TY @TeagansDad 2nd medal on its way :)

    M
     
    TeagansDad and Tryz like this.
  34. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Good stuff.

    I was trying to think of a way to have a "BasicAttributeInvProFloat", but since the base type is still a float, it would throw off the editor. I need to think about that more.

    @TeagansDad solution works. :)

    You can post it.

    Putting it on the Vault works for me too. I've just got my hands full for a bit.
     
    TeagansDad likes this.
  35. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    I'm going to look silly wearing all of these medals. :p

    I can almost just use the BasicAttributesEditor as the custom inspector, but I needed to make fields for the Default Category and Separator values, instead of hard-coding them as "Default" and "_" respectively.

    Make sure this goes in an "Editor" folder:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using com.ootii.Actors.Attributes;
    4. using com.ootii.Helpers;
    5. using UnityEditor;
    6. using UnityEditorInternal;
    7. using UnityEngine;
    8.  
    9. namespace CodexFramework.Integrations.Inventory_Pro.Editors
    10. {
    11.     [CanEditMultipleObjects]
    12.     [CustomEditor(typeof(InventoryProAttributeSource))]
    13.     public class InventoryProAttributeSourceEditor : EditorBase
    14.     {
    15.         // The actual class we're stroing
    16.         private InventoryProAttributeSource mTarget;
    17.         private SerializedObject mTargetSO;
    18.  
    19.         // List object for our Items
    20.         private ReorderableList mAttributeItemList;
    21.  
    22.         // Index to the Attribute types
    23.         private int mAttributeItemTypeIndex = 0;
    24.  
    25.         /// <summary>
    26.         /// Called when the script object is loaded
    27.         /// </summary>
    28.         void OnEnable()
    29.         {
    30.             // Grab the serialized objects
    31.             mTarget = (InventoryProAttributeSource)target;
    32.             mTargetSO = new SerializedObject(target);
    33.  
    34.             // Initialize the cache
    35.             mTarget.Awake();
    36.  
    37.             // Temporary
    38.             int lCount = 0;
    39.             for (int i = mTarget.Items.Count - 1; i >= 0; i--)
    40.             {
    41.                 if (mTarget.Items[i] == null) { lCount++; mTarget.Items.RemoveAt(i); }
    42.             }        
    43.  
    44.             // Create the list of items to display
    45.             InstantiateAttributeItemList();
    46.         }
    47.  
    48.         /// <summary>
    49.         /// Called when the inspector needs to draw
    50.         /// </summary>
    51.         public override void OnInspectorGUI()
    52.         {
    53.             // Pulls variables from runtime so we have the latest values.
    54.             mTargetSO.Update();
    55.  
    56.             GUILayout.Space(5);
    57.  
    58.             EditorHelper.DrawInspectorTitle("Inventory Pro Attribute Source");
    59.  
    60.             EditorHelper.DrawInspectorDescription("Allows us to assign Attributes to actors.", MessageType.None);
    61.  
    62.             GUILayout.Space(5);
    63.  
    64.             GUILayout.BeginVertical(EditorHelper.GroupBox);
    65.  
    66.             if (EditorHelper.TextField("Default Category", "Default Category to use when getting an Inventory Pro Stat",
    67.                 mTarget.StatCategory, mTarget))
    68.             {
    69.                 mIsDirty = true;
    70.                 mTarget.StatCategory = EditorHelper.FieldStringValue;
    71.             }
    72.  
    73.             if (EditorHelper.TextField("Separator", "Separator used when specifying an Inventory Pro stat outside the Default category (e.g. 'Skill_Melee' or 'Resistance_Magic'",
    74.                 mTarget.Separator, mTarget))
    75.             {
    76.                 mIsDirty = true;
    77.                 mTarget.Separator = EditorHelper.FieldStringValue;
    78.             }
    79.  
    80.             EditorGUILayout.EndVertical();
    81.  
    82.             GUILayout.Space(5);
    83.  
    84.             //EditorGUILayout.LabelField("Attributes", EditorStyles.boldLabel, GUILayout.Height(16f));
    85.  
    86.             GUILayout.BeginVertical(EditorHelper.GroupBox);
    87.  
    88.             mAttributeItemList.DoLayoutList();
    89.  
    90.             if (mAttributeItemList.index >= 0)
    91.             {
    92.                 GUILayout.Space(5f);
    93.                 GUILayout.BeginVertical(EditorHelper.Box);
    94.              
    95.  
    96.                 bool lListIsDirty = DrawAttributeItemDetail(mTarget.Items[mAttributeItemList.index]);
    97.                 if (lListIsDirty) { mIsDirty = true; }
    98.  
    99.                 GUILayout.EndVertical();
    100.             }
    101.  
    102.             EditorGUILayout.EndVertical();
    103.  
    104.  
    105.             // Show the events
    106.             GUILayout.BeginHorizontal();
    107.  
    108.             if (GUILayout.Button(new GUIContent("Events"), EditorStyles.boldLabel))
    109.             {
    110.                 mTarget.EditorShowEvents = !mTarget.EditorShowEvents;
    111.             }
    112.  
    113.             GUILayout.FlexibleSpace();
    114.  
    115.             if (GUILayout.Button(new GUIContent(mTarget.EditorShowEvents ? "-" : "+"), EditorStyles.boldLabel))
    116.             {
    117.                 mTarget.EditorShowEvents = !mTarget.EditorShowEvents;
    118.             }
    119.  
    120.             GUILayout.EndHorizontal();
    121.  
    122.             GUILayout.BeginVertical(EditorHelper.GroupBox);
    123.             EditorHelper.DrawInspectorDescription("Assign functions to be called when specific events take place.", MessageType.None);
    124.  
    125.             if (mTarget.EditorShowEvents)
    126.             {
    127.                 GUILayout.BeginVertical(EditorHelper.Box);
    128.  
    129.                 SerializedProperty lActivatedEvent = mTargetSO.FindProperty("AttributeValueChangedEvent");
    130.                 if (lActivatedEvent != null)
    131.                 {
    132.                     EditorGUI.BeginChangeCheck();
    133.                     EditorGUILayout.PropertyField(lActivatedEvent);
    134.                     if (EditorGUI.EndChangeCheck())
    135.                     {
    136.                         mIsDirty = true;
    137.                     }
    138.                 }
    139.  
    140.                 GUILayout.EndVertical();
    141.             }
    142.  
    143.             GUILayout.EndVertical();
    144.  
    145.             GUILayout.Space(5);
    146.  
    147.             // If there is a change... update.
    148.             if (mIsDirty)
    149.             {
    150.                 // Flag the object as needing to be saved
    151.                 EditorUtility.SetDirty(mTarget);
    152.  
    153. #if UNITY_4_0 || UNITY_4_0_1 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5_0 || UNITY_5_1 || UNITY_5_2
    154.             EditorApplication.MarkSceneDirty();
    155. #else
    156.                 if (!EditorApplication.isPlaying)
    157.                 {
    158.                     UnityEditor.SceneManagement.EditorSceneManager.MarkSceneDirty(UnityEditor.SceneManagement.EditorSceneManager.GetActiveScene());
    159.                 }
    160. #endif
    161.  
    162.                 // Pushes the values back to the runtime so it has the changes
    163.                 mTargetSO.ApplyModifiedProperties();
    164.  
    165.                 // Serialize to the definitions
    166.                 mTarget.OnBeforeSerialize();
    167.  
    168.                 // Clear out the dirty flag
    169.                 mIsDirty = false;
    170.             }
    171.         }
    172.  
    173.         #region Attribute
    174.  
    175.         /// <summary>
    176.         /// Create the reorderable list
    177.         /// </summary>
    178.         private void InstantiateAttributeItemList()
    179.         {
    180.             mAttributeItemList = new ReorderableList(mTarget.Items, typeof(BasicAttribute), true, true, true, true);
    181.             mAttributeItemList.drawHeaderCallback = DrawAttributeItemListHeader;
    182.             mAttributeItemList.drawFooterCallback = DrawAttributeItemListFooter;
    183.             mAttributeItemList.drawElementCallback = DrawAttributeItemListItem;
    184.             mAttributeItemList.onAddCallback = OnAttributeItemListItemAdd;
    185.             mAttributeItemList.onRemoveCallback = OnAttributeItemListItemRemove;
    186.             mAttributeItemList.onSelectCallback = OnAttributeItemListItemSelect;
    187.             mAttributeItemList.onReorderCallback = OnAttributeItemListReorder;
    188.             mAttributeItemList.footerHeight = 17f;
    189.  
    190.             if (mTarget.EditorItemIndex >= 0 && mTarget.EditorItemIndex < mAttributeItemList.count)
    191.             {
    192.                 mAttributeItemList.index = mTarget.EditorItemIndex;
    193.             }
    194.             else
    195.             {
    196.                 mAttributeItemList.index = -1;
    197.             }
    198.         }
    199.  
    200.         /// <summary>
    201.         /// Header for the list
    202.         /// </summary>
    203.         /// <param name="rRect"></param>
    204.         private void DrawAttributeItemListHeader(Rect rRect)
    205.         {
    206.             EditorGUI.LabelField(rRect, "Attributes");
    207.  
    208.             Rect lNoteRect = new Rect(rRect.width + 12f, rRect.y, 11f, rRect.height);
    209.             EditorGUI.LabelField(lNoteRect, "-", EditorStyles.miniLabel);
    210.  
    211.             if (GUI.Button(rRect, "", EditorStyles.label))
    212.             {
    213.                 mAttributeItemList.index = -1;
    214.                 OnAttributeItemListItemSelect(mAttributeItemList);
    215.             }
    216.         }
    217.  
    218.         /// <summary>
    219.         /// Allows us to draw each item in the list
    220.         /// </summary>
    221.         /// <param name="rRect"></param>
    222.         /// <param name="rIndex"></param>
    223.         /// <param name="rIsActive"></param>
    224.         /// <param name="rIsFocused"></param>
    225.         private void DrawAttributeItemListItem(Rect rRect, int rIndex, bool rIsActive, bool rIsFocused)
    226.         {
    227.             if (rIndex < mTarget.Items.Count)
    228.             {
    229.                 BasicAttribute lItem = mTarget.Items[rIndex];
    230.  
    231.                 rRect.y += 2;
    232.  
    233.                 float lNameWidth = EditorGUIUtility.labelWidth;
    234.  
    235.                 Rect lNameRect = new Rect(rRect.x, rRect.y, lNameWidth, EditorGUIUtility.singleLineHeight);
    236.                 EditorGUI.LabelField(lNameRect, lItem.ID);
    237.  
    238.                 Rect lValueRect = new Rect(rRect.x + lNameWidth + 5f, rRect.y, rRect.width - (lNameWidth + 5f), EditorGUIUtility.singleLineHeight);
    239.                 bool lIsDirty = lItem.OnInspectorGUI(lValueRect);
    240.                 if (lIsDirty) { mIsDirty = true; }
    241.             }
    242.         }
    243.  
    244.         /// <summary>
    245.         /// Footer for the list
    246.         /// </summary>
    247.         /// <param name="rRect"></param>
    248.         private void DrawAttributeItemListFooter(Rect rRect)
    249.         {
    250.             Rect lMotionRect = new Rect(rRect.x, rRect.y + 1, rRect.width - 4 - 28 - 28, 16);
    251.             mAttributeItemTypeIndex = EditorGUI.Popup(lMotionRect, mAttributeItemTypeIndex, EnumAttributeTypes.Names);
    252.  
    253.             Rect lAddRect = new Rect(rRect.x + rRect.width - 28 - 28 - 1, rRect.y + 1, 28, 15);
    254.             if (GUI.Button(lAddRect, new GUIContent("+", "Add Item."), EditorStyles.miniButtonLeft)) { OnAttributeItemListItemAdd(mAttributeItemList); }
    255.  
    256.             Rect lDeleteRect = new Rect(lAddRect.x + lAddRect.width, lAddRect.y, 28, 15);
    257.             if (GUI.Button(lDeleteRect, new GUIContent("-", "Delete Item."), EditorStyles.miniButtonRight)) { OnAttributeItemListItemRemove(mAttributeItemList); };
    258.         }
    259.  
    260.         /// <summary>
    261.         /// Allows us to add to a list
    262.         /// </summary>
    263.         /// <param name="rList"></param>
    264.         private void OnAttributeItemListItemAdd(ReorderableList rList)
    265.         {
    266.             mTarget.AddAttribute("", EnumAttributeTypes.Types[mAttributeItemTypeIndex]);
    267.  
    268.             mAttributeItemList.index = mTarget.Items.Count - 1;
    269.             OnAttributeItemListItemSelect(rList);
    270.  
    271.             mIsDirty = true;
    272.         }
    273.  
    274.         /// <summary>
    275.         /// Allows us process when a list is selected
    276.         /// </summary>
    277.         /// <param name="rList"></param>
    278.         private void OnAttributeItemListItemSelect(ReorderableList rList)
    279.         {
    280.             mTarget.EditorItemIndex = rList.index;
    281.         }
    282.  
    283.         /// <summary>
    284.         /// Allows us to stop before removing the item
    285.         /// </summary>
    286.         /// <param name="rList"></param>
    287.         private void OnAttributeItemListItemRemove(ReorderableList rList)
    288.         {
    289.             if (EditorUtility.DisplayDialog("Warning!", "Are you sure you want to delete the item?", "Yes", "No"))
    290.             {
    291.                 int lIndex = rList.index;
    292.  
    293.                 rList.index--;
    294.  
    295.                 mTarget.RemoveAttribute(mTarget.Items[lIndex]);
    296.  
    297.                 OnAttributeItemListItemSelect(rList);
    298.  
    299.                 mIsDirty = true;
    300.             }
    301.         }
    302.  
    303.         /// <summary>
    304.         /// Allows us to process after the motions are reordered
    305.         /// </summary>
    306.         /// <param name="rList"></param>
    307.         private void OnAttributeItemListReorder(ReorderableList rList)
    308.         {
    309.             mIsDirty = true;
    310.         }
    311.  
    312.         /// <summary>
    313.         /// Renders the currently selected step
    314.         /// </summary>
    315.         /// <param name="rStep"></param>
    316.         private bool DrawAttributeItemDetail(BasicAttribute rItem)
    317.         {
    318.             bool lIsDirty = false;
    319.  
    320.             EditorHelper.DrawSmallTitle("Attribute - " + EnumAttributeTypes.GetName(rItem.ValueType));
    321.  
    322.             lIsDirty = rItem.OnInspectorGUI(mTarget);
    323.  
    324.             return lIsDirty;
    325.         }
    326.  
    327.         #endregion
    328.  
    329.     }
    330. }
    331.  
    And as a bonus item, here's a script so that you can have spells (from the Spellcasting Motion Pack) usable from the Inventory Pro skillbar:

    Code (CSharp):
    1. #if OOTII_SCMP
    2. using com.ootii.Actors.AnimationControllers;
    3. using com.ootii.Actors.Magic;
    4. using com.ootii.MotionControllerPacks;
    5. using Devdog.General;
    6. using Devdog.InventoryPro;
    7. using UnityEngine;
    8.  
    9. namespace CodexFramework.Integrations.Inventory_Pro
    10. {
    11.     public class SpellInventoryProItem : InventoryItemBase
    12.     {
    13.         [Tooltip("Spell asset for use with the ootii Spellcasting Motion Pack")]
    14.         public Spell spellPrefab;
    15.  
    16.         [Tooltip("Mana cost of this spell")]
    17.         public int manaCost;
    18.  
    19.         public override int Use()
    20.         {
    21.             int used = base.Use();
    22.             if (used < 0)
    23.                 return used;
    24.  
    25.             MotionController motionController = PlayerManager.instance.currentPlayer.GetComponent<MotionController>();
    26.             SpellInventory spellInventory = PlayerManager.instance.currentPlayer.GetComponent<SpellInventory>();
    27.  
    28.             if (spellInventory == null || motionController == null || spellPrefab == null) { return -1; }
    29.  
    30.             int spellIndex = spellInventory.GetSpellIndex(spellPrefab.Name);
    31.             // Check if the spell exists in the actor's SpellInventory; if not, add it
    32.             if (spellIndex == -1) { spellIndex = AddSpell(spellInventory); }
    33.          
    34.             BasicSpellCasting lCastMotion = motionController.GetMotion<BasicSpellCasting>();          
    35.             if (lCastMotion == null) { return -1; }          
    36.  
    37.          
    38.             if (!lCastMotion.IsActive && (!lCastMotion.RequiresStance
    39.                 || motionController.ActorController.State.Stance == EnumControllerStance.SPELL_CASTING))
    40.             {
    41.                 motionController.ActivateMotion(lCastMotion, spellIndex);
    42.             }        
    43.  
    44.             NotifyItemUsed(1, true);
    45.  
    46.             return 1; // 1 item used          
    47.         }
    48.  
    49.         protected virtual int AddSpell(SpellInventory spellInventory)
    50.         {
    51.             SpellInventoryItem newItem = new SpellInventoryItem {
    52.                 Name = spellPrefab.Name,
    53.                 Owner = PlayerManager.instance.currentPlayer.gameObject,
    54.                 SpellPrefab = spellPrefab
    55.             };
    56.  
    57.             spellInventory._Spells.Add(newItem);
    58.             return spellInventory.GetSpellIndex(spellPrefab.Name);
    59.         }
    60.     }
    61. }
    62. #endif
    63.  
    This will have the spell cast immediately when you right-click the spell in its inventory window or when you press the hotkey for its slot on the skillbar. You'll need to have the BasicSpellcasting.RequiresStance disabled for this.

    You can easily make a Spellbook inventory window -- just follow the example of the Skills Window in the main Inventory Pro demo scene. Just set its collection filter to only allow items of type SpellInventoryProItem -- and set your main Inventory collection window to not allow that type.

    I'm currently looking into handling spells as special-case equippable items to see if that might work a bit more smoothly (so it would work more like in Skyrim as opposed to say Dragon Age or Risen). I'm running into a snag where I can't exclude an EquippableSpellInventoryItem from the primary Inventory collection and still have it able to be equipped to an EquippableSlot.

    EDIT: Also, here's the script to pass on "Block Player Input" to Motion Controller. As a bonus, it also disables the "Targeting In" motor on the Camera Controller (if you're using it) so that right-clicking to equip an item won't engage the targeting motor if you happen to be in a stance where that motor is able to start.

    Code (CSharp):
    1. using UnityEngine;
    2. using com.ootii.Actors.AnimationControllers;
    3. using com.ootii.Cameras;
    4. using com.ootii.Game;
    5. using Devdog.General;
    6.  
    7. namespace CodexFramework.Integrations.Inventory_Pro
    8. {
    9.     [RequireComponent(typeof(MotionController))]
    10.     public class InventoryOotiiInputController : MonoBehaviour, IPlayerInputCallbacks
    11.     {
    12.         private MotionController mMotionController;
    13.        
    14.        
    15.         private void Start()
    16.         {
    17.             mMotionController = GetComponent<MotionController>();      
    18.         }
    19.  
    20.         public void SetInputActive(bool rActive)
    21.         {
    22.             if (mMotionController == null) { return; }
    23.             Debug.Log("SetInputActive: " + rActive);
    24.             mMotionController.InputSource.IsEnabled = rActive;
    25.  
    26. #if OOTII_CC
    27.             var cameraController = mMotionController.CameraRig as CameraController;
    28.  
    29.             if (cameraController != null)
    30.             {              
    31.                 // Disable Targeting In motor so it doesn't engage when right clicking to equip the bow
    32.                 var targetingIn = cameraController.GetMotor("Targeting In");
    33.                
    34.                 if (targetingIn != null)
    35.                 {
    36.                     Debug.Log("Targeting In motor enabled: " + rActive);
    37.                     targetingIn.IsEnabled = rActive;
    38.                 }
    39.             }
    40. #endif
    41.  
    42.             if (GameCore.Core != null)
    43.             {
    44.                 GameCore.Core.IsCursorVisible = !rActive;
    45.             }
    46.         }
    47.     }
    48. }
     
    Tryz and hopeful like this.
  36. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Man, these are awesome.. ty :) Yep, I think theres a huge expansion coming to the vault IPro integrations section :)

    BTW, I removed the basic attributes script and added your IPro script and it all works fine.. my health bar is going up and down like a rabbit on heat as things happen in game from character damage and item stats :)

    Happy Dance.

    As to the medals.. okay we'll find something else for the future otherwise you'll start to fall over from the weight :)

    As an aside, it's proved to me how reliable and extensible MC and the packs are and what a great decision it was to actually stick with these and start to learn something new.. Kudos to @Tryz for a really solid product and support from him and you guys.

    M
     
  37. rubble1

    rubble1

    Joined:
    Apr 25, 2010
    Posts:
    84
    For those working on the Photon integration, I thought I'd share what I found, and see if anyone had any feedback. Using the reactors, I was able to get my player to kill himself, instead of the other guy. Brilliant...
    Seriously though, it does make me think that the system will work.

    In my setup, the MC is only enabled on the local player. I can't call up motions or react to anything on the remote, because the MC isn't there. However, I guess I could send it across the network by getting the PhotonView ID, and calling the function on that player's MC, right?

    From what I've read, the info where we tell the target it's been hit is happening on the OnImpact function. It's actually the sword that calls this up, is that right? Is there a way I can send a message from that, like we can with the reactors?

    I found this post, and thought I'd try this out:
    Unfortunately, this is giving me an error. It tells me that Sword Core does not contain a definition for OnHit or OnImpactHandler.

    Is there something I'm missing here?
     
  38. tchris

    tchris

    Joined:
    Oct 10, 2012
    Posts:
    133
    I haven't done a networked game before, but I would think that the remote players would be almost like an NPC on each local player's instance. So since MC works fine on NPCs wouldn't it work fine on the remote player ?
     
    rubble1 and Tryz like this.
  39. francescobr

    francescobr

    Joined:
    Apr 2, 2017
    Posts:
    45
    @Tryz I've got to ask you, why didn't you make BasicInventoryItem class a scriptable object? Wouldn't that be the easiest way to create collectables items?
     
  40. zeb33

    zeb33

    Joined:
    Nov 17, 2014
    Posts:
    95
    No luck am afraid. Whatever I try it loops equip/unequip over and over.
    The easy touch events Ive tried on the touch button are OnDown, OnPressed, OnPressedValue and OnUp()
     
  41. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    hahaha... Small steps. I'm a big fan of breaking things down into little pieces. So, that's a win! :D

    The post you referenced is pretty old (Jan 2017). It's really the WeaponCore that determines the hit in TestImpact() and when one occurs, OnImpact() is fired. That's where I create the CombatMessage that talks about the damage.

    The SwordCore inherits from WeaponCore and has a function called OnImpactComplete() where I play the sounds.

    I'm not 100% sure how you pass the messages back and forth across the network, but you could have a ActorCore on the remote players (which are like NPCs). They could have a new "NetworkDamagedReactor" that gets the CombatMessage and sends it off to the real version of the play who then reacts normally. The resulting animation would then flow back down to the remotes.

    I'm just not sure if this breaks the "authoritative model". I think in that approach, all the work is really done on the server (including hit resolution) and the results are sent to the clients.

    Unfortunately, I'm just shooting from the hip on this network stuff. :(
     
    rubble1 likes this.
  42. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    When I was doing my small bit of research for the UNet video I did, it seemed to me like remote players were like shadows. What I mean is that the local player has the AC, MC, ActorCore, etc. It's taking input and determining what to do. Across the network, the remote version of the player on each of the clients really only cares about 3 things: position, rotation, and animation. That's because all the control was happening over on the local player and that machine.

    In the post I just did, I suggested that the remote (the shadow) could have a message sink. This way if another player's local version across the network affected our remote version, we could react. I'm thinking that message sink could be the ActorCore's Reactors who would send the information to our local version (or authoritative server) where decisions could be made.

    If anyone has some real multiplayer experience, I'd love to hear what you think. :)
     
    rubble1 likes this.
  43. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Originally, I just wanted to create the Inventory Source so that you could use any inventory solution that you wanted. With that, I figured having a basic example would be good. So, I created Basic Inventory... not to compete with Inventory Pro and all the other inventory assets, but to show how you could integrate with them or create your own.

    With Basic Inventory I went down that road a while back, but hit two major roadblocks:

    1. ScriptableObjects can not be stored in prefabs
    2. ScriptableObjects create references and not instances

    #1 meant that I couldn't create a prefab of my goblin character and have him instanced with the weapon. (I ran into this again with Basic Attributes.)

    #2 meant that if I created a "dagger" scriptable object and referenced it in 3 different goblins, it's not 3 different daggers. It's literally the same dagger. So, if I reduced the dagger's durability with 1 goblin, it was reduced for all.

    Solutions like Inventory Pro get around some of these limitations by creating databases and managing instances. That was just too much for my "basic" inventory.

    That isn't to say I won't create an Advanced Inventory solution that uses ScriptableObjects, it just wasn't my goal.
     
    Last edited: Feb 3, 2018
  44. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    How about emailing tim@ootii.com and lets see if we can get this working.

    What are you returning for the GetValue() function? I'm looking in Basic Inventory and it appears I'm using:
    if (InputSource.GetValue(_ToggleWeaponSetAlias) > 0)

    and not
    if (InputSource.IsJustPressed(_ToggleWeaponSetAlias))


    If the GetValue() function is returning something greater than 0, that could cause the repeating.

    With the Unity Input Manager, keyboard buttons return 0 or 1 and Xbox buttons are setup to return 0 or 1 as well. I'm wondering if Easy Touch 5 is ramping values.
     
  45. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Just wondered if you had had any luck with this one at all or even any time to look at it yet?

    This was to do with the target for a location spell not showing up when Archery was installed.

    M
     
  46. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    Sorry about that. I thought I responded. I did do a test and I didn't see any issues.

    But, I'm glad you followed up...

    I was just doing stuff with attributes and I'll bet your scene doesn't have the ground tagged as "Ground".



    The "Select Position" prefab that's the ground projector has "Tags" set to "Ground" by default. This way we can choose what can be selected as a target.

     
    hopeful likes this.
  47. francescobr

    francescobr

    Joined:
    Apr 2, 2017
    Posts:
    45
    I understand what you mean, so could you give me an advice? I've create a scriptableobject class that encapsulates a basic inventory item. This way I can create them in an editor window and can create a kind of database. I have another editor window where I can create chests and have your components automatically added and this way I might add an option for the user to select the content of the chest. When the user opens the chest I can simply take the scriptableobject basic inventory item, clone it, and add it to his inventory. Do you think this could work? I'm asking since you obviously already know all the pros and cons of your simple inventory component.
    And btw thanks for your always complete and precise answers :)
     
    Last edited: Feb 3, 2018
  48. Tryz

    Tryz

    Joined:
    Apr 22, 2013
    Posts:
    3,402
    I don't think there would be an issue with that. You'd just have to add the Basic Inventory Item to the list.

    In the inspector (line 400), I do this:
    Code (CSharp):
    1. BasicInventoryItem lItem = new BasicInventoryItem();
    2. mTarget.Items.Add(lItem);
    If you already have a BasicInventoryItem, you just add it.

    :)
     
    francescobr likes this.
  49. TeagansDad

    TeagansDad

    Joined:
    Nov 17, 2012
    Posts:
    957
    @francescobr - you can also take the approach of using ScriptableObjects for "ItemDefinition" data objects, as separate from item "instance" objects that are added to the player's inventory. The item instance would hold a reference to the ItemDefinition SO and would read from that to populate its own properties. So you're not adding an SO directly to a prefab. I use SOs to store easily editable data for weapons, attack styles, weapon types, etc and I have prefabs and instanced objects just pulling data from the SOs at runtime. Haven't had any problems.

    A simple example: you could create an InventoryItemDefinition SO script with the same properties as BasicInventoryItem. You can also add a method called "AsBasicinventoryItem" that creates a new BasicInventoryItem, populates its properties from the SO fields, then returns the created object.

    Create a component to initialize the inventory that exposes a List of InventoryItemDefinition, and have that component iterate through the list, call AsBasicinventoryItem on each, and add that to the BasicInventory.Items collection. You can also create the WeaponSets here, although this would be another good use case for a WeaponSetDefinition SO. Or you can have the ItemDefinition contain rules for what weapons can be paired up and then build your WeaponSets based on all of the valid pairings.

    So you could fill a chest with a collection of InventoryItemDefinitions, and then when the character collects the items, you add the BasicInventoryItem to BasicInventory.

    You could think of SOs as a flexible database. It's annoying to have to duplicate a lot of properties between two classes, but it does help in keeping the data (for ease of entry) and in-game behaviour separate.

    Inventory Pro doesn't actually use SOs for its items (I thought it did initially). Stats, EquipmentTypes, and virtually every other data object is an SO, but items themselves are still stored as prefabs. InventoryItemBase is a Monobehaviour.
     
    francescobr and Tryz like this.
  50. MaliceA4Thought

    MaliceA4Thought

    Joined:
    Feb 25, 2011
    Posts:
    406
    Hmmmmm really odd.. my ground is tagged as ground. I really get a choice here as it stands right now... I can have a reticule and use the bow and not do position based spells.. or I can disable the reticule and do ground based spells and guess where the archery is pointing :)

    I'm fully aware this may be a specific issue because of UMA/Ipro and the mods made so far as in.. I don't have a basic Attributes as I am using the replacement from Teagansdad to interface with Inv Pro and I looked through my character but had no Select Position Core in there (not sure why) but adding that made no difference. I have also tried turning off the "manage the reticule" in Basic Ranged Attack but if the reticule script is enabled.. no ground spells.. if its disabled, no archery target.

    Is this going to be one where I zip up 9 gig and dropbox it for you or are there other things to test on my end?

    M