Why does Unity crash when I move a sprite horizontally? - c#

I just started Unity and I was making a 2D game of a player (sprite) that shoots an arrow when I click a specific button. The player moves vertically and the arrow moves horizontally. The player moves fine but, when I click to shoot the arrow, Unity crashes and I have to close it from Task Manager.
The code shows 0 errors and everything else works fine except for Unity.
I don't know where the problem is so, I'll show the whole code; the function that shoots the arrows is called shootingsysytem.
void Start()
{
health = 100;
playerspeed = 2;
shotspeed = 3;
bulletcount = 3;
playerpos();
if (delay <= 0)
{
delay = 0;
}
stopbullets();
}
// Update is called once per frame
void Update()
{
playermouvement();
shootingsystem();
playerpos();
delay -= Time.deltaTime;
}
public void playermouvement()// works
{
if (Input.GetKey("z"))
{
player[0].transform.Translate(Vector2.up * Time.deltaTime * playerspeed);
}
if (Input.GetKey("s"))
{
player[0].transform.Translate(Vector2.down * Time.deltaTime * playerspeed);
}
}// works
public void shootingsystem() // this function shoots the arrows.........
{
if (Input.GetKey("k"))
{
if (bulletcount == 3 & delay <= 0.0f)
{
bullet3shot = true;
while (bullet3shot)
{
player[3].transform.Translate(Vector2.left * Time.deltaTime * shotspeed);
}
if (delay <= 0.0f)
{
bulletcount--;
delay = 1;
}
}
else if (bulletcount == 2 & delay <= 0.0f)
{
bullet2shot = true;
while (bullet2shot)
{
player[2].transform.position += goingside * Time.deltaTime;
}
if (delay <= 0.0f)
{
bulletcount--;
delay = 1;
}
}
else if (bulletcount == 1 & delay <= 0.0f)
{
bullet1shot = true;
while (bullet1shot)
{
player[1].transform.Translate(Vector2.left * Time.deltaTime * shotspeed);
}
if (delay <= 0.0f)
{
bulletcount--;
bulletcount = 3; // remove later
delay = 1;
}
}
}
}
public void playerpos()//works
{
playerposition = player[0].transform.position;
if (!bullet1shot)
{
player[1].transform.position = playerposition;
}
if (!bullet2shot)
{
player[2].transform.position = playerposition;
}
if (!bullet3shot)
{
player[3].transform.position = playerposition;
}
}//works
private void stopbullets()
{
if (player[1].transform.position.x <= -13) //stop first bullet
{
bullet1shot = false;
}
if (player[2].transform.position.x <= -13) //stop second bullet
{
bullet2shot = false;
}
if (player[3].transform.position.x <= -13) //stop third bullet
{
bullet3shot = false;
}
}

Its because you have an infinite loop.
bullet1shot = true;
while (bullet1shot)
{
player[1].transform.Translate(Vector2.left * Time.deltaTime * shotspeed);
}

Related

WaitForSecondsRealtime not working as expected

