Friday, August 31, 2018

Unity Quick Tip: Snap to grid with arrow keys


Explanation

If you're working with pixel art in Unity, you know how difficult it can be to have a workflow that's fast and comfortable. First off, if you're not sure about the relationship between pixel art, PPU and Orthographic camera size, you should read thist post and this thread.

GameObjects Positions

As you know, GameObjects have a Transform component that determines its position in the game world, measured in Units
The problem when you're working with pixel art is that a GameObject position cannot be any number we want, it should be a multiple of our "pixel size". This means that if one pixel occupies 0.0625 units, we want every position to be a multiple of 0.0625. 
PPU stands for Pixel Per Unit, so as you probably guessed, our pixel size will be 1/PPU.

Unity Built-in snapping

You should know that Unity has a built-in function to move objects a fixed amount. It's called Unit snapping, you can customize the amount in Edit/Snap Settings and move an object by that amount by dragging it while holding Ctrl.
This helps, partially, because you can set your Snap amount to your pixel size in every axis and always move objects holding Ctrl. The problem is that if the starting position of the object is not a multiple of your pixel size, you will end up with a position thats outside the grid anyway, because snapping only moves the object by a fixed amount, it doesn't really snaps to a grid. Also, dragging objects is not precise, and it's uncomfortable.
What we want is to be able to move an object using the arrow keys, and to make its position only take values that are multiples of our pixel size.

Our own snapping

First off, calculate your pixel size. Remember that it is 1/PPU. Personally I like to set it in Snap Settings in every axis, and I'll asume that you're doing it that way too, but you could store this value anywhere you like, just have in mind that we will need to be able to access it from an Editor script.
The script itself is pretty simple so I'll make a broad explanation of what we are doing and you can check the details in the script itself. What we are doing is based on this script to use the arrow keys, so be sure to check it out!.
  • We will: 
    • Subscribe to OnSceneGUIDelegate, to be able to get the key events.
    • Check if the Move tool is currently selected (You can ignore this if you want)
    • Check the current event to see if an arrow key is pressed
    • Get our pixel size from the Snap Settings (or from anywhere you store it)
    • Check which direction we are moving
    • Get every selected object, add one pixel size to its position
    • Clamp the new position to our grid so every component is a multiple of our pixel size

Note that we are only setting X and Y, that's because as we are working with pixel art I don't need to change the Z axis, but you could do it the same way.

using System;
using System.Collections;
using UnityEditor;
using UnityEngine;

[InitializeOnLoad]
public class ArrowEditorMove {

   static ArrowEditorMove() {
       //avoid registering twice to the SceneGUI delegate
       SceneView.onSceneGUIDelegate -= OnSceneView;
       SceneView.onSceneGUIDelegate += OnSceneView;
   }

   static void OnSceneView(SceneView sceneView) {
       if (Tools.current != Tool.Move) { return; }

       Event currentEvent = Event.current;
       bool keyDown = currentEvent.isKey && currentEvent.type == EventType.KeyDown;
       bool arrowKeys = (currentEvent.modifiers == EventModifiers.None
|| currentEvent.modifiers == EventModifiers.FunctionKey); //arrow keys are function keys
       //if the event is a keyDown on an orthographic camera
       if (keyDown && arrowKeys && sceneView.camera.orthographic) {
           Vector3 movement = Vector3.zero;
           float xStep = EditorPrefs.GetFloat("MoveSnapX");
           float yStep = EditorPrefs.GetFloat("MoveSnapY");

           switch (currentEvent.keyCode) {
               case KeyCode.RightArrow:
                   movement.x = xStep;
                   break;
               case KeyCode.LeftArrow:
                   movement.x = -xStep;
                   break;
               case KeyCode.UpArrow:
                   movement.y = yStep;
                   break;
               case KeyCode.DownArrow:
                   movement.y = -yStep;
                   break;
           }

           moveSelectedObjects(movement, xStep, yStep);
       }

   }

   static void clampPosition(ref Vector3 position, float xStep, float yStep) {
       position.x = Mathf.Round(position.x / xStep) * xStep;
       position.y = Mathf.Round(position.y / yStep) * yStep;
   }

