Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Beginner problem - basic player controls

Discussion in 'Scripting' started by Carl_Slate, May 29, 2020.

  1. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    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.
     

    Attached Files:

  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    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
     
    Joe-Censored likes this.
  3. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    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.
     
    Last edited: May 29, 2020
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    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


    2. get the
    transform.eulerAngles.y
    of the camera (this would be the
    heading
    )

    3. produce a fresh rotation from purely that
    heading
    :

    Code (csharp):
    1. Quaternion rot = Quaternion.Euler( 0, heading, 0);
    4. rotate your control input vector by the above rotation:
    Code (csharp):
    1. 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.
     
  5. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    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:

    Code (CSharp):
    1. // Get fresh rotation from camera heading
    2. Quaternion rotFix = Quaternion.Euler(0, mainCamera.eulerAngles.y, 0);
    3.  
    4. // Rotate input vector by that
    5. var finalInput = rotFix * moveDirection;
    6.  
    7. // use it to make the character go the right way
    8. transform.rotation = Quaternion.Slerp(transform.rotation, finalInput, rotationSpeed * Time.deltaTime);
    9. 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:
    Code (CSharp):
    1.  
    2. //Get a Vector3 for the raw inputs, give it the camera heading
    3. Vector3 moveDirection = new Vector3(0, mainCamera.eulerAngles.y, 0);
    4.  
    5. //(...get all the WASD inputs to Vector3.left/right/etc...)
    6.  
    7. // get a quaternion to look the direction of the inputs with the camera heading
    8. Quaternion rotMe = Quaternion.LookRotation(moveDirection);
    9. // use it to make the character go the right way
    10. transform.rotation = Quaternion.Slerp(transform.rotation, rotMe, rotationSpeed * Time.deltaTime);
    11. transform.Translate(Vector3.forward * movementSpeed * Time.deltaTime);
    12.  
    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...
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    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

    https://gitlab.com/kurtdekker/proximity_buttons

    https://sourceforge.net/projects/proximity-buttons/
     
  7. Carl_Slate

    Carl_Slate

    Joined:
    May 27, 2020
    Posts:
    12
    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! :mad:
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    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.