I have an object that moves forward and backwards. Just as it is about to move in the opposite direction, I am trying to add a very brief delay (1.0f) before it moves again.
public class PushPlayer : MonoBehaviour
{
public float moveAmount = 3.3f;
public float speed = 1.1f;
private Vector3 startPos;
void Start()
{
startPos = transform.position;
}
void Update()
{
Vector3 v = startPos;
v.z += moveAmount * Mathf.Sin(Time.time * speed);
transform.position = v;
}
}
I attempted to implement a coroutine in two different ways with one of them not working and the other making my entire game basically freeze. I tried to call the method again as well which I am not sure works at all however there were no results.
using System.Collections;
using UnityEngine;
public class PushPlayer : MonoBehaviour
{
public float moveAmount = 3.3f;
public float speed = 1.1f;
private Vector3 startPos;
[SerializeField] private float _delay = 1f;
void Start()
{
startPos = transform.position;
StartCoroutine(DoMoving());
}
private IEnumerator DoMoving()
{
while (true)
{
yield return DoCycle();
yield return new WaitForSeconds(_delay);
}
IEnumerator DoCycle()
{
var time = 0f;
while (time * speed < Mathf.PI * 2f)
{
Vector3 v = startPos;
v.z += moveAmount * Mathf.Sin(time * speed);
transform.position = v;
yield return null;
time += Time.deltaTime;
}
}
}
}
But it would be better to use dotween or dotween + unitask for async moving
Related
I want to move an object from position A to position B on X axis endlessly. But it does move and comeback only once. How to make it continuosly? I've tried Vector3.Lerp or just creating new Vector3 but it only teleports.
`
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovingTarget : MonoBehaviour
{
[SerializeField] private Vector3 firstPosition = new Vector3(-14f, 2.5f, 17f);
[SerializeField] private Vector3 secondPosition = new Vector3(14f, 2.5f, 17f);
public float speed = 10f;
void Start()
{
transform.position = firstPosition;
}
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, secondPosition, Time.deltaTime * speed);
if(transform.position == secondPosition)
{
secondPosition = firstPosition;
}
}
}
`
As alternative you could also use Mathf.PingPong like e.g.
// By default afaik a full cycle takes 2 seconds so in order to normalize
// this to one second we will divide by this times 2 later
public float cycleDuration = 1;
private void Update ()
{
transform.position = Vector3.Lerp(firstPosition, secondPosition, Mathf.PingPong(Time.time / (cycleDuration * 2f), 1f));
}
In case your object is spawned later in the game you might want to rather always start at the first position and do
private float timer;
private void Update ()
{
transform.position = Vector3.Lerp(firstPosition, secondPosition, Mathf.PingPong(timer / (cycleDuration * 2f), 1f));
timer += Time.deltaTime;
}
I don't use Unity, but since nobody else answered....
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MovingTarget : MonoBehaviour
{
[SerializeField] private Vector3 firstPosition = new Vector3(-14f, 2.5f, 17f);
[SerializeField] private Vector3 secondPosition = new Vector3(14f, 2.5f, 17f);
private Vector3 target;
public float speed = 10f;
void Start()
{
transform.position = firstPosition;
target = secondPosition;
}
void Update()
{
transform.position = Vector3.MoveTowards(transform.position, target, Time.deltaTime * speed);
if (transform.position == firstPosition)
{
target = secondPosition;
}
else if (transform.position == secondPosition)
{
target = firstPosition;
}
}
}
I am trying to make a grappling hook more fluent but as of right now it is very choppy and does not have the right feel. It currently makes a line and pulls the player there. I have not tried anything yet because I am not even sure we're to start on fixing this. Here is all the grappling code below. `using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(SFPSC_PlayerMovement))] // PlayerMovement also requires Rigidbody
public class SFPSC_GrapplingHook : MonoBehaviour
{
public bool IsGrappling
{
get { return isGrappling; }
}
private SFPSC_PlayerMovement pm;
private Rigidbody rb;
private int segments;
private void Start()
{
segments = rope.segments;
pm = this.GetComponent<SFPSC_PlayerMovement>();
rb = this.GetComponent<Rigidbody>();
}
private bool isGrappling = false;
private void Update()
{
if (crossHairSpinningPart != null)
{
// we need 2 raycasts bc w/ 1 you can grapple through colliders which isn't good
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance, layerMask))
{
hitName = hitInfo.collider.name;
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance))
{
if (hitName != hitInfo.collider.name)
goto _else;
crossHairSpinningPart.gameObject.SetActive(true);
crossHairSpinningPart.Rotate(Vector3.forward * crossHairSpinSpeed * Time.deltaTime);
goto _out;
}
}
_else:
crossHairSpinningPart.gameObject.SetActive(false);
}
_out:
if (!isGrappling)
{
if (Input.GetKeyDown(SFPSC_KeyManager.Grapple))
Grapple();
return;
}
else
{
if (!Input.GetKey(SFPSC_KeyManager.Grapple))
UnGrapple();
GrappleUpdate();
return;
}
}
[Header("Properties")]
public float maxGrappleDistance = 100.0f;
public SFPSC_Rope rope;
public float maximumSpeed = 100.0f;
public float deceleration = 2500.0f; // This is how much the player is going to decelerate after stopped grappling
public float deceleratingTime = 1.4f; // This is the time the decelerating is going to act on the player after stopped grappling
public RectTransform crossHairSpinningPart;
public float crossHairSpinSpeed = 200.0f;
public float distanceToStop = 2.0f;
public LayerMask layerMask;
public float grappleCooldown = 1.0f;
private bool isBlocked = false;
private Transform location; // the grappled location
private RaycastHit hitInfo;
private string hitName;
public void Grapple()
{
if (isBlocked)
return;
// we need 2 raycasts bc w/ 1 you can grapple through colliders which isn't good
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance, layerMask))
{
hitName = hitInfo.collider.name;
if (Physics.Raycast(SFPSC_FPSCamera.cam.transform.position, SFPSC_FPSCamera.cam.transform.forward, out hitInfo, maxGrappleDistance))
{
if (hitName != hitInfo.collider.name)
return;
// We create a GameObject and we parent it to the grappled object.
// If we don't parent it to the object and the object moves the player is stuck only on one location instead of the moving object.
location = new GameObject().transform;//Instantiate(new GameObject(), hitInfo.point, Quaternion.identity).transform;
location.position = hitInfo.point;
location.parent = hitInfo.collider.transform;
if (decelerateTimer != 0.0f)
StopCoroutine(Decelerate());
pm.DisableMovement();
// Rope attaching
rope.segments = (int)((hitInfo.distance / maxGrappleDistance) * segments);
rope.Grapple(transform.position, hitInfo.point);
rb.useGravity = false;
isGrappling = true;
}
}
}
private Vector3 grappleForce;
public void UnGrapple()
{
if (!isGrappling)
return;
if (location != null)
Destroy(location.gameObject);
if (decelerateTimer == 0.0f)
StartCoroutine(Decelerate());
else
decelerateTimer = 0.0f;
pm.EnableMovement();
// Rope detaching
rope.UnGrapple();
Invoke("UnblockGrapple", grappleCooldown);
rb.useGravity = true;
isGrappling = false;
}
private void UnblockGrapple()
{
isBlocked = false;
}
private float decelerateTimer = 0.0f, max;
private IEnumerator Decelerate()
{
WaitForEndOfFrame wfeof = new WaitForEndOfFrame();
max = deceleratingTime * Mathf.Clamp01(targetDistance / 10.0f) * Mathf.Clamp01(rb.velocity.magnitude / 30.0f);
for (; decelerateTimer < max; decelerateTimer += Time.deltaTime)
{
rb.AddForce(-rb.velocity.normalized * deceleration * (1.0f - decelerateTimer / max) * Mathf.Clamp01(rb.velocity.sqrMagnitude / 400.0f) * Time.deltaTime, ForceMode.Acceleration);
yield return wfeof;
}
decelerateTimer = 0.0f;
}
private Vector3 dir;
private float speed = 0.0f, targetDistance;
private void GrappleUpdate()
{
if (location == null)
return;
targetDistance = Vector3.Distance(transform.position, location.position);
rope.segments = (int)((targetDistance / maxGrappleDistance) * segments);
dir = (location.position - transform.position).normalized;
rb.velocity = Vector3.Lerp(rb.velocity, dir * maximumSpeed * Mathf.Clamp01(targetDistance / (4.0f * distanceToStop)), Time.deltaTime);
// Rope updating
rope.UpdateStart(transform.position);
rope.UpdateGrapple();
}
private Vector3 ClampMag(Vector3 vec, float maxMag)
{
if (vec.sqrMagnitude > maxMag * maxMag)
vec = vec.normalized * maxMag;
return vec;
}
}
`
Try using FixedUpdate instead of Update for physics based work (basically all of your code in Update right now). Update is dependent on your computer's clock speed and refresh rate (more or less), and gets called at fairly irregular intervals, because the next update is called in the next frame, after the present frame has finished processing. FixedUpdate makes it frame-rate independent.
Also, you can cap your framerate using Application.targetFrameRate and cap it to a decent FPS.
You could also multiply your movement with Time.deltaTime for smoother movement, although this is a standard practice and yet debatable for use as a smoothing value.
I have 2 issues. (1) For some reason my grenade doesn't initialize. (2) Transform.LookAt(Player) doesn't work. I am trying to have a floating monster that will throw grenades. I know that the IEnumerator runs (I put a debug.Log) so I know that the grenade issue isn't because it doesn't run. I am unsure why the transform.Lookat doesn't work though. Thanks for the help!
Script: (Sorry if the code is bad I am a programming noob)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZKAttack_lvl3 : MonoBehaviour
{
public Transform Player;
public float MoveSpeed = 3.5f;
public float InRadius = 4.0f;
public float AttackRange = 1.0f;
private Coroutine hasCourutineRunYet;
public GameObject grenade;
public GameObject FloatingMonster;
private Animator anim;
private Rigidbody rigid;
private void Start()
{
anim = GetComponent<Animator>();
Player = GameObject.FindGameObjectsWithTag("Player")[0].transform;
rigid = GetComponent<Rigidbody>();
}
void Update()
{
transform.LookAt(Player);
float dstSqr = (Player.position - transform.position).sqrMagnitude;
bool inRadius = (dstSqr <= InRadius * InRadius);
bool inAttackRange = (dstSqr <= AttackRange * AttackRange);
anim.SetBool("inRadius", inRadius);
anim.SetBool("AttackingPlayer", inAttackRange);
if (inRadius)
{
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
}
rigid.AddForce(1, 10, 1);
if (inAttackRange)
{
if (hasCourutineRunYet == null)
{
hasCourutineRunYet = StartCoroutine(GrenadeAttack());
}
}
}
IEnumerator GrenadeAttack()
{
GameObject bulletObject = Instantiate(grenade);
bulletObject.transform.position = FloatingMonster.transform.position + FloatingMonster.transform.forward;
bulletObject.transform.forward = FloatingMonster.transform.forward;
yield return new WaitForSeconds(2.0f);
}
}
I discovered the reason for it not initializing is because of the line bulletObject.transform.forward = FloatingMonster.transform.forward; . I assume that this somehow obstructed it.
I have code in my PlayerScript that, on collision with the floor game object (which I've tagged with "FloorTag"), decrements a variable called "Lives." Lives is decrementing, so I know the collision is registering (and everything is tagged correctly). However, I also want the Player game object's position to be reset to a specific Vector3 I've declared when it collides with the floor. For some reason, though, it's not doing this. Where have I gone wrong?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class PlayerScript : MonoBehaviour
{
public int Lives;
public Text LivesText;
public int Points;
public Text PointsText;
public Text GameOverText;
public CharacterController CharController;
public float moveSpeed = 9;
public float rotSpeed = 85;
float yVelocity = 0;
public float jumpForce = 2.5f;
public float gravityModifier = 0.025f;
bool prevIsGrounded;
Vector3 StartingPlatformCoords = new Vector3 (38, 16, 38);
// Start is called before the first frame update
void Start()
{
Lives = 8;
SetLivesText();
Points = 0;
SetPointsText();
prevIsGrounded = CharController.isGrounded;
//CharController = gameObject.GetComponent<CharacterController>();
}
// Update is called once per frame
void Update()
{
// L-R Forward-Back Motion
float hAxis = Input.GetAxis("Horizontal");
float vAxis = Input.GetAxis("Vertical");
transform.Rotate(0, rotSpeed * Time.deltaTime * hAxis, 0);
Vector3 amountToMove = transform.forward * moveSpeed * Time.deltaTime * vAxis;
// Jump Motion
if (CharController.isGrounded)
{
if (!prevIsGrounded && CharController.isGrounded)
{
yVelocity = 0;
}
if (Input.GetKeyDown(KeyCode.Space))
{
yVelocity = jumpForce;
}
}
else
{
if (Input.GetKeyUp(KeyCode.Space))
{
yVelocity = 0;
}
yVelocity += Physics.gravity.y * gravityModifier;
}
amountToMove.y = yVelocity;
// Modify the y-value within this Vector3 (which contains an x, y, z, and some utility functions like distance etc.) manually
// Final Motion
CharController.Move(amountToMove);
// Update
prevIsGrounded = CharController.isGrounded;
// Camera
Vector3 camPos = transform.position + transform.forward * -10 + Vector3.up * 3;
Camera.main.transform.position = camPos;
Camera.main.transform.LookAt(transform);
//if (Input.GetKeyDown(KeyCode.Space))
//{
//yVelocity = jumpForce;
//}
//yVelocity += Physics.gravity.y * gravityModifier;
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("FloorTag"))
{
transform.position = StartingPlatformCoords;
Lives -= 1;
SetLivesText();
Debug.Log(transform.position);
}
if (other.gameObject.CompareTag("CellTag"))
{
Points += 1;
SetPointsText();
}
}
void SetLivesText()
{
LivesText.text = "Lives: " + Lives.ToString();
if (Lives <= 0)
{
GameOverText.text = "Game Over";
}
}
void SetPointsText()
{
PointsText.text = "Score: " + Points.ToString();
}
}
CharacterController can override changes made to transform.position. Simplest workaround is to disable it, then re-enable it after directly modifying transform.position:
public CharacterController CharController;
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("FloorTag"))
{
CharController.enabled = false;
transform.position = StartingPlatformCoords;
CharController.enabled = true;
Lives -= 1;
SetLivesText();
Debug.Log(transform.position);
}
if (other.gameObject.CompareTag("CellTag"))
{
Points += 1;
SetPointsText();
}
}
I'm trying to get the distance between my player, and the nearest object with the tag 'wall' however I can't seem to get it to work.
To my knowledge my code isn't working at all.
So my question is;
What am I doing wrong? Again, I want to find the distance from my player and the nearest object with the tag 'wall'. If I'm near a object with the tag 'wall' I want it to set the variable to true.(nearWall = true) then once I'm away from the object(About 10.0f) I want it back to false.(nearWall = false)
This is the code I have been working with.
using UnityEngine;
using System.Collections;
public class PlayerMotor : MonoBehaviour {
private CharacterController controller;
private Vector3 moveVector;
private float speed = 2.0f;
private float verticalVelocity = 0.0f;
private float gravity = 12.0f;
private bool nearWall;
public GameObject playerObject;
GameObject closestObject;
float distance = Mathf.Infinity;
public float distanceToWall = Mathf.Infinity;
private void Start() {
nearWall = false;
playerObject = GameObject.Find("Player");
distanceToWall = 0;
controller = GetComponent<CharacterController> ();
}
public void getNearestWall()
{
if (distance <= 10.0f) {
nearWall = true;
print ("Near wall!");
}
else
nearWall = false;
}
GameObject findNearestWall()
{
GameObject[]objectArray;
objectArray = GameObject.FindGameObjectsWithTag("wall");
Vector3 position = playerObject.transform.position;
foreach(GameObject currentObject in objectArray)
{
Vector3 distanceCheck = currentObject.transform.position - position;
float currentDistance = distanceCheck.sqrMagnitude;
if (currentDistance < distance)
{
closestObject = currentObject;
distance = currentDistance;
}
}
return closestObject;
}
private void Update()
{
findNearestWall ();
moveVector = Vector3.zero;
if (controller.isGrounded)
{
verticalVelocity = -0.5f;
}
else
{
verticalVelocity -= gravity * Time.deltaTime;
}
if (Input.GetMouseButton (0)) {
if (!nearWall) {
if (Input.mousePosition.x > Screen.width / 2)
moveVector.x = speed;
else
moveVector.x = -speed;
}
else
{
moveVector.x = transform.forward.x * speed;
transform.Rotate(new Vector3(0, -90, 0));
}
}
moveVector.y = verticalVelocity;
moveVector.z = transform.forward.z * speed;
controller.Move (moveVector * Time.deltaTime);
}
}
One thing is that you are not calling getNearestWall() method - which is actually changing the flag - anywhere.
And second why don't you just try:
currentDistance = Vector3.Distance(currentObject.transform.position, position);
When calculating distance
first of all you need to call getNearestWall(); inside the Update() method ( after findNearestWall() of course ). also what you are doing now is getting the minimal distance the player reached in the whole game. you might want to add distance = Mathf.Infinity; in top of findNearestWall() so it will something like this:
GameObject findNearestWall()
{
GameObject[] objectArray;
objectArray = GameObject.FindGameObjectsWithTag("wall");
distance = Mathf.Infinity;
Vector3 position = playerObject.transform.position;
foreach (GameObject currentObject in objectArray)
{
Vector3 distanceCheck = currentObject.transform.position - position;
float currentDistance = distanceCheck.sqrMagnitude;
if (currentDistance < distance)
{
closestObject = currentObject;
distance = currentDistance;
}
}
return closestObject;
}
now whenever you get near a wall it should print Near wall!
note:
also you are calling FindObjectsWithTag() at an Update method which might significantly drain your processing power. you might want to avoid that by declaring a private GameObject[] objectArray in the class.
and then use objectArray = GameObject.FindGameObjectsWithTag("wall"); once at Awake() or Start()