There are many simple mobile games out there that are extremely popular. Knife Hit from Estoty, published by Ketchapp is no exception. Really, how simpler can a game mechanic even be?

It doesn’t matter how simple the mechanic behind a game is, the only thing that actually matters is if the game is fun to play! That’s what separates successful games from those on the mobile game graveyard.

The best way to learn game development is by studying and replicating the successful ones. This is what this tutorial is about. You will learn how to make Knife Hit!

In this first part out of two you will learn how to create the rotating log and how to hit it with a single knife. The second part will deal with spawning more knives, creating a game over sequence, working with UI, creating game effects (particles!) and more, so stay tuned for that!

Do you prefer video tutorials?

 

Resources you might want to download

This Unity tutorial uses custom sprite assets which you are free to use if you would like to follow along with the same exact sprites. It is also completely fine to create your own artwork. I used an open-source vector graphics software called Inkscape.

You can download these assets from this link.

Create a new Unity project

We will work in a fresh project with the 2D template selected.

Changing the look & feel

Create a new folder under Assets and name it Art. Drag all of the provided sprites (or your own) in there. Then you want to select all of the sprites and set their Pixels Per Unit to 300.

Next, to make sure you have the correct aspect ratio of the camera for a mobile game (9:16), you should adjust the aspect ratio in the game tab. Feel free to also switch to a mobile build platform (Android / iOS) and there you will have a 9:16 ratio automatically. Since this tutorial doesn’t deal with publishing your game, you can also leave the build platform on PC/Mac/Linux. The beauty of Unity is that you can export this game to mobile literally with one click of a button.

Lastly, change the camera background color to a nice shade of dark blue. You could also add a cool background image as a child of the camera if you’d like to. This tutorial uses a color #021C32.

Creating the rotating log object

Right click on the hierarchy and create an empty Game Object. Set its name to be LogMotor. Center its position on all but Y axis which will be set to 2. Add a new component Wheel Joint 2D onto it.

Creating a Wheel Joint 2D automatically adds a Rigidbody 2D component as well. Set its body type to Kinematic so that it will not be affected by physics.

Now that we have the LogMotor, drag the log sprite from the art folder onto the LogMotor. This will create a new Game Object as a child of LogMotor called Log. Center this new object’s transform position.

The Log Game Object already has one Sprite Renderer component. Let’s add two other components Rigidbody 2D and Circle Collider 2D.

Make sure you have set the Rigidbody’s Linear Drag, Angular Drag and Gravity Scale to be 0. The Collision Detection will be best set to “Continuous”. The Radius of the Circle Collider should be 0.75 to leave some room for the knifes to appear as they are stuck in the log.

Let’s recap for a little bit. You have a Log object which is a child of LogMotor. On this Log is a Rigidbody 2D which the Wheel Joint 2D on the LogMotor will use to rotate the log using a JointMotor2D which we are going to create in a script below.

There is one last step for this to be possible. You need to connect the Log’s Rigidbody to the LogMotor’s Wheel Joint. Unity makes it really simple. Simply select LogMotor in the hierarchy and drag the child object called Log into the Wheel Joint 2D’s field Connected Rigid Body like in the picture below.

Scripting the log rotation

Now that we have the foundation in place, it is time to get into coding. To make things organized, create a a Scripts folder under Assets and create a new C# script over there. Give it a name LogRotation and open it up in Visual Studio or other IDE of your choice. You will later attach this script to the LogMotor Game Object.

Below is the full LogRotation script with exhaustive comments for explanation.

using System.Collections;
using UnityEngine;

public class LogRotation : MonoBehaviour {

    [System.Serializable] //this will allow us to edit it in the editor
    //a custom class representing a single rotation "element" of the log's rotation pattern
    private class RotationElement
    {
        //to get rid of an obnoxious warning about these fields not being initialized
        #pragma warning disable 0649
        public float Speed;
        public float Duration;
        #pragma warning restore 0649
    }

    [SerializeField] //attribute making private fields editable in the Unity Editor
    //the aforemention full rotation pattern of the log
    private RotationElement[] rotationPattern;

    //this will be set to the Wheel Joint 2D from the LogMotor object
    private WheelJoint2D wheelJoint;
    //something has to actually apply a force to the log through the Wheel Joint 2D
    private JointMotor2D motor;

    private void Awake()
    {
        //setting fields
        wheelJoint = GetComponent<WheelJoint2D>();
        motor = new JointMotor2D();
        //starting an infinitely looping coroutine defined below right when this script loads (awakes)
        StartCoroutine("PlayRotationPattern");
    }

    private IEnumerator PlayRotationPattern()
    {
        int rotationIndex = 0;
        //infinite coroutine loop
        while (true)
        {
            //working with physics, executing as if this was running in a FixedUpdate method
            yield return new WaitForFixedUpdate();

            motor.motorSpeed = rotationPattern[rotationIndex].Speed;
            //hard coded 10000, feel free to experiment with other torques if you wish
            motor.maxMotorTorque = 10000;
            //set the updated motor to be the motor "sitting" on the Wheel Joint 2D
            wheelJoint.motor = motor;

            //let the motor do its thing for the specified duration
            yield return new WaitForSecondsRealtime(rotationPattern[rotationIndex].Duration);
            rotationIndex++;
            //infinite loop through the rotationPattern
            rotationIndex = rotationIndex < rotationPattern.Length ? rotationIndex : 0;
        }
    }
}