   static void moveSelectedObjects(Vector3 movement, float xStep, float yStep) {
       UnityEngine.Object[] selectedObjects = Selection.GetFiltered(typeof(GameObject),
SelectionMode.Editable | SelectionMode.ExcludePrefab);
       for (int i = 0; i < selectedObjects.Length; i++) {
           Transform objectTransform = (selectedObjects[i] as GameObject).transform;
           Undo.RecordObject(objectTransform, "Move Step"); //allow undo of the movements
           Vector3 newPosition = objectTransform.position + movement;
           clampPosition(ref newPosition, xStep, yStep);
           objectTransform.position = newPosition;
       }

       // only consume the event if there was at least one gameObject selected, otherwise the camera will move as usual
       if (selectedObjects.Length > 0) {
           Event.current.Use();
       }

   }

}

Now just put this script in a folder named Editor inside your Assets folder, if you don't have an Editor folder just create it.

Any feedback or questions? Let me know in the comments!
If you enjoyed the post, remember to check the Patreon!

You can also follow Strangewire on Facebook, TwitterTumblr

Sunday, July 1, 2018

Unity Quick Tip: Editing .anim files



What's an .anim file?

An .anim file is created when we create a new animation clip in Unity. It contains all the data that the Animator needs to play a clip, be it object positions, names, rotations or anything else.

Actually these files are YAML, you can simply open them with any text editor and change them.


Why would I want to manually edit these files?

That's a great question! You normally wouldn't want to edit them as text, you would use the Unity Animator. But the Animator, as you probably know, has some flaws.
  • Changed an object name? The animation clip will lose the reference to it.
  • Want to change every position of every keyframe by a fixed amount? you'll need to edit them one by one.
  • You made some animations and then realized that the root bone had a different scale than 1 or you changed your sprites PPU? Changing those things would break all your animations.

Oh no! What can we do?

Do not worry! As we said we can open and edit these files manually, which means we can edit them with a script to change the values we need.

If you changed an object name, that's easy enough. Just search and replace as with any text.
Object names are stored like this: path: Bones/Hip, so you just need to change that with your new object path.

If you changed your root bone scale, position o sprites PPU, you'll need to get the positional values of every object and make some operation with them.
Positions are stored like this: value: {x: 0.43749998, y: -0.31250006, z: 0}.
We need to parse the file, get every string that matches that format, get every number inside it and replace it with our new values. As an example let's say we want to multiply them by 2.


Dirty work

Disclaimer: I know this code is awful and can be improved, but I know very little Python and just wanted to get the job done. Feel free to suggest a cleaner way to do it!

We will solve this using Python and Notepad++ (you could just as easily do it without Notepad++).
First we'll need to download Notepad++ (the 32-bit version) and this plugin that allows us to run Python scripts.
Once you have everything set up, open Notepad++ and go to Plugins/Python Script/New Script to create a new script and call it whatever you want and paste this code:


def multiply(match):
   return "value: {x: " + "{0}".format(str(float(match.group(1))*2)) + ", y: " + "{0}".format(str(float(match.group(3))*2))

editor.rereplace(r'value: {x: ([+-]?([0-9]*[.])?[0-9]+), y: ([+-]?([0-9]*[.])?[0-9]+)', multiply)


This code is defining a method that gets matches from a regular expresion and replaces them with what we tell it to. In this case, with the same string but with every number multiplied by 2.
Note that I only included X and Y coordinates, because I'm working in 2D, but you can easily extend this to cover the Z axis.

Now we just need to open the .anim file we want to edit and go to Plugins/Python Script/Scripts/yourScript, and it will change the file! Save it and go to Unity, once it's reimported you should see the changes in your animation right away.

Warning

While the code above will work and will change your animations, if you try to edit them in Unity the animator will go back to the previous state. That's because we didn't actually edited the local position of the objects. The problem is that a simple regular expression won't work for that and we'll need a YAML editor or something more powerful to do it but that escapes the scope of this post.

Any feedback or questions? Let me know in the comments!
If you enjoyed the post, remember to check the Patreon!

You can also follow Strangewire on FacebookTumblr

Sunday, May 13, 2018

Hitboxes and Hurtboxes in Unity


Explanation

So what are hitboxes and hurtboxes anyway? Aren’t they the same thing?
Well... The answer can differ depending on who you ask, but here we will abide to the notion that hitboxes and hurtboxes are two different things and have different uses, as any fighting game worth mentioning does.
A Hitbox is an invisible box (or sphere) that determines where an attack hits.
A Hurtbox on the other side is also an invisible box (or sphere), but it determines where a player or object can be hit by a Hitbox.

