I have a simple jumping game. In this game there are rotating platforms, and a player object.
Whenever the player clicks the mouse button, it should jump and sticks to the next platform and rotates with it, until he clicks again. I want the game object to jump perpendicular to the rotating platforms.
If i use Vector3.up the game object will fall down instead. But I want the player to jump in the direction of a green arrow and stick to the next platform.
I'm posting here, because I've posted on the Unity Forms 2 weeks ago and still got no answer.
TLDR:
here is what i've worked on recently :
my player code :
Rigidbody2D Rig;
public float Force =500;
public bool gamejump = true;
public Transform platformParent;
bool playerforce = false;
bool setpos = false;
Vector2 pos = new Vector2(0, 0);
public Collider2D Ccollider;
public bool bottom =false;
void Start()
{
Rig = GetComponent<Rigidbody2D>();
Ccollider = GetComponent<CircleCollider2D>();
}
private void FixedUpdate()
{
if (gamejump == true)
{
transform.SetParent(null);
Rig.isKinematic = false;
setpos = false;
}
else
{
transform.SetParent(platformParent);
Rig.AddForce(new Vector2(0, 0));
Rig.isKinematic = true;
if (setpos == false)
{
setpos = true;
transform.position = pos;
}
}
}
void OnTriggerStay2D(Collider2D other)
{
if (other.tag == "Rotate")
{
//if (Input.GetKey(KeyCode.Space))
if (Input.GetMouseButton(0))
{
gamejump = true;
if (bottom == true)
{
Rig.AddForce(other.transform.up * Force);
}
else
{
Rig.AddForce(other.transform.up * -Force);
}
}
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "Rotate")
{
ContactPoint2D contact = collision.contacts[0];
pos = contact.point;
if (collision.contacts.Length>0)
{
bottom = true;
}
else
{
bottom = false;
}
gamejump = false;
}
}
}
and my platform code :
public bool counterclockwise;
Transform player;
player2 playerCode;
public Collider2D collidPlatform;
private int speed=100;
// Start is called before the first frame update
void Start()
{
player = GameObject.Find("player").GetComponent<Transform>();
playerCode = FindObjectOfType<player2>();
if (counterclockwise)
speed = -speed;
}
void FixedUpdate()
{
// float currentZ = transform.eulerAngles.z;
/* if (Limit == true)
{
if (currentZ > 180)
{
currentZ = 180;
}
Vector3 newEuler = new Vector3(0, 0, currentZ);
transform.eulerAngles = newEuler;
}
//transform.Rotate(new Vector3(0, 0, speed * Time.deltaTime));
}
*/
}
private void OnCollisionEnter2D(Collision2D collision)
{
playerCode.platformParent = transform;
playerCode.Ccollider = collidPlatform;
}
}
and still got crazy results, suddenly the player rotates in the air or dose not sticks to a platform and falls or when it sticks to a platform ,it
Increases platform's speed (i know it's because of rigid body that attaches to platforms but if i remove it and try to control it manually it dose not work the way i want ,so if you could give me suggestion on how to rotate platforms manually and without rigid body so i be able to control the speed .
if you make the player a child object of the platform using transform.parent, then jump using transform.up on the players local axis, if you want the player to land on the same position where they jumped, the player can remain parented to the rotating platform, otherwise you need to remove the player as a child object to the platform after you jump. But since you are using rigidbody physics, I think you will get mixed results from gravity.
Related
Context
So I'm making a clone of Crossy Roads where the camera follows the player. It does some linear interpolation (Lerp) after moving, and the camera starts moving away from the player in the positive direction (x-axis until camera reaches to a certain range where player is not visible enough). Things I have tried is by flagging it, but I think I'm doing it wrong.
Problem
I have done my camera movements accordingly, but I am having an issue where the conditions are not properly met. I'm get the offset camera after not moving, but it does not the Lerp, and vice-versa. I want both to happen after a certain condition after the game starts. When the player moves, the camera follows it in Lerp. However, once the player is "Idle", its still Lerping. I want the camera to continue by itself and at the same time focus at the player's object.
Example
Camera with Lerp, but not moving away from the player
Camera moving away, but not following player with lerp
Code
CameraController.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
** Camera following player (Smoothing and angle): https://youtu.be/4HpC--2iowE
** Maximo: https://www.youtube.com/watch?v=bXNFxQpp2qk&ab_channel=iHeartGameDev
** Moving character relative to camera: https://forum.unity.com/threads/moving-character-relative-to-camera.383086/
** Camera follow v2: https://youtu.be/Jpqt2gRHXtc?list=PLq_nO-RwB516fNlRBce0GbtJSfysAjOgU
*/
public class CameraController : MonoBehaviour
{
public GameObject player;
public PlayerControl playerControlScript;
private Vector3 newCameraPos;
public bool stillIdle;
void Start()
{
stillIdle = false;
PlayerControl playerControlScript = GetComponent<PlayerControl>();
}
void LateUpdate()
{
player = GameObject.FindGameObjectWithTag("Player");
if (playerControlScript.GetfirstInput()) //True
{
stillIdle = true;
newCameraPos = Vector3.Lerp(transform.position, playerControlScript.transform.position, Time.deltaTime);
transform.position = new Vector3(newCameraPos.x, 1, newCameraPos.z);
}
if (stillIdle)
transform.position = new Vector3(transform.position.x + 0.69f * Time.deltaTime, transform.position.y, transform.position.z); //Moving camera away effect
}
}
PlayerControl.cs
public class PlayerControl : MonoBehaviour
{
bool firstInput;
Vector3 startPos;
Vector3 endPos;
public bool GetfirstInput() //I was learning how to have a Get function while my member was private from another script file
{
return firstInput;
}
void Update()
{
if (Input.GetButtonDown("up") || Input.GetButtonDown("left") || Input.GetButtonDown("right") || Input.GetButtonDown("down"))
{
//if game starts
{
//Other variables being initialized here
firstInput = true;
}
}
}
}
Hierarchy/Inspector
Main Camera
Player Object
Some help would be appreciate it. I feel I have been staring at this problem and I bet it is something minimal and small from just thinking it.
Let me know if you need clarifications. I'm happy to edit and answer them for everyone
If player in your game does not change, you don't have to find the player reference in each LateUpdate().
I notice that once stillIdle is set true, it never goes back to false, is this your intention to do that?
You call Lerp when playerControlScript.GetfirstInput() is true, so maybe we need to look at its implementation. Maybe it turns true in some conditions you do not intend it to.
Maybe Try this
public class PlayerControl : MonoBehaviour
{
private bool _hasFireFirstInput = false;
private bool _isIdle = true;
public bool IsIdle => _isIdle;
public bool HasFireFirstInput => _hasFireFirstInput;
private void Update()
{
if (Input.GetButton("Horizontal") || Input.GetButton("Vertical"))
{
_hasFireFirstInput = true;
_isIdle = false;
Vector3 pos = transform.position;
pos = new Vector3(pos.x, pos.y, pos.z + .2f * Time.deltaTime);
transform.position = pos;
}
else
{
_isIdle = true;
}
}
}
I use Input.GetButton() rather than Input.GetButtonDown(), since the later only return true at the frame the button is pressed, meaning that if i long-press the button, it will return false after the next frame.
public class CameraController : MonoBehaviour
{
[SerializeField] PlayerControl _playerControlScript;
[SerializeField] Vector3 _offset;
[SerializeField] float _lerpSpeed;
bool _iskeepLerping = false;
float _lerpVal = 0f;
private void LateUpdate()
{
if (!_playerControlScript.HasFireFirstInput)
{
return;
}
if (_playerControlScript.IsIdle)
{
MoveAway();
}
else
{
Lerp();
}
}
private void MoveAway()
{
_iskeepLerping = false;
transform.position = new Vector3(transform.position.x + 0.69f * Time.deltaTime, transform.position.y, transform.position.z);
}
private void Lerp()
{
if (!_iskeepLerping)
{
_lerpVal = 0f;
}
Vector3 newCameraPos = Vector3.Lerp(transform.position, _playerControlScript.transform.position + _offset, _lerpVal);
transform.position = newCameraPos;
_lerpVal += _lerpSpeed * Time.deltaTime;
_iskeepLerping = true;
}
}
I am trying to write a script for an enemy to chase a player for about 2 seconds and then stopping. I want to have the player run into a boxcollider and when this happens the enemy will chase the player for 2 seconds. I've been trying for a while and had no luck. I'm hoping someone with more skill can help me write this code so it works properly using Unity 2d. Thanks
void Start()
{
var x = 0;
var y = 0;
player = GameObject.Find("Player").GetComponent<PlayerMovement>().playerBox;
}
public void OnCollisionEnter2D(Collision2D collision)
{
//If the player is touching the knights targetting box, then run the command to chase.
if (collision.collider.tag == "Player")
{
isChasing = true;
chase();
}
}
public void chase()
{
if (isChasing)
{
var x = playerTransform.position.x - enemyTransform.position.x;
var y = playerTransform.position.y - enemyTransform.position.y;
knightRB.velocity = new Vector2(x / 20, y / 20);
StartCoroutine(StopChasing());
}
}
IEnumerator StopChasing()
{
yield return new WaitForSeconds(2);
isChasing = false;
}
Below is my implementation:
Transfrom target;
bool isChasing;
float speed = 5;
RigidBody knightRB;
// -----------------------------------------------------------------------------
// Sets up the knight
void Start()
{
target = GameObject.Find("Player").transform;
knightRB = GetComponent<RigidBody>();
}
// -----------------------------------------------------------------------------
//Checks for a collision with the player
void OnCollisionEnter2D(Collision2D collision)
{
//If the player is touching the knights targetting box, then run the command to chase.
if (collision.collider.tag == "Player" && !isChasing)
{
StartCoRoutine(ChaseSequence());
}
}
// -----------------------------------------------------------------------------
// handles the chase
void FixedUpdate()
{
Chase();
}
void Chase()
{
if (!isChasing)
return;
var direction = (target.position - transform.position).normalized;
knightRB.MovePosition(transfrom.position + direction * Time.deltaTime * speed);
}
// -----------------------------------------------------------------------------
// Stops and starts the chase sequence
IEnumerator ChaseSequence()
{
isChasing = true;
yield return new WaitForSeconds(2);
isChasing = false;
}
There are some assumptions I have made. Mainly that the this script belongs on the knight. Also the collider is what interacts with the environment. Meaning physically. If you have a trigger that does the detection you should be using OnTriggerEnter instead of OnCollisionEnter
I'm making a 2D game in Unity, which has falling platforms that the player can "ride" down. I want the player to still be able to move left or right (ie horizontally) while standing on a falling platform. Without additional code, just using the Rigidbody physics, the player does fall along with the platform, but the falling is choppy, and the game doesn't always see the player is standing on the platform (important because the player can only jump while standing on something).
I've tried setting the player object's transform.translate, which prevents the player from moving left or right as long as it is touching the platform. I've also tried setting the player object's transform.parent to the platform's transform, but that "glues" the player in place to the platform, preventing even jumping. I've also tried searching for a solution/example, and there are plenty of examples for riding a left-right moving platform, but I haven't been able to get those examples to work for a falling platform.
Here is the script controlling the players left-right movement and jumping. This is attached to the player object:
public class Player : MonoBehaviour
{
public float jumpForce = 5;
public float horizontalSpeed = 0.1F;
public LayerMask whatIsGround;
private Rigidbody2D rb2d;
private Collider2D myCollider;
private bool grounded;
private float lastHorizontalInput;
void Start()
{
rb2d = GetComponent<Rigidbody2D>();
myCollider = GetComponent<Collider2D>();
}
void Update()
{
// If the player is trying to jump, only do so if the player is on a platform
grounded = Physics2D.IsTouchingLayers(myCollider, whatIsGround);
if (Input.GetKeyDown(KeyCode.Space) && grounded)
{
rb2d.velocity = new Vector2(rb2d.velocity.x, jumpForce);
}
MoveHorizonltally();
}
private void MoveHorizonltally()
{
float horizontalVelocity;
float horizontalInput = Input.GetAxis("Horizontal");
horizontalVelocity = GetHorizontalVelocity(horizontalInput);
if (horizontalVelocity != 0)
{
rb2d.position = new Vector2(rb2d.position.x + horizontalVelocity, rb2d.position.y);
}
}
private float GetHorizontalVelocity(float horizontalInput)
{
// Default to no horizontal motion
float result = 0;
bool leftPressed = Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow);
bool rightPressed = Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow);
// Only a left key is being pressed; the player is going left
if (leftPressed && !rightPressed)
{
result = -1 * horizontalSpeed;
}
// Only a right key is being pressed; the player is going right
else if (rightPressed && !leftPressed)
{
result = horizontalSpeed;
}
// Both keys are being pressed
else if (leftPressed && rightPressed)
{
// The most recent key press gets priority; ignore the oldest key press
if (lastHorizontalInput < 0)
{
// Oldest key pressed is a left direction, so go right
result = horizontalSpeed;
}
else
{
// Oldest key pressed is a right direction, so go left
result = -1 * horizontalSpeed;
}
}
lastHorizontalInput = horizontalInput;
return result;
}
}
Here is the script responsible for making the platform fall. This is attached to the platform object:
public class PlatformFalling : MonoBehaviour
{
public float fallSpeed;
private GameObject player;
public void Start()
{
player = GameObject.FindGameObjectWithTag("Player");
}
// Update is called once per frame
void Update()
{
bool playerIsOnPlatform = player.GetComponent<Collider2D>().IsTouching(GetComponent<Collider2D>()); ;
Vector2 fallDistance = Vector2.down * fallSpeed;
transform.Translate(fallDistance);
if (playerIsOnPlatform)
{
player.transform.Translate(fallDistance);
}
}
}
This is the code i have wrtten so far which makes the player controlled charcter be able to jump contanstantly i only want them to be able to jump when on the ground.
void Update()
{
this.transform.Translate(Input.GetAxis("Horizontal"), 0, 0);
xdirectionMovement = Input.GetAxis("Horizontal") * runspeed; //GetAxisRaw("Horizontal")
if (Input.GetMouseButtonDown(0) || Input.GetKeyDown(KeyCode.Space)) //makes player jump
{
GetComponent<Rigidbody2D>().AddForce(jumpdistance, ForceMode2D.Impulse);
Ensure you only allow jumping when the character is grounded. One approach to check for that is to use a downwards raycast and see if the hit is below a certain threshold:
void Update()
{
print(IsGrounded());
}
bool IsGrounded()
{
const float distanceToGround = 1f;
return Physics.Raycast(
transform.position, -Vector3.up, distanceToGround) != null;
}
Another is to use a CharacterController component and check its bool:
CharacterController controller = null;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
print(controller.isGrounded);
}
Another is to listen for a collision event and set a bool:
bool collides = false;
void FixedUpdate()
{
print(collides);
collides = false;
}
void OnCollisionStay(Collision collision)
{
collides = true;
}
Note that sometimes, it's good usability practice to allow a bit of leeway so the user can jump even if they miss the ground by a few pixels, or miss the timing by a few milliseconds. Good luck!
Add a bool to check if player is grounded, add Vectors and Colliders to determine where player is, relative to the ground.
private BoxCollider2D box;
Vector3 maxValue= box.bounds.max;
Vector3 minValue=box.bounds.minValue;
Vector2 x = new Vector2(max.x, minValue.y -0.1f);
Vector2 y = new Vector2(minValue.x, minValue.y - 0.1f);
Collider2D ground = Physics.OverlapArea(x,y);
bool jump = false;
if (ground != null)
{
jump = true;
}
Finally you can add the bool to your Input, for example,
if (Input.GetKeyDown(KeyCode.Space) && jump == true)
{
//player jump
}
i have a 2d character and i want to make its head pop off.
Add force seems the most logical but i cannot get any force and it also must depend on the characters rotation. So if hes laying sideways the head must shoot off to the left (or right).
public GameObject RagdollBody;
HingeJoint2D joint;
bool cut = false;
Rigidbody2D rb;
void Start()
{
joint = GetComponent<HingeJoint2D>();
rb = GetComponent<Rigidbody2D>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "Blade" && !cut)
{
joint.enabled = false;
cut = true;
rb.AddForce(-RagdollBody.transform.forward * 500);
}
}
I watched a video that used -transform so it will shoot in the oppersite direction which is what i want. As the head is always 0,0,0 rotation, i need to get it from the parent but it still doesnt add any force.
You are using transform.forward, which represents the Z axis, or "inwards" if you will, in a 2d game.
If you want to add force upwards (relative to its orientation), i suggest trying this instead
rb.AddForce(RagdollBody.transform.up * 500);
Could it be possible that you need to be using "AddRelativeForce" instead of "AddForce" on the last line there?
If this script is placed on the head you're launching you could try:
public GameObject RagdollBody;
HingeJoint2D joint;
bool cut = false;
Rigidbody2D rb;
void Start()
{
joint = GetComponent<HingeJoint2D>();
rb = GetComponent<Rigidbody2D>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "Blade" && !cut)
{
joint.enabled = false;
cut = true;
rb.AddRelativeForce(Vector2.up * 500);
}
}
or you could get the 2d rigid body all in the one line (only to save lines):
public GameObject RagdollBody;
HingeJoint2D joint;
bool cut = false;
void Start()
{
joint = GetComponent<HingeJoint2D>();
}
private void OnTriggerEnter2D(Collider2D collision)
{
if (collision.gameObject.name == "Blade" && !cut)
{
joint.enabled = false;
cut = true;
GetComponent<Rigidbody2D> ().AddRelativeForce(Vector2.up * 500);
}
}