Problem with calling a function only one time in unity - c#

i'm fairly new to programming, and i have a problem with this code for my unity game, basically what happen is that the first time i try to call SelectGravity() it do it 2 or 3 times, after that it seems to work correctly, i can't figure out why.
IsRotating = false is called in another script and i'm using visual studio 2019 for coding, if this can help.
void Update()
{
Rotation = Input.GetAxisRaw("RotatoWorld");
if (Rotation != 0 && !IsRotating)
{
IsRotating = true;
SelectGravity();
}
Physics2D.gravity = new Vector2(XGravity, YGravity);
}
For those who asked this is the script in which i set IsRotating false
public IEnumerator Rotate90()
{
if(changeGravity.Rotation > 0.1)
{
Direction = 90;
}
else if(changeGravity.Rotation < -0.1)
{
Direction = -90;
}
float timeElapsed = 0;
Quaternion startRotation = transform.rotation;
Quaternion targetRotation = transform.rotation * Quaternion.Euler(0, 0, Direction);
while (timeElapsed < lerpDuration)
{
transform.rotation = Quaternion.Slerp(startRotation, targetRotation, timeElapsed / lerpDuration);
timeElapsed += Time.deltaTime;
yield return null;
}
transform.rotation = targetRotation;
StartCoroutine(CameraShake());
changeGravity.IsRotating = false;
}
and i've declared it like this
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ChangeGravity : MonoBehaviour
{
CameraRotation cameraRotation;
PlayerController playerController;
private float XGravity;
private float YGravity;
public float Side;
public float Rotation;
public bool IsRotating;
// Start is called before the first frame update
void Start()
{
cameraRotation = GameObject.FindGameObjectWithTag("MainCamera").GetComponent<CameraRotation>();
playerController = GameObject.FindGameObjectWithTag("Player").GetComponent<PlayerController>();
Side = 0;
YGravity = -9.81f;
XGravity = 0f;
IsRotating = false;
}
Other than this i don't call this function or modify this variable anywhere.

Check the IsRotating boolean. It should modifying somewhere else or bool decleration function is not correct.

I found the problem was that the script was attached to more than one object, consequentially void update() were called two times per frame.

Related

transform.position not working in Unity 3d

I'm really new to Unity 3d and I'm trying to make a respawn with my character. It seems that the answer is really easy but I cannot see why my code is not working. If this is a duplicate, let me know.
public Vector3 PointSpawn;
void Start()
{
PointSpawn = gameObject.transform.position;
}
void Update()
{
if (gameObject.transform.position.y < 10)
{
gameObject.transform.position = PointSpawn; // This doesn't work
// gameObject.transform.LookAt(PointSpawn); ---> This DOES work ok
}
}
Parallel Script
public float HorizontalMove;
public float VerticalMove;
private Vector3 playerInput;
public CharacterController player;
public float MoveSpeed;
private Vector3 movePlayer;
public float gravity = 9.8f;
public float fallVelocity;
public float JumpForce;
public bool DoubleJump = false;
public Camera mainCamera;
private Vector3 camForward;
private Vector3 camRight;
void Start()
{
player = GetComponent<CharacterController>();
}
void Update()
{
HorizontalMove = Input.GetAxis("Horizontal");
VerticalMove = Input.GetAxis("Vertical");
playerInput = new Vector3(HorizontalMove, 0, VerticalMove);
playerInput = Vector3.ClampMagnitude(playerInput, 1);
CamDirection();
movePlayer = playerInput.x * camRight + playerInput.z * camForward;
movePlayer = movePlayer * MoveSpeed;
player.transform.LookAt(player.transform.position + movePlayer);
setGravity();
PlayerSkills();
player.Move(movePlayer * Time.deltaTime );
}
void CamDirection()
{
camForward = mainCamera.transform.forward;
camRight = mainCamera.transform.right;
camForward.y = 0;
camRight.y = 0;
camForward = camForward.normalized;
camRight = camRight.normalized;
}
void PlayerSkills()
{
if (player.isGrounded && Input.GetButtonDown("Jump"))
{
fallVelocity = JumpForce;
movePlayer.y = fallVelocity;
DoubleJump = true;
}
else if (player.isGrounded == false && Input.GetButtonDown("Jump") && DoubleJump == true)
{
fallVelocity = JumpForce *2;
movePlayer.y = fallVelocity;
DoubleJump = false;
}
}
void setGravity()
{
if (player.isGrounded)
{
fallVelocity = -gravity * Time.deltaTime;
movePlayer.y = fallVelocity;
}
else
{
fallVelocity -= gravity * Time.deltaTime;
movePlayer.y = fallVelocity;
}
}
Thanks in advance!
Just so the answer to the question is not in the comments:
The original problem is that the assignment gameObject.transform.position = PointSpawn appeared to do nothing. As the line is written properly, the position of this gameObject, must have been getting overwritten elsewhere.
With the addition of OP's movement script, the position of the player was getting overwritten in the movement's Update function. As the other assignment was being done in Update, the call order was not guaranteed to work as intended. The fix is either to assure that the movement Update is run not the frame of the new position assignment or to move the conditional and the assignment to a function that always runs after Update regardless of script execution order, LateUpdate.

2d sprite goes too fast with transform.translate in C# script (unity)

Sup. My sprite goes too fast when I press the C button. It's a wolf that will lunge as an attack. But it just goes from one spot to the next, and I got the idea that I'm simply using the wrong kind of code entirely. I'm guessing it has to do more with Rigidbody2D = new Vector2.... but I don't know where to go from there. Here's what I'm working with currently.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class tulMoveMount : MonoBehaviour {
private Animator anim;
private Rigidbody2D rb;
private bool goRight = true;
private bool jump = false;
private bool idle = true;
public float lungeDistance;
public float lungeSpeed;
public float lungeHeight;
void Start ()
{
anim = GetComponent<Animator>();
rb = GetComponent<Rigidbody2D>();
}
void Update ()
{
HandleCommands ();
}
void HandleCommands()
{
if (!jump && goRight && Input.GetKeyDown (KeyCode.C)) {
idle = false;
jump = true;
anim.SetTrigger ("jump");
rb = transform.Translate (lungeSpeed + lungeDistance, lungeHeight, 0); // HERE
idle = true;
jump = false;
anim.SetTrigger ("idle");
}
if (!jump && !goRight && Input.GetKeyDown (KeyCode.C)) {
idle = false;
jump = true;
anim.SetTrigger ("jump");
rb = transform.Translate (lungeSpeed + -lungeDistance, lungeHeight, 0); // HERE
idle = true;
jump = false;
anim.SetTrigger ("idle");
}
}
}
Multiplying the translation by Time.DeltaTime will smooth the movement over many frames, and you will then need to tweak only the lungeSpeed to get the speed you want.
rb = transform.Translate ((lungeSpeed + lungeDistance, lungeHeight, 0)*Time.deltaTime);
To get a smooth translation from one point to another you can use Lerp inside a Corouting.
In Lerp the first parameter is the start position and the second the targe. The third parameter is a float between 0 and 1. If it's 0, you get the first parameter in Lerp. If it's 1, you get the second. If 0.5 a middle point between both and so on...
So what you need to do is to start a courutine, which will be independent of the fps rate, and will move your GameObject in a constant speed defined by the distance between start-target and the time you want it takes to move from one to the other.
public class WolfMovement : MonoBehaviour {
Vector3 start;
Vector3 target;
float lungeSpeed = .8f;
float lungeDistance = 5;
private IEnumerator coroutine;
void Update () {
if(Input.GetKeyDown(KeyCode.M) )
{
start = transform.position;
target = new Vector3(transform.position.x + lungeDistance,transform.position.y , transform.position.z);
coroutine = MoveObject(start,target,lungeSpeed);
StartCoroutine(coroutine);
}
}
IEnumerator MoveObject (Vector3 start, Vector3 target, float speed){
float i = 0.0f;
float rate = 1.0f/speed;
while (i < 1.0) {
i += Time.deltaTime * rate;
transform.position = Vector3.Lerp(start, target, i);
yield return null;
}
}
}

Unity 2D how to make instantiated object fly to some other object

So I am trying to make something like a machine gun, and I can not make Rigidbody.AddForce() work like I want. I want instantiated bullets to fly exactly to the direction of the player, but it does not always work correctly:
And here is my code:
using UnityEngine;
using System.Collections;
public class Laser : MonoBehaviour {
public Transform target;
public GameObject ammo;
public int bulletsPerSec = 10;
public float shootPauseDuration = 3.0f;
public float force = 5.0f;
int bullets = 0;
bool pause = false;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
TrackPlayer();
}
void TrackPlayer()
{
float AngleRad = Mathf.Atan2(target.position.y - transform.position.y,
target.position.x - transform.position.x);
float AngleDeg = 180 / Mathf.PI * AngleRad;
transform.rotation = Quaternion.Euler(0, 0, AngleDeg);
Debug.Log(transform.rotation);
Shoot();
}
void Shoot()
{
if(bullets < bulletsPerSec)
{
bullets++;
GameObject bullet = Instantiate(ammo, transform.position,
transform.rotation) as GameObject;
bullet.GetComponent<Rigidbody2D>().AddForce(
transform.rotation * transform.up * force,
ForceMode2D.Impulse);
Destroy(bullet, 3.0f);
}
else if(pause==false)
{
pause = true;
StartCoroutine("ShootPause");
}
}
IEnumerator ShootPause()
{
yield return new WaitForSeconds(shootPauseDuration);
bullets = 0;
pause = false;
}
}
why did you do
// Quaternion? // * Vector3?
transform.rotation * transform.up * force
shouldn't it be...
transform.eulerAngles.normalized * force
other solution which will work
(target.position - transform.position).normalized * force