In this image from SFIV, the red box is the hitbox and the green one the hurtbox


It’s worth mentioning that the size and position of both hitboxes and hurtboxes change depending on the frame of animation that is playing:


Gif from Killer Instinct. Look how the hitboxes only appear on hitting frames and move with the sword


In the Killer Instinct example we can also see a third type of box, the Pushbox (the yellow one, the Hurtbox is the empty green box). A Pushbox is a box that represents the physical occupied space by a character, and keeps characters from overlapping.
In most fighting games or brawlers there’s two other types of boxes that for simplicity we will not cover:
The grab or throw box, that determines where a character can be grabbed or thrown, and the block box that determines where an attacked player that’s pressing the back button will start blocking a certain attack instead of walking backwards.

All these boxes are really important from a design point of view. Hitboxes and Hurtboxes of an attack determine not only how many frames an attack hits but also the blind spots of that attack and how vulnerable it leaves the player.
For a great explanation on this focused on Street Fighter check this video

Does this only apply to fighting games?

No! Almost every game has Hitboxes and Hurtboxes, from Dark Souls to Rayman, they can be three dimensional or two dimensional.

So now that we have our terminology straight, let’s start working.


What we want

Let’s check every type of box we’ll cover and see what we want from them:

Pushbox: We need for two pushboxes to collide with each other and not overlap (that’s why it’s called a pushbox, it pushes the other character). Pushboxes should only interact with other pushboxes.
Hurtbox: It can register a hit, but it should not collide in the physical sense. Hurtboxes should only interact with Hitboxes.
Hitbox: It should be able to check if it’s overlapping a Hurtbox in arbitrary frames. It should only interact with Hurtboxes.


Using Unity default components

The first approach one could do is map every kind of box that we talked about to a Unity default component. The obvious choice is some type of Collider.
The Pushbox can be directly mapped to a Collider plus a Rigidbody. That behaves exactly as we want it, it collides with things and doesn’t overlap.
The only part we need to worry about (besides setting our Rigidbody as we want it) is the part about only colliding with other Pushboxes. If you’re familiar with Unity physics system, you already know that the solution is to use Layers and the Layer Collision Matrix. For clarity we can create a layer called Pushbox, assign it to our object and set the collision matrix so Pushbox only collides with Pushbox.







For Hurtboxes we can use Collider using isTrigger. This ensures that it won’t collide in a physical sense and will only register other colliders entering it’s area. For actually registering the hit we will need to add a script in the same object that implements OnTriggerEnter, probably check the tag of the incoming collider to check that the one that triggered the event is the one we want and then do whatever damage and health calculations our game needs. You are probably familiar with this approach.
We also need to create the layers Hurtbox and Hitbox, and use the Layer Collision Matrix again to make Hurtbox only collide with Hitbox and vice versa.

  • Note that we don’t need a Rigidbody, but only because I’m assuming that every trigger we will add is a child object of the Pushbox object that already has a Rigidbody. This is important because Colliders without a Rigidbody in itself or some of its parents will be set as Static by Unity and moving them will be really inefficient.
  • Also, we will probably need to distinguish between a Hitbox from the player or one from the enemies. The same goes for Hurtboxes. This way we can make the Hitbox from the player only hit the Hurtbox from the enemies, and the Hitboxes of the enemies only hit the Hurtboxes of the player. You don’t need this if you want to allow friendly fire, but you gotta be careful to avoid a player hitting its own Hurtbox.

Hitboxes are maybe the least clear in how we should implement them. What we can use is a Collider using isTrigger to avoid a physical collision, but there are really no colliders that “enter” a Hitbox. Actually is the other way around: A Hitbox “enters” (or checks if it’s overlapping) a Hurtbox. Nevertheless, we need a Collider or Unity will never call OnTriggerEnter in our Hurtbox.
For dealing damage to the Hurtbox we will need to add a script in the same object, so that our Hurtbox can use GetComponent<T> and get it to know how much damage needs to be dealt. You can also do it the other way around, OnTriggerEnter gets called for both Colliders. We also need a way to make our Hitbox active only when we want to and not in every frame or when the character is not attacking for example. For this we can’t just disable our script because as the documentation says: “Trigger events will be sent to disabled MonoBehaviours, to allow enabling Behaviours in response to collisions”.
What we can do is enable and disable the collider, or add a boolean property to our script that handles if it should hit or not.


