I am using the Third Person Controller asset by Opsive. It is a fairly complex third person controller that controls animations, damage, movement, inputs, etc etc.
http://opsive.com/assets/ThirdPersonController/documentation.php
I would like to update the ControllerHandler.cs script to make the character move in the direction that the character is facing, regardless of camera orientation. (In the style of old Resident Evil games)
In the original script, the character would move forward in relation to which direction the camera was facing.
I received some advice to change a line in this script, but with the changes, the character moves forward in one fixed direction. (E.G.: When I turn to the right with the D key, and then press W to move forward, the character turns back in the direction he was originally facing and moves in that direction.)
Here is the original part of the script:
#if ENABLE_MULTIPLAYER
if ( isLocalPlayer) {
#endif
if (m_Controller.Movement == RigidbodyCharacterController.MovementType.Combat || m_Controller.Movement == RigidbodyCharacterController.MovementType.Adventure) {
m_LookRotation = m_CameraTransform.rotation;
Here is what someone told me to change it to:
#if ENABLE_MULTIPLAYER
if ( isLocalPlayer) {
#endif
if (m_Controller.Movement == RigidbodyCharacterController.MovementType.Combat || m_Controller.Movement == RigidbodyCharacterController.MovementType.Adventure) {
m_LookRotation = Quaternion.Euler(PlayerInput.GetAxisRaw(Constants.YawInputName), 0, 0);
Unfortunately, this does not have the result that I intended.
Any assistance would be greatly appreciated. Thanks!
Here is a link to the controller script:
https://docs.google.com/document/d/1B4sstqtCqRMCLuHuxEuA9I7tO_3W4aHqEZwr73uFDjY/edit?usp=sharing
I think you want
transform.position += transform.rotation * Vector3.forward;
A complete block of code would look like this...
void Update() {
if (Input.GetKey(KeyCode.W)) {
transform.position += transform.rotation * Vector3.forward * MOVESPEED;
}
}
I have got it working. Take a look at the picture first it will help you set up the player correctly. My player is just two cubes. I added the second cube to give a face to where the player is pointing. I have added those 2 cube to a parent object and I move the parent object with my PlayerMovement.cs.
public float rotSpeed;
public float playerSpeed;
void Update()
{
if (Input.GetKey(KeyCode.RightArrow))
{
transform.Rotate( Vector3.up, Time.deltaTime * rotSpeed);
} else if (Input.GetKey(KeyCode.LeftArrow))
{
transform.Rotate(-Vector3.up, Time.deltaTime * rotSpeed);
}
if (Input.GetKey(KeyCode.UpArrow))
{
transform.Translate(Vector3.forward * Time.deltaTime * playerSpeed);
} else if (Input.GetKey(KeyCode.DownArrow))
{
transform.Translate(-Vector3.forward * Time.deltaTime * playerSpeed);
}
}
Related
I'm trying make a game wherein for each level, the character starts off by moving in a counter-clockwise direction around the inside border of the square over and over again (Shown in picture).
Also, the character should not be controlled by the user, it moves by itself around.
The picture of my screen and how I want the square to function
I've tried using triggers, changing the position coordinates of the transform, and collision detections between the outer walls to change the direction of the character, but nothing seems to work. Here is some of the code I've tried for using the transform.MoveTowards method and the OnCollisionEnter2D function:
public Vector2 targetPosition;
public Vector2 targetPosition2;
public Vector2 targetPosition3;
public Vector2 targetPosition4;
public float speed = 5f;
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.tag == "Bottom Wall")
{
Debug.Log("Hit");
transform.position = Vector2.MoveTowards(transform.position, targetPosition, speed * Time.deltaTime);
}
else if (collision.collider.tag == "Right wall")
{
transform.position = Vector2.MoveTowards(transform.position, targetPosition2, speed * Time.deltaTime);
}
}
I have a feeling that the main problem is the fact that I cannot use the collision detection function in the fixed update function to make sure the character continuously moves towards the target.
Does anyone have any idea as to how I can solve this problem? Any help would be appreciated!
I'm creating a movement function for my character(which I've done many times but this time it's not working correctly) and here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Animator))]
public class Movement : MonoBehaviour {
public CharacterController controller;
public float moveSpeed;
public float jumpForce;
public float gravityScale;
public Animator animator;
private bool shiftPressed = false;
private void Update()
{
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
shiftPressed = true;
else
shiftPressed = false;
if(shiftPressed)
{
moveSpeed = 20f;
} else
{
moveSpeed = 10f;
}
Vector3 moveDirection = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0.0f, Input.GetAxis("Vertical") * moveSpeed);
if(Input.GetKey(KeyCode.Space) && controller.isGrounded)
{
moveDirection.y = jumpForce;
}
if (moveDirection != Vector3.zero)
animator.SetFloat("Speed", moveSpeed);
else if (moveDirection == Vector3.zero)
animator.SetFloat("Speed", 0f);
else if (moveDirection != Vector3.zero)
animator.SetFloat("Speed", moveSpeed);
if(moveDirection != Vector3.zero)
transform.rotation = Quaternion.LookRotation(moveDirection);
moveDirection = Camera.main.transform.TransformDirection(moveDirection);
moveDirection.y = moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale);
controller.Move(moveDirection * Time.deltaTime);
}
}
As you can see that there is no function to go up in the y axis except the jump function. Mysteriously, when I press the 'S' key or 'downArrow' the player moves -z as he should but ironically he moves in +y axis as well. To ensure there is no y axis function I tried making jump function a comment but did the same way still. I thought it might be some character specific problem so I tried adding the code to a cube(thinking it to be my animation mistake) but it didn't helped at any point. I ensured the character controller is set nicely(collider and stuff); I've attached screenshots.
Please help!
Thanks in advance.
The problem has already been stated by several here, but it seems you still do not understand the issue, concluding from your reactions.
This line will always make your character move up.
moveDirection.y = moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale);
You are trying to use gravity (which is a force) in conjunction with manipulating transform. In Unity, you either do one of the two, not both. This will lead to undesired and hard to fix results.
If you want to use forces in your code, then i suggest the follow:
Add a RigidBody to your character. Check the "use gravity" checkbox.
Get the RigidBody in your controller script by calling and add force to it to move it.
var rb = getComponent<RigidBody>();
rb.AddForce(10f);
Do note that if you add force, you can add it continuosly in the Update method, or just once by passing a second paramater "forcemode".
rb.AddForce(10, ForceMode.Impulse); // add instant force, using mass
// Or
rb.AddForce(10, ForceMode.VelocityChange); // add instant force, ignoring mass
// Or
rb.AddForce(10, ForceMode.Force); // add continuous force, using mass
// Or
rb.AddForce(10, ForceMode.Acceleration); // add continous force, ignoring mass
Let me guess.. your character keeps moving up by about the current downwards slope of the camera?
As your code stands, as an example, if your Camera's is Vector3(10,0,0) and if you're trying to move Vector3(5, 0, 5), you've asked the movement vector to be transformed to world space, based off of the camera transform. So, your new movement vector will be something like Vector3(5,1,5). This should do the trick:
var worldDirection = Camera.main.transform.TransformDirection(moveDirection);
moveDirection = new Vector3(
worldDirection.x,
moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale),
worldDirection.z );
moveDirection.y = moveDirection.y + (Physics.gravity.y * Time.deltaTime * gravityScale);
This line always sets "y", and is modified/set as the last function prior to the ultimate statement. It is here, you should validate and verify all factors that has influence the final calculation of "y".
You must validate that each of the variables are calculated to your expected values:
moveDirection.y
Physics.gravity.y
Time.deltaTime
gravityScale
Each will influence the final value of moveDirection.y. Once you have verified each individual value, the final y value will make sense to you. If any of these values are not what you expect, you have a bug in the calculation of that variable.
Happy hunting!
First of all: Sorry for my bad English, I'm Dutch.
I'm trying to create a player object that can walk forward and backwards (with the up and down keys), and rotate the player with the right and left keys. But when I press the left or right key, the position of the player changes, it looks like it rotates around a certain point. But it should rotate and stay on the same place, like I do when I turn around.
I have some other small programs, with the same 'move script' and the same inputmanager settings. There it works fine, so I have no idea why it doesn't work this time.
This is my move script, but this script works fine with other programs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveScript : MonoBehaviour
{
public float speed = 3f;
public float rotate = 50f;
private Rigidbody rb;
// Update is called once per frame
private void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
if (Input.GetButton("Up"))
transform.Translate(Vector3.forward * speed * Time.deltaTime);
if (Input.GetButton("Down"))
transform.Translate(-Vector3.forward * speed * Time.deltaTime);
if (Input.GetButton("Right"))
transform.Rotate(Vector3.up, rotate * Time.deltaTime);
if (Input.GetButton("Left"))
transform.Rotate(-Vector3.up, rotate * Time.deltaTime);
if (gameObject.GetComponent<Rigidbody>().velocity.y < 0.01)
{
if (Input.GetButtonDown("Jump"))
rb.AddForce(0, 225, 0);
}
}
}
The InputManager settings (also the same as other programs where it works fine):
If someone wants a screenshot of something else of my program, you can always ask it of course. I have no idea what the problem could be, if it isn't in the script or the inputmanager.
Following the comments in the OP, the solution should be to use:
if (Input.GetButton("Right"))
transform.localEulerAngles = transform.localEulerAngles + new Vector3(xRotation, 0, 0) * Time.deltaTime;
if (Input.GetButton("Left"))
transform.localEulerAngles = transform.localEulerAngles - new Vector3(xRotation, 0, 0) * Time.deltaTime;
Where xRotation is a float with the amount you want to rotate per second when and while one of the rotation keys is down.
(PS: Don't have unity open right now, so + and - might be inverted, but should be something like that.)
I was trying to create a car in unity using a C# Script, everything seems to be fine, the car rotates left and right, except 1 problem. when I press the forward or backwards keys, the car moves left and right instead of forward and backwards, I can't see anything wrong with my code, here's my code:
using UnityEngine;
using System.Collections;
public class Car : MonoBehaviour {
private Rigidbody carRigid;
public int speed;
public int rotateSpeed;
// Use this for initialization
void Start () {
carRigid = GetComponent<Rigidbody> ();
}
// Update is called once per frame
void Update () {
}
void FixedUpdate(){
if (Input.GetButton("Forward")){
carRigid.AddForce (transform.forward * speed * Time.deltaTime);
}
if (Input.GetButton("Reverse")){
carRigid.AddForce (transform.forward * -speed * Time.deltaTime);
}
if (Input.GetButton("Left")){
transform.Rotate (0, rotateSpeed, 0);
}
if (Input.GetButton("Right")){
transform.Rotate (0, rotateSpeed, 0);
}
}
}
Your car is moving on another axis which is different than the axis you want. try transform.right / transform.left or transform.up / transform.down .
I've just tested your code in a blank Unity scene, and I think you AddForce() is the culprit!
I used
if (Input.GetKey(KeyCode.W))
{
transform.position += transform.forward * speed * Time.deltaTime;
}
and this seems to be working great!
Maybe it's because you have imported a 3D model which it's local forward is not correct.
You have some choices:
1) Fix it in the 3d modeling program an export it again.
2) Create an empty GameObject and make this the parent of your car. Assign the rigid body and relevant codes to this GameObject and Rotate the car model in it's local space until it's fixed ( 90 degrees I guess).
3) use transform.right or transform.left depending on the rotation of your model.
I personally prefer first choice.
I am making a 2d game that can use either the keyboard or an Xbox One controller as movement.
So far, I can move the players and play a running animation, jump animation etc using the keyboard, and I can move using the Xbox controller.
However, I can't play animations with the Xbox controller.
I have this:
void Update()
{
movement.x = Input.GetAxis("LeftJoystickX") * speed * Time.deltaTime;
// Orange player movement
if (orange)
{
transform.position += movement;
if (Input.GetKey(KeyCode.D))
{
ChangeDirection("right");
ChangeState(STATE_RUN);
transform.position += Vector3.right * speed * Time.deltaTime;
if (!onGround)
ChangeState(STATE_JUMP);
}
}
}
Here, if you use the keyboard, the animations play. If you use the controller, the player moves but the animations don't play. I've tried and narrowed it down to the fact that this piece of code will not evaluate:
if (Input.GetAxis("LeftJoystickX"))
as Input.GetAxis() returns a float and not a bool (?) and therefore cannot be put in an if statement.
I guess what I am asking is, is it possible to detect a direction of a Joystick push from a controller, such as something like Input.GetAxis().joystickPushedRight?
Or better yet, is there a different way I could execute
if (Input.GetKey(KeyCode.D))
{
ChangeDirection("right");
ChangeState(STATE_RUN);
transform.position += Vector3.right * speed * Time.deltaTime;
if (!onGround)
ChangeState(STATE_JUMP);
}
But use the joystick instead of Input.GetKey?
Thanks!
Input.GetAxis returns a float between -1 and 1.
If you take that into account together with a threshold for values close to zero you can determine if you need to go up or down or need to stop.
Your implementation will look like this:
const float threshold = 0.05;
const string axis = "LeftJoystickX";
if (Input.GetAxis(axis) < -threshold)
{
//go left
}
else if (Input.GetAxis(axis) > threshold)
{
//go right
}
else
{
// don't move
}