Add Force teleporting the player - unity3d

I want to push back my player when it collides with an object but when it collide with the object, it just teleporting back rather then pushing smoothly. I tweaked with values like Mass, Drag on player's rigidbody or knockbackStrenght value from script. It just teleporting further positions with higher values and teleporting to closer positions with lower values but it always teleports not pushback.
My code on the object that will push back player looks like:
public class StickRotator : MonoBehaviour
{
[SerializeField] float rotateSpeed;
[SerializeField] float knockbackStrenght;
[SerializeField] Vector3 rotateDir;
Vector3 _parentPos;
void Start()
{
_parentPos = GetComponentInParent<Transform>().position;
}
void Update()
{
transform.RotateAround(_parentPos, rotateDir, rotateSpeed * Time.deltaTime);
}
void OnCollisionEnter(Collision other)
{
if (other.gameObject.CompareTag("Player"))
{
other.gameObject.GetComponent<Rigidbody>().AddForce
(Vector3.back * knockbackStrenght, ForceMode.Impulse);
}
}
}
Player's rigidbody settings
When player collide with stick, it just teleporting back rather then pushing back

Along with #absinthe's comment, you could try using rigidbody.velocity instead of AddForce.

I find out that Animator component on the player causing the issue. Unticking 'Apply root motion' seems solved my problem but now when player pushing back smoothly, its jittering.

Related

How do I rotate an object's parent without the child being moved along?

In my game on unity 2d I have spaceship and a planet. The planet is orbiting a star so I made a script that parents the planet to the player when I get within a range so the planet doesn't fly past or into the player. This script makes the player move with the planet so they land on it and fly around it easily.
Here is the script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ParentPlayer : MonoBehaviour
{
[SerializeField] GameObject Player;
private float Dist;
[SerializeField] float Threshold;
private CircleCollider2D ParentTrigger;
// Start is called before the first frame update
void Start()
{
ParentTrigger = GetComponents<CircleCollider2D>()[1];
ParentTrigger.isTrigger = true;
ParentTrigger.radius = Threshold / transform.localScale.x;
}
// Update is called once per frame
void Update()
{
}
private void OnTriggerEnter2D(Collider2D collider)
{
if(collider.gameObject == Player)
{
collider.gameObject.transform.SetParent(transform);
}
}
private void OnTriggerExit2D(Collider2D collider)
{
if(collider.gameObject == Player)
{
collider.gameObject.transform.SetParent(null);
}
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, Threshold);
}
}
The problem is that as the planet rotates it ends up moving the player that has been parented to it. How can I make the planet's rotation not affect the position and rotation of the player, but still make the planets position affect the position of the player?
This might not be what you're looking for but I'm going to add it reguardless. Given that the Child-object will follow the parent, I would suggest putting the planet and spaceship as a child of the empty gameobject. Then you could rotate the the planet object, and if planets are in movement, you could add the movement to the parent object.
How about instead of parenting the player, write a script to set its position to the planets + some offset, and then the rotation wouldn't be an issue. Alternatively, if the player doesn't rotate at all, add constraints to its Rigidbody. Maybe something like this:
player.transform.position = planet.transform.position + offset;
Hope that works!

Object won fall of the platform in Unity

