Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 12 Next capture
2021 2022 2023
1 capture
12 Jun 22 - 12 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 MZembaty · Apr 27, 2020 at 10:33 AM · editor-scriptingscriptableobjectdesign-patterns

Modular ability creation in editor

Newbie here

My goal:
I want to modular generate different abilties in the inspector that can be attached to a Monobehaviour. Abilty values can also be tweaked in the inspector seperatly from each other

What i came up with so far
Every unique Ability is a ScriptableObject asset. It contains an array of AbilityProperties. AbilityProperty is also an ScriptableObject and acts as a "superclass". Unique AbilityProperties derive from AbilityProperty and implement a simple interface, which only holds a method called execute(). With a custom drawer you are able to attach unique AbilityProperties and tweak the values of every single one of them.

The problem
Now the big obvious flaw in this design is, when i tweak an AbilityProperty value in one Ability it will change in every other Ability too. Because there is only one AbilityProperty_Damage ScriptableObject. Or I have too create a ScriptableObject Asset for every property of every ability which seems nuts.

So anyone has an idea how to tackle this problem? Since I'm at the beginning I can redesign the whole thing.



The code
Sorry for the wierd formating but here i had an issue with the web editor:

[CreateAssetMenu(fileName = "Ability")]
public class Ability : ScriptableObject
{
    public Property[] properties;
}

public interface IProperty
{
    void execute();
}

public class AbilityProperty : ScriptableObject
{
    public string propName;
}

 [CreateAssetMenu(fileName = "propDamage")] public class Property_Damage : Property, IProperty { public int damageAmont; 
               

 public void execute()
 {
     // some damage specific logic
 }

}


 using UnityEngine; using UnityEditor; using System.Reflection; [CustomPropertyDrawer(typeof(AbilityProperty))] public class AbilityPropertyDrawer : PropertyDrawer { public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (property.objectReferenceValue == null) return base.GetPropertyHeight(property, label); 
               

     var modifier = property.objectReferenceValue as AbilityProperty;
     var fields = modifier.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);

     return base.GetPropertyHeight(property, label) * (float)(fields.Length + 1);
 }


 public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
 {
     position.height = base.GetPropertyHeight(property, label);

     EditorGUI.PropertyField(position, property);

     if (property.objectReferenceValue == null)
         return;

     var modifier = property.objectReferenceValue as AbilityProperty;
     var fields = modifier.GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
     var sObj = new SerializedObject(property.objectReferenceValue);

     position.x += 20f;
     position.xMax -= 38f;
     foreach (var field in fields)
     {
         position.y += position.height;
         EditorGUI.PropertyField(position, sObj.FindProperty(field.Name));
     }

     sObj.ApplyModifiedProperties();
 }

}

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
0

Answer by logicandchaos · Apr 27, 2020 at 04:02 PM

Awesome I made something similar to this in my current project! Was pretty proud of it :P I called them Character Actions though.. :P You will need to make a SO instance for each ability.. but that is normal for SOs, when you start using SO variables it becomes second nature. Instead of an interface I made an abstract base class with a virtual method Perform, but I think it is pretty much the same.. I wanted to be able to add and remove actions for different characters, nothing hard coded, extendable modular and more decoupled! But how I implemented it was pretty neat too I made an informal finite state machine that used fuzzy pattern matching to select the state. I did this by making another abstract class called Condition that is also an SO with a virtual method bool Check() so basically anything can be a condition, pressing a certain button, health level, anything! Then I made my actions have a list of conditions and a method bool CheckConditions(), then I can check if all the conditions are met. So then in the script that implements it all I have a list of CharacterActions that I sort based on how many conditions there are, I got the fuzzy pattern matching and sorting by number of conditions from a GDC talk on Left4Dead, you want the actions with the most conditions to fire off first.. then I loop through it all like this:

     List<CharacterAction> characterActions;
     bool canAct=true;
     ..
     Update(){
     if(canAct){
     foreach(CharacterAction action in characterActions)
     {
         if(action.CheckConditions())
         {
             action.PerformAction();
             canAct=false;
             ResetCanAct(action.delay);
             break;
         }
     }
     }
     }
     void ResetCanAct(float p_value)
     {
         Invoke("InvokeReset",p_value);
     }
     void InvokeReset()
     {
         canAct=true;
     }
     // I just like Invoke should probably be a coroutine..


so you do have to make an SO for each ability, but it's works pretty good.

Comment
Add comment · Show 1 · 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 Bunny83 · Apr 27, 2020 at 04:47 PM 0
Share

I also don't really see any issue in creating seperate SO instances for every "ability" you create. That way you can reuse the same SO when appropriate or if you need it to be different just create a copy of the shared one, rename it and tweak it as you need it. It's more of a matter how you organise them in your project. Since it's extremely easy to "follow" a SO asset reference it's quite simple to navigate. Though of course you can get crazy with editor tools to show certain things inline or perform some of the housekeeping stuff in editor code.


I can highly recommend this Unite Talk from 2017 to get a few ideas how a modular system could be setup. Note that Schell games is a relatively large studio. Working in a studio with a $$anonymous$$m is in general quite different than working indy on your own.

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

141 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 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 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 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 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 avatar image

Related Questions

Cannot include ScriptableObject in asset bundle in Unity 5 0 Answers

Animator Editor Window disappear when generate AnimatorController inside other asset 0 Answers

Scriptable Object save List 0 Answers

Create List of custom class types, for use in custom editor 0 Answers

Is it possible to write a function in the backend of an editor script for a scriptableObject? 0 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