Unity C# Animator Transitions

I'm trying to get my enemies run animation to play when he is moving, and switch back to idle when he has stopped. However my current code doesn't seem to be doing this and instead my enemy remains in the idle state constantly. I have checked that my variables are being set but they just don't seem to be getting filtered through to my animator to make the transitions. I also have an error which doesn't seem to stop the game from playing but pops up in the console. The error is Controller 'Pirate': Transition " in state 'Idle_Pirate' uses parameter 'walking' which is not compatible with condition type. I assume this is the culprit but after trying a few different suggestions from googling I am struggling to find a solution. This is the code from the script attached to my enemy. Apologies if it is a little crude I am still learning. Any help is greatly appreciated.
using UnityEngine;
using System.Collections;
public class AI : MonoBehaviour {
public float walkSpeed = 2.0f;
public float wallLeft = 0.0f;
public float wallRight = 2.0f;
float walkingDirection = 1.0f;
Vector3 walkAmount;
float timeCheck = 0.0f;
float walkCheck = 0.0f;
public float maxSpeed = 5f;
bool facingRight = true;
bool idle = true;
Animator anim;
// Use this for initialization
void Start () {
anim = GetComponent<Animator>();
}
// Update is called once per frame
void FixedUpdate () {
}
void Update () {
if (timeCheck >= 2.0f) {
walkAmount.x = walkingDirection * walkSpeed * Time.deltaTime;
if (walkingDirection > 0.0f && transform.position.x >= wallRight) {
walkingDirection = -1.0f;
Flip ();
} else if (walkingDirection < 0.0f && transform.position.x <= wallLeft) {
walkingDirection = 1.0f;
Flip ();
}
walkCheck = walkCheck + Time.deltaTime;
idle = false;
}
if (walkCheck >= 2.0f) {
idle = true;
walkAmount.x = 0;
timeCheck = 0.0f;
walkCheck = 0.0f;
}
timeCheck = timeCheck + Time.deltaTime;
transform.Translate(walkAmount);
anim.SetBool ("walking", idle);
}
void Flip () {
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
Managed to figure it out myself anyway, turns out I was using my animation in my animator instead of my sprites, must of dragged the wrong thing at some point. Thanks to those who took the time to read anyway.

Simple resetting timer method to help lerp between a materials alpha values 1 - 0

I am working on a 'Shield' script (sci-fi, not RPG, imagine a spaceship) that only becomes active once a collision has happened. I'm trying to achieve this by having the alpha value of the material be set to 0f - then once 'hit' going straight up to 1f and then lerping back down to 0f. Rinse, repeat. However i'm having a problem coming up with the timer element of the lerp. The timers i've looked at tend to involve the update method or do not allow me to use it in the lerp. This is my code so far:
using UnityEngine;
using System.Collections;
public class Shield : MonoBehaviour {
public int shieldHealth;
private SpriteRenderer sRend;
private float alpha = 0f;
void Start () {
shieldHealth = 10;
sRend = GetComponentInChildren<SpriteRenderer>();
}
void OnCollisionEnter2D (Collision2D other) {
shieldHealth --;
LerpAlphaOfShield ();
if(shieldHealth <= 0) {
Destroy(this.gameObject);
}
}
void LerpAlphaOfShield () {
float lerp = Mathf.SmoothStep(1.0f, 0.0f, /*missing timer*/);
alpha = Mathf.Lerp(0.0f, 1.0f, lerp);
sRend.material.color = new Color(1, 1, 1, alpha);
}
}
Now i've thought that the SmoothStep part may be unnecessary once I have a timer, however this part I found in another question that was originally a PingPong that allowed the alpha values to go back and forth: I was trying to get it to do it just once then, obviously, reset with a timer.
Thanks in advance for any advice!
SOLUTION
I finally came up with this to reset and trigger again every hit and turn the alpha values of the shield from 1 - 0 in 1 second. If anyone thinks this code that I have could be improved please let me know, I would be very interested!
using UnityEngine;
using System.Collections;
public class Shield : MonoBehaviour {
public int shieldHealth;
private SpriteRenderer sRend;
private float alpha = 0f;
private bool hasCollided = false;
private float timer = 1f;
void Start () {
shieldHealth = 10;
sRend = GetComponentInChildren<SpriteRenderer>();
}
void Update () {
timer -= Time.deltaTime;
if(timer >= 0.001) {
alpha = Mathf.Lerp(0.0f, 1.0f, timer);
sRend.material.color = new Color(1, 1, 1, alpha);
}
if (timer <= 0) {
hasCollided = false;
}
}
void OnCollisionEnter2D (Collision2D other) {
shieldHealth --;
hasCollided = true;
timer = 1f;
if(shieldHealth <= 0) {
Destroy(this.gameObject);
}
}
}
A possible solution is to do this:
public float lerpSpeed = 5f;
float currAlpha;
float goal = 0f;
void Update()
{
currAlpha = Mathf.Lerp(currAlpha, goal, lerpSpeed * Time.deltaTime;
sRend.material.color = new Color(1f, 1f, 1f, alpha);
if(1f - currAlpha > .001f)
{
goal = 0f;
}
}
And then in the OnCollisionEnter2D function set goal = 1f;
lerpSpeed is a variable you can play with to change how fast it lerps.

Categories