So decided to give game dev a try, picked up unity,Now I decided to create a simple ping pong game.
My game has Bat.cs class, ball.cs, and GameHandler.cs.
The GameHandler.cs initializes the batRight, batLeft, ball using the Bat.cs, Ball.cs class and prefabs, it also keeps track of if someone scores then starts a serve by stopping the rally:
public class GameHandler : MonoBehaviour
{
public Bat bat;
public Ball ball;
public Score score;
public static Vector2 bottomLeft;
public static Vector2 topRight;
public static bool rallyOn = false;
public static bool isServingLeft = true;
public static bool isServingRight = false;
public static bool isTwoPlayers = true;
static Bat batRight;
static Bat batLeft;
public static Ball ball1;
static Score scoreLeft;
static Score scoreRight;
// Start is called before the first frame update
void Start()
{
//Convert screens pixels coordinate into games coordinate
bottomLeft = Camera.main.ScreenToWorldPoint(new Vector2(0, 0));
topRight = Camera.main.ScreenToWorldPoint(new Vector2(Screen.width, Screen.height));
ball1 = Instantiate(ball) as Ball;
//Debug.Log("GameHandler.Start");
batRight = Instantiate(bat) as Bat;
batRight.Init(true);
batLeft = Instantiate(bat) as Bat;
batLeft.Init(false);
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
//Instatiate scores
scoreLeft = Instantiate(score, new Vector2(-2, -4), Quaternion.identity) as Score;
scoreRight = Instantiate(score, new Vector2(2, -4), Quaternion.identity) as Score;
}
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
if (GameHandler.rallyOn)
{
StopCoroutine(batRight.serveAi());
}
}
}
}
public static void increaseScoreByOne(bool isRight)
{
rallyOn = false;
if (isRight)
{
scoreRight.increaseScore();
isServingRight = true;
}
else
{
scoreLeft.increaseScore();
isServingLeft = true;
}
}
}
The ball.cs listens to the static GameHandler.rallyOn and starts moving the ball accordingly, it also changes direction of the ball if it hits a vertical wall or the bat:
public class Ball : MonoBehaviour
{
[SerializeField]
float speed;
float radius;
public Vector2 direction;
public Vector3 ballPosition;
// Start is called before the first frame update
void Start()
{
direction = Vector2.one.normalized; // direction is (1, 1) normalized
//Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
radius = transform.localScale.x / 2;
}
// Update is called once per frame
void Update()
{
ballPosition = transform.position;
if (GameHandler.rallyOn)
{
startRally();
}
}
void startRally()
{
transform.Translate(direction * speed * Time.deltaTime);
Debug.Log("direction * speed * Time.deltaTime:" + direction * speed * Time.deltaTime);
if ((transform.position.y + radius) > GameHandler.topRight.y && direction.y > 0)
{
direction.y = -direction.y;
}
if ((transform.position.y + radius) < GameHandler.bottomLeft.y && direction.y < 0)
{
direction.y = -direction.y;
}
if ((transform.position.x + radius) > GameHandler.topRight.x && direction.x > 0)
{
// Left player scores
GameHandler.increaseScoreByOne(false);
//For no, just freeza the script
// Time.timeScale = 0;
//enabled = false;
}
if ((transform.position.x - radius) < GameHandler.bottomLeft.x && direction.x < 0)
{
// right player scores
GameHandler.increaseScoreByOne(true);
}
}
void OnTriggerEnter2D(Collider2D collision)
{
if(collision.tag == "Bat")
{
if (collision.GetComponent<Bat>().isRight && direction.x > 0)
{
direction.x = -direction.x;
}
if (!collision.GetComponent<Bat>().isRight && direction.x < 0)
{
direction.x = -direction.x;
}
}
}
public float getRadius()
{
return radius;
}
}
The bat.cs initiazes the two paddles, and either listens to user input if its 2 players or listens to player and use AI if it is player vs CPU.:
public class Bat : MonoBehaviour
{
float height;
[SerializeField] // this make this appear on editor without making this field public
float speed;
string input;
public bool isRight;
string PLAYER1_INPUT = "PaddleLeft";
string PLAYER2_INPUT = "PaddleRight";
// Start is called before the first frame update
void Start()
{
height = transform.localScale.y;
}
// Update is called once per frame
void Update()
{
if (GameHandler.isTwoPlayers)
{
if (isRight)
{
movePaddleonUserInput(PLAYER2_INPUT);
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
else
{
if (isRight)
{
movePaddleAi();
}
else
{
movePaddleonUserInput(PLAYER1_INPUT);
}
}
}
void movePaddleAi()
{
if (isRight && GameHandler.ball1.direction.x > 0 && GameHandler.ball1.ballPosition.x > 0)
{
//transform.Translate(direction * speed * Time.deltaTime);
if ((transform.position.y) > GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y < 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
if ((transform.position.y) < GameHandler.ball1.ballPosition.y && GameHandler.ball1.direction.y > 0)
{
transform.Translate(GameHandler.ball1.direction * speed * Time.deltaTime * Vector2.up);
}
}
}
void movePaddleonUserInput(string input)
{
// move = (-1 -> 1) * speed * timeDelta(this keep move framerate independent)
float move = Input.GetAxis(input) * speed * Time.deltaTime;
//Debug.Log((transform.position.y + height / 2) + " > "+ GameHandler.topRight.y+ "&&" + move +" > 0");
//Restrict paddle movement to to the screen
// (top edge of paddle > Screen top and we are moving up)
if ((transform.position.y + height / 2) > GameHandler.topRight.y && move > 0)
{
move = 0;
}
// (bottom edge of paddle < Screen top and we are moving down)
if ((transform.position.y - height / 2) < GameHandler.bottomLeft.y && move < 0)
{
move = 0;
}
transform.Translate(move * Vector2.up);
}
public void Init(bool isRightPaddle)
{
isRight = isRightPaddle;
Vector2 pos;
if (isRightPaddle)
{
isRight = isRightPaddle;
pos = new Vector2(GameHandler.topRight.x, 0);
// offset since center is the anchor
pos -= Vector2.right * transform.localScale.x;
input = "PaddleRight";
}
else
{
pos = new Vector2(GameHandler.bottomLeft.x, 0);
// offset since center is the anchor
pos += Vector2.right * transform.localScale.x;
input = "PaddleLeft";
}
transform.name = input;
transform.position = pos;
}
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
}
Now I also have score.cs and mainMenu scene , but no need to include that for this question, What I am struggling with now is the AI not stopping after it scores a point, I want the AI paddle to stop for a few seconds before it serves.
As you can see in the code, I added a yield return new WaitForSecondsRealtime(2f);
public IEnumerator serveAi()
{
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
GameHandler.isServingRight = false;
}
But this only cause the paddle to wait for the first time it scores , and then if it scores again in quick interval, it doesn't wait at all.
Not sure what I doing wrong here, thanks for your time.
The more plausible explanation to me would be that GameHandler.rallyOn and isServing* aren't all being reset to the correct values to prevent the serve from occurring before the coroutine even begins, or another check is needed somewhere to prevent a serve from occurring if all of the correct booleans aren't set. Try placing appropriate breakpoints and stepping through in a debugger.
You'd probably be better off using WaitForSeconds rather than WaitForSecondsRealtime, by the way, at least if there's a chance you might want to allow the game to be paused in the future.
Realized that the coroutine is called multiple times even before its finished due do it being called from update function in GameHandler.cs. Needed a way to check if the co-routine is already running and not start a new one from update if so, used the Game.isServing variable to do so:
public IEnumerator serveAi()
{
GameHandler.isServingRight = false; // coroutine started , no need to start new one
yield return new WaitForSecondsRealtime (2f);
GameHandler.rallyOn = true;
}
And my update in GameHandler is already checking for that variable before starting the coroutine:
private void Update()
{
if (isServingLeft)
{
ball1.transform.position = new Vector3(batLeft.transform.position.x + ball1.getRadius() * 2, batLeft.transform.position.y);
if (Input.GetKey(KeyCode.LeftControl))
{
rallyOn = true;
isServingLeft = false;
}
}
if (isServingRight)
{
ball1.transform.position = new Vector3(batRight.transform.position.x - ball1.getRadius() * 2, batRight.transform.position.y);
if (isTwoPlayers && Input.GetKey(KeyCode.RightControl))
{
rallyOn = true;
isServingRight = false;
}
else
{
StartCoroutine(batRight.serveAi());
}
}
}

How to fix with a few taps?

I have a character rotation, it is based on this. There is a joystick. If you put your finger first on the rotation of the character, and then on the joystick - everything is fine. But if at first on the joystick, and after trying to turn, nothing will happen! Help. A few days can not decide
void Start()
{
mContr = GameObject.FindGameObjectWithTag("Joystick").GetComponent<MobileController>();
}
void Update()
{
if(xp > 0)
{
deadStatus = false;
ch_animator.SetBool("dead", false);
}
if(xp <= 0)
{ if(deadStatus == false)
{
menu.gameObject.SetActive(false);
ch_animator.SetBool("Run", false);
ch_animator.SetBool("Walk", false);
ch_animator.SetBool("right", false);
ch_animator.SetBool("left", false);
ch_animator.SetBool("dead", true);
dead.gameObject.SetActive(true);
if(GameObject.Find("selectLvl"))
{
GameObject.Find("selectLvl").SetActive(false);
}
if(GameObject.Find("settings"))
{
GameObject.Find("settings").SetActive(false);
}
deadStatus = true;
}
}
if(eat > 10)
{
if(xp>0&&xp!=100) {
xp += Time.deltaTime * 1f;
eat -= Time.deltaTime * 0.5f;
}
speedMove = 3;
} else {
speedMove = 1;
if(eat < 1 ) {
xp -= Time.deltaTime * 0.06f;
}
}
if(xp.ToString() != hpText.text) {
hpText.text = Math.Round(xp).ToString();
}
if(eat.ToString() != eatText.text)
{
eatText.text = Math.Round(eat).ToString();
}
if(star.ToString() != starText.text)
{
starText.text = star.ToString();
}
if(gun.ToString() != gunText.text)
{
gunText.text = gun.ToString();
}
int k = 1;
while(Input.touchCount > k)
{
Vector2 deltaposition = Vector2.zero;
if(Input.GetTouch(k).position.x > Screen.width / 2 - 100)
{
if(k == 0)
deltaposition = Input.GetTouch(k).deltaPosition;
deltaposition.x /= Screen.dpi;
if(deltaposition.x != 0)
{
float speedX = 3 * deltaposition.x;
player.transform.Rotate(Vector3.up * speedX);
}
}
k++;
}
CharacterMove();
GameGravity();
}
Jostic code
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
public class MobileController: MonoBehaviour, IDragHandler, IPointerUpHandler, IPointerDownHandler
{
private Image jostickBG;
[SerializeField]
private Image jostick;
public Vector2 inputVector;
private void Start()
{
jostickBG = GetComponent<Image>();
jostick = transform.GetChild(0).GetComponent<Image>();
}
public virtual void OnPointerDown(PointerEventData ped)
{
}
public virtual void OnPointerUp(PointerEventData ped)
{
inputVector = Vector2.zero;
jostick.rectTransform.anchoredPosition = Vector2.zero;
}
public virtual void OnDrag(PointerEventData ped)
{
Vector2 pos;
if(RectTransformUtility.ScreenPointToLocalPointInRectangle(jostickBG.rectTransform, ped.position, ped.pressEventCamera, out pos))
{
pos.x = (pos.x / jostickBG.rectTransform.sizeDelta.x);
pos.y = (pos.y / jostickBG.rectTransform.sizeDelta.y);
inputVector = new Vector2(pos.x * 2 - 0, pos.y * 2 - 0);
inputVector = (inputVector.magnitude > 1.0f) ? inputVector.normalized : inputVector;
jostick.rectTransform.anchoredPosition = new Vector2(inputVector.x * (jostickBG.rectTransform.sizeDelta.x / 2), inputVector.y * (jostickBG.rectTransform.sizeDelta.y / 2));
}
}
public float Horizontal()
{
return inputVector.x;
}
public float Vertical()
{
return inputVector.y;
}
}
the problem is coming from the while loop:
your logic is only for k=0 on rotation player and k=1 for joy, and you begin to enter in the while loop with the value k=1, the test if is always false if for this value its the position of rotation player
if(Input.GetTouch(k).position.x > Screen.width / 2 - 100)
i suggest you to refactor your code like that:
when you have 2 touches k=0 and k=1, find the right action for each touches.
i dont understant why you dont enter in the while loop with k=0?

Ai spins all the time when collision occurs

Have a simple AI thats follows the player when in range and randomly moves the ai around when it's not in the player range. When the AI hits a wall and is out of the players range it starts to spin all the time. Can't work out why it keeps doing so.
I may be missing a simple thing...
Many thanks for any help.
void Update()
{
Target = GameObject.FindGameObjectWithTag("Player");
if (Vector3.Distance(Target.transform.position, transform.position) < 25)
{
followPlayer();
}
else
{
randomMovement();
}
}
public void followPlayer()
{
if (Vector3.Distance(transform.position, Target.transform.position) >= MinDist)
{
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
transform.LookAt(Target.transform);
if (Vector3.Distance(transform.position, Target.transform.position) <= MaxDist)
{
}
}
else
{
}
}
public void randomMovement()
{
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
transform.Rotate(RandomDirection * Time.deltaTime * 10.0f);
}
void OnCollisionEnter(Collision col)
{
bool hasTurned = false;
if (col.transform.gameObject.name != "Terrain")
{
if(hasTurned == false)
{
RandomDirection = new Vector3(0, Mathf.Sin(TimeBetween) * (RotationRange / 2) + OriginalDirection, 0);
randomMovement();
hasTurned = true;
}
else
{
randomMovement();
hasTurned = false;
}
Debug.Log("Hit");
}
The reason it is continuously spinning is because you are continuously calling randomMovement() in your Update() which continously applies a rotation to your object with Rotate(). It sounds like what you are instead trying to do is have the object wander aimlessly every few seconds. You could do this by implementing on timer on your randomMovement() so that every few seconds, it generates a new rotation(similar to what you have in the onCollision). Example below.
float t = 0;
public void randomMovement()
{
transform.position += transform.forward * MoveSpeed * Time.deltaTime;
t += Time.deltaTime;
if (t > 3f) // set to a new rotation every 3 seconds.
{
t = 0; // reset timer
RandomDirection = new Vector3(0, Random.Range(0f, 360f), 0); // turn towards random direction
transform.Rotate(RandomDirection);
}
}

Can't get my player to rotate back to 0,0,0 when respawning

I am making a basketball game where you shoot then the ball is positioned back into your hands after a timer runs out and you are sent back to your default position to shoot again. I can't get the player to rotate back to 0,0,0 though. any advice would be greatly appreciated.(This is my first game and i'm kinda winging it so i'm sure the rest of my code that works is still horrible, its a learning experience so any constructive criticism is welcome.)
My code...
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Player : MonoBehaviour {
public Ball ball;
public GameObject playerCamera;
public float ballDistance = 2f;
public float ballThrowingForce = 5f;
public float powerTimer = 0f;
public bool holdingBall = true;
public Player player;
public float resetTimer = 5f;
// Use this for initialization
void Start () {
ball.GetComponent<Rigidbody> ().useGravity = false;
}
// Update is called once per frame
void Update ()
{
if (holdingBall) {
{
ball.transform.position = playerCamera.transform.position + playerCamera.transform.forward * ballDistance;
}
if (Input.GetMouseButton (0)) {
if (powerTimer == 10) {
powerTimer = 10;
} else if (powerTimer < 10) {
powerTimer = powerTimer + Time.deltaTime;
ballThrowingForce = ballThrowingForce + 2 * powerTimer;
}
}
}
if (holdingBall) {
if (Input.GetMouseButtonUp (0)) {
holdingBall = false;
ball.GetComponent<Rigidbody> ().useGravity = true;
ball.GetComponent<Rigidbody> ().AddForce (playerCamera.transform.position + playerCamera.transform.forward * ballThrowingForce);
}
}
if (player.holdingBall == false) {
resetTimer -= Time.deltaTime;
if (resetTimer <= 0) {
player.transform.position = new Vector3 (-0.2427547f, 2.6f, -2.357f);
// player roation to 0,0,0 here
holdingBall = true;
ball.GetComponent<Rigidbody> ().useGravity = false;
powerTimer = 0;
ballThrowingForce = 400;
resetTimer = 5;
}
if (Input.GetKeyDown (KeyCode.Return)) {
resetTimer = 0;
}
}
}
}
I think player.transform.rotation = Quaternion.identity should work.
Let's take a look at that :
if (Input.GetMouseButton (0)) {
if (powerTimer == 10) {
powerTimer = 10;
} else if (powerTimer < 10) {
powerTimer = powerTimer + Time.deltaTime;
ballThrowingForce = ballThrowingForce + 2 * powerTimer;
}
}
This part is absurd :
if (powerTimer == 10) {
powerTimer = 10;
}
Should be powerTimer >= 10.
And after, you execute powerTimer += Time.deltaTime which seems good, but ballThrowingForce += 2 * powerTimer is not what you want i think. Here ballThrowingForce is growing exponentially with powerTimer. Should perhaps be ballThrowingForce += 2 * Time.deltaTime.

How to stop an audioclip when the condition is over?

I'm making a game in Unity and I'm having some problems on adding audio in my enemies. I have an audio clip for walking, attacking and dying. But when I play the game the audioclips starts playing in the right condition, but they never stop like I was expecting. I want them to only play while they're in the right condition and stop playing when in another condition.
Here's my code:
public override void ActionCharacter(){
if (!isDead) {
currentTimeToChangeAction += Time.deltaTime;
if (currentDistanceToPlayer <= distanceToAttack && currentTimeToAttack < timeToAttack) {
currentTimeToAttack += Time.deltaTime;
inAttack = true;
axiVertical = 0;
audio.PlayOneShot(ZombieWalkAudio);
animationCharacter.CrossFade (attackAnimation.name);
} else {
currentTimeToAttack = 0;
inAttack = false;
}
if (inStun) {
currentTimeToStun += Time.deltaTime;
if (currentTimeToStun > timeToStun) {
currentTimeToStun = 0;
inStun = false;
}
axiVertical = 0;
animationCharacter.CrossFade (damageAnimation.name);
}
if (!inAttack && !inStun) {
if (currentTimeToChangeAction > timeToChangeAction) {
currentTimeToChangeAction = 0;
//axiHorizontal = Time.deltaTime * walkVelocity;
axiVertical = Time.deltaTime * walkVelocity;
audio.PlayOneShot(ZombieAttackAudio);
}
if (currentDistanceToPlayer <= distanceMinToRun) {
callRun = true;
} else {
callRun = false;
}
transform.LookAt (player.transform);
//currentGun.Shoot();
}
}
}

Categories

Resources