Problems

  • Hierarchy: we need to have a script in every object with a Collider to be able to respond to OnTriggerEnter. If you like to have your scripts in the same place for organizational reasons, you will need to create a script just to delegate the call to your other object. 
  • Overhead: With this approach our Hitboxes have a lot of functionality we don’t need. 
  • Events: We rely on OnTriggerEnter for our functionality. Using Unity events may not be a problem, but there’s reasons to at least think if we should. You can also check this (in the section“Avoiding expensive calls to the Unity API”) to know more.
  • Visuals: If you want to use different Hitboxes for different attacks, not only will the aforementioned problems repeat a lot, but you will have a lot of visual clutter on your editor window.
  • Little flexibility: Using Colliders as Hitboxes means that if you want to change the shape of the collider, for example from a Box to a Sphere, you’ll have to remove the BoxCollider and add a SphereCollider manually (or implement an editor script to do this for you)


Rolling our own

As you probably realized while reading the previous section, Pushboxes and Hurtboxes map pretty much okay to Unity default components.
Hurtboxes still have the problems mentioned and we will solve some of them, but the entity that seems to need its own abstraction is the Hitbox.
If you’re making a combat heavy game with a lot of attacks and combos, you probably want to have all your attacks neatly organized in an object and use several combinations of Hitboxes for any of them.To do that you would need a script that strictly delegates OnTriggerEnter calls to your active attack or something along those lines.

You don’t want to create a specific Hitbox object for every attack, here we can reuse the same changing the size!


Hitboxes

Our new component will need to cover the following:
  1. Have Hitbox behaviour: It should be able to check if it’s overlapping a Hurtbox in arbitrary frames. It should only interact with Hurtboxes. 
  2. Have a visual representation in the Scene view. 
  3. Be customizable and flexible. 
  4. Ideally, not depend on Unity API events. 
  5. Be independent enough to allow an script in another object to use it. 
  6. Not be coupled to a specific attack, Hitboxes should be usable by several different attacks.


Behaviour

First off, how do we check if some area is overlapping a Collider? The answer is to use UnityEngine.Physics.
Physics has a lot of methods that can do what we want. We can specify the shape we want (Box, Sphere, Capsule) and also if we want to get the Colliders we hit (if any) as an array or pass an array to be filled with them. You shouldn’t worry right now about this, but the first one is allocating a new array, the other just fills the one you already had.

Let’s start by checking a rectangular area and see if we hit something. For this we can use OverlapBox.

We need to define the dimensions of the box we want to check. For this we need the center of the box, its half-extents, its rotation and the layers that it should hit. Half-extents are the half of the size in every direction, for example if you have a box with size (2, 6, 8) its half extents would be (1, 3, 4).
For the center you can use the GameObject transform position and for the rotation the GameObject’s transform rotation or you can add public variables to set them specifically.
Half-extents is simply a Vector3 so expose it and use it.
For the layers to hit you can expose a public property of type LayerMask. That will let you select layers via the inspector.

Collider[] colliders = Physics.OverlapBox(position, boxSize, rotation, mask);

if (colliders.Length > 0) {
Debug.Log("We hit something");
}

If you set that correctly and the box we are projecting is overlapping a Collider in the correct mask when you call this, you should see the message on the console.


Visual Representation

That’s cool but... It’s not very functional. Right now we can’t see the box we are defining anywhere, it would be really difficult to set correct sizes and positions of Hitboxes this way.
So how do we draw our box on the Scene view but not in-game? Using OnDrawGizmos.
As its documentation says: “Gizmos are used to give visual debugging or setup aids in the scene view.”, just what we were looking for!
We need to give our Gizmo a color and a transformation matrix. Don’t worry about it, we’ll just create a matrix with the position, rotation and scale of our transform.


private void OnDrawGizmos() {
Gizmos.color = Color.red;
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.localScale);
Gizmos.DrawCube(Vector3.zero, new Vector3(boxSize.x * 2, boxSize.y * 2, boxSize.z * 2)); // Because size is halfExtents
}


