2D Player Shaking When Platforms Move Up and Down? - unity3d

For some reason, my player character shakes up and down when the platform moves up and down, which prevents the player from jumping because the player is not grounded. I tried several things including adding a kinematic rigidbody to the platform and trying to make the player a child of the platform after landing on the platform but nothing has worked so far. Any help would be appreciated. Thank you!
Here is my code:
public class MovingPlatform : MonoBehaviour
{
private Vector3 posA;
private Vector3 posB;
private Vector3 nexPos;
public GameObject Player;
[SerializeField]
private float speed;
[SerializeField]
private Transform childTransform;
[SerializeField]
private Transform transformB;
void Start()
{
posB = childTransform.localPosition;
posB = transformB.localPosition;
nexPos = posB;
}
// Update is called once per frame
void Update()
{
Move();
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.collider.tag == "Player")
{
collision.collider.transform.SetParent(transform);
}
}
private void OnCollisionExit2D(Collision2D collision)
{
if (collision.collider.tag == "Player")
{
collision.collider.transform.SetParent(null);
}
}
private void Move()
{
childTransform.localPosition = Vector3.MoveTowards(childTransform.localPosition, nexPos, speed * Time.deltaTime);
if (Vector3.Distance(childTransform.localPosition,nexPos) <= 0.1)
{
ChangeDestination();
}
}
private void ChangeDestination()
{
nexPos = nexPos != posA ? posA : posB;
}
}

Move(); should be executed in lateupdate, because otherwise you will set the position of the player and later the physics system will update it, causing stuttering.
Another solution would be raycasting straight down and placing your GameObject on the collision point (plus some kind of offset)

Related

How to spawn multiple prefab, with individual physics

I Did apply some of the responses , most likely in the wrong way.. this is still not working with this RAYCAST. What am I doing wrong here?
Want to spawn a prefab, which is a a ball, this ball is flying forward on flick finger on the screen.
What I want is to spawn OnClick FEW/Multiple of this prefab.
, prefab is spawning on Raycast Hit, BUT.. when I am flicking the object EVERY prefab in the scene is moving in the same way.
If I flick first one in to the Left, it goes there, but If now I flick second one to right, BOTH go to the RIGHT, but I would like them to work independent. Maybe this is easy fix to this but I can't find answer. (I'm planning to have up to 30/50 of this prefabs, so attaching separate scripts would be bit time consuming)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BallScript1 : MonoBehaviour
{
Vector2 startPos, endPos, direction;
float touchTimeStart, touchTimeFinish;
public float timeInterval = 5f;
public float throwForceInXandY = 1f;
public float throwForceinZ = 40f;
public static bool SpawnButtonAppear = true;
public static bool thrown = false;
public static bool moving = false;
public static bool fly = false;
public bool Pressed = false;
Rigidbody rb;
public GameObject player;
public Vector3 originalPos;
public GameObject playerPrefab;
string touched;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.isKinematic = true;
}
private void OnMouseDown()
{
PlayerTest.clicked = true;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit _hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out _hit))
{
touched = _hit.collider.tag;
if (touched == "Player")
{
Invoke("spawned", 0.5f);
}
}
}
if (touched == "Player")
{
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Began)
{
touchTimeStart = Time.time;
startPos = Input.GetTouch(0).position;
}
if (Input.touchCount > 0 && Input.GetTouch(0).phase == TouchPhase.Ended)
{
fly = false;
touchTimeFinish = Time.time;
endPos = Input.GetTouch(0).position;
direction = startPos - endPos;
rb.isKinematic = false;
rb.AddForce(-direction.x * throwForceInXandY, -direction.y * throwForceInXandY, throwForceinZ * timeInterval);
BackWall.canSpawnNow = 1;
}
}
}
public void spawned()
{
GameObject spawnedprefab = Instantiate(playerPrefab, new Vector3(originalPos.y, originalPos.x, originalPos.z), Quaternion.identity);
Destroy(spawnedprefab, 5f);
}
The thrown variable is not declared inside your class, so when you set it to true you are setting it true for all the instances of the class.
Declare the bool thrown; inside the EnemySpawn class, so that OnMouseDown, only the corresponding intance's thrown variable is set to true.

