I have the following script attached to my ball on a game:
public class MovePlayer : MonoBehaviour {
//public GameObject packman;
// Use this for initialization
private Vector3 currentSpeed;
void Start () {
currentSpeed = new Vector3(0.0f, 0.0f, 0.0f);
}
// Update is called once per frame
void Update () {
if (Input.GetKey(KeyCode.LeftArrow)){
currentSpeed.x = -(0.0001f);
}
else if (Input.GetKey(KeyCode.RightArrow))
{
currentSpeed.x = 0.0001f;
}
else currentSpeed.x = 0;
/*if (Input.GetKeyDown(KeyCode.UpArrow))
{
}*/
//move packman
this.transform.Translate(Time.deltaTime * currentSpeed.x, Time.deltaTime * currentSpeed.y,
Time.deltaTime * currentSpeed.z);
}
}
Then I touch left or right arrow on the game, and the ball moves really fast to one direction and never stops even if I touch the other arrow.
I found it is because I added "Physics -> character controller" to
the ball. Removing this component did the job. Why was character
controller producing the described effect? – Daniel Roca Lopez
It sounds like the Character Controller you had added accidentally, had pre-written values for how the Object behaved.
So on top of your MovePlayer script, you also got the Movement from CharacterController.
use FixedUpdate() like this
public class MovePlayer : MonoBehaviour {
//public GameObject packman;
// Use this for initialization
private Vector3 currentSpeed;
void Start () {
currentSpeed = new Vector3(0.0f, 0.0f, 0.0f);
}
// Update is called once every 1/60th second
void FixedUpdate () {
if (Input.GetKey(KeyCode.LeftArrow)){
currentSpeed.x = -(0.0001f);
}
else if (Input.GetKey(KeyCode.RightArrow))
{
currentSpeed.x = 0.0001f;
}
else currentSpeed.x = 0;
/*if (Input.GetKeyDown(KeyCode.UpArrow))
{
}*/
//move packman
this.transform.Translate(Time.deltaTime * currentSpeed.x, Time.deltaTime *
currentSpeed.y, Time.deltaTime * currentSpeed.z);
}
}
Related
So i was trying 3rd character movement in unity an got stuck in here. The player animation is moving in loop but player is moving ahead of camera and than coming back, its doing it every cycle.
Let me provide char_control code and video link.
video link - https://drive.google.com/file/d/15VEIcOqy7yhQfACT4Pjxh-BZoVsrYdFS/view?usp=sharing
code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class char_control : MonoBehaviour
{
public GameObject Player;
//variable - type of variable
public bool isRunning;
public float horizontal_move;
public float vertical_move;
// Update is called once per frame
void Update()
{
if (Input.GetButton("Horizontal") || Input.GetButton("Vertical"))
{
Player.GetComponent<Animation>().Play("Running");
horizontal_move = Input.GetAxis("Horizontal") * Time.deltaTime * 100;
vertical_move = Input.GetAxis("Vertical") * Time.deltaTime * 1;
isRunning = true;
transform.Rotate(0, horizontal_move, 0);
transform.Translate(0, 0, vertical_move);
}
else
{
Player.GetComponent<Animation>().Play("Idle");
isRunning = false;
}
}
}
You should use Animator and Animator Controller for your purpose. To fix your problem you could probably disable root motion in your animation (Bake Into Pose on Root Transform Position (XZ), setting up Mask should work too) but still you will end up using Animator Controller so better do that asap
Have you checked that your "Running" animation has both "Loop Time" and "Loop Pose" checked. I know that the pose option is the one which makes my character act the way you described.
Use scripting to control character movement and movement animations:
[System.Serializable]
public class Anim//Game control animation
{
public AnimationClip idle;
public AnimationClip runForward;
public AnimationClip runBackward;
public AnimationClip runRight;
public AnimationClip runleft;
}
public class playermove : MonoBehaviour {
public float h = 0.0f;
public float v = 0.0f;
//assign the variable,
private Transform tr;
//move speed variable
public float movespeed = 10.0f;
//Rotate can use the Rotate function,
public float rotSpeed = 100.0f;
//The animation class variable to display to the inspector
public Anim anim;
//To access the variables of the following 3d model animation component objects
public Animation _animation;
// Use this for initialization
void Start () {
//Assign the Tr component to the initial part of the script
tr = GetComponent<Transform>();
// Find the anim component that is subordinate to itself and assign it to a variable.
_animation = GetComponentInChildren<Animation>();
_animation.clip = anim.idle;
_animation.Play();
}
// Update is called once per frame
void Update() {
h = Input.GetAxis("Horizontal");
v = Input.GetAxis("Vertical");
Debug.Log("H=" + h.ToString());
Debug.Log("V="+ v.ToString());
//Calculate the moving direction vector of left, right, front and rear.
Vector3 moveDir = (Vector3.forward * v) + (Vector3.right * h);
//translate (movement direction *time.deltatime*movespeed, space.self)
tr.Translate(moveDir.normalized *Time.deltaTime*movespeed , Space.Self);
//vector3.up axis as the benchmark, rotate at rotspeed speed
tr.Rotate(Vector3.up * Time.deltaTime * rotSpeed * Input.GetAxis("Mouse X"));
if (v >= 0.1f)
{
//forward animation
_animation.CrossFade(anim.runForward.name, 0.3f);
}
else if (v <= -0.1f)
{
//back animation
_animation.CrossFade(anim.runBackward.name, 0.3f);
}
else if (h >= 0.1f)
{
//right animation
_animation.CrossFade(anim.runRight.name, 0.3f);
}
else if (h <= -0.1f)
{
//left animation
_animation.CrossFade(anim.runleft.name, 0.3f);
}
else
{
_animation.CrossFade(anim.idle.name, 0.3f);
}
//Based on the keyboard input value, execute the animation to be operated
}
}
hope it helps you.
My problem is two-fold. Animation and a GameObject jumping off during Play. I don't know the exact phrases of what happens, I'll try to explain best I can.
I want to increase a float upon movement, which should trigger animation for my character. It is the SpeedBlend in image below. It's between 0 and 1.
The movement works fine and debugging works fine. But I cannot get the SpeedBlend to increase.
Here are the issues:
It says "NullReferenceException: Object reference not set to an instance of an object" when I press Play. I narrowed it down to the GameObject jumping off the public Animator when i press Play. I don't know the exact wording of what happens, but the "Animation (Animator)" is no longer attached to the Scripts' Animator. Does that make sense?
See below.
The "Animation (Animator)" jumps off on Play. If I declare the animator in Start function, it jumps off. If I don't declare it, it stays on during Play. See below.
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
controller = GetComponent<CharacterController>();
animator = GetComponentInChildren<Animator>();
}
If I re-apply the "Animation (Animator)" to the Scripts' Animator during Play, it changes the problem to
"NotImplementedException: The method or operation is not implemented."
My current solution for animating my character is:
//animation
if (direction != Vector3.zero)
{
animator.SetFloat("SpeedBlend", 0.5f);
Debug.Log("moving works fine");
}
The debugging works fine.
So my questions are two-fold:
Why is the "Animation (Animator)" no longer attached to the Script during Play?
My solution animator.SetFloat("SpeedBlend", 0.5f); doesn't work. Why not?
Just in case you want the read the entire code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThirdPersonMovement : MonoBehaviour
{
public CharacterController controller;
public Transform cam;
//moving
public float speed = 6f;
public float turnSmoothTime = 0.1f;
float turnSmoothVelocity;
//https://www.youtube.com/watch?v=_QajrabyTJc&ab_channel=Brackeys
//gravity + jumping
public float gravity = -9.81f;
public Transform groundCheck;
public float groundDistance = 0.4f;
public LayerMask groundMask;
public float jumpHeight = 3f;
Vector3 velocity;
bool isGrounded;
//Animation
public Animator animator;
// Start is called before the first frame update
private void Start()
{
Cursor.lockState = CursorLockMode.Locked;
controller = GetComponent<CharacterController>();
animator = GetComponentInChildren<Animator>();
}
// Update is called once per frame
void Update()
{
Move();
/*
Idle();
*/
Run();
}
void Move()
{
//isgrounded
isGrounded = Physics.CheckSphere(transform.position, groundDistance, groundMask);
if (isGrounded && velocity.y < 0)
{
velocity.y = -2f;
}
//moving or walking
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized;
if (direction.magnitude >= 0.1f)
{
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;
float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);
transform.rotation = Quaternion.Euler(0f, angle, 0f);
Vector3 moveDirection = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;
controller.Move(moveDirection.normalized * speed * Time.deltaTime);
}
//gravity
velocity.y += gravity * Time.deltaTime;
controller.Move(velocity * Time.deltaTime);
//jumping
if (Input.GetButtonDown("Jump") && isGrounded)
{
velocity.y = Mathf.Sqrt(jumpHeight * -2f * gravity);
}
//animation
if (direction != Vector3.zero)
{
animator.SetFloat("SpeedBlend", 0.5f);
Debug.Log("moving works fine");
}
}
/*
void Idle()
{
animator.SetFloat("SpeedBlend", 0);
}
*/
void Run()
{
//running
if (Input.GetKey(KeyCode.LeftShift))
{
speed = 12f;
Debug.Log("left shift presseed");
/*
animator.SetFloat("SpeedBlend", 1f);
*/
}
else
{
speed = 6f;
}
}
}
I tried changing movement scripts, changing animation types. Instead of the current Blend Tree, I tried using a bool parameter "isWalking". None of it works, and I can't for the love of me grasp why. If I manually increase the SpeedBlend during Play, the animation changes as it should.
If you cannot run your app in debug mode (which would show you the exception and its StackTrace):
Add a try-catch to your code
try
{
// the code that throws
}
catch (Exception ex)
{
// Set a break point or log the exception and its StackTrace.
Console.WriteLine(ex.ToString());
}
Try to log the StackTrace for example to a file or to the console (if you have no logging set up). That will show you what method throws the exception.
You can also get the whole exception as a string, with inner exception and all StackTraces via ex.ToString() and log that (instead of the StackTrace property only). See the code example above.
In case of the NotImplementedException: probably a base class has a virtual or abstract method that that you need to override.
How can I make this script work, or another alternative player movement script? This basic movement script in Unity doesn't do anything when i press WASD for some reason. I am a beginner at C# and unity and I kind of need an alternative player movement script that actually works.
void Update()
{
if (Input.GetKeyDown(KeyCode.W))
transform.Translate(Vector3.forward);
if (Input.GetKeyDown(KeyCode.S))
transform.Translate(Vector3.back);
if (Input.GetKeyDown(KeyCode.A))
transform.Translate(Vector3.left);
if (Input.GetKeyDown(KeyCode.D))
transform.Translate(Vector3.right);
I recommend using the GetAxis("Horizontal") and GetAxis("Vertical") methods which maps wasd and arrow keys by default to help slim down your big if tree.
Below is a small example from an old unversity project of mine.
Note: the "* speed * Time.deltaTime" as this is used to help translate as time/frames move on, speed is just a multiplier in this case.
public float speed = 10.0f;
private float translation;
private float straffe;
// Use this for initialization
void Start()
{
// turn off the cursor
Cursor.lockState = CursorLockMode.Locked;
}
// Update is called once per frame
void Update()
{
// Input.GetAxis() is used to get the user's input
// You can further set it on Unity. (Edit, Project Settings, Input)
translation = Input.GetAxis("Vertical") * speed * Time.deltaTime;
straffe = Input.GetAxis("Horizontal") * speed * Time.deltaTime;
transform.Translate(straffe, 0, translation);
if (Input.GetKeyDown("escape"))
{
// turn on the cursor
Cursor.lockState = CursorLockMode.None;
}
}
Input.GetKeyDown checks if you pressed the w key on that frame. You need Input.GetKey. That checks if you are holding
You should use GetAxis("Horizontal") & GetAxis("Vertical");
Here is my basic code for my projects default movement:
//movement
Rigidbody rb;
float xInput;
float yInput;
public float speed;
public float defSpeed;
public float sprint;
public bool isGrounded = true;
public float jump;
// Start is called before the first frame update
private void Awake()
{
rb = GetComponent<Rigidbody>();
}
void Start()
{
}
// Update is called once per frame
void Update()
{
xInput = Input.GetAxis("Horizontal");
yInput = Input.GetAxis("Vertical");
//Things is still can't understand
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
float cameraRot = Camera.main.transform.rotation.eulerAngles.y;
rb.position += Quaternion.Euler(0, cameraRot, 0) * input * speed * Time.deltaTime;
//sprint
if (Input.GetKeyDown(KeyCode.LeftShift))
{
speed = sprint;
}
else if (Input.GetKeyUp(KeyCode.LeftShift))
{
speed = defSpeed;
}
//jump
if (Input.GetKeyDown(KeyCode.Space) && isGrounded == true)
{
rb.AddForce(0, jump, 0);
//Debug.Log("Jump!");
}
Hope this helps:)
I've been trying to figure this out for a few days now, and I'm very sure it has something to do with my code. What I want the enemy monster to do is to stop moving forward when the player right next to it and run the attack animation. What it actually does is run the attack animation while orbiting around the player like a planet, and you can't really outrun it.
I'm using Unity3d as the engine and my code is written in C#. It's very simple so I'm worried I'm missing something important.
public class enemyAITest : MonoBehaviour
{
public Transform player; // target
public float playerDistance; // determines how far from target before action takes place
public float rotationDamping; // determines how quickly rotation occurs
public float chaseSpeed; // determines how quickly to pursue target
public float wanderSpeed; // determines how quickly to move around map
public float maxDist;
static Animator anim;
Vector3 wayPoint;
void Awake()
{
anim = GetComponent<Animator>();
}
// Update is called once per frame
void Update ()
{
transform.position += transform.TransformDirection(Vector3.forward) * wanderSpeed * Time.deltaTime;
playerDistance = Vector3.Distance(player.position, transform.position);
while ((transform.position - wayPoint).magnitude < 3)
Wander();
if (playerDistance < 20f)
{
LookAtPlayer();
wanderSpeed = 0;
anim.SetBool("isIdle", true);
}
if (playerDistance < 10f)
{
Chase();
anim.SetBool("isIdle", false);
anim.SetBool("isWalking", false);
anim.SetBool("isRunning", true);
}
if(playerDistance < 1f)
{
wanderSpeed = 0;
anim.SetBool("isRunning", false);
anim.SetBool("isAttacking", true);
}
else anim.SetBool("isWalking", true);
}
void LookAtPlayer()
{
Quaternion rotation = Quaternion.LookRotation(player.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * rotationDamping);
wanderSpeed = 0;
}
void Chase()
{
Vector3 direction = player.position - transform.position;
direction.y = 0;
transform.Translate(Vector3.forward * chaseSpeed * Time.deltaTime);
}
void Wander()
{
Vector3 MonsterPosition = new Vector3(Random.Range(transform.position.x - maxDist, transform.position.x + maxDist), 1, Random.Range(transform.position.z - maxDist, transform.position.z + maxDist));
wayPoint.y = 1;
transform.LookAt(wayPoint);
//Debug.Log(wayPoint + " and " + (transform.position - wayPoint).magnitude);
}
}
Any advice will help (Please forgive the strange formatting, I was having trouble with keeping the entire Wander method and the on Awake line in the code block).
// Here is the code i have so far below. Both of my balls are moving at the same time no matter which controls i use. can someone please lend me a helping hand?
public class PlayerController : MonoBehaviour
{
public float speed = 80.0f; // Code for how fast the ball can move. Also it will be public so we can change it inside of Unity itself.
public GameObject player1; //Player 1 Rigidbody
public GameObject player2; //Player 2 Rigidbody
private Rigidbody rb;
private Rigidbody rb2;
void Start ()
{
rb = GetComponent<Rigidbody> ();
rb2 = GetComponent<Rigidbody> ();
player1 = GameObject.Find("Player");
player2 = GameObject.Find("Player 2");
}
//Player 1 Code with aswd keys
void Player1Movement()
{
if (player1 = GameObject.Find("Player"))
{
if (Input.GetKey (KeyCode.A)) {
rb.AddForce (Vector3.left * speed);
}
if (Input.GetKey (KeyCode.D)) {
rb.AddForce (Vector3.right * speed);
}
if (Input.GetKey (KeyCode.W)) {
rb.AddForce (Vector3.forward * speed);
}
if (Input.GetKey (KeyCode.S)) {
rb.AddForce (Vector3.back * speed);
}
}
}
//Player 2 Code with arrow keys
void Player2Movement()
{
if( player2 = GameObject.Find("Player 2"))
{
if (Input.GetKey(KeyCode.LeftArrow))
{
rb2.AddForce(Vector3.left * speed);
}
if (Input.GetKey(KeyCode.RightArrow))
{
rb2.AddForce(Vector3.right * speed);
}
if (Input.GetKey(KeyCode.UpArrow))
{
rb2.AddForce(Vector3.forward * speed);
}
if (Input.GetKey(KeyCode.DownArrow))
{
rb2.AddForce(Vector3.back * speed);
}
}
}
// Update is called once per frame
void Update()
{
Player1Movement();
Player2Movement();
}
}
How do i change it so both of my players aren't moving at the same time?
You are using the same rigidbody for both characters somehow. rb1 and 2 are the same rigidbody. You should use GameObject.Find or something like that to make rb2 the second players rigidbody.
Edit: you can use player2.GetComponent() to grab the second player's rigidbody. Assuming this script is attached to the first player
For both Player1 and Player2 you are using the same transition code. You are displacing both at the same rate.
For difference in speed lets say you want to update player 2 at double speed on left arrow use rb2.AddForce(Vector3.left *2* speed);
Now if you want player to move only on some even then inside Update() enclose your Player movement inside mouse down or other events. You can use RaycastHit to check which GameObject was tapped and update that one only.