dsm1891

Members
  • Content count

    343
  • Joined

  • Last visited

Community Reputation

2746 Excellent

About dsm1891

  • Rank
    Crossbones+
  1. Agreed. The designer isn't sure, and is hedging. When I've been unsure like that, I've said that the feature should be made flexible so it can be easily changed. I've also worked with a designer who would poll the team before designing a feature. dsm, you say you'd rather be told. Would you like to be told to do it one way, then be told to change it later? I don't think you'd like that. But a designer can't be certain all the time, so why don't you just discuss with the designer - sounds like he/she/they is laboring in a vacuum.   Well, in previous projects where there was no designer per se I was more than capable and enjoyed filling out a mechanic of what felt good. But atleast on this project numerous times I have... been made aware of that is what the designer did not intend (when I have fledged out a mechanic with what I thought should happen).    So now it seems I am in a place where the designer cant/wont make concrete decisions and if I fill out ambiguities I will be told that that is not what they had in mind.   Of course being told what to do, and potentially having to redo it would be annoying. But I think that would only be the case if the iterations are frequent.   as previously said, discussions lead no where. I will be provided with a vague task, I ask about the task, the answers are equally vague. Trying to promt some decision I give multiple options, in which the designer will say "any of those options". Then the next day I will be told something totally differently  (without the designer seeing the implementation)
  2. No producer (yet, may hopefully change)   These ARE first pass, so it is, in a way prototyping. However, I would much rather be told what the first implementation should do.   For instance I Just asked the designer, "how should this be implemented the options are , A,B or C" to which the reply I got was "Yes, any of them". It seems the designer is afraid of commitment. Previously I have communicated verbally to him, which turned out to be a disaster.   I asked about X feature which I was to implement and he described the feature with some ambiguity. I thought fine, I can just do the obvious path. For example, I was to implement the character throwing a ball. It seems obvious to me, that when the ball is thrown, it is thrown with some force and is effected by gravity, has some sort of friction and restoration. After implementing it, I was told it was "just wrong" and that it would "obviously" travel in a straight line, not effected by gravity.    Yesterday I questioned him (again verbally) about something else, and resolved the ambiguities. But today he when questioned about something else he contradicted himself.     I am fine with things changing, but changing your idea of how something works day by day is frustrating. My idea how it should be is: Design it one way, play test, if it works great if not change it.   After the first instance of the ambiguities and my restricted freedoms (obviously the designer and I, don't share common ideas) I have stopped querying him face to face, instead I use the task manager comment system. So atleast I can refer to things he has said in the past on 'why I made it which ever way'     And before anyone asks we don't have a GDD *(or atleast one I can view)   and yes this is scrum, kinda, not really though :/
  3. Hello Designers   I come to you with a question. I am currently working with a designer whose writing style is, quite frankly, annoying to me. I am given a task to do X, but the description of X is full of indeterminable words.   "maybe it could, possibly, this pass, do THIS sort of thing, for now" (literal quote)   Designers I have worked with previously have never used this language, if something needs doing it was always definite   "It should be done like this"   I had no problem with this, if it needs to change in the future fine. Everything read clear cut. However using  indeterminable words make it sounds like I should keep the Thing I am developing open, as the designer thinks it will likely change in the future, and it makes me question how it should work.   Is this normal, or am I just complaining for no reason :)
  4. Welcome,   I think I need help. When ever I code a feature/system/helper/tool/whatever for a game, it has to be generic. I feel like I am addicted to making things as generic as possible, even when such systems don't need to be generic. Sure having generic systems can be great, but when ever I have to create a specific system, I still can get out of the mind set of 'how can this thing be more generic', and frankly things take longer than the should because of this.   So let me tell you where it all began. My first project in the industry was made using an inhouse engine with no editor. We tried to make thing as generic as possible so they would 'just work'. no faffing about. We used other editors, such as Tiled or someother software, to create data assets which would be loaded in to game, and 'just work'.   I was in charge of implementing enemies, particles, projectiles and such (which all came from one art package). Looking back on the project I love how it all 'just worked', The artist would create a character, I would go in *do some magic* export. Run the game, and that character (with simple AI) would be working as in tended. The whole thing was so independent of code you could have a character fire a gun, when the bullet exploded it could spawn a character, which then would explode spawn particles, damage surrounding,x ,y z - no code required.   It was great.   However, now I am working with unity, that has an editor. Things don't need to be as automatic as the previous project. its perfectly acceptable and easy to enter values. Because its easy to attach components to game objects, specific components are often a way to go. The existing code base when I joined the project was alien to be, because often it was very specific. Even now when I have to create a new system / re-write an old one, I write it generically. But it is Bottle necked by specific systems, and im left with a choice, make my system less generic or Change another system (which would spiral out of control!).   I think I need to learn how to know when to drop the Generic implementation of a system in favour for a more Specific implementation.   Any advice?   TL;DR: I always try and create generic systems in game, as a result things take longer than if it was a Specific implementation. How do you decide if something should be generic or specific.
  5. Maximized IPBoard Chat

    what was Yoshi talking to you about
  6. Unity Editor Data Entry 2.0

    Unity Data Entry So, unity has a problem. Well, ok lots of problems, but I want to talk about a specific one. Data entry and how things can quickly get out of hand. For those who are unaware, unity allows you to edit serialize data through the editor using an 'inspector window'. My script has 3 variables that can be edited with types enum, int and float. (unity offers many other data types which can be edited through the inspector). Entering data through the inspector is fine for simple objects/scripts. However, once a object/scripts becomes more complicated the default data entry becomes a burden. Specifically when you have a variable which will determine if another variable is used or not. A good example of this is you may have a projectile, this projectile could behave in different ways. It could be a homing projectile, it could be a bullet, it could be anything. If the projectile is homing, it will use additional parameters to a standard projectile, if it is a bullet it would use different parameters again. The solution to this problem, as stated a lot of places on the internet is to create a custom drawer for the (projectile) script. However, in practice this is impractical. Scripts where I needed the above behaviour required writing 200 lines, just so I could show/hide some variables in the inspector! furthermore this 'solution' just isn't scalable, as you would have to write custom draw code for each script!. My solution to this involves using attributes to define when a variable is shown or not (and to handle the drawing) (in real time!) Which changes the above image to: So, What do we need to do? Create a generic attribute which any variable can use Use reflection to get another variable Check to see if that variable is of a particular value The most basic condition (to decide if one variable should be shown or not) is a Boolean.if Varible A is True Show Varible Belse Don't show Varible B First we have to declare our fields, this is pretty standard, however on variable B we will have to declare it with our attribute (conditional)public bool a;[Conditional("a", true)]public int b; as you can see, the attribute takes in two parameters; "a" and True. The first parameter is the name of the parameter we want to check. The second parameter is the value the first parameter needs to be to make variable b show. These are both stored with in the Attribute. We need to create a drawer, which will draw the variable in editor, for our attribute. We do this by doing:[CustomPropertyDrawer(typeof(ConditionalAttribute))]public class ConditionalDrawer : PropertyDrawer{ public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { .... }} The OnGUI method will handle drawing the variable in editor. As you can see, it has a SerializedProperty parameter, this is our variable "b". We need to do some reflection magic on that parameter to get variable "a" and check it's value. public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { ConditionalAttribute conAtr = attribute as ConditionalAttribute; string path = GetPath(property); string conditionname = path + conAtr.ConditionVaribleName; ConditionalProperty = property.serializedObject.FindProperty(conditionname);} private string GetPath(SerializedProperty property) { string path = property.propertyPath; int index = path.LastIndexOf("."); return path.Substring(0, index + 1); } This code gets the condition variable ("bool a") and stores it in ConditionalProperty. The GetPath Method is needed as the variables could be nested in an object. ? ? Next we need to check the value of ConditionalProperty, against the value we passed (and stored) into the attribute. if (ConditionalProperty.propertyType == SerializedPropertyType.Boolean) { conAtr.ShouldShow = ConditionalProperty.boolValue == conAtr.CheckValue; } as the same instance of the drawer is used to draw all the variables with our attribute, we can not store anything with in the drawer. we have to store everything in the attribute. Next, still within the OnGUI method we need to draw (or not draw) the variable ("int b").if (conAtr.ShouldBeShown) EditorGUI.PropertyField(position, property, label, false); We also need to alter the height of the variable being drawn otherwise there will be a blank space. Luckily we can just do: public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { ConditionalAttribute conAtr= attribute as ConditionalAttribute; if (!conAtr.ShouldBeShown) return 0.0f; return EditorGUI.GetPropertyHeight(property, label, true); } within the drawer class. Great!! we now have a variable which is shown/not shown depending on another Boolean variable. But what if we don't want to use a Boolean, what if we want to make it dependant on another type, what if it has to be greater than X or less than X. What if we want it conditional to multiple things. Don't fear, I have thought of that! I have another constructor in the attribute:public enum OperatorEnum { Equals, NotEqualTo, GreaterThan, LessThan, EqualsOrGreaterThan, EqualsOrLessThan } public enum LogicEnum { AND, OR } //LHS, is the varible name to check which are got through reflection //Opperator, is the operator to use for the check //RHS, is the value to check against //BetweenElements, and/or to use between the last element and this element public ConditionalAttribute(string[] LHS, int[] Operator, object[] RHS, int[] BetweenElements) { int maxsize = LHS.Length; m_LHSVaribleNames = new string[maxsize]; m_Operator = new OperatorEnum[maxsize]; m_RHSValues = new object[maxsize]; m_BetweenElementsLogic = new LogicEnum[maxsize - 1]; m_LHSVaribleNames = LHS; for (int i = 0; i < maxsize; i++) { if (i < Operator.Length) { m_Operator = (OperatorEnum)Operator; } else m_Operator = (int)OperatorEnum.Equals;//Set it to == if no value was given } for (int i = 0; i < maxsize; i++) { if (i < RHS.Length) { m_RHSValues = RHS; } else m_RHSValues = RHS[RHS.Length - 1];//Set it to the last value if no value was given } for (int i = 0; i < maxsize - 1; i++) { if (i < BetweenElements.Length) { m_BetweenElementsLogic = (LogicEnum)BetweenElements; } else m_BetweenElementsLogic = LogicEnum.AND;//Set it to && if no value was given } } unfortunately, there are only certain types which can be passed into attributes. I would have liked to do all this using a lambda to decide all this, but alas that was not possible so I had to parse the values to make the correct statement. Also, enum values can not be passed through so they need to be cast to an int. So now if we want a new variable ("c") to be shown when:if a == true && b > 5 showelse don't show the declaration would look like: public bool a; [Conditional("a", true)] public int b; [Conditional(new string[] { "a","b"}, new int[] { (int)ConditionalAttribute.OperatorEnum.Equals, (int)ConditionalAttribute.OperatorEnum.GreaterThan }, new object[] { true, 5}, new int[] { (int)ConditionalAttribute.LogicEnum.AND} )] public float c; yikes that's a big constructor :( One last thing was that because I don't know the type of the variable who's name is passed in (the condition variable) - I only know the type of the variable being drawn, I had to use(IComparable)LHS).CompareTo(RHS) == 0 for the check to know if the variable should be shown or not. Using this attribute allows the data entry for unity to be much easier, as now you can edit fields that are relative to the options you have already chosen! You can now write, simple/complex statements and control the visibility of variables in the editor without the need of creating custom drawer's for each script. I am really happy with how this has turned out, it is really flexible and really generic. Hopefully someone else will find it as useful as I do :) Until next time, dsm full code:using UnityEngine;using System.Collections;using UnityEditor;using System;public class ConditionalAttribute : PropertyAttribute{ public enum OperatorEnum { Equals, NotEqualTo, GreaterThan, LessThan, EqualsOrGreaterThan, EqualsOrLessThan } public enum LogicEnum { AND, OR } protected string[] m_LHSVaribleNames; protected OperatorEnum[] m_Operator; protected object[] m_RHSValues; protected LogicEnum[] m_BetweenElementsLogic; protected bool m_ShouldBeShown = true; public bool ShouldBeShown { get { return m_ShouldBeShown; } set { m_ShouldBeShown = value; } } public string[] LHSVaribleNames { get { return m_LHSVaribleNames; } } public OperatorEnum[] Operator { get { return m_Operator; } } public object[] RHSValues { get { return m_RHSValues; } } public LogicEnum[] BetweenElementsLogic { get { return m_BetweenElementsLogic; } } //LHS, is the varible name to check which are got through reflection //Opperator, is the operator to use for the check //RHS, is the value to check against //BetweenElements, and/or to use between the last element and this element public ConditionalAttribute(string[] LHS, int[] Operator, object[] RHS, int[] BetweenElements) { int maxsize = LHS.Length; m_LHSVaribleNames = new string[maxsize]; m_Operator = new OperatorEnum[maxsize]; m_RHSValues = new object[maxsize]; m_BetweenElementsLogic = new LogicEnum[maxsize - 1]; m_LHSVaribleNames = LHS; for (int i = 0; i < maxsize; i++) { if (i < Operator.Length) { m_Operator = (OperatorEnum)Operator; } else m_Operator = (int)OperatorEnum.Equals;//Set it to == if no value was given } for (int i = 0; i < maxsize; i++) { if (i < RHS.Length) { m_RHSValues = RHS; } else m_RHSValues = RHS[RHS.Length - 1];//Set it to the last value if no value was given } for (int i = 0; i < maxsize - 1; i++) { if (i < BetweenElements.Length) { m_BetweenElementsLogic = (LogicEnum)BetweenElements; } else m_BetweenElementsLogic = LogicEnum.AND;//Set it to && if no value was given } } public ConditionalAttribute(string LHSVaribleName, object RHSValue) { m_LHSVaribleNames = new string[] { LHSVaribleName }; m_RHSValues = new object[] { RHSValue }; m_Operator = new OperatorEnum[] { OperatorEnum.Equals }; } public ConditionalAttribute() { }}///////Conditional//Decides if a varible should be shown in the inspector depending on another (boolean) varible[CustomPropertyDrawer(typeof(ConditionalAttribute))]public class ConditionalDrawer : PropertyDrawer{ public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (!bute.ShouldBeShown) return 0.0f; return EditorGUI.GetPropertyHeight(property, label, true); } SerializedProperty ConditionalProperty; public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { bute.ShouldBeShown = ShouldShow(property); if (bute.ShouldBeShown) EditorGUI.PropertyField(position, property, label, false); } private string GetPath(SerializedProperty property) { string path = property.propertyPath; int index = path.LastIndexOf("."); return path.Substring(0, index + 1); } protected virtual ConditionalAttribute bute { get { return (ConditionalAttribute)attribute; } } protected bool ShouldShow(SerializedProperty property) { string path = GetPath(property); bool previous = false; for (int i = 0; i < bute.LHSVaribleNames.Length; i++) { string conditionname = path + bute.LHSVaribleNames; ConditionalProperty = property.serializedObject.FindProperty(conditionname); bool test = false; object lhsValue; if (ConditionalProperty.propertyType == SerializedPropertyType.Integer) { lhsValue = ConditionalProperty.intValue; } else if (ConditionalProperty.propertyType == SerializedPropertyType.Float) { lhsValue = ConditionalProperty.floatValue; } else if (ConditionalProperty.propertyType == SerializedPropertyType.Boolean) { lhsValue = ConditionalProperty.boolValue; } else if (ConditionalProperty.propertyType == SerializedPropertyType.Enum) { lhsValue = ConditionalProperty.enumNames[ConditionalProperty.enumValueIndex]; } else throw new Exception("Type needs implementing"); test = Check(lhsValue, bute.Operator, bute.RHSValues); if (bute.BetweenElementsLogic == null) { return test; } if (i != 0 && test && bute.BetweenElementsLogic[i - 1] == (int)ConditionalAttribute.LogicEnum.AND) { if (!previous) { test = false; } } if (test && i < bute.BetweenElementsLogic.Length && bute.BetweenElementsLogic == ConditionalAttribute.LogicEnum.OR) { return true; } previous = test; } return previous; } protected bool Check(object LHS, ConditionalAttribute.OperatorEnum op, object RHS) { if (!(LHS is IComparable) || !(RHS is IComparable)) throw new Exception("Check using non basic type"); switch (op) { case ConditionalAttribute.OperatorEnum.Equals: return ((IComparable)LHS).CompareTo(RHS) == 0; case ConditionalAttribute.OperatorEnum.NotEqualTo: return ((IComparable)LHS).CompareTo(RHS) != 0; case ConditionalAttribute.OperatorEnum.EqualsOrGreaterThan: return ((IComparable)LHS).CompareTo(RHS) >= 0; case ConditionalAttribute.OperatorEnum.EqualsOrLessThan: return ((IComparable)LHS).CompareTo(RHS) 0; case ConditionalAttribute.OperatorEnum.LessThan: return ((IComparable)LHS).CompareTo(RHS) < 0; default: break; } return false; }}
  7. How do you like your eggs in the morning?

    OMG YOU REMBERED, THAT WAS MY THREAD :')   -- im satisfied so long as I get my kiss
  8. How do you like your eggs in the morning?

    Scrambled or fried?
  9. Note to self

    I almost deleted all .png's from my C drive once. That was a scary day at work. :)
  10. They called me crazy!

    washu wrote me this :) struct beufint_t { public: beufint_t () : t(et::n), u(0) {} beufint_t (bool b) : t(et::b), b(b) {} beufint_t (float f) : t(et::f), f(f) {} beufint_t (int i) : t(et::i), i(i) {} beufint_t (unsigned u) : t(et::u), u(u) {} operator bool () const { return t == et::b ? b : false; } operator int () const { return t == et::i ? i : 0; } operator float () const { return t == et::f ? f : 0; } operator unsigned () const { return t == et::u ? u : 0; } operator void const * () const { return t != et::n ? this : 0; } bool operator () (bool) const { return t == et::b; } bool operator () (int) const { return t == et::i; } bool operator () (float) const { return t == et::f; } bool operator () (unsigned) const { return t == et::u; } private: enum class et { b, f, i, u, n }; union { bool b; float f; int i; unsigned u; }; et t; };
  11. They called me crazy!

    Ladies and gentle men, I bring to you, the Binteger (bool + int).
  12. turns out I wasn't banned. but when I tried to join multiple times, it said I didn't hqave permission :(