Why does my charakter in unity gets stuck in the tilemap?

In my Unity my Player gets everytime stuck in the collider when he has a big force (If he falls from a high place, The Gravity Scale or his jumppower is high). In the picture you can see Colliders and Renderer.
Only one Component is not on in screen at the platformcomponents, Tilemap.
Here is my code for Playermovement:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour
{
[SerializeField] private LayerMask platformsLayerMask;
private Rigidbody2D rigidbody2d;
private BoxCollider2D boxCollider2d;
private void Awake()
{
rigidbody2d = transform.GetComponent<Rigidbody2D>();
boxCollider2d = transform.GetComponent<BoxCollider2D>();
}
private void Update()
{
if (IsGrounded() && Input.GetKeyDown(KeyCode.Space))
{
float jump_power = 17.5f;
rigidbody2d.velocity = Vector2.up * jump_power;
}
HandleMovement();
}
private bool IsGrounded()
{
RaycastHit2D raycastHit2d = Physics2D.BoxCast(boxCollider2d.bounds.center, boxCollider2d.bounds.size, 0f, Vector2.down, .1f, platformsLayerMask);
return raycastHit2d.collider != null;
}
private void HandleMovement()
{
float moveSpeed = 10f;
if (Input.GetKey(KeyCode.A))
{
rigidbody2d.velocity = new Vector2(-moveSpeed, rigidbody2d.velocity.y);
}
else if (Input.GetKey(KeyCode.D))
{
rigidbody2d.velocity = new Vector2(+moveSpeed, rigidbody2d.velocity.y);
}
else
{
rigidbody2d.velocity = new Vector2(0, rigidbody2d.velocity.y);
}
}
}
Have you tried setting the player's rigidbody collision detection to continuous? If the collision detection is set to discrete, it's really easy to come accross this kind of problem when using the built in physics system

Stop an Object if it reached the transform value

So I have a 2d gameObject that behaves likes a spike trap that springs out of the ground when the character collides on the trigger. I use AddForce to the rigidbody 2D of the gameObject to manipulates its speed when coming out of the ground and I want it to just sticking out of the ground. How can I stop it when it reaches a certain tranform Y value.
Here is my code:
public float speed;
Rigidbody2D rb;
void Start () {
rb = GetComponent<Rigidbody2D>();
}
void Update () {
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.tag == "Player")
{
rb.AddForce(new Vector2(0, speed * Time.time), ForceMode2D.Impulse);
}
}
Certain transform value, or certain transform.position value?
I'll do it like this:
private float threshold = 10f;
private float startPosition = 0;
private RigidBody2D pikeRigidbody;:
private void Start()
{
startPosition = = this.transform.position;
pikeRigidbody = this.GetComponent<RigidBody2D>();
}
private void Update(){
if(this.transform.position.y >= (startPosition.y + threshold))
{
pikeRigidbody.velocity = Vector3.zero;
}
}
And attach the script to the pike object.
Edited to position.y instead of position

Trying to create a nice character controller?

