I'm facing an issue when I pick up an object in my game. Whenever I pick up an object and look around while holding the object, it stretches based on the perspective. Here is an example of an object before and after picking up:
Before picking up:
After picking up:
How can I maintain the object's scale and prevent it from stretching?
public void PickupObject()
{
physicsObject = lookObject.GetComponentInChildren<PhysicsObjects>();
currentlyPickedUpObject = lookObject;
pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
/* priorConstraints = pickupRB.constraints; // <--- NEW
pickupRB.constraints = RigidbodyConstraints.FreezeAll; // <--- NEW*/
pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
physicsObject.playerInteractions = this;
pickupRB.isKinematic = true;
pickupRB.transform.parent = PickupParent.transform;
// pickupRB.isKinematic = true;
// StartCoroutine(physicsObject.PickUp());
}
The following code snippet is in Update() :
if (currentlyPickedUpObject != null)
{
HoldingItemIcon.SetActive(true);
InteractIcon.SetActive(false);
CenterIcon.SetActive(false);
currentDist = Vector3.Distance(PickupParent.position, pickupRB.position);
currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
currentSpeed *= Time.fixedDeltaTime;
pickupRB.transform.position = PickupParent.position;
// pickupRB.transform.SetParent(PickupParent.transform);
Vector3 direction = PickupParent.position - pickupRB.position;
pickupRB.velocity = direction.normalized * currentSpeed;
Vector3 camerDirection = mainCamera.transform.forward;
// Throw object
if (Throw)
{
HoldingItemIcon.SetActive(false);
InteractIcon.SetActive(false);
pickupRB.constraints = RigidbodyConstraints.None;
pickupRB.isKinematic = false;
pickupRB.AddForce(camerDirection * 500);
currentlyPickedUpObject = null;
pickupRB.transform.parent = null;
}
Throw = false;
}
public void BreakConnection()
{
pickupRB.isKinematic = false;
pickupRB.transform.parent = null;
pickupRB.constraints = priorConstraints;
// pickupRB.constraints = RigidbodyConstraints.None;
currentlyPickedUpObject = null;
lookObject = null;
physicsObject.pickedUp = false;
currentDist = 0;
pickupRB.useGravity = true;
}
pickupParent's lossy scale while an object is picked:
What you can do is have an empty gameObject as a child of your player. That object is going to be the pickableObjectsParent and give this parent object the scale values of 1/(player's scale).
Related
I'm trying to make the crouching/standing-up smoother and slower, as currently crouching/uncrouching is so quick(I mean transition between crouching/uncrouching)
private void Start()
{
startYScale = transform.localScale.y;
mainCamera = Camera.main;
}
private void PlayerMovement()
{
currentSpeed = moveSpeed;
move = controls.Player.Movement.ReadValue<Vector2>();
movement = (move.y * transform.forward) + (move.x * transform.right);
if (isRunning)
{
//run = controls.Player.Run.ReadValue<float>();
currentSpeed = runSpeed;
Vector3 running = (move.y * transform.forward) + (move.x * transform.right);
controller.Move(running * currentSpeed * Time.deltaTime);
}
if (crouching)
{
currentSpeed = crouchSpeed;
isRunning = false;
transform.localScale = new Vector3(transform.localScale.x, crouchYScale, transform.localScale.z);
// controller.radius = 0.2f;
}
else
{
currentSpeed = moveSpeed;
transform.localScale = new Vector3(transform.localScale.x, startYScale, transform.localScale.z);
}
controller.Move(movement * currentSpeed * Time.deltaTime);
}
How would I fix that? is there a way to make the transition slower and smoother? please help.
Edit:
I tried changing the position of the camera too when crouching to make the transition from standing up to crouching smoother.
private void FixedUpdate()
{
var desierdHeight = crouching ? crouchYScale : startYScale;
if (controller.height != desierdHeight)
{
AdjustHeight(desierdHeight);
/* var camPos = playerCamera.transform.position;
camPos.y = controller.height;
playerCamera.transform.position = camPos;*/
playerCamera.transform.localPosition = new Vector3(0,controller.height, 0);
}
}
private void AdjustHeight(float height)
{
float center = height / 2;
controller.height = Mathf.Lerp(controller.height, height, crouchSpeed);
controller.center = Vector3.Lerp(controller.center, new Vector3(0, center,0), crouchSpeed);
}
but the transition is still fast.
I'm trying to throw an object after it is being held. Here is how the pickup works:
public void PickupObject()
{
physicsObject = lookObject.GetComponentInChildren<PhysicsObjects>();
currentlyPickedUpObject = lookObject;
pickupRB = currentlyPickedUpObject.GetComponent<Rigidbody>();
priorConstraints = pickupRB.constraints;
pickupRB.constraints = RigidbodyConstraints.FreezeAll;
pickupRB.constraints = RigidbodyConstraints.FreezeRotation;
physicsObject.playerInteractions = this;
pickupRB.isKinematic = true;
pickupRB.transform.parent = PickupParent.transform;
// pickupRB.isKinematic = true;
StartCoroutine(physicsObject.PickUp());
}
in the update():
if (currentlyPickedUpObject != null)
{
currentDist = Vector3.Distance(PickupParent.position, pickupRB.position);
currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
currentSpeed *= Time.fixedDeltaTime;
pickupRB.transform.position = PickupParent.position;
// pickupRB.transform.SetParent(PickupParent.transform);
Vector3 direction = PickupParent.position - pickupRB.position;
pickupRB.velocity = direction.normalized * currentSpeed;
Vector3 camerDirection = mainCamera.transform.forward;
// Throw object
if (Throw)
{
pickupRB.constraints = RigidbodyConstraints.None;
pickupRB.isKinematic = false;
Debug.Log("Object is being thrown");
pickupRB.AddForce(camerDirection * 100);
}
Throw = false;
}
as shown above I was trying to add force to the direction the player to be able to throw the item in that direction in this part:
Vector3 camerDirection = mainCamera.transform.forward;
if (Throw)
{
pickupRB.constraints = RigidbodyConstraints.None;
pickupRB.isKinematic = false;
Debug.Log("Object is being thrown");
pickupRB.AddForce(camerDirection * 100);
}
Throw = false;
The line is printed in the console when the throw button is pressed but nothing happens. How to fix this?
I think you're throwing the object but you're not releasing it, so on the next frame the currentlyPickedUpObject is not null so you go right back to moving it with the PickupParent again. Try setting it to null inside your if (Throw) statement so you don't keep moving it:
if (currentlyPickedUpObject != null)
{
currentDist = Vector3.Distance(PickupParent.position, pickupRB.position);
currentSpeed = Mathf.SmoothStep(minSpeed, maxSpeed, currentDist / maxDistance);
currentSpeed *= Time.fixedDeltaTime;
pickupRB.transform.position = PickupParent.position;
// pickupRB.transform.SetParent(PickupParent.transform);
Vector3 direction = PickupParent.position - pickupRB.position;
pickupRB.velocity = direction.normalized * currentSpeed;
Vector3 camerDirection = mainCamera.transform.forward;
// Throw object
if (Throw)
{
pickupRB.constraints = RigidbodyConstraints.None;
pickupRB.isKinematic = false;
Debug.Log("Object is being thrown");
pickupRB.AddForce(camerDirection * 100);
currentlyPickedUpObject = null; // <--- NEW
}
Throw = false;
}
The problem is when you pick the object up you are setting the pickupRB kinematic with line
pickupRB.isKinematic = true
So to fix this, you should add
pickupRB.isKinematic = false
before you add force to the rigidbody.
I want to flip my sprites depending on which direction they are going and then stay in that position until they move again. I've tried velocity detection and the flipping the sprites accordingly, but since my movement is not by force but by changing position it can't detect velocity (I think), so any suggestions would be helpful.
Here's the movement script I've got so far:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Movement : MonoBehaviour
{
//DRAG AND DROP
bool isBeingDragged = false;
//POSITIONS AND TARGET
public float speed = 0.5f;
float timer = 0f;
public float waitTime;
public float distanceToAchieve = 0.2f;
bool isFollowing = true;
bool isWaiting = false;
//GOAL TARGET
public GameObject goalGameObject;
Vector2 target;
public Vector2 bounds = new Vector2(1.75f, 3);
private Vector2 RP;
private float startPosX;
private float startPosY;
void Start()
{
if (this.gameObject.tag == "1")
{
transform.position = RandomizePosition();
}
target = RandomizePosition();
isFollowing = true;
}
private void Update()
{
if (!isBeingDragged)
{
if (!isWaiting && Vector2.Distance(transform.position, target) < distanceToAchieve)
{
isWaiting = true;
isFollowing = false;
RandomizeGoal();
}
if (isWaiting)
{
timer += Time.deltaTime;
if (timer > waitTime)
{
timer = 0f;
isWaiting = false;
isFollowing = true;
}
}
}
}
private void FixedUpdate()
{
if (isFollowing && !isBeingDragged)
{
transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
if (isBeingDragged)
{
Vector3 mousePos;
mousePos = Input.mousePosition;
mousePos = Camera.main.ScreenToWorldPoint(mousePos);
this.gameObject.transform.localPosition = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY, 0);
}
}
Vector2 RandomizePosition()
{
RP = new Vector2(transform.position.x - Random.Range(-1f, 1f), transform.position.y - Random.Range(-1f, 1f));
if (RP.x < bounds.x && RP.x > bounds.x * -1 && RP.y < bounds.y && RP.y > bounds.y * -1)
{
return RP;
}
else
{
return new Vector2(transform.position.x, transform.position.y);
}
}
void RandomizeGoal()
{
waitTime = Random.Range(2, 10);
target = RandomizePosition();
goalGameObject.transform.position = target;
}
private void OnMouseDown()
{
isBeingDragged = true;
Vector3 mousePos;
mousePos = Input.mousePosition;
mousePos = Camera.main.ScreenToWorldPoint(mousePos);
startPosX = mousePos.x - this.transform.localPosition.x;
startPosY = mousePos.y - this.transform.localPosition.y;
}
private void OnMouseUp()
{
isBeingDragged = false;
GetComponent<Merging>().CheckNearest();
}
}
private void FixedUpdate()
{
if (isFollowing && !isBeingDragged)
{
transform.position = Vector2.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
if (isBeingDragged)
{
Vector3 mousePos;
mousePos = Input.mousePosition;
mousePos = Camera.main.ScreenToWorldPoint(mousePos);
// capture the current position of target
// by the way, why you use "loclPosition" for moving ??
// I don't thinkg this is appropriate.
var currentPos = this.gameObject.transform.localPosition;
var newPos = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY, 0);
// then compare this with new position
bool isLeftSided = false;
if (newPos.x > currentPos.x)
{
isLeftSided = true;
}
else
{
isLeftSided = false;
}
// And figure out the direction . in this example, I wrote just right-left case
// use the y pos for up and down
// then flip the sprite ( this case, default is right sided )
this.gameObject.GetComponent<SpriteRenderer>().flipX. = isLeftSided;
this.gameObject.transform.localPosition = new Vector3(mousePos.x - startPosX, mousePos.y - startPosY, 0);
}
}
My game is a 2D top down platform, I have an zombie enemy that moves up and down the stage, I can place obstacles (such as a create) in its way to stop the enemy, the enemy has the ability to dodge these obstacles at any random moment. If the enemy collided with the create, the enemy will stop its movement to break the create. Once the create is broken, the enemy will continue to moving up, hit point B and then will move back down the stage. My Problem: If the enemy were to dodge left (for example) and then continues to move down and passes another create, the enemy will ignore collision and the function for it to stop and break that create. How do I fix this issue?
public bool hitCollider = false;
public bool hitCollider2 = false;
public bool canMove = true;
public bool moveDown = false;
public bool isMovingUp = true;
public bool isMovingDown = false;
public bool isSomethere = false;
public bool ifMoving;
public float velocidadMax;
public float xMax;
public float xMin;
public float delay;
public float x;
private float tiempo;
public float countDown, countUp, startTime;
void Start () {
Bcol = GetComponent<BoxCollider2D> ();
Bcol.isTrigger = true;
isMovingUp = true;
rigid = GetComponent <Rigidbody2D> ();
velocidadMax = 0.12f;
x = velocidadMax;
InvokeRepeating ("turnFalse", startTime, countDown); // changing lanes
InvokeRepeating ("turnTrue", 0, countUp); // moving up or down
ifMoving = true;
movedownSpeed = -4f;
moveupSpeed = 4f;
hascollidedwHouse = false;
}
void Update () {
if (moveDown == false) {
rigid.velocity = new Vector2 (0, moveupSpeed); // moving up
if (ifMoving == true) {
//irrelevant - don't need to know code here!
} else if (ifMoving == false) {
movedownSpeed = -4;
moveupSpeed = 0;
Move ();
}
}
if (moveDown == true) {
if (hitMascot2 == true) {
} else if (hitMascot2 == false) {
movingDown = true;
Bcol.isTrigger = true;
StartCoroutine (waitMove ());
StartCoroutine (destroyObj ());
}
}
if (isMovingDown == true) {
Debug.Log ("MovingDown");
Bcol.isTrigger = true;
if (canMove == false) {
Debug.Log ("is False" + canMove);
moveupSpeed = 4f;
}
hitCollider = false;
hitCollider2 = false;
}
if (hitCollider == true) {
StartCoroutine (wait ());
Debug.Log ("I HAVE COLLIDED");
if (canMove == true) {
movedownSpeed = 0f;
}
if (canMove == false) {
movedownSpeed = -4f;
}
moveupSpeed = 0f;
}
if (hitCollider2 == true) {
StartCoroutine (wait2 ());
Debug.Log ("I HAVE COLLIDED");
if (canMove == true) {
movedownSpeed = 0f;
}
if (canMove == false) {
movedownSpeed = -4f;
}
moveupSpeed = 0f;
}
}
void OnTriggerEnter2D (Collider2D col) {
if (col.tag == "objects") {
hitCollider = true;
woodBox = true;
canMove = false;
moveDown = false;
xMax = 0;
xMin = 0;
if (hascollidedwHouse == true) {
moveDown = false;
isMovingDown = false;
movedownSpeed = 0;
moveupSpeed = 0;
hitCollider = false;
ifMoving = false;
xMax = 0;
xMin = 0;
StartCoroutine (waitDown ());
}
}
if (col.tag == "objects2") {
hitCollider2 = true;
metalBox = true;
canMove = false;
hitwoodenC = false;
hitmetalC = true;
moveDown = false;
xMax = 0;
xMin = 0;
if (hascollidedwHouse == true) {
moveDown = false;
isMovingDown = false;
movedownSpeed = 0;
moveupSpeed = 0;
ifMoving = false;
hitCollider2 = false;
xMax = 0;
xMin = 0;
StartCoroutine (waitDown2 ());
}
}
if (col.tag == "pointB") {
if (ifMoving == false) {
moveupSpeed = 0;
movedownSpeed = -4;
} else if (ifMoving == true) {
moveupSpeed = 0;
movedownSpeed = -4;
}
Debug.Log ("Collided");
moveDown = true;
isMovingDown = true;
isMovingUp = false;
canMove = false;
hascollidedwHouse = true;
}
void Move () {
if (isSomethere == false) {
if (isMovingUp == true) {
tiempo += Time.deltaTime;
if (transform.localPosition.x < xMin) {
x = Random.Range (0.0f, velocidadMax);
x = velocidadMax;
tiempo = 0.0f;
Debug.Log ("Left");
}
if (tiempo > 1.0f) { //1.0 0.3
x = -velocidadMax;
tiempo = 0.0f;
Debug.Log ("Right");
}
transform.localPosition = new Vector3 (transform.localPosition.x + x, transform.localPosition.y);
}
} else if (isSomethere == true) {
movedownSpeed = -4;
moveupSpeed = 4;
if (iSPdeath == true) {
movedownSpeed = 0;
moveupSpeed = 0;
}
}
}
void turnFalse ()
{
if( hitCollider == false) {
ifMoving = false; // moves left and right
}
if( hitCollider2 == false) {
ifMoving = false; // moves left and right
}
}
void turnTrue() {
if( hitCollider == false) {
ifMoving = true; // moves up and down
}
if( hitCollider2 == false) {
ifMoving = true; // moves up and down
}
}
IEnumerator wait() {
yield return new WaitForSeconds (2.5f);
hitCollider = false;
if (isMovingUp == true) {
canMove = true;
}
if (isMovingUp == false) {
canMove = false;
moveupSpeed = 0f;
movedownSpeed = -4f;
}
if (canMove == true) {
moveupSpeed = 4f;
}
}
IEnumerator wait2() {
yield return new WaitForSeconds (5.2f);
hitCollider = false;
if (isMovingUp == true) {
canMove = true;
}
if (isMovingUp == false) {
canMove = false;
moveupSpeed = 0f;
movedownSpeed = -4f;
}
if (canMove == true) {
moveupSpeed = 4f;
}
}
IEnumerator waitDown() {
yield return new WaitForSeconds (2.5f);
movedownSpeed = -4f;
moveupSpeed = 0f;
moveDown = true;
}
IEnumerator waitDown2() {
yield return new WaitForSeconds (5.2f);
movedownSpeed = -4f;
moveupSpeed = 0f;
moveDown = true;
}
}
what I'm trying to achieve, is that while the player holds the mouse button
on a tile (any grid element, verically or horizontally aligned with the player), the player will move towards that tile with the possible directions of left,right,up,down only.
currently my code doesn't work for while pressing the mouse button, I think it has something to do with the raycasting.
second thing I want to achieve is that while the player is moving in the grid, if the player decides to change direction, he will be able, no matter if it's just opposite direction, or if he decideds to take a sudden turn left/right.
(I managed to achieve it without using the isMoving boolean condition only in the opposite direction, but I added it because when the player clicked while moving it slowed him down)
right now no change in movement while moving is available.
using UnityEngine;
using Holoville.HOTween;
using System.Collections;
public class Player : MonoBehaviour {
public float speed = 100f;
private Vector3 startPos;
private Vector3 endPos;
private float startTime;
private float journeyLength;
private tile currentTile;
private tile tileToMove;
private float angleToTurn = 0f;
private bool isMoving = false;
public static Player use;
void Awake()
{
use = this;
}
void Start () {
startPos = endPos = transform.position;
tileToMove = currentTile = fieldGenerator.use.tilesList[0];
}
// Update is called once per frame
void Update () {
MovePlayer();
float distCovered = (Time.time - startTime) * speed;
float fracJourney = distCovered / journeyLength;
if (!startPos.Equals(endPos))
transform.position = Vector3.Lerp(startPos, endPos, fracJourney);
if (transform.position == endPos)
{
isMoving = false;
}
}
void MovePlayer()
{
Ray ray;
RaycastHit hit;
if (Input.GetMouseButtonDown(0) && !isMoving)
{
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
for (int i = 0; i < fieldGenerator.use.tilesList.Count; i++)
{
if (fieldGenerator.use.tilesList[i].selfObject.collider.Raycast(ray, out hit, float.PositiveInfinity))
{
if (fieldGenerator.use.tilesList[i].selfObject.transform.position.x < transform.position.x && fieldGenerator.use.tilesList[i].selfObject.transform.position.y == transform.position.y)
{
angleToTurn = -180f;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
}
else if (fieldGenerator.use.tilesList[i].selfObject.transform.position.x > transform.position.x && fieldGenerator.use.tilesList[i].selfObject.transform.position.y == transform.position.y)
{
angleToTurn = 0;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
}
else if (fieldGenerator.use.tilesList[i].selfObject.transform.position.y < transform.position.y && fieldGenerator.use.tilesList[i].selfObject.transform.position.x == transform.position.x)
{
angleToTurn = -90f;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
}
else if (fieldGenerator.use.tilesList[i].selfObject.transform.position.y > transform.position.y && fieldGenerator.use.tilesList[i].selfObject.transform.position.x == transform.position.x)
{
angleToTurn = 90f;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
}
startTime = Time.time;
startPos = transform.position;
endPos = tileToMove.selfObject.transform.position;
journeyLength = Vector3.Distance(startPos, endPos);
transform.eulerAngles = new Vector3(0f, 0f, angleToTurn);
}
}
}
}
}
Unsure on what you're doing with the tiles and raycasting but here's how i'd do it. Apologies for the formatting, it's just how I work.
EDIT: Okay, given you said 'grid' movement I assumed the tiles were equidistant from each other. GetMouseButtonDown changed to GetMouseButton as well. This will mean that a ray is shot every update which you may want to look into making more efficient.
using UnityEngine;
using Holoville.HOTween;
using System.Collections;
public class Player : MonoBehaviour {
public float speed = 100.0f;
private float delta = 0.0f;
private float distance = 1.0f;
private Vector3 startPos;
private Vector3 endPos;
private tile currentTile;
private tile tileToMove;
private float angleToTurn = 0f;
private bool isMoving = false;
public static Player use;
void Awake() {
use = this;
}
void Start () {
startPos = endPos = transform.position;
tileToMove = currentTile = fieldGenerator.use.tilesList[0];
}
// Update is called once per frame
void Update () {
GetInput();
MovePlayer();
}
void MovePlayer() {
if ( isMoving ) {
if ( delta < 1 ) {
// Distance independant movement.
delta += ( speed/distance ) * Time.deltaTime;
transform.position = Vector3.Lerp(startPos, endPos, delta);
} else {
isMoving = false;
}
}
}
void GetInput() {
Ray ray;
RaycastHit hit;
if ( Input.GetMouseButton(0) ) {
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
for (int i = 0; i < fieldGenerator.use.tilesList.Count; i++) {
if ( fieldGenerator.use.tilesList[i].selfObject.collider.Raycast( ray, out hit, float.PositiveInfinity ) ) {
if (fieldGenerator.use.tilesList[i].selfObject.transform.position.x < transform.position.x && fieldGenerator.use.tilesList[i].selfObject.transform.position.y == transform.position.y) {
angleToTurn = -180f;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
} else if (fieldGenerator.use.tilesList[i].selfObject.transform.position.x > transform.position.x && fieldGenerator.use.tilesList[i].selfObject.transform.position.y == transform.position.y) {
angleToTurn = 0;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
} else if (fieldGenerator.use.tilesList[i].selfObject.transform.position.y < transform.position.y && fieldGenerator.use.tilesList[i].selfObject.transform.position.x == transform.position.x) {
angleToTurn = -90f;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
} else if (fieldGenerator.use.tilesList[i].selfObject.transform.position.y > transform.position.y && fieldGenerator.use.tilesList[i].selfObject.transform.position.x == transform.position.x) {
angleToTurn = 90f;
tileToMove = fieldGenerator.use.tilesList[i];
isMoving = true;
}
isMoving = true;
delta = 0f;
startPos = transform.position;
endPos = tileToMove.selfObject.transform.position;
distance = Vector3.Distance( startPos, endPos );
transform.eulerAngles = new Vector3(0f, 0f, angleToTurn);
}
}
}
}
}