Once you have this LogRotation script written and understood, drag it onto the LogMotor object in the editor. Then fill the values of the rotationPattern array how you wish. The best thing about this approach is that you can customize it very easily and even generate random values for new levels. The rotationPattern used in this tutorial looks like this:

Making the knife

Now that you have the rotating log, it’s time to hit it with a knife! In this tutorial you are going to make a single knife and in the next (and final) part you will make them spawn a certain number of times and also create the accompanying user interface.

To create a knife, drag the Knife sprite from the Art folder into the scene. Set its position to X=0, Y=-3.5, Z=0. Add a Rigidbody 2D component and set the Gravity Scale to 0 (we don’t want it to fall down as soon as the game starts). Also add a Box Collider 2D with the following size:

The Box Collider needs to be a bit wider than the sprite because of Unity’s unreliable collision detection. Otherwise knives could be overlapping which should not be possible!

Coding the KnifeScript

This KnifeScript will be attached to every Knife Game Object. Clarification for this code is below.

using UnityEngine;

public class KnifeScript : MonoBehaviour {

    [SerializeField]
    private Vector2 throwForce;

    //knife shouldn't be controlled by the player when it's inactive 
    //(i.e. it already hit the log / another knife)
    private bool isActive = true;

    //for controlling physics
    private Rigidbody2D rb;
    //the collider attached to Knife
    private BoxCollider2D knifeCollider;

    private void Awake()
    {
        rb = GetComponent<Rigidbody2D>();
        knifeCollider = GetComponent<BoxCollider2D>();
    }

    void Update () 
	{
        //this method of detecting input also works for touch
		if (Input.GetMouseButtonDown(0) && isActive)
        {
            //"throwing" the knife
            rb.AddForce(throwForce, ForceMode2D.Impulse);
            //once the knife isn't stationary, we can apply gravity (it will not automatically fall down)
            rb.gravityScale = 1;
            //TODO: Decrement number of available knives
        }
	}

    private void OnCollisionEnter2D(Collision2D collision)
    {
        //we don't even want to detect collisions when the knife isn't active
        if (!isActive)
            return;

        //if the knife happens to be active (1st collision), deactivate it
        isActive = false;

        //collision with a log
        if (collision.collider.tag == "Log")
        {
            //stop the knife
            rb.velocity = new Vector2(0, 0);
            //this will automatically inherit rotation of the new parent (log)
            rb.bodyType = RigidbodyType2D.Kinematic;
            transform.SetParent(collision.collider.transform);

            //move the collider away from the blade which is stuck in the log
            knifeCollider.offset = new Vector2(knifeCollider.offset.x, -0.4f);
            knifeCollider.size = new Vector2(knifeCollider.size.x, 1.2f);

            //TODO: Spawn another knife
        }
        //collision with another knife
        else if (collision.collider.tag == "Knife")
        {
            //start rapidly moving downwards
            rb.velocity = new Vector2(rb.velocity.x, -2);
            //TODO: Game Over
        }
    }
}

Let’s clarify. The bit of code which operates on the knifeCollider field

...
knifeCollider.offset = new Vector2(knifeCollider.offset.x, -0.4f);
knifeCollider.size = new Vector2(knifeCollider.size.x, 1.2f);
...

will make the Box Collider 2D look like this when the knife hits the log (green outline):

Do you see that the blade which will be stuck in the log doesn’t have a collider around it? This is important.  Otherwise knives could think they collided when the player shoots them really close to each other because the log is round.

Another thing is that the script uses tags to check what is the other object with which the knife is colliding. You need to set up these tags for this code to function.

Select the Log object from the hierarchy. Under the name there is a dropdown marked as Tag. Let’s create new tags called Log and Knife (I already have them on the pictures, you don’t).

Once you have these tags, set them on their respective Game Objects (Log and Knife).

Now that you have everything set up correctly, making the knife actually do something is easy! Simply drag the KnifeScript onto the Knife object and fill in the throwForce.

Lastly, set the following on the Log object’s components. We need to freeze Log‘s position because the Knife would actually move it once it hits. The order in layer of the Sprite Renderer will make sure the Log is displayed in front of the Knife, not behind.

 

The only thing left for you to do now is to test it out!

Conclusion

In this first part you learned how to make a semi-functional Knife Hit replica. The basic game mechanics are fully implemented. The next part will teach you how to make it fully-functional by creating a knife count, spawning knives, creating a game over sequence, working with UI, creating game effects (particles!) and more. Be sure to stay tuned for it. See you in the next post!

About the author 

Matt Rešetár

Matt is an app developer with a knack for teaching others. Working as a freelancer and most importantly developer educator, he is set on helping other people succeed in their Flutter app development career.

You may also like

  • Really helpful for someone learning Unity like me, When is the second part coming ? Will you cover animations too ?

  • I got this 2 errors how to solve this? 🙁
    1.Error CS1061: ‘UnityEngine.Rigidbody2D’ does not contain a definition for ‘bodyType’ and no extension method ‘bodyType’ accepting a first argument of type ‘UnityEngine.Rigidbody2D’ could be found (are you missing a using directive or an assembly reference?) (CS1061) (Assembly-CSharp)
    2.Error CS0103: The name ‘RigidbodyType2D’ does not exist in the current context (CS0103) (Assembly-CSharp)

  • Please make a video to show us how to add levels to knife hit game, using different graphic assets for the log and the knife for each level. Show us example of at least two levels with two different logs and knives. Thanks

  • Thanks for the tutorial and I have made Knife hit replica it working perfectly, Please make a video to show us how to add levels with different knife and logs.

  • my knife was not stay on log it bounce back every time help me plzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
    >