🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

A Single Step

posted in My First Game
Published July 16, 2021
Advertisement

A Warning

I should probably preface this entire blog with a single statement. I have no idea what I am doing. I have played around with programming and the Unity Game Engine quite a bit, did a few little projects that never really got off the ground, and then decided to finally sit down and force myself to really make a game. So if you want tried and true advice from an industry professional, then you are in the wrong place. I am a Novice at best and can give very little in the way of best practices but what I can do is write about my experience and my attempts at going from some schmuck who is lost in a pile of spaghetti code to someone who can at least tell you what not to do. For those who have any critiques, advice, or wisdom to share with me, though, I will happily listen to the experience of those who have been at this longer than I have. So whether it's about my code, architecture, the way I do my blogs, or any other piece of criticism, I would love your input as long as you can tell me what's wrong and how I can improve.

The Plan

The game I'm going to make as my first Complete project is simple. I'm going to make a 3d RPG that takes its cues from the late PlayStation 1 and early PlayStation 2 era. It'll have a set player character that can level up, items and equipment, a procedurally generated dungeon to explore, and a town to buy things in. I don't know the story I'm going to use for it right now, but that's okay; making up an excuse to go into a dungeon and kill horrifying monsters is a whole lot easier than programming the systems necessary to do so. And without further ado, it's time to move on to how the first day of development went.

What I Got So Far

After spending hours of work, liters of coffee, and an extensive series of obscure curses, I have complete… not much. The first thing I wanted to work on was mouse-camera movement, and since I prefer not to reinvent the wheel, I used one of Unity's inbuilt solutions, Cinemachine. It is a godsend and works so easily right out of the box that I feel like I have been given a blessing by Developer Heaven. It'll probably turn into trouble in the future, but for the time being, it works so smoothly that it's hard to say no. If you want a lot of control with your camera and the ability to hook it up and have a function 3rd person camera right out of the box, I recommend looking into it.

I know most people aren't necessarily interested in what went well, though, so now it's time to tell you about the struggle I have endured only on the first day.

Player Controller

Right now, the player controller is its own script that, well, controls the player. Using the Character Controller component and the Move function, I've set up a little piece of code that has the player move based off of the user's input. Using the Move function of the Character Controller, I discovered how to make my capsule-shaped protagonist zoom across the ground fractions of meters at a time until I remembered to implement a variable to control the character's speed so I can make it move faster than my internet connection. After the momentary embarrassment, I fell into my first real challenge. How do I get the player to move in the direction the camera is facing?

After quite a bit of stumbling, attempting to set the Player gameObject's forward to the main camera's forward, I found a function under the transform property that I realized might just be the ticket. Thanks to my new friend TransformDirection I can easily move the player in the camera is pointing. After a whopping half-hour, my labor of the movement code was completed, and I have completed this behemoth.

private void CharacterMove()
   {
       Vector3 moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
       moveDirection = Camera.main.transform.TransformDirection(moveDirection);
       moveDirection *= speed * Time.deltaTime;
       characterController.Move(moveDirection);
   }

Okay, so it's not actually that impressive. But it did make me feel clever, and for me, that's enough for the time being. However, I wasn't going to just stop there. Now that I could make the character move and look with the camera, my greed began to grow, and I was overtaken with the desire to sink my teeth into more. That is when I had the daring idea to add a character model to this project and, even more scandalous, some animations. Lacking the skills and knowledge to create anything resembling a humanoid in a blender or any other 3d modeling software, I simply took the XBot on Mixamo. I don't plan on releasing my game, so any possible issue with licensing didn't really matter.

From a Bad Idea to a Good One

So I at first, I had two states in my Animator. One state being Idle and the other being Running with each being separated a single bool of isRunning. After plugging the Animator into the PlayerController, I realized that I had made an error in the structure of my code. My Animator had no reason to be in the same script as my Player Controller. Why does it need to know movement code? What about the parameters and values that control animations that will eventually bloat my beautiful 5 line movement code? So I did the only thing that made sense. I made an AnimationController to go with my PlayerController. After quite a bit of reading, I decided to simply save the parameters used to control the Animation Controller as hashes and then use them to quickly change the values of the parameters within the Animator. So now I have what I hope to be an easily expandable script for any future parameters and functionality I decide to add to the PlayerController.

public class AnimationController : MonoBehaviour
{
   private Animator animator;

   int isRunning_Hash;
   bool isRunning = false;
   void Start()
   {
       animator = GetComponentInChildren<Animator>();
       isRunning_Hash = Animator.StringToHash("isRunning");
   }
   public void SetRunning(bool isRunning)
   {
       if (this.isRunning == isRunning) return;
       this.isRunning = isRunning;
       animator.SetBool(isRunning_Hash, isRunning);
   }
}

An hour and a half in, I only had one last thing I wanted to take care of before I had to get some sleep before work the next day. I had to make sure my player model actually turned to face the direction of movement. As much as I love moonwalking, I would rather it be intentional rather than accidental. Luckily there was one function out there that I was already familiar with. The good ol' Slerp. A cursory look at the documentation showed that it was basically the same as the Vector3. So, Slerp, all I needed was a single line of code to get the turning I was looking for. With that, the basis of my movement code was done. I could look, I could move, and the AnimationController ensured that the proper animations were played. With those out of the way, I could finally get some rest before work and leave the code for attacking and an attack animation for tomorrow. For those interested, though, here is what my movement script ended up looking like:

using UnityEngine;

[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(AnimationController))]
public class PlayerController : MonoBehaviour
{
   private CharacterController characterController;
   private AnimationController animationController;
   [SerializeField] private float speed = 10;
   private void Awake()
   {
       characterController = GetComponent<CharacterController>();
       animationController = GetComponent<AnimationController>();
       characterController.center = new Vector3(0, 1, 0);
   }

   private void Start()
   {
       Cursor.lockState = CursorLockMode.Locked;
   }

   private void Update()
   {
       if (Input.GetAxis("Vertical") != 0 || Input.GetAxis("Horizontal") != 0)
           CharacterMove();
       else
           animationController.SetRunning(false);
   }

   private void CharacterMove()
   {
       Vector3 moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
       //Set's user input to be in relation to main camera
       moveDirection = Camera.main.transform.TransformDirection(moveDirection);
       //removes y movement so the character doesn't start flying
       moveDirection = new Vector3(moveDirection.x, 0, moveDirection.z);
       moveDirection *= speed * Time.deltaTime;
       characterController.Move(moveDirection);
       transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(moveDirection), 0.1f);
       animationController.SetRunning(true);
   }
}
Next Entry Basic Combat
0 likes 0 comments

Comments

Nobody has left a comment. You can be the first!
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement

Latest Entries

Basic Combat

5432 views

A Single Step

5022 views
Advertisement