Hi all,
I am a person who cares about order too much. So when I write scripts I hate from seeing them in chaos. I want to see them more clean and in order so whats the tricks for scripting more clearly and more orderly.
Hi all,
I am a person who cares about order too much. So when I write scripts I hate from seeing them in chaos. I want to see them more clean and in order so whats the tricks for scripting more clearly and more orderly.
Well… for starters it really depends on your own idea of what is clean and orderly.
There’s also different aspects of cleanliness. Such as naming conventions, brevity/wordiness, organization of your code across classes, design patterns (which can help in organization, not just in design of the software… you’ll learn to navigate your code because the patterns will be familiar).
The topic is so broad that it could hardly be covered in a forum thread with out being ironically disorganized.
Line up your brackets!
I am not talking about the performance stuff or things like that with clean and orderly. I am talking about the view of code. When I open it should be easy to read.
I shouldnt say “Does this bracket is connected to that function?” because when I check my scripts I am seeing just plain and messy scripts.
Yeah, neither of us were talking about performance either.
Lining up brackets doesn’t change performance.
Naming conventions usually don’t either.
And so on.
good naming conventions, breaking things into separate classes or methods when needed. using whitespace and comments, thinking before you type.
Really up to you
Order your stuff. For example, all my classes are ordered this way;
Constant in one place.
Field on top of the class, with their associated property after them.
Private/Internal fields that doesn’t have properties.
Events.
Unity’s call method after, and in order of execution (OnEnable, Awake, Start, Update, OnDestroy)
Public method following.
Private method last.
I never do
if (condition) DoAction();
I do;
if (condition)
DoAction();
Don’t be afraid to leave white lines to separate logic blocks of actions.
Don’t comment everything, comment what needs comments.
All class name, properties, methods, events are pascal case.
All fields and variables are camel case.
Do not use underscores, hyphens, or any other nonalphanumeric characters.
Prefer readability over brevity.
Well I am writing like that too but the problem is when the script reaches to five hundred lines it is starting to be hard to read even with spacing and etc.
btw thanks for suggestions guys.
if you’re classes are getting long. Maybe time to break that up into a couple separate scripts.
Each script should accomplish a specific job… not be a do all script.
I of course use ‘regions’ to organize my code though further. Monodevelop and Visual Studio and Notepad++ all allow shrinking regioned areas.
Example:
An AI state I just wrote an hour ago:
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using com.spacepuppy;
using com.spacepuppy.AI;
using com.spacepuppy.Geom;
using com.spacepuppy.Utils;
using com.apoc.Components.Movement;
using com.apoc.Components.Movement.Mob;
using com.apoc.Components.Movement.Mob.Jelly;
using com.apoc.Components.Anim.Mob;
namespace com.apoc.Components.Role.Mob.Jelly
{
public class JellyWanderState : ApocAIState
{
#region Fields
public Interval Speed = Interval.Stutter(2.0f, 0.5f);
public Interval TurnSpeed = Interval.Stutter(5.0f, 0.5f);
public float ReflectSpeedBoost = 1.0f;
public float ReflectSpeedDownDuration = 1.0f;
public float TurnRange = 90.0f;
public Interval ChangeDirectionInterval = Interval.MinMax(2.0f, 4.0f);
public Interval StutterInterval = Interval.MinMax(0.4f, 0.6f);
private RadicalCoroutine _thinkRoutine;
private JellyFlyMovementStyle _flyStyle;
#endregion
#region CONSTRUCTOR
protected override void Awake()
{
base.Awake();
}
#endregion
#region AIState Entry Point
protected override void OnStateEntered(AIController ai, IAIState lastState)
{
base.OnStateEntered(ai, lastState);
_flyStyle = this.Motor.GetStyle<JellyFlyMovementStyle>();
if(_flyStyle == null)
{
_flyStyle = this.Motor.AddComponent<JellyFlyMovementStyle>();
}
this.Motor.ChangeStyle(_flyStyle, float.PositiveInfinity);
_thinkRoutine = this.StartRadicalCoroutine(this.State_Wander());
}
protected override void OnStateExited(AIController ai, IAIState nextState)
{
if (_thinkRoutine != null)
{
_thinkRoutine.Cancel();
_thinkRoutine = null;
}
base.OnStateExited(ai, nextState);
}
#endregion
#region Wander
private System.Collections.IEnumerable State_Wander()
{
WanderRestart:
_flyStyle.Speed = Random.Range(Speed.Min, Speed.Max);
_flyStyle.TurnSpeed = Random.Range(TurnSpeed.Min, TurnSpeed.Max);
_flyStyle.ReflectSpeedBoost = ReflectSpeedBoost;
_flyStyle.ReflectSpeedDownDuration = ReflectSpeedDownDuration;
var startM = this.Motor.GetTransformMatrix2D();
var m = startM;
m.Rotate(Random.Range(-this.TurnRange * 0.5f, this.TurnRange * 0.5f) * Mathf.Deg2Rad);
_flyStyle.SetTargetDirection(m.right);
var endTime = GameTime.Time + Random.Range(ChangeDirectionInterval.Min, ChangeDirectionInterval.Max);
float wait = Random.Range(ChangeDirectionInterval.Min, ChangeDirectionInterval.Max);
while (true)
{
_flyStyle.Speed = Random.Range(Speed.Min, Speed.Max);
_flyStyle.TurnSpeed = Random.Range(TurnSpeed.Min, TurnSpeed.Max);
var stutter = Random.Range(StutterInterval.Min, StutterInterval.Max);
if (wait > stutter)
{
yield return new WaitForSeconds(stutter);
}
else
{
if(wait > 0f) yield return new WaitForSeconds(wait);
break;
}
wait -= stutter;
}
goto WanderRestart;
}
#endregion
}
}
I agree! Aim for scripts under 200 lines and methods under 8. It might sound extreme, and it’s not the best fit in all cases, but give it a shot as a general approach. It really forces you to keep classes and methods focused on a single job, which is ideal for component-based approaches like Unity. It’s much easier to keep a 100 line script organized than a 1,000 line script.
And keeping your method under 8 lines means you can’t throw in the kitchen sink. Instead of computing a value and using it in the same method, you have to compute the value in a different method and return it. This method is then available to use elsewhere in your code, which helps with the DRY (Don’t Repeat Yourself) principle. It’s also more self-documenting.
Here’s a completely fabricated example. This method does too much:
public void Attack() {
var weapon = GetComponent<Weapon>();
float damage;
if (weapon != null) {
damage = weapon.damage;
} else {
damage = unarmedDamage;
}
var body = target.GetComponent<Body>();
if (body != null) {
body.TakeDamage(damage);
}
}
The code below makes each step clearer.
public void Attack(GameObject target) {
float damage = GetDamage();
ApplyDamage(target, damage);
}
float GetDamage() {
var weapon = GetComponent<Weapon>();
if (weapon != null) {
return weapon.damage;
} else {
return unarmedDamage;
}
}
void ApplyDamage(GameObject target, float damage) {
var body = target.GetComponent<Body>();
if (body != null) {
body.TakeDamage(damage);
}
}
Plus, you can re-use GetDamage() and ApplyDamage() elsewhere.