using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ShootBullets : MonoBehaviour
{
public float bulletDistance;
public bool automaticFire = false;
public float fireRate;
public Rigidbody bullet;
private float gunheat;
private bool shoot = false;
private GameObject bulletsParent;
private GameObject[] startpos;
// Start is called before the first frame update
void Start()
{
bulletsParent = GameObject.Find("Bullets");
startpos = GameObject.FindGameObjectsWithTag("Fire Point");
}
private void Fire()
{
for (int i = 0; i < startpos.Length; i++)
{
Rigidbody bulletClone = (Rigidbody)Instantiate(bullet, startpos[i].transform.position, startpos[i].transform.rotation, bulletsParent.transform);
bulletClone.velocity = transform.forward * bulletDistance;
Destroy(bulletClone.gameObject, 0.5f);
}
}
// Update is called once per frame
void FixedUpdate()
{
if (automaticFire == false)
{
if (Input.GetMouseButtonDown(0))
{
Fire();
}
}
else
{
if (shoot == true)
{
Fire();
shoot = false;
}
}
if (gunheat > 0) gunheat -= Time.deltaTime;
if (gunheat <= 0)
{
shoot = true;
gunheat = fireRate;
}
}
}
now the bullets firing up the air and i want the bullets to fire to a target with physics.
the main goal later is to make some kind of side mission where the player third person view should shoot on object and if and when hitting the object the object will fall down and then the player will be able to pick it up.
Related
does anyone know how to improve this code?
I have this mechaniŃ : ball player creates a bullet ball in front of him and reduces his size, need to disable the reduction of the player's ball if the bullet is already created and flies forward.
I will be glad to any ideas
using UnityEngine;
public class DecreasePlayerBall : MonoBehaviour
{
[SerializeField] private float speedDecrease;
[SerializeField] private int healthPlayer;
public GameOver gameOver;
void Update()
{
if (GameObject.FindWithTag("ballBullet").transform.position.z <= 25.3481f)
{
if (Input.GetMouseButton(0))
{
Decrease();
healthPlayer--;
if (healthPlayer <= 0)
{
Destroy(gameObject);
gameOver.GameOverScreen();
}
}
}
}
void Decrease()
{
transform.localScale -= new Vector3(speedDecrease, speedDecrease, speedDecrease) * Time.deltaTime;
}
}
You can keep the position of the object in a variable and check if the position changes to check if it has moved or use Transform.hasChanged or a boolean of your choice to handle "hasMoved" state.
I'd try something like (not debuggued):
using UnityEngine;
public class DecreasePlayerBall : MonoBehaviour
{
[SerializeField] private float speedDecrease;
[SerializeField] private int healthPlayer;
public GameOver gameOver;
void Start() {
transform.hasChanged = false; // its false by default probably
}
void Update()
{
// if (GameObject.FindWithTag("ballBullet").transform.position.z <= 25.3481f)
if (!transform.hasChanged) {
if (Input.GetMouseButton(0))
{
Decrease();
healthPlayer--;
if (healthPlayer <= 0)
{
Destroy(gameObject);
gameOver.GameOverScreen();
}
}
}
}
void Decrease()
{
transform.localScale -= new Vector3(speedDecrease, speedDecrease, speedDecrease) * Time.deltaTime;
transform.hasChanged = true;
}
}
I'm making this flappy bird replica but instead of a bird it's a rocket.
The controlls are different however the idea is the same.
I have setup a GameManager script:
using UnityEngine;
public class GameManager : MonoBehaviour
{
// Script Refrences
public BarrierSpawnner spawnner;
public MainMen menu;
public MoveLeft moveLeft;
public rockeyMovement movement;
void Start()
{
spawnner.StartedGame = false;
movement.dead = false;
spawnner.StartedGame = false;
movement.rend.enabled = true;
}
void Update()
{
if (spawnner.StartedGame)
{
menu.menuOn = false;
}
if (movement.dead == true)
{
spawnner.StartedGame = false;
}
if (spawnner.StartedGame == false)
{
menu.menuOn = true;
}
}
}
And a Movement Script:
using UnityEngine;
public class rockeyMovement : MonoBehaviour
{
// Variables
private float gravity;
private Vector2 startPos;
public bool dead;
// Refrences
public Rigidbody2D rb;
public BarrierSpawnner spawnner;
public Renderer rend;
public MainMen menStart;
public static rockeyMovement Instance { get; private set; }
void Start()
{
Instance = this;
startPos = transform.position;
rb = GetComponent<Rigidbody2D>();
gravity = rb.gravityScale;
rb.gravityScale = 0;
rend = GetComponent<Renderer>();
}
void OnCollisionStay2D(Collision2D collision)
{
dead = true;
gravity = rb.gravityScale;
rb.gravityScale = 0;
startPos = transform.position;
}
void Update()
{
if (spawnner.StartedGame)
{
rb.gravityScale = 2;
}
if (spawnner.StartedGame == false)
{
transform.position = new Vector2(0, 0);
}
Vector2 vel = rb.velocity;
float ang = Mathf.Atan2(vel.y, 10) * Mathf.Rad2Deg;
transform.rotation = Quaternion.Euler(new Vector3(0, 0, ang - 90f));
if (Input.GetButton("Jump"))
{
rb.AddForce(Vector2.up * gravity * Time.deltaTime * 1000f);
}
}
}
As well as a MenuScript:
using UnityEngine;
public class MainMen : MonoBehaviour
{
public BarrierSpawnner spawnner;
public GameObject CanvasObject;
public bool menuOn;
void Update()
{
if (menuOn)
{
CanvasObject.GetComponent<Canvas> ().enabled = true;
}
}
public void Go()
{
spawnner.StartedGame = true;
CanvasObject.GetComponent<Canvas> ().enabled = false;
}
}
The game starts out normally in the correct way, the problems pop up the moment the player dies. When the player comes in contact with the obstacles I have the script set a bool to true "dead". And when "dead" is true the menu pops back again however, I you cannot interact with it and the page stays like that.
How do I fix this issue?
Is my logic right?
If not, where did I go wrong?
Don't disable Canvas component. Instead, create a panel with buttons on it and activate this panel when needed. Keep it deactivated otherwise.
I am trying to update the lives of my player in a brick breaker game, however I find myself unable to update the text UI responsible for displaying the score (it always displays 3 lives remaining).
Is there any way to fix this issue?
Here is the relevant code
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameManager : MonoBehaviour
{
// Start is called before the first frame update
int lives;
public bool isDead;
public GameObject[] bricks;
int numberBricks;
public Text livesText;
private void Start()
{
isDead = false;
lives = 3;
livesText.text = "lives left: " + lives.ToString();
Debug.Log(lives);
}
// Update is called once per frame
void Update()
{
livesText.text = "lives left: " + lives.ToString();
numberBricks = GameObject.FindGameObjectsWithTag("brick").Length;
if (numberBricks == 0) {
passLevel();
}
}
private void passLevel() {
}
public void ReduceHealth() {
lives--;
Debug.Log(lives);
}
public void CheckDeath() {
if (lives == 0) {
isDead = true;
}
}
}
the ReduceHealth() function is called at
Ball.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Ball : MonoBehaviour
{
// Start is called before the first frame update
Vector3 Direction;
int speedFactor;
float minX;
float maxX;
float additionalForce;
Rigidbody2D rb;
public GameObject paddle;
public AudioSource collisionSound;
public GameObject gameManager;
GameManager gm;
void Start()
{
float sign = Mathf.Sign(Random.Range(-1,1));
minX = -10f * sign;
maxX = -2f * sign;
Direction.x = Random.Range(minX,maxX) ;
Direction.y = -40f;
speedFactor = 1;
rb = GetComponent<Rigidbody2D>();
gm = gameManager.GetComponent<GameManager>();
}
// Update is called once per frame
void Update()
{
transform.position += Direction * speedFactor * Time.deltaTime;
}
void Reset() {
transform.position = new Vector3(0.14f,-4.58f,0f);
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.tag == "Player" || other.gameObject.tag == "border-vertical") {
Direction.y *=-1;
} else if(other.gameObject.tag=="border-bottom") {
gm.ReduceHealth();
Reset();
}else {
Direction.x *= -1;
}
}
}
and here is the Screenshot of my inspector (GameManager object)
any help would be appreciated.
It looks like the function ReduceHealth() has no references. I created a button to see if the lives are reduced or not, it's working. Here is an attached image of OnClick() in button inspector
A few tips
It is not a good practice to update the text in Update function, instead do it in the function where the value of lives is changing. Also check if the lives == 0 in the same function only, there is no need for the function CheckDeath().
public void ReduceHealth() {
lives--;
livesText.text = "lives left: " + lives.ToString();
if (lives == 0) {
isDead = true;
}
}
It is also not a good practice to keep checking the length of the number of bricks at every frame, instead have a check for it in whichever function the breaking of bricks is dealt with.
For eg when the health of the brick reaches zero, get a reference to the GameManager script and do the length check there.
This is a screenshot of the blend tree. The top first animation is idle and on the left side bottom there is a Forward and I added also a Forward parameter. This Forward controls the player's movement speed.
and with this script attached to the player, I'm controlling the Forward parameter and slow down the player movement.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class PlayerSpaceshipAreaColliding : MonoBehaviour
{
public float rotationSpeed =250;
public float movingSpeed;
public float secondsToRotate;
public GameObject uiSceneText;
public TextMeshProUGUI textMeshProUGUI;
private float timeElapsed = 0;
private float lerpDuration = 3;
private float startValue = 1;
private float endValue = 0;
private float valueToLerp = 0;
private Animator playerAnimator;
private bool exitSpaceShipSurroundingArea = false;
private bool slowd = true;
private bool startRotatingBack = false;
private bool displayText = true;
private float desiredRot;
public float damping = 10;
private Rigidbody playerRigidbody;
// Start is called before the first frame update
void Start()
{
playerAnimator = GetComponent<Animator>();
playerRigidbody = GetComponent<Rigidbody>();
desiredRot = transform.eulerAngles.y;
}
// Update is called once per frame
void Update()
{
if (exitSpaceShipSurroundingArea)
{
if (slowd)
SlowDown();
if (playerAnimator.GetFloat("Forward") == 0)
{
slowd = false;
LockController.PlayerLockState(false);
if (displayText)
{
uiSceneText.SetActive(true);
if (textMeshProUGUI.text != "")
textMeshProUGUI.text = "";
textMeshProUGUI.text = "I can see something very far in the distance, but it's too long to walk by foot.";
StartCoroutine(UITextWait());
displayText = false;
}
}
}
}
IEnumerator UITextWait()
{
yield return new WaitForSeconds(5f);
textMeshProUGUI.text = "";
uiSceneText.SetActive(false);
startRotatingBack = true;
}
private void OnTriggerEnter(Collider other)
{
if (other.name == "CrashLandedShipUpDown")
{
exitSpaceShipSurroundingArea = false;
Debug.Log("Entered Spaceship Area !");
}
}
private void OnTriggerExit(Collider other)
{
if (other.name == "CrashLandedShipUpDown")
{
exitSpaceShipSurroundingArea = true;
Debug.Log("Exited Spaceship Area !");
}
}
private void SlowDown()
{
if (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
playerAnimator.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
}
playerAnimator.SetFloat("Forward", valueToLerp);
valueToLerp = 0;
}
}
The problem is when Forward gets to value 0 and the player stops its kind of jumping to the idle animation in the blend tree and not smooth changing to it.
The value of the idle animation (Changes animation speed) in the inspector I marked with a red circle was 1 like the rest but because it was kind of jumping to the idle I changed it to 0.5 but now the whole idle animation is playing too slow like in slow motion.
I'm not sure why it's jumping the change from the slow down to the idle is looks like it's cutting jumping to it and not smoothly change to the idle animation ?
The solution that worked for me.
Inside the script ThirdPersonUserControl instead of disabling the whole script like I'm doing in the line LockController.PlayerLockState(false); I just added a public static bool and by setting the bool to true it will avoid using the input's in the script :
The new bool variable is name stop :
using System;
using UnityEngine;
using UnityStandardAssets.CrossPlatformInput;
namespace UnityStandardAssets.Characters.ThirdPerson
{
[RequireComponent(typeof (ThirdPersonCharacter))]
public class ThirdPersonUserControl : MonoBehaviour
{
private ThirdPersonCharacter m_Character; // A reference to the ThirdPersonCharacter on the object
private Transform m_Cam; // A reference to the main camera in the scenes transform
private Vector3 m_CamForward; // The current forward direction of the camera
private Vector3 m_Move;
private bool m_Jump; // the world-relative desired move direction, calculated from the camForward and user input.
public static bool stop = false;
private void Start()
{
// get the transform of the main camera
if (Camera.main != null)
{
m_Cam = Camera.main.transform;
}
else
{
Debug.LogWarning(
"Warning: no main camera found. Third person character needs a Camera tagged \"MainCamera\", for camera-relative controls.", gameObject);
// we use self-relative controls in this case, which probably isn't what the user wants, but hey, we warned them!
}
// get the third person character ( this should never be null due to require component )
m_Character = GetComponent<ThirdPersonCharacter>();
}
private void Update()
{
if (!m_Jump)
{
m_Jump = CrossPlatformInputManager.GetButtonDown("Jump");
}
}
// Fixed update is called in sync with physics
private void FixedUpdate()
{
if (stop == false)
{
// read inputs
float h = CrossPlatformInputManager.GetAxis("Horizontal");
float v = CrossPlatformInputManager.GetAxis("Vertical");
bool crouch = Input.GetKey(KeyCode.C);
// calculate move direction to pass to character
if (m_Cam != null)
{
// calculate camera relative direction to move:
m_CamForward = Vector3.Scale(m_Cam.forward, new Vector3(1, 0, 1)).normalized;
m_Move = v * m_CamForward + h * m_Cam.right;
}
else
{
// we use world-relative directions in the case of no main camera
m_Move = v * Vector3.forward + h * Vector3.right;
}
#if !MOBILE_INPUT
// walk speed multiplier
if (Input.GetKey(KeyCode.LeftShift)) m_Move *= 0.5f;
#endif
// pass all parameters to the character control script
m_Character.Move(m_Move, crouch, m_Jump);
m_Jump = false;
}
}
}
}
Then in my script, the player is slow down stop and then not moving and it's changing smoothly to the idle animation because it's doing it already in the blend tree the problem is not with the blend tree but was with the way I tried to lock the player from moving.
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityStandardAssets.Characters.ThirdPerson;
public class PlayerSpaceshipAreaColliding : MonoBehaviour
{
public float rotationSpeed =250;
public float movingSpeed;
public float secondsToRotate;
public GameObject uiSceneText;
public TextMeshProUGUI textMeshProUGUI;
private float timeElapsed = 0;
private float lerpDuration = 3;
private float startValue = 1;
private float endValue = 0;
private float valueToLerp = 0;
private Animator playerAnimator;
private bool exitSpaceShipSurroundingArea = false;
private bool slowd = true;
private bool startRotatingBack = false;
private bool displayText = true;
public float damping = 10;
private Quaternion playerRotation;
// Start is called before the first frame update
void Start()
{
playerAnimator = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (exitSpaceShipSurroundingArea)
{
if (slowd)
SlowDown();
if (playerAnimator.GetFloat("Forward") == 0)
{
slowd = false;
ThirdPersonUserControl.stop = true;
if (displayText)
{
uiSceneText.SetActive(true);
if (textMeshProUGUI.text != "")
textMeshProUGUI.text = "";
textMeshProUGUI.text = "I can see something very far in the distance, but it's too long to walk by foot.";
StartCoroutine(UITextWait());
displayText = false;
}
}
if (startRotatingBack)
{
transform.rotation = Quaternion.RotateTowards(transform.rotation, playerRotation, rotationSpeed * Time.deltaTime);
}
}
}
IEnumerator UITextWait()
{
yield return new WaitForSeconds(5f);
textMeshProUGUI.text = "";
uiSceneText.SetActive(false);
startRotatingBack = true;
}
private void OnTriggerEnter(Collider other)
{
if (other.name == "CrashLandedShipUpDown")
{
exitSpaceShipSurroundingArea = false;
Debug.Log("Entered Spaceship Area !");
}
}
private void OnTriggerExit(Collider other)
{
if (other.name == "CrashLandedShipUpDown")
{
playerRotation = transform.rotation;
exitSpaceShipSurroundingArea = true;
Debug.Log("Exited Spaceship Area !");
}
}
private void SlowDown()
{
if (timeElapsed < lerpDuration)
{
valueToLerp = Mathf.Lerp(startValue, endValue, timeElapsed / lerpDuration);
playerAnimator.SetFloat("Forward", valueToLerp);
timeElapsed += Time.deltaTime;
}
playerAnimator.SetFloat("Forward", valueToLerp);
valueToLerp = 0;
}
}
I am a newbie to Unity and I am trying to build a little shooter 2d game in C#. I am now stuck and confess that I am a little lost not knowing what the best approach is, but the problem is that my hero shoots at the enemies and they die but how do I get to the next level after the enemies are all dead? If I make a dead counter, what script do I put in? In the enemy script? Or do I make a new script but associate it with what? I also need the game to end if the hero fires his six bullets (already have a counter that makes the hero not shoot anymore after six shoots) and there are still enemies left ...
Does anyone give me some tips? Thanks!
Enemy script:
using System.Collections.Generic;
using UnityEngine;
public class BadguyScript : MonoBehaviour
{
public int maxHealth;
public int curHealth;
private Animator myAnimator;
private bool isDead;
[SerializeField]
private float DespawnTime = 2.5f;
[SerializeField]
private string DeathAnimHash = "isDead";
void Start()
{
myAnimator = GetComponent<Animator>();
myAnimator.enabled =true;
myAnimator.SetBool (DeathAnimHash ,isDead);
maxHealth = 1;
curHealth = maxHealth;
}
void Update()
{
if (curHealth < 1)
{
isDead = true;
myAnimator.SetBool (DeathAnimHash ,isDead);
Destroy(gameObject,DespawnTime);
}
}
void OnTriggerEnter2D(Collider2D col)
{
if (isDead)
return;
if (col.tag == "bullet")
{
curHealth -= 1;
Destroy(col.gameObject);
}
}
}
Count Bullets Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class GameFlow : MonoBehaviour
{
public static float remainingShots = 6;
public Transform shot1;
public Transform shot2;
public Transform shot3;
public Transform shot4;
public Transform shot5;
public Transform shot6;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (remainingShots > 0)
{
shot1.GetComponent<Image> ().enabled = true;
}
else
{
shot1.GetComponent<Image> ().enabled = false;
}
if (remainingShots > 1)
{
shot2.GetComponent<Image> ().enabled = true;
}
else
{
shot2.GetComponent<Image> ().enabled = false;
}
if (remainingShots > 2)
{
shot3.GetComponent<Image> ().enabled = true;
}
else
{
shot3.GetComponent<Image> ().enabled = false;
}
if (remainingShots > 3)
{
shot4.GetComponent<Image> ().enabled = true;
}
else
{
shot4.GetComponent<Image> ().enabled = false;
}
if (remainingShots > 4)
{
shot5.GetComponent<Image> ().enabled = true;
}
else
{
shot5.GetComponent<Image> ().enabled = false;
}
if (remainingShots > 5)
{
shot6.GetComponent<Image> ().enabled = true;
}
else
{
shot6.GetComponent<Image> ().enabled = false;
}
if(Input.GetButtonDown("Fire1"))
{
remainingShots -= 1;
}
}
}
To switch to another scene after your conditions do the following:
1. Add the OtherScenes to your game by doing this:
File -> Build Settings -> Add Open Scenes
2. Do something like this in your code:
Enemy Script.cs
using UnityEngine.SceneManagement; // Contains scene management functions
public GameObject[] enemies;
void Update()
{
enemies = GameObject.FindGameObjectsWithTag("Enemy"); // Checks if enemies are available with tag "Enemy". Note that you should set this to your enemies in the inspector.
if (enemies.length == 0)
{
SceneManager.LoadScene("OtherSceneName"); // Load the scene with name "OtherSceneName"
}
}
Bullet Script.cs
using UnityEngine.SceneManagement;
void Update()
{
if (remainingShots == -1)
{
SceneManager.LoadScene("OtherSceneName");
}
}
use an empty gameobject and attach this line of code in update method .
if (enemies.length == 0)
{
SceneManager.LoadScene("OtherSceneName"); // Load the scene with name "OtherSceneName"
}
As you were using the enemy script and when all the enemies dies then there is no gameobject which hold the script.