Beginner problem - basic player controls

Hello, Unity Forum users. I want to set up a traditional RPG-style control method (such as in Legend of Zelda, God of War, Kerbal EVA, etc.), but I can’t find anything relevant to how to code this. I have looked all through the Unity “Learning” courses and tutorials, as well as days of web-search and youtube videos, and nothing useful has turned up for me. I have tried everything I can find and can think of, but I haven’t yet figured out anything that works.

I might assume maybe this is something Unity is simply incapable of, except that I’ve seen it in games made with Unity (ie Kerbal Space Program). Could anyone point me in the right direction? What am I missing?

I’ll upload my WIP control script in case seeing what broken-approaches I have already made is useful to anyone who might be willing to help me. And maybe when you see how much I have commented out, you’ll get a feel for how frustrating this hasbecome for me.

5914016–631631–PlayerCharControl.cs (5.83 KB)

Legend of Zelda, God of War, Kerbal… as far as I know those games have COMPLETELY different controls.

Have you tried googling something like “youtube unity rpg” and taken a few hours and worked through a few tutorials? They’re all really pretty straightforward… but don’t stop at the first one… give at least two of them a shot. If you have any specific questions, come on back.

If you end up with questions, here is how to report problems productively in the Unity3D forums:

http://plbm.com/?p=220

1 Like

Hi, Kurt. Those games all have the same basic control in that the player can move their character any direction they want relative to the camera by simply using the input for that direction. Another example I couldn’t think of before but meant to mention would be ninja gaiden, which uses the same common rpg-style control. All I can find in movement control tutorials is this weird rotate left/rotate right stuff, that probably no 3D game has used in over 20 years.

Whenever I include “rpg” in the criteria of a web search, mostly what I get is a zillion pages about camera scripting, which I feel like I don’t need help with at the moment (and if I did, it’d obviously be easy to find). My camera behavior works beautifully, I just haven’t been able to figure out a way to get my character to move in a direction (relative to the camera) based on input. I’ve gone through what few RPG control tutorials I could find, but they’re all this top-down fixed-camera style that doesn’t have any info useful for if your camera has more complex (traditional) behavior. My camera chases and is mouse-controllable, so I need some way for my controls to respect the camera angle.

My most recent attempt was to take the euler angles from the camera, +/- the Z with a value representing the keys, and reaching it with a quaternion.slerp, but any - change to Z acts like a 180, and any + change does nothing.

I’ve also been pouring through the “Unity Scripting API” online reference for options, but, so much of it makes no obvious sense without some practical demonstration of what something does. It isn’t like I’m not trying. I’ve spent probably 30-and some hours spinning me wheels on just this. It’s kind of basic, I can’t do anything else until I find some way to make the player’s character adequately controllable, because everything is dependent on that.

Well you are certainly on the correct track with this.

Here are the essential steps of doing that properly:

  1. gather your user input from the player into a traditional Vector3():
  • left/right goes in x
  • y should be zero (up/down)
  • fore/aft goes in z
  • We’ll call this RawInputValues
  1. get the transform.eulerAngles.y of the camera (this would be the heading)

  2. produce a fresh rotation from purely that heading:

Quaternion rot = Quaternion.Euler( 0, heading, 0);
  1. rotate your control input vector by the above rotation:
var FinalInputValues = rot * RawInputValues

That should be all the steps you need to do. Now move your character by FinalInputValues

You can trivially set up a little test script and verify for yourself this works before winding it into your player controller.

Kurt, thank you so much for your help, your guidance has definitely gotten me closer. A problem I found with the method you described is that ‘var finalinput’ produces a vector3, and the quaternion.slerp to make the character go the right direction requires a quaternion, so I get a ‘can’t convert vector3 to quaternion’ error. Here is what it looked like when I put it all together:

// Get fresh rotation from camera heading
Quaternion rotFix = Quaternion.Euler(0, mainCamera.eulerAngles.y, 0);

// Rotate input vector by that
var finalInput = rotFix * moveDirection;

// use it to make the character go the right way
transform.rotation = Quaternion.Slerp(transform.rotation, finalInput, rotationSpeed * Time.deltaTime);
transform.Translate(Vector3.forward * movementSpeed * Time.deltaTime);

Here is a version (I really did try to fix it on my own until I was simply stumped again) of this that worked when I disabled the camera script:

//Get a Vector3 for the raw inputs, give it the camera heading
Vector3 moveDirection = new Vector3(0, mainCamera.eulerAngles.y, 0);

//(...get all the WASD inputs to Vector3.left/right/etc...)

// get a quaternion to look the direction of the inputs with the camera heading
Quaternion rotMe = Quaternion.LookRotation(moveDirection);
// use it to make the character go the right way
transform.rotation = Quaternion.Slerp(transform.rotation, rotMe, rotationSpeed * Time.deltaTime);
transform.Translate(Vector3.forward * movementSpeed * Time.deltaTime);

But if I enable the camera script, the player character flips weird directions. I realize what is broken about this- the x 0 / and y 0 are meaningless when I am about to give it Vector3.(direction) to those values, but it is also necessary for making the character stand upright/not flip around, and that’s why you said to get a ‘fresh rotation from camera heading’, but I haven’t figured out how to get those fresh x/z zeroes without erasing the inputs, since they go into the same place. I tried giving it zeroes to x/z after assigning the input to the quaternion, but that doesn’t seem to have affected it.

Also, as to why the enabled-state of the camera script effected it, I am baffled. I would think that result should happen exactly the same regardless…

I’m unfamiliar with using Slerp for anything like this. I’m not saying it’s wrong, I just haven’t considered it since I have solved the problem another way.

I have the control system I usually use in a small demo scene in my proximity_buttons project.

It has a bunch of other control schemes too. The one we’re talking about here is called:

DemoCameraRotatedControls.unity

It can work with or without a CharacterController. This scene has a CharacterController in it.

It gathers input from both touchscreen using my virtual buttons (VAButton) and from UnityInput.

It overlays other input from the 1/2 keys and from Unity Input.

Perhaps something in there will be of use to you?

proximity_buttons is presently hosted at these locations:

https://bitbucket.org/kurtdekker/proximity_buttons

https://github.com/kurtdekker/proximity_buttons

Oooookay, I figured it out. It was so much simpler than everything else I tried. It’s only a matter of making a quaternion of camera rotation.y+input, and then using that as the slerp vector. Derp derp! I feel intensely unsmart.

So, the rotation relative to the camera is now working, but I suddenly have the awkward problem of not being able to get input from more than one key at a time. Good grief! :rage:

Well that’s easily fixed. Zero the input values, then if there is input from each source, add it in. It’s what I do in all my examples in the proximity_buttons thing above. You should be breaking apart the collection of and acting upon the commands anyway, just for sanity.