I'm kind of new in the 2D environment of Unity.
I'm trying to create a platformer. For now, I have a simple map and my player.
My simple map and my player
My player have one script attached :
public class Player : MonoBehaviour
{
public float speed;
public float jump;
public GameObject raycastPoint; // Positioned at 0.01 pixel below the player
private SpriteRenderer spriteRenderer;
private Rigidbody2D body; // Gravity Scale of the Rigidbody2D = 50
private Animator animator;
private void Start()
{
spriteRenderer = GetComponent<SpriteRenderer>();
body = GetComponent<Rigidbody2D>();
animator = GetComponent<Animator>();
}
private void Update()
{
float horizontal = Input.GetAxisRaw("Horizontal");
if (horizontal == 1 && spriteRenderer.flipX)
{
spriteRenderer.flipX = false;
}
else if (horizontal == -1 && !spriteRenderer.flipX)
{
spriteRenderer.flipX = true;
}
body.velocity = new Vector2(horizontal * speed, body.velocity.y);
animator.SetFloat("Speed", Mathf.Abs(horizontal));
float vertical = Input.GetAxisRaw("Vertical");
if (vertical == 1)
{
RaycastHit2D hit = Physics2D.Raycast(raycastPoint.transform.position, Vector2.down, 0.01f);
if (hit.collider != null)
{
body.AddForce(new Vector2(0f, jump));
}
}
}
}
For now I have achieved the right and left movements.
For the jump, I have a child gameobject just under the player and I'm firing a raycast to the bottom so I can know if my player is grounded or not.
I have two problems.
PROBLEM NUMBER ONE.
Sometimes I feel like my "AddForce" line is executed multiple times my player is jumping really high
Problem number one image
PROBLEM NUMBER TWO.
When I'm jumping to the left or right wall, if I keep pressing the left or right key my player is not falling anymore and stay against the wall.
Problem number two image
I tried to put my code into the FixedUpdate method (I know it's better) but I had the same results.
And I tried to set the Collision Detection on Continuous but I had the same results.
Try this code for your first problem :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(BoxCollider2D))]
[RequireComponent(typeof(Rigidbody2D))]
[RequireComponent(typeof(Animator))]
public class Player_Controller : MonoBehaviour {
private Rigidbody2D body;
private bool canJump, facingRight;
private Animator anim;
[SerializeField]
private float moveSpeed, jumpForce;
void Start ()
{
SetStartValues();
}
void FixedUpdate ()
{
float horizontal = Input.GetAxis("Horizontal");
animator.SetFloat("Speed", Mathf.Abs(horizontal));
Flip(horizontal);
Move(horizontal);
Jump();
}
private void SetStartValues()
{
body = GetComponent<Rigidbody2D>();
anim = GetComponent<Animator>();
canJump = true;
facingRight = true;
}
private void Jump()
{
if (Input.GetKeyDown(KeyCode.Space) && canJump)
{
body.AddForce(new Vector2(0, jumpForce));
canJump = false;
}
}
private void Move(float x)
{
body.velocity = new Vector2(x * moveSpeed * Time.deltaTime, body.velocity.y);
}
private void Flip(float x)
{
if (x > 0 && !facingRight|| x < 0 && facingRight)
{
facingRight = !facingRight;
transform.localScale = new Vector2(transform.localScale.x * -1, transform.localScale.y) ;
}
}
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Ground")
{
canJump = true;
}
}
}
And don't forget to put the "Ground" tag on your ground object.

How to make an enemy stop when he enter the required distance to shoot

The problem that i have is that when the enemy enters the range to shoot it stops and never follows the player again even if the player gets out of the shooting range. To detect if the player entered the shooting range I have made a sphere collider for the enemy.
using UnityEngine;
using System.Collections;
public class EnemyWithRifleMovement : MonoBehaviour {
private GameObject player;
private NavMeshAgent nav;
private bool playerInRange = false;
private Rigidbody rb;
void Awake()
{
rb = GetComponent<Rigidbody>();
player = GameObject.FindGameObjectWithTag("Player").gameObject;
nav = GetComponent<NavMeshAgent>();
}
void Update()
{
if(playerInRange)
{
nav.SetDestination(transform.position);
}
else if(playerInRange == false)
nav.SetDestination(player.transform.position);
}
void OnTriggerEnter(Collider other)
{
if(other.gameObject.CompareTag("Player"))
{
playerInRange = true;
}
}
void OnTriggetExit(Collider other)
{
if(other.gameObject.CompareTag("Player"))
{
playerInRange = false;
}
}
}
Your code looks all fine, except there is one typo. Replace OnTriggetExit with OnTriggerExit, and it should work!
Also, in my opinion it is easier to get the distance between the enemy and the player by doing playerInRange = (Vector3.Distance(transform.position, player) <= range.