So i made an ball(player) which moves forward on it's own with script. I want to make that ball act like a normal ball. when it riches the edge of platform it won't fall off. Basicaly it stops on the edge. Here's my image:
Here's my controller script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SwerveInputSystem : MonoBehaviour
{
private float _lastFrameFingerPositionX;
private float _moveFactorX;
public float MoveFactorX => _moveFactorX;
void Start(){
}
// Update is called once per frame
void Update()
{
if (Input.GetMouseButtonDown(0))
{
_lastFrameFingerPositionX = Input.mousePosition.x;
}
else if (Input.GetMouseButton(0))
{
_moveFactorX = Input.mousePosition.x - _lastFrameFingerPositionX;
_lastFrameFingerPositionX = Input.mousePosition.x;
}
else if (Input.GetMouseButtonUp(0))
{
_moveFactorX = 0f;
}
}
}
This is Second script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour{
private SwerveInputSystem _swerveInputSystem;
[SerializeField] private float swerveSpeed = 5f;
[SerializeField] private float maxSwerveAmount = 1f;
[SerializeField] private float verticalSpeed;
void Start(){
_swerveInputSystem = GetComponent<SwerveInputSystem>();
}
void Update(){
float swerveAmount = Time.deltaTime * swerveSpeed * _swerveInputSystem.MoveFactorX;
swerveAmount = Mathf.Clamp(swerveAmount, -maxSwerveAmount, maxSwerveAmount);
transform.Translate(swerveAmount, 0, 0);
float verticalDelta = verticalSpeed * Time.deltaTime;
transform.Translate(swerveAmount, verticalDelta, 0.1f);
}
}
EDITED: Adjusted the answer since we now have some source code.
You are positioning the player directly (using its transform) which will mess up the physics. The purpose of a rigidbody is to let Unity calculate forces, gravity, and so on for you. When you are using physics, and you want to move an object you have three main options:
Teleporting the object to a new position, ignoring colliders and forces like gravity. In this case use the rigidbody's position property.
_ourRigidbody.position = new Vector3(x, y, z);
Moving the object to the new position, similar to teleporting but the movement can be interrupted by other colliders. So, if there is a wall between the object and the new position, the movement will be halted at the wall. Use MovePosition().
_ourRigidbody.MovePosition(new Vector3(x, y, z));
Adding some force to the object and letting the physics engine calculate how the object is moved. There are several options like AddForce() and AddExplostionForce(), etc... see the Rigidbody component for more information.
_ourRigidbody.AddRelativeForce(new Vector3(x, y, z));
In your case you can simply remove the transsform.Translate() calls and instead add some force like this:
//transform.Translate(swerveAmount, 0, 0);
//transform.Translate(swerveAmount, verticalDelta, 0.1f);
Vector3 force = new Vector3(swerveAmount, verticalDelta, 0);
_ourRigidbody.AddForce(force);
We can get the _ourRigidbody variable in the Awake() or Start() method as normal. As you can see I like the Assert checks just to be safe, one day someone will remove the rigidbody by mistake, and then it is good to know about it...
private SwerveInputSystem _swerveInputSystem;
private Rigidbody _ourRigidbody;
void Start()
{
_swerveInputSystem = GetComponent<SwerveInputSystem>();
Assert.IsNotNull(_swerveInputSystem);
_ourRigidbody = GetComponent<Rigidbody>();
Assert.IsNotNull(_ourRigidbody);
}
One likely reason your Rigidbody is not being affected by gravity is due to having the field isKinematic checked to on. From the Rigidbody docs, when toggling on isKinematic,
Forces, collisions or joints will not affect the rigidbody anymore.
The rigidbody will be under full control of animation or script
control by changing transform.position
As gravity is a force and no forces act on the object when this setting is checked, your object will not fall when it is no longer on the platform. A simple solution is to uncheck this box.

How to call a method every time, when player stay at any collider?