If you want, you can use OnDrawGizmosSelected instead to only draw the box when you select the object.


Customization and flexibility

Customization is a broad subject and it’ll depend a lot on what kind of game you’re making and what functionality you are looking for.
In this case we will allow for a quick change in hitbox shape and color. If you are using Anima2D or some kind of bone oriented animation, you’ll probably want to also allow for the Hitbox to scale following a bone scale.
Changing the shape it’s as easy as adding a boolean and changing OverlapBox to some other shape, for example OverlapSphere. You need to add a public radius property to configure the sphere. Remember that you’ll also need to change what’s inside OnDrawGizmos to actually draw the new shape (in our example, DrawSphere).
Note that we are not adding a new component or removing anything, it’s just a boolean that will select the shape to overlap when it checks collision. That allows us to change the shape of our hitbox basically for free depending on the attack (or even in the same attack if we want to).
For color, I would like for a Hitbox to change color depending on if it’s inactive, if it’s checking for collisions or if it’s actually colliding with something. We will also need those states for our logic later so let’s add them.

We’ll create an enum for the state and 3 colors and add them as properties of our Hitbox.

public enum ColliderState {

Closed,
Open,
Colliding
}


Your class probably looks something like this:

public class Hitbox: MonoBehaviour {
public LayerMask mask;
public bool useSphere = false;
public Vector3 hitboxSize = Vector3.one;
public float radius = 0.5f;
public Color inactiveColor;
public Color collisionOpenColor;
public Color collidingColor;

private ColliderState _state;

/*
and your methods
*/
}


And now you can update your gizmos replacing the line Gizmos.color = Color.red; with a call to a new method:

private void checkGizmoColor() {
switch(_state) {
case ColliderState.Closed:
Gizmos.color = inactiveColor;
break;
case ColliderState.Open:
Gizmos.color = collisionOpenColor;
break;
case ColliderState.Colliding:
Gizmos.color = collidingColor;
break;
}
}

So where are we going to change our state? We will need three things:
  1. a way to tell the Hitbox to start checking for collisions 
  2. a way to tell it to stop 
  3. a way to actually check the collision
The first two are obvious:

public void startCheckingCollision() {
_state = ColliderState.Open;
}

public void stopCheckingCollision() {
_state = ColliderState.Closed;
}

Now, while a Hitbox is active we want to check every frame if it’s colliding with something until it stops being active. That brings us to the next point…


Independence of Unity Events API

As you probably know, to check something every frame you can use Update (for sake of simplicity I didn’t add the check to change the shape):

private void Update() {
if (_state == ColliderState.Closed) { return; }
Collider[] colliders = Physics.OverlapBox(position, boxSize, rotation, mask);

if (colliders.Length > 0) {
_state =  ColliderState.Colliding;
// We should do something with the colliders
} else {
_state =  ColliderState.Open;
}

}

You can see we are returning only if the current state is “Closed”. This means we are still checking collisions if the Hitbox is colliding, wich allows the Hitbox to hit several objects at the same time and not only the first it hits. It depends on your game how you want this to work.
We are using Update and we said we didn’t want to depend on Unity Events API! Well, depending on how you want to structure your code the solution is to make your own public update method, we could name it hitboxUpdate (the contents would be the same as our Update method above), and call it only in the Hitboxes used by the current attack.
Obviously we would have a call to Update() in some object higher in the hierarchy, but we certainly don’t need to use it on every Hitbox all the time just because it’s there.


Allowing an script in another object to use a Hitbox

Remember that a problem of using a Collider was that you needed a script in the same GameObject to implement OnTriggerEnter? As we are using our own script and can add to it whatever we want, the solution is pretty clear.
We will add an object as a property so we could call some method on it when the Hitbox collides with something.
There are several approaches to this:
  • You can add a public GameObject and use SendMessage. (This is not performant at all) 
  • You can do the same with a Monobehaviour that has a specific method to be called when a Hitbox collides. This has the disadvantage that if you want several different scripts to use Hitboxes you would need to add all those properties or inherit from a base script that has the method to be called
  • You can create an interface with the method you want to call and implement it in every class you want to use Hitboxes. 
Design wise, an interface is the clear choice for me. The only problem in Unity is that the editor by default does not renders interfaces as public properties, so you can’t assign it via the editor. We’ll cover why that is not a real problem in the next point.

