I'm trying to get an object to move every second in Unity, but it doesn't seem to work. I'm trying to make the game snake, and I'm starting off by centering the Sprite of the head, and starting it by moving it to the right every second, later adding player controls.
Any help with getting it to work?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Snake_Move : MonoBehaviour
{
private Vector2 pos;
private Vector2 moveDirection;
private float moveTimer;
private float timerSeconds;
private void Startup()
{
pos = new Vector2(5, 5);
timerSeconds = 1f;
moveTimer = timerSeconds;
moveDirection = new Vector2(1, 0);
}
private void Update()
{
moveTimer += Time.deltaTime;
if (moveTimer > timerSeconds)
{
pos += moveDirection;
moveTimer -= timerSeconds;
}
transform.position = new Vector2(pos.x, pos.y);
}
}
Well Startup is never called so all your values will keep their default values - in particular pos = Vector2.zero and moveDirection = Vector2.zero so your object will never move at all.
You probably rather wanted to call it Start in order to implement the Unity message MonoBehaviour.Start that is called automatically
on the frame when a script is enabled just before any of the Update methods are called the first time.
public class Snake_Move : MonoBehaviour
{
// These you adjust in the Inspector in Unity
// Later changes to the values here will have no effect!
[Tooltip("Time interval between steps in seconds")]
[SerializeField] private float stepInterval = 1f;
[Tooltip("Initial position")]
private Vector2 startPos = new Vector2(5, 5);
private Vector2 moveDirection;
private float moveTimer;
// What you wanted is probably the Unity message method Start
// which is called when you app starts
private void Start()
{
moveTimer = stepInterval;
moveDirection = Vector2.right;
transform.position = startPos;
}
private void Update()
{
moveTimer += Time.deltaTime;
if (moveTimer > stepInterval)
{
moveTimer -= stepInterval;
// No need to store the pos, simply only assign a new value
// to the position when needed
transform.position += moveDirection;
}
}
}
Related
I have a player in unity with the movement controlled by a rigidbody. The movement on the Z axis is kept contstant by the game to keep the player moving forward. However, this means that the rigidbody keeps speeding up so its speed at the start of the game is much slower than the speed at the end of the game. Here is my script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
public class Controller : MonoBehaviour
{
[Tooltip("Rigidbody component attached to the player")]
public Rigidbody rb;
public float forwardMax;
public float slowBy;
private float movementX;
private float movementY;
private float gravity = -9.81f;
private bool isJumping = false;
private bool isSlowing = false;
private bool isSpeeding = false;
private float speedX = 100;
private float speedY = 150000;
private float speedZ = 60;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
}
void Update()
{
// if(!controller.isGrounded)
// {
// Vector3 gravityVector = new Vector3(0.0f, gravity, 0.0f);
// rb.AddForce(gravityVector * Time.deltaTime);
// }
}
void OnCollisionEnter(Collision collision)
{
// SceneManager.LoadScene(1);
}
// Update is called once per frame
void OnMove(InputValue movementValue)
{
Vector2 movementVector = movementValue.Get<Vector2>();
movementX = movementVector.x;
movementY = movementVector.y;
}
void OnJump()
{
isJumping = true;
}
void CalculateMovement()
{
if(rb.velocity.z > 20)
{
rb.drag = 20;
}
else
{
rb.drag = 0;
}
Vector3 movement = new Vector3(movementX * speedX, 0.0f, speedZ);
if(isJumping)
{
movement.y += Mathf.Sqrt(speedY * -3.0f * gravity);
isJumping = false;
}
rb.AddForce(movement);
Debug.Log("Speed is " + rb.velocity.z);
}
void FixedUpdate()
{
CalculateMovement();
}
}
Is there a way to keep the forward velocity constant? The problem is worse when the player jumps.
First I tried clamping the forward (z-axis) vector but that had no effect. Then, I tried adding a backward vector onto the total when the forward velocity was above a certain number but this led to it speeding up and slowing down all the time. Then I tried the same thing with the drag on the rigidbody but that had the same effect.
You can use rigidbody.velocity and set it to constant value or whatever you want instead of adding force. By adding force, your character's speed increases.
Also you can use AddForce but you have to tune the force value dynamically according to the current velocity.
rigidbody velocity
How about directly setting the z value you want at the end of FixedUpdate() ?
......
void FixedUpdate()
{
CalculateMovementWithoutZMovement();
rb.velocity = new Vector3 (rb.velocity.x, rb.velocity.y, ConstantZValue);
}
I am trying to take the current position of something once when collided and im not sure how to
do that could anyone help me out please?
The problem i have is that the script is grabbing the playerLocation constantly i need it so it grabs it once it collides.
basically when my object colides with something it moves towards a diferent object but i dont want it to follow it constantly i want it to get the position of that 1 object only once it has collided.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CircleMover : MonoBehaviour
{
public float speed = 10.0f;
public Transform playerLocation;
public float redirectSpeed;
public bool isCurrentlyColliding;
Vector3 playerposition;
private Rigidbody2D rb;
private Vector2 screenBounds;
// Start is called before the first frame update
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
rb.velocity = new Vector2(-speed, 0);
screenBounds = Camera.main.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, Camera.main.transform.position.z));
}
// Update is called once per frame
void Update()
{
//if (transform.position.x < -11.6f)
//{
// Destroy(this.gameObject);
//}
if (isCurrentlyColliding)
{
transform.position = Vector2.MoveTowards(transform.position, playerposition.transform.position, redirectSpeed * Time.deltaTime);
}
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("CopyCat"))
{
playerposition = (playerLocation.transform.position);
isCurrentlyColliding = true;
}
}
}
The reason it grabs the playerLocation constantly because you are using isCurrentlyColliding which you are never making false and also using it in Update() method which calls every frame.
You can do two things (choose whichever goes well with your code) :
by making isCurrentlyColliding false inside Update() method like this:
void Update()
{
if (isCurrentlyColliding)
{
transform.position = Vector2.MoveTowards(transform.position, playerposition.transform.position, redirectSpeed * Time.deltaTime);
isCurrentlyColliding = false;
}
}
by removing isCurrentlyColliding and setting transform.position directly inside OnTriggerEnter2D() method like this:
void OnTriggerEnter2D(Collider2D other)
{
if (other.CompareTag("CopyCat"))
{
playerposition = (playerLocation.transform.position);
transform.position = Vector2.MoveTowards(transform.position, playerposition.transform.position, redirectSpeed * Time.deltaTime);
}
}
I want to move a cube using some device and periodically (every 3 seconds) print those coordinates to a file. I am not sure how to accomplish this with my code below. Does anybody have ideas as to how this can be done?
Thank you!
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
[RequireComponent(typeof(MeshCollider))]
public class UserController : MonoBehaviour {
public int speed = 20;
// Update is called once per frame
void Update()
{
// get input data from keyboard or controller
float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");
// update player position based on input
Vector3 position = transform.position;
position.x += moveHorizontal * speed * Time.deltaTime;
position.z += moveVertical * speed * Time.deltaTime;
transform.position = position;
}
void OnMouseDrag()
{
if(Input.GetMouseButton(0))
{
float distance_to_screen = Camera.main.WorldToScreenPoint(gameObject.transform.position).z;
transform.position = Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y, distance_to_screen));
}
}
}
I would suggest creating a separate script and attach it to your cube.
public class CubeTracker : MonoBehaviour
{
private bool logging = true;
void Awake()
{
StartCoroutine(LogPosition());
}
private IEnumerator LogPosition()
{
while (logging)
{
Debug.Log(transform.position);
yield return new WaitForSeconds(3f);
}
}
}
This will start a coroutine as soon as the cube is created and should log your desired result into console. If that's what you desire, you can then go ahead and replace the Debug.Log with a write-to-file implementation.
Use a global variable, and feed it inside Update() method.
for example:
private Vector3 LastCoordinate{get; set;}
and the use a periodic timer like :
private System.Threading.Timer timer;
timer = new System.Threading.Timer(GetLastCoordinate, null, 3000, 0);
private void GetLastCoordinate()
{
lock(this)
{
Vector3 lastCoordEachThreeSecs = LastCoordinate;
}
}
Okay im trying to make my object (player) to jump everything is okay until i go against a wall and keep going against (still W is down) i cant jump wen im hitting a wall if i stop walking he will be enable to jump i tried making the walls on touch to make the player to have velocity = zero but it does not work,
i tried to add rigid body to the walls and freezing them in place, trying to make them kinematic does not work too .
I wish wen i go against walls and keep walking against them to be enable to jump.
If you know how i can do that please share thanks .
Here is the move script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MoveScript : MonoBehaviour {
private float speed;
private float jumpHight;
private float straffeSpeed;
private float fallMultiplier;
private Rigidbody rig;
private Collider coll;
// Use this for initialization
private void Awake()
{
rig = GetComponent<Rigidbody>();
coll = GetComponent<Collider>();
straffeSpeed = 1.5f;
fallMultiplier = 2.5f;
speed = 10f;
jumpHight = 4f;
}
void Start () {
GroundCheck();
}
// Update is called once per frame
void Update () {
Move();
GroundCheck();
BetterFall();
}
private void Move()
{
float hAxis = Input.GetAxis("Horizontal") * straffeSpeed;
float vAxis = Input.GetAxis("Vertical");
Vector3 movement = new Vector3(hAxis, 0, vAxis) * speed * Time.deltaTime;
rig.MovePosition(transform.position + movement);
if (Input.GetKey(KeyCode.Space) && GroundCheck())
{
rig.velocity = Vector3.up * jumpHight;
}
}
private bool GroundCheck()
{
return Physics.Raycast(transform.position, -Vector3.up, coll.bounds.extents.y + 0.2f);
}
private void BetterFall()
{
if(rig.velocity.y < 0)
{
rig.velocity += Vector3.up * Physics.gravity.y * (fallMultiplier - 1) * Time.deltaTime;
}
}
if (Input.GetKeyDown(KeyCode.Space) && GroundCheck())
{
rig.velocity = Vector3.up * jumpHight;
}
I don't think you are doing this quite right. Try this:
if (Input.GetKeyDown(KeyCode.Space) && GroundCheck())
{
rig.AddForce(Vector3.up * jumpHight, ForceMode.Impulse);
}
:-)
Got stuck with camera movement in my Unity3D C# project.
What I have:
some objects on the scene
a camera, which would fly from any object's poition or from it's own current position
What I need:
smooth rotare camera to one of the object's origin
fly to the spot near the object (there is an empty, so I fly to empty's coords)
Algorithm: rotate to the object's origin, when rotation finishes, start to fly to the empty's position. while flying, look at object's origin.
The problem is that it's not smooth, the camera "jumps" at the end of the movement.
My C# code (attached to the camera):
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class testMove : MonoBehaviour {
public GameObject startObj;
public GameObject endObj;
public float speed = 1.0F;
private float startTime;
private float journeyLength;
private string endObjName;
private GameObject endObjLookAt;
void Start () {
startTime = Time.time;
if (startObj) {
} else {
startObj = this.gameObject;
}
journeyLength = Vector3.Distance(startObj.transform.position, endObj.transform.position);
endObjName = endObj.name;
endObjLookAt = GameObject.Find(endObjName + "LookAt");
}
void Update () {
if (endObj) {
float distCovered = (Time.time - startTime) * speed;
float fracJourney = distCovered / journeyLength;
tweenLook(endObjLookAt, fracJourney);
float angle = Quaternion.Angle(transform.rotation, Quaternion.LookRotation(endObjLookAt.transform.position - transform.position));
if (angle <= 0.0001) {
Debug.Log("rotation finished");
tweenPos(startObj, endObj, fracJourney);
transform.LookAt(endObjLookAt.transform.position);
}
}
}
private void tweenPos(GameObject startObj, GameObject endObj, float fracJourney) {
Vector3 newposition = Vector3.Lerp(startObj.transform.position, endObj.transform.position, fracJourney);
transform.position = newposition;
}
private void tweenLook(GameObject endObjLookAt, float fracJourney) {
Quaternion newrotation = Quaternion.LookRotation(endObjLookAt.transform.position - transform.position);
transform.rotation = Quaternion.Slerp(transform.rotation, newrotation, fracJourney);
}
}
Since what you're trying to achieve implies doing actions one after another, I'd recommend using a Coroutine:
public class testMove : MonoBehaviour
{
public Transform startObj;
public Transform endObj;
private Transform endObjLookAt;
public float rotationDuration;
public AnimationCurve rotationCurve;
public float movementDuration;
public AnimationCurve movementCurve;
private IEnumerator moveAndRotateCameraIEnumerator;
void Start()
{
// If you want to do it on start just call MoveAndRotateCamera() here, else call if from anywhere you want (a script, a game button, ...)
}
void Update()
{
if(Input.GetKeyDown(KeyCode.Space))
{
MoveAndRotateCamera();
}
}
public void MoveAndRotateCamera(Transform startTransform = null, Transform endTransform = null)
{
if(startTransform)
{
startObj = startTransform;
}
else
{
startObj = this.transform;
}
if(endTransform)
{
endObj = endTransform;
}
endObjLookAt = GameObject.Find(endObj.name + "LookAt").transform;
if(moveAndRotateCameraIEnumerator != null)
{
StopCoroutine(moveAndRotateCameraIEnumerator);
}
moveAndRotateCameraIEnumerator = MoveAndRotateCameraCoroutine();
StartCoroutine(moveAndRotateCameraIEnumerator);
}
private IEnumerator MoveAndRotateCameraCoroutine()
{
//ROTATION
Vector3 startEulerAngles = transform.eulerAngles;
transform.LookAt(endObjLookAt);
Vector3 deltaEulerAngles = new Vector3(Mathf.DeltaAngle(startEulerAngles.x, transform.eulerAngles.x), Mathf.DeltaAngle(startEulerAngles.y, transform.eulerAngles.y), Mathf.DeltaAngle(startEulerAngles.z, transform.eulerAngles.z));
Debug.Log("Starting rotation...");
float timer = 0.0f;
while(timer < rotationDuration)
{
timer += Time.deltaTime;
transform.eulerAngles = startEulerAngles + deltaEulerAngles * rotationCurve.Evaluate(timer / rotationDuration);
yield return new WaitForEndOfFrame();
}
transform.eulerAngles = startEulerAngles + deltaEulerAngles;
Debug.Log("Rotation done!");
//----
//MOVEMENT
Vector3 startPosition = transform.position;
Debug.Log("Starting movement...");
timer = 0.0f;
while(timer < movementDuration)
{
timer += Time.deltaTime;
transform.position = Vector3.Lerp(startPosition, endObj.position, movementCurve.Evaluate(timer / movementDuration));
transform.LookAt(endObjLookAt);
yield return new WaitForEndOfFrame();
}
transform.position = endObj.position;
transform.LookAt(endObjLookAt);
Debug.Log("Movement done!");
//----
}
}
Please note a few things here:
Changed your GameObject variables to Transform ones because you always used them to get to the Transform component so you can use it directly instead
Added a time notion instead of a speed notion for rotation and movement (you can also use speed instead: simply multiply the Time.deltaTime by your speed factor)
Using AnimationCurve allows you to adjust the way the rotation/movement will occur: simply set the curve in Inspector (curve must start at (0, 0) and end at (1, 1))
Hope this helps,