how are you doing?
I am working on a simple mechanic of knockback where if my character collides with the name "enemy", the players rigidbody which is paraphrsased as (rb), has force added 'back'.
Here is my code, Please refer to where I outline with asterisk.
public class Move : MonoBehaviour
{
public float speed;
private Rigidbody rb;
public int health;
private float knockback;
// Use this for initialization
void Start()
{
rb = GetComponent<Rigidbody>();
knockback = 2f;
}
void OnCollisionEnter(Collision col)
{
if (col.gameObject.name == "enemy")
{
health = health - 20; //**this works**
rb.AddRelativeForce(Vector3.forward * knockback); //**but this doesnt :c **
}
}
void death()
{
if (health <= 0)
{
print("i died");
}
}
void playerWalk()
{
var x = Input.GetAxis("Horizontal") * Time.deltaTime * 75f;
var z = Input.GetAxis("Vertical") * Time.deltaTime * 5f;
transform.Rotate(0, x, 0);
transform.Translate(0, 0, z);
}
void Update()
{
death();
playerWalk();
}
}
The problem is as you may have guessed, My triggers do not work.
My health = health - 20; line works but my rb.addforce doesn't.
What could be the problem here? Thank you :)
edit 2#
Just want to edit this and say That I have figured out the problem. The problem was that my float value just was not high enough xD
As you wrote the snippet, ´rb´ is not a field, but a local variable inside the ´Start´ method. If you are getting an exception in the menctioned line, maybe it is because of this. If you want ´rb´ to be a field, accesible all arround the class methods, you'll need to declare it in the class body, like this:
public int health;
private float knockback;
private RigidBody rb;
// (...) the rest of your code
If this is not the case, just tell me and give us more info on your problem.
Try removing the deltaTime:
rb.AddRelativeForce(Vector3.forward * knockback);
The default ForceMode for AddRelativeForce is AddForce and does not require time scaling.
I am not expert but this is my answer....
You attached rigidbody to the transform....so changing rigidbody position equal to transform position...
You calling two methods in update...so they going to be continuously called....so you move transform forward direction with uparrow key.. But you add force only at collision enter...collision enter is called only one time but playerwalk method is called continuously...that's why add force is not recognised.... Check this link
http://unityweltech.blogspot.com/2018/09/rbforce-is-not-responding.html?m=1
Related
I am new to Unity so forgive me if I just did a stupid mistake. I am currently watching a tutorial from Brackeys, but I wanted to challenge myself by figuring out the movement myself. I got the moving forward correct, but I couldn't do the sideways movement. Since I've been spending a long time on the sideways movement, I just decided to watch the tutorial, but even when I used their code, it still didn't work. Can someone tell me why this isn't working? (FYI, in the code below, I did set all the public variables to some type of value).
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Sides : MonoBehaviour
{
public KeyCode left;
public KeyCode right;
public float sidewaysForce;
Rigidbody rb;
Vector3 v3;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
// Update is called once per frame
void FixedUpdate()
{
if (Input.GetKey(left))
{
Debug.Log("Left");
rb.velocity = new Vector3(-sidewaysForce, 0, 0);
}
if (Input.GetKey(right))
{
Debug.Log("Right");
rb.velocity = new Vector3(sidewaysForce, 0, 0);
}
}
}
try left and right between quotation marks:
if (Input.GetKey("left"))
{
Debug.Log("Left");
rb.velocity = new Vector3(-sidewaysForce, 0, 0);
}
if (Input.GetKey("right"))
{
Debug.Log("Right");
rb.velocity = new Vector3(sidewaysForce, 0, 0);
}
You can check how to get the different keys in:
InputManager is in: Edit -> ProjectSettings -> Input
Other option is to use KeyCodes, which I prefer instead of the string argument for the intellisense benefits:
Update()
{
if ( Input.GetKey(KeyCode.UpArrow) )
//move up
if ( Input.GetKey(KeyCode.DownArrow) )
//move down
if ( Input.GetKey(KeyCode.RightArrow) )
//move right
if ( Input.GetKey(KeyCode.LeftArrow) )
//move left
}
If you're not getting the logs you added in the console, then you may have forgotten either:
To set the values of variables left and right in the inspector.
To add the Sides component to your GameObject.
I will assume your KeyCodes and the float are configured in the Inspector.
Either way you shouldn't do it like that!
You are completely overwriting the forward/backward movement and also the up/down movement with a hard 0 => you won't have any gravity and might break the forward movement - depending on which script is executed last.
You didn't share the forwards movement code so I can only guess but I suspect that there you do the very same thing like e.g.
rb.velocity = new Vector3(0, 0, someValue);
and therefore erase any sidewards movement from this script ;)
I would
a) make sure to have all movement input related stuff in a single script. Everything else just makes it unnecessarily hard to maintain and debug
b) make sure that your inputs don't eliminate each other
So something like e.g.
public class Movement : MonoBehaviour
{
[Header("References")]
[SerializeField] private Rigidbody _rigidbody;
[Header("Config")]
[SerializeField] private KeyCode _forward = KeyCode.W;
[SerializeField] private KeyCode _backward = keyCode.S;
[SerializeField] private KeyCode _left = KeyCode.A;
[SerializeField] private KeyCode _right = KeyCode.D;
public float speed;
private void Awake()
{
if(!_rigidbody) _rigidbody = GetComponent<Rigidbody>();
}
private void FixedUpate()
{
// by default input is 0,0,0
var input = Vector3.zero;
// user input for forward
if(Input.GetKey(_forward)) input.z = 1;
else if(Input.GetKey(_backward)) input.z = -1;
// user input for sidewards
if(Input.GetKey(_left)) input.x = -1;
else if(Input.GetKey(_right)) input.x = 1;
// make sure both combined are not bigger then 1 (avoid faster diagonal movement)
input = Vector3.ClampMagnitude(input, 1);
// apply speed multiplier
var velocity = input * speed;
// preserve the Y velocity
velocity.y = _rigidbody.velocity.y;
// finally assign back to rigidbody
_rigidbody.velocity = velocity;
}
}
In general though way more flexible and without having to configure and check the KeyCodes manually you could rather use Input.GetAxis and do e.g.
public class Movement : MonoBehaviour
{
[Header("References")]
[SerializeField] private Rigidbody _rigidbody;
[Header("Config")]
public float speed;
private void Awake()
{
if(!_rigidbody) _rigidbody = GetComponent<Rigidbody>();
}
private void FixedUpate()
{
var input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
// make sure both combined are not bigger then 1 (avoid faster diagonal movement)
input = Vector3.ClampMagnitude(input, 1);
// apply speed multiplier
var velocity = input * speed;
// preserve the Y velocity for the gravity
velocity.y = _rigidbody.velocity.y;
// finally assign back to the rigidbody
_rigidbody.velocity = velocity;
}
}
You can configure the mappings in Edit → Project Settings → Input Manager but by default the
Horizontal already refers to both A/D as well as LeftArrow/RightArrow
Vertical already refers to both W/S as well as UpArrow/DownArrow
and additionally GetAxis slightly interpolates the input so it doesn't immediately jump from 0 to 1 and back but rather increases and decreases smoothly over some frames.
If the latter bothers you you can also use GetAxisRaw which does not do the smoothing.
I just realized that I did in fact made a stupid mistake. In my other script that makes the player move forward, it sets the velocity to (0, 0, 100) in the FixedUpdate() which meant that the x axis doesn't change. Sorry for wasting your time.
I have a problem where I want to addForce to a 2D object only in the start in a random direction but the object adds the force in occurring periods.
public float RandomX;
public float RandomY;
public Rigidbody2D Rb;
void Start()
{
RandomPosition ();
}
void RandomPosition()
{
RandomX = Random.Range(-2f,2f);
RandomY = Random.Range(-2f,2f);
Rb.AddForce(new Vector2 (RandomX,RandomY), ForceMode2D.Impulse);
Invoke("RandomPosition",1.5f);
}
I have no idea what I have done wrong nor how to fix it.
This has nothing to do with Start itself but you are letting your method call itself again after 1.5 seconds using Invoke.
If this isn't what you want but rather just have it called by Start once then just remove that recursive call to
Invoke("RandomPosition",1.5f);
I think you need to move this to its own method and apply in FixedUpdate()
Rb.AddForce(new Vector2 (RandomX,RandomY), ForceMode2D.Impulse);
I think Physics calculations are only done in FixedUpdate...?
enter image description hereI am able to set Y axis of my player with a simple transform.position call, in a single step, all within onTriggerEnter method, but the motion has a single step and is therefore jerky. Now I am trying to make the motion smooth by putting the transform.position function in an Update method within the same class. However, it seems that the position values determined/updated by onTriggerEnter method are not accessible in the Update function. If I print the x and z values to console, they contain expected values from onTriggerEnter function, but appear to be 0 when I print to console from the update function.
Any ideas of what I am doing wrong?
I would never call myself a programmer, so assume the worst :-)
Thanks in advance for any help!
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Step1SetElevation : MonoBehaviour
{
private float moveSpeed = 3f;
private float currX = 0.0f;
private float currZ = 0.0f;
private Vector3 currentPos;
private GameObject player;
private Collider other;
void OnTriggerEnter(Collider other)
{
player = GameObject.FindWithTag("Player");
currentPos = GameObject.Find("PlayerController").transform.position;
currX = currentPos.x;
currZ = currentPos.z;
}
void Update()
{
player = GameObject.FindWithTag("Player");
player.transform.position = new Vector3(currX, 3.4f, currZ) * Time.deltaTime * moveSpeed;
}
}
I believe your problem may be that you are using OnTriggerEnter() to set the position you want your player to move to, this will be called on the frame your player enters your trigger but then won't be called again until the player left and re-entered...
If you instead use OnTriggerStay() - something like
void Start(){ // this lookup can be expensive so lets only do it once
player = GameObject.FindWithTag("Player");
playerController = GameObject.Find("PlayerController");
}
void OnTriggerStay(Collider other){ // this is called once per frame that a collider remains in a trigger
if(other.gameObject.tag == "Player"){ // just in case anything else ever enters the collider
currentPos = playerController.transform.position;
currX = currentPos.x;
currZ = currentPos.z;
}
}
void FixedUpdate(){ // it's generally advised to move objects in fixed update
player.transform.position = new Vector3(currX, 3.4f, currZ) * Time.fixedDeltaTime * moveSpeed;
}
I've been programming like an hour or so, then i realice that in unity 5 the charactercontroller.isGrounded doesn't work. Could anyone give me a answer?
This is the code i had
public float playerSpeed = 3f;
public float realSpeed = 3f;
public float jumpSpeed= 7f;
public float sprintSpeed= 5f;
public float gravity = 20f;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
CharacterController CC = GetComponent<CharacterController>();
if(Input.GetKey(KeyCode.W)){
transform.Translate(Vector3.forward * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.S)){
transform.Translate(Vector3.back * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.D)){
transform.Translate(Vector3.right * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.A)){
transform.Translate(Vector3.left * playerSpeed* Time.deltaTime);
}
if(Input.GetKey(KeyCode.Space) && CC.isGrounded){
transform.Translate(Vector3.up * jumpSpeed* Time.deltaTime);
}
if (Input.GetKey(KeyCode.LeftShift)) {
playerSpeed = sprintSpeed;
} else {
playerSpeed = realSpeed;
}
}
}`
So you're trying to make your character jump but only when it's on the ground?
I had this problem before a well. My solution was to make an empty gameobject and place it as a child of your character and a little bit and then put a collider as a trigger on your empty object.
Then you can have collision detection on your empty object to detect whether it is ontriggerstay on just the bottom side. It also compensates for little bumps and stuff.
According to your code you are not using any character controller. You are just changing the position of Object by using translate which will never collide with your ground. Where as to use character controller you have to provide a move direction with gravity to character controller so that its will use character controller to move your player. Gravity vector will pull your character downward and collide with ground then isGrounded will be true. Check Character Controller implementation in this unity script reference for detail.
When reading this, keep in mind I'm new to both programming and Unity, so I might be missing some terms or tools Unity offer. Please elaborate your answers in an ELI5 manner. Thanks in advance!
I am currently working on some game-physics for a small personal project. Currently I've created a platform, a character and what should be, a following companion.
However, since I'm still not on a level, where I can create perfect code on own hand, I found an "enemy" script and tried to modify it a bit.
It Works to an extend, but it needs some tweaks which I hope I can help aquire with you guys.
This is how it looks now (the orange square is the companion)
It follows the player, and I can tweak the speed to fit as a companion, and not a player. However, as the Picture presents, the companion runs for the center of the player. What I want to create is a companion which follows the player, but still keeps a small gap from the player.
My first thoughts was to create some kind of permanent offset, but I fail to figure out how to do this without messing up the follow function.
I hope you can help me, it will be much appreciated!
Here's the code for reference.
Code attached to Player:
using UnityEngine;
using System.Collections;
public class PlayerCompanion : MonoBehaviour
{
//In the editor, add your wayPoint gameobject to the script.
public GameObject wayPoint;
//This is how often your waypoint's position will update to the player's position
private float timer = 0.5f;
void Update ()
{
if (timer > 0) {
timer -= Time.deltaTime;
}
if (timer <= 0) {
//The position of the waypoint will update to the player's position
UpdatePosition ();
timer = 0.5f;
}
}
void UpdatePosition ()
{
//The wayPoint's position will now be the player's current position.
wayPoint.transform.position = transform.position;
}
}
Code attached to companion:
using UnityEngine;
using System.Collections;
public class FollowerOffset : MonoBehaviour {
//You may consider adding a rigid body to the zombie for accurate physics simulation
private GameObject wayPoint;
private Vector3 wayPointPos;
//This will be the zombie's speed. Adjust as necessary.
private float speed = 10.0f;
void Start ()
{
//At the start of the game, the zombies will find the gameobject called wayPoint.
wayPoint = GameObject.Find("wayPoint");
}
void Update ()
{
wayPointPos = new Vector3(wayPoint.transform.position.x, transform.position.y, wayPoint.transform.position.z);
//Here, the zombie's will follow the waypoint.
transform.position = Vector3.MoveTowards(transform.position, wayPointPos, speed * Time.deltaTime);
}
}
bump, I guess ? :)
You can use smooth follow script. I have created a sample class for you. This class has features to follow any given gameobject with some delay and offset. You will have to tweak some values according to your need.
using UnityEngine;
using System.Collections;
public class PlayerCompanion : MonoBehaviour
{
[SerializeField]
private GameObject wayPoint;
[SerializeField]
public Vector3 offset;
public Vector3 targetPos;//Edit: I forgot to declare this on firt time
public float interpVelocity;
public float cameraLerpTime = .1f;
public float followStrength = 15f;
// Use this for initialization
void Start ()
{
//At the start of the game, the zombies will find the gameobject called wayPoint.
wayPoint = GameObject.Find("wayPoint");
offset = new Vector3 (5,0,0);//input amount of offset you need
}
void FixedUpdate () {
if (wayPoint) {
Vector3 posNoZ = transform.position;
Vector3 targetDirection = (wayPoint.transform.position - posNoZ);
interpVelocity = targetDirection.magnitude * followStrength;
targetPos = transform.position + (targetDirection.normalized * interpVelocity * Time.deltaTime);
transform.position = Vector3.Lerp (transform.position, targetPos + offset, cameraLerpTime);
}
}
}
Attach this class to your player companion, play with different values.
To preserve object orientation your companion schould not be anyways child of your main character.
Your wayPoint doesn't needs to be a GameObject but a Transform instead and your code will looks like better.
If your game is a 2D platform your and your companion needs to be backwards your player it probabli applys to just one axis (X?) so you can decrement your waiPoint in a more directly way by calculating it on your UpdatePosition function like this:
wayPoint.position = transform.position * (Vector3.left * distance);
where your "distance" could be a public float to easily setup.
so on your companion script Update just do:
transform.position = Vector3.MoveTowards(transform.position, wayPoint.position, speed * Time.deltaTime);
I can't test it right now so you could have problems with Vector3 multiply operations, just comment and I'll try to fix as possible ;)