Let’s create and use the interface:

public interface IHitboxResponder {
void collisionedWith(Collider collider);
}


Let’s add it as a property of our Hitbox…

public class Hitbox : MonoBehaviour {
...
private IHitboxResponder _responder = null;
...

/*
and the rest of the class
*/
}

You could also use an array instead of a single responder if you want.
Let’s use the responder:

public void hitboxUpdate() {
if (_state == ColliderState.Closed) { return; }
Collider[] colliders = Physics.OverlapBox(position, boxSize, rotation, mask);

for (int i = 0; i < colliders.Length; i++) {
Collider aCollider = colliders[i];
_responder?.collisionedWith(aCollider);
}

_state = colliders.Length > 0 ? ColliderState.Colliding : ColliderState.Open;

}

If you’re not familiar with the ‘?’ operator, check this.
Cool! But how do we set the _responder property? Let’s add a setter and cover that in the next point.

public void useResponder(IHitboxResponder responder) {
_responder = responder;
}


Not be coupled to a specific attack, Hitboxes should be usable by several different attacks

This section should make it clear why it doesn’t matter that we can’t set our HitboxResponders using the editor.
First let’s talk about these “responders”. In the approach we took to implement our Hitboxes, a responder is any class that should do something when a Hitbox collides with a Collider, and therefore implements IHitboxResponder. An example would be an attack script, you probably want to do damage to the thing you hit.
As we want to be uncoupled from any particular attack and be reusable, setting responders from the editor would not accomplish anything because we want to be able to swap responders on the fly.
As an example, let’s suppose we have two types of attack, a straight punch and an uppercut with the same arm, and each one of them has its own script that says in which frames of the animation they should hit, how much damage they should do and those kind of things. As they both are attacks of the same extremity, let’s reuse the same Hitbox.

public class Attack: Monobehaviour, IHitboxResponder {
...
public int damage;
public Hitbox hitbox;
...

public void attack() {
hitbox.setResponder(this);
// and do the rest of your attack
}

void collisionedWith(Collider collider) {
Hurtbox hurtbox = collider.GetComponent<Hurtbox>();
hurtbox?.getHitBy(damage);
}

}

Great! We got some working hitboxes. As you can see in the code above, we added a method getHitBy(int damage) to our hurtboxes. Let’s check if we can improve those.


Improving our Hurtboxes

Ideally we would want to cover more or less the same points we did with the Hitboxes. It should be easier because a Collider actually has the behaviour we want. Also we need to use a Collider or Physics.Overlap… won’t report a hit.
Note that because of the way we structured our code, we don’t need to use OnTriggerEnter for anything, we are getting our script using GetComponent.
That leaves us with customization and flexibility. To be as flexible as our Hitboxes we would need to add and remove colliders on the fly, and for customization we can draw a color over the collider depending on the state.

public class Hurtbox : MonoBehaviour {
public Collider collider;
private ColliderState _state = ColliderState.Open;

public bool getHitBy(int damage) {
// Do something with the damage and the state
}

private void OnDrawGizmos() {
// You can simply reuse the code from the hitbox,
// but taking the size, rotation and scale from the collider
}

}

Adding and removing Colliders on the fly is not as easy as with our Hitboxes. I haven’t found a satisfactory way to do this. What you can do is add several different Colliders to your script and select which one you want using a boolean as we did with the Hitboxes. the problem with this is that you need to add every Collider you want as a component and you end up with a lot of visual clutter in your editor window and in your object.
Another approach is to add and remove the components via code, but that would add a lot of unnecessary garbage and probably not be as precise.
What would be ideal is to be able to make Hurtbox inherit from Collider and make all the shape logic internal and only draw the one we are currently using, but I couldn’t make this work the way I wanted.


So now what?

If you followed the post until here, you now have hitboxes, hurtboxes and pushboxes implemented in Unity. But most importantly, you now know those abstractions if you didn’t before and that will simplify everything you need to build on top of them.
Your script inspector probably looks awful though, but don’t worry, we will cover that in another post:

You can convert this…

Into something like this!


Any feedback or questions? Let me know in the comments!
If you enjoyed the post, remember to check the Patreon!

You can also follow Strangewire on Facebook, Tumblr