I have a game like CubeSurfer. When player goes through an collectable, two methods are called (for "jumping" and creating a cube under player). But, when player goes through second, or third collectable, nothing happens. I tried to attached script to collectable, and tried to put the method "OnTriggerEnter" in the body of methods "Start" and "Update". But it doesn't work.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerCollider : MonoBehaviour
{
[SerializeField] Collider player;
[SerializeField] GameObject destroyIt;
[SerializeField] GameObject objToClone;
[SerializeField] Transform rootObjInScene;
Transform curParent;
Vector3 posOffset, posPlayer;
float distance = 1f;
private void OnTriggerStay(Collider player)
{
PlayerJumping();
CreateAnother();
Destroy(destroyIt);
}
public void PlayerJumping()
{
posPlayer = Vector3.up * distance;
Vector3 playerPos = rootObjInScene.position + posPlayer;
rootObjInScene.transform.position = playerPos;
}
public void Awake()
{
curParent = rootObjInScene;
posOffset = Vector3.down * distance;
}
public void CreateAnother()
{
Vector3 newPos = curParent.position + posOffset;
GameObject newObj = Instantiate(objToClone, newPos, Quaternion.identity, curParent);
curParent = newObj.transform;
}
}
You should also check your Rigibody collision detection mode in the inspector.
By default, this is set to Discrete, but if your object is fast-moving, you should set it to Continuous or ContinuousDynamic, otherwise the collisions won't be registered because the object is moving too quickly.
These are a little bit performance intensive, so I'd still recommreading up on the Unity documentation or digging through a couple of good articles to know what's best for you :)
You shouldn't call OnTriggerEnter explicitly (in your Update()), it's an event message and gets called automatically by unity when you enter a Collider marked isTrigger.
You can use OnTriggerEnter only if your collider is marked isTrigger, if you want to get a collision with a Collider that is not explicitly a trigger, you use OnCollisionEnter
To execute a method repeatedly while touching a Collider use OnCollisionStay, while touching or inside a Collider with isTrigger use OnTriggerStay
OnCollisionStay
OnTriggerStay
You can use OnCollisionStay or OnTriggerStay
void OnCollisionStay(Collision collisionInfo)
{
//Do something when collisionInfo.gameObject stay in this.gameObject collider
}

Bullet passes through the player

I'm using unity and when the enemy shoots, the bullet passes right threw the player. I don't know how to solve this. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class EnemyBullet : MonoBehaviour
{
public float speed;
public Rigidbody2D rb;
private Transform player;
private Vector2 target;
private Vector2 moveDirection;
// Start is called before the first frame update
void Start()
{
player = GameObject.FindGameObjectWithTag("Player").transform;
moveDirection = (player.transform.position - transform.position).normalized * speed;
}
// Update is called once per frame
void Update()
{
rb.velocity = new Vector2(moveDirection.x, moveDirection.y);
//transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
void OnCollisionEnter2D(Collision2D other) {
if (other.gameObject.tag == "Player") {
Destroy(this.gameObject);
}
}
}
I put a tag named BulletEnemy on the bullet but it doesn't work
How fast is your speed value?
At high speeds a bullet might move farther in one frame than the depth of the object you want it to hit. You can still detect collisions by every frame storing the position of your bullet as a vector and on the next frame casting a ray between the current position and the last known position in the previous frame. If the ray hits your enemy then call the same function that you would on a physics collision.
There is no way to do it with only OnCollisionEnter because of the effect of bullet speed.
Check your bullet's speed. if they are too fast, your physics engine just ignore the collision and therefore no OnCollisionEnter will be called.
Use larger Collider for your player. and also check Player tag on your player object. also make sure your tagged object has Collider2D component.
Change OnCollisionEnter2D to OnCollisionStay2D. if you want to Destroy bullet, there will be no difference in runtime

Unity2D - Ignore collision with edge collider

I am trying to have my player ignore the collision with an edge collider on a platform i have.
Here's the script that I have added to the player
public class TestMovement : MonoBehaviour
{
public Rigidbody2D ball;
private GameObject purplePlat1;
private GameObject player;
// Start is called before the first frame update
void Start()
{
purplePlat1 = GameObject.Find("purple_plat");
player = GameObject.Find("circle-png-44659");
ball = GetComponent<Rigidbody2D>();
ball.AddForce(new Vector2(0, 10), ForceMode2D.Impulse);
Debug.Log("start");
}
// Update is called once per frame
void Update()
{
}
void OnCollisionEnter2D(Collision2D collision)
{
Physics2D.IgnoreCollision(purplePlat1.GetComponent<EdgeCollider2D>
(), GetComponent<CircleCollider2D>());
Debug.Log("collision");
}
}
The ball is still hitting the platform. I have confirmed that the oncollisionenter method is firing.
You can use the layer system of Unity to avoid collisions between both. Set a layer for a player and another for the edge and untick the collision between them.
What you can do is create a layer mask for the different type of game objects. Then, open your Physics2D settings.
On the bottom part, you can see a matrix of physics objects that can collide to one another. Just uncheck which layer should not collide with the other.