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.
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.
I want to change between 2 materials, depending on the platforms (gameobject) rotation.
Here is what I've done so far:
public class PlatformSpawner : MonoBehaviour
{
public GameObject platform;
public Material[] platformMaterial;
Material currentMaterial;
Renderer _renderer;
}
void Start()
{
_renderer = this.GetComponent<Renderer>();
}
I also wrote this, but I don't want to change materials by buttons:
public void LeftTurn()
{
_renderer.material = platformMaterial[0];
currentMaterial = _renderer.material;
}
public void RightTurn()
{
_renderer.material = platformMaterial[1];
currentMaterial = _renderer.material;
}
}
And this is where the platform rotates randomly 90 degrees to the left or to the right:
public struct SpawnPoint
{
public Vector3 position;
public Quaternion orientation;
public void Step(float distance)
{
if (Random.value < 0.5)
{
position.x += distance;
orientation = Quaternion.Euler(0, 90, 0); //change to one of the materials
}
else
{
position.z += distance;
orientation = Quaternion.Euler(0, 0, 0); //change to the other of the materials.
//This is where I want to material to switch.
//When the objects position changes, the material changes too.
}
}
}
There is a picture of the gameplay. I want to change the material of all the corner platforms to have a nice curve line view.
Can anyone help me what and how to do in this case? I am a bit lost there.
Every help is highly appreciated!
EDIT: new code looks like that. The only issue is that Unity gives me 15 errors (see on the picture below), even if Visual Studio says no issue has been found. The errors refer to the switch.
public class PlatformSpawner : MonoBehaviour
{
public GameObject platform;
public Transform lastPlatform;
SpawnPoint _spawn;
bool stop;
public Material straightMaterial;
public Material turnLeftMaterial;
public Material turnRightMaterial;
public Renderer roadPrefab;
[System.Serializable]
public struct SpawnPoint
{
public Vector3 position;
public Quaternion orientation;
public RoadType type;
public enum RoadType
{
Straight,
LeftTurn,
RightTurn
}
private enum Direction
{
Z,
X,
}
private Direction lastDirection;
public void Step(float distance)
{
type = RoadType.Straight;
if (Random.value < 0.5f)
{
position.x += distance;
orientation = Quaternion.Euler(0, 90, 0);
if (lastDirection == Direction.Z)
{
type = RoadType.RightTurn;
}
}
else
{
position.z += distance;
orientation = Quaternion.Euler(0, 0, 0);
if (lastDirection == Direction.X)
{
type = RoadType.LeftTurn;
}
lastDirection = Direction.Z;
}
}
}
void Start()
{
_spawn.position = lastPlatform.position;
_spawn.orientation = transform.rotation;
StartCoroutine(SpawnPlatforms());
}
IEnumerator SpawnPlatforms()
{
while (!stop)
{
var _spawn = new SpawnPoint();
for (var i = 0; i < 20; i++)
{
var newPlatform = Instantiate(roadPrefab, _spawn.position, _spawn.orientation);
_spawn.Step(1.5f);
var roadMaterial = _spawn.type switch
{
SpawnPoint.RoadType.LeftTurn => turnLeftMaterial,
SpawnPoint.RoadType.RightTurn => turnRightMaterial,
_ => straightMaterial
};
newPlatform.GetComponent<Renderer>().material = roadMaterial;
yield return new WaitForSeconds(0.1f);
}
}
}
}
So it sounds like you basically have a working system for switching the materials and spawning you road parts and materials already look correctly according to your rotations - now you only need to identify the curves.
Actually this is pretty simple:
is the current part in X direction and the next will be in Z -> Left Turn
is the current part in Z direction and the next will be in X -> RightTurn
any other case is straight
So you could probably do something like
public struct SpawnPoint
{
public Vector3 position;
public Quaternion orientation;
public RoadType type;
public enum RoadType
{
Straight,
LeftTurn,
RightTurn
}
private enum Direction
{
// since your orientation by default equals the Z direction use that as default value for the first tile
Z,
X,
}
private Direction lastDirection;
public void Step(float distance)
{
type = RoadType.Straight;
if (Random.value < 0.5f)
{
position.x += distance;
orientation = Quaternion.Euler(0, 90, 0);
if(lastDirection == Direction.Z)
{
type = RoadType.RightTurn;
}
lastDirection = Direction.X;
}
else
{
position.z += distance;
orientation = Quaternion.Euler(0, 0, 0);
if(lastDirection == Direction.X)
{
type = RoadType.LeftTurn;
}
lastDirection = Direction.Z;
}
}
}
And you didn't show your spawn code but I would assume something like
public class Example : MonoBehaviour
{
public Material straightMaterial;
public Material turnLeftMaterial;
public Material turnRightMaterial;
public Renderer roadPrefab;
private void Awake()
{
var spawnPoint = new SpawnPoint();
for(var i = 0; i < 20; i++)
{
var roadTile = Instantiate(roadPrefab, spawnPoint.position, spawnPoint.orientation);
// do the Step after spawning the current tile but before assigning the material
// -> we want/need to know already where the next tile is going to be
spawnPoint.Step(1f);
var roadMaterial = spawnPoint.type switch
{
SpawnPoint.RoadType.LeftTurn => turnLeftMaterial,
SpawnPoint.RoadType.RightTurn => turnRightMaterial,
_ => straightMaterial
};
roadTile.GetComponent<Renderer>().material = roadMaterial;
}
}
}
Behold my Paint skills ;)
This will get you started using Quaternion.Dot.
using UnityEngine;
[RequireComponent(typeof(Renderer))]
public class NewBehaviourScript : MonoBehaviour
{
public Material Material1;
public Material Material2;
public Vector3 Euler = new(90, 0, 0);
private Renderer _renderer;
private void Start()
{
_renderer = GetComponent<Renderer>();
_renderer.material = Material1;
}
private void Update()
{
var dot = Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler));
if (Mathf.Approximately(dot, 1.0f))
{
_renderer.material = Material2;
}
else
{
_renderer.material = Material1;
}
}
}
Using different materials for N, E, S, W corners:
using UnityEngine;
[RequireComponent(typeof(Renderer))]
public class NewBehaviourScript : MonoBehaviour
{
public Material Material1;
public Material Material2;
public Material Material3;
public Material Material4;
public Vector3 Euler1 = new(0, 0, 0);
public Vector3 Euler2 = new(0, 90, 0);
public Vector3 Euler3 = new(0, 180, 0);
public Vector3 Euler4 = new(0, 270, 0);
private Renderer _renderer;
private void Start()
{
_renderer = GetComponent<Renderer>();
_renderer.material = Material1;
}
private void Update()
{
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler1)), 1.0f))
{
_renderer.material = Material1;
}
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler2)), 1.0f))
{
_renderer.material = Material2;
}
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler3)), 1.0f))
{
_renderer.material = Material3;
}
if (Mathf.Approximately(Quaternion.Dot(transform.rotation, Quaternion.Euler(Euler4)), 1.0f))
{
_renderer.material = Material4;
}
}
}
Make sure to wrap the rotation past 360 degrees, else it'll always look yellow (4th material).
Hey I am trying to change a float when my player collides with a object. I tried many ways of reference but only got null when trying to debug I came up with this so far. I want to get the gameobject that contains the player script meaning the player and after I want to get the component script tankmovement to change the variable in it.
Getting the null reference error in the powerups script line 79 reset function Tank=GameObject.FindWithTag("Player")
using System.Collections.Generic;
using UnityEngine;
public class PowerUp : MonoBehaviour {
public bool boosting = false;
public GameObject effect;
public AudioSource clip;
public GameObject Tank;
private void Start()
{
Tank = GameObject.Find("Tank(Clone)");
TankMovement script = GetComponent<TankMovement>();
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (!boosting)
{
clip.Play();
GameObject explosion = Instantiate(effect, transform.position, transform.rotation);
Destroy(explosion, 2);
GetComponent<MeshRenderer>().enabled = false;
GetComponent<Collider>().enabled = false;
Tank.GetComponent<TankMovement>().m_Speed = 20f;
//TankMovement.m_Speed = 20f;
boosting = true;
Debug.Log(boosting);
StartCoroutine(coolDown());
}
}
private IEnumerator coolDown()
{
if (boosting == true)
{
yield return new WaitForSeconds(4);
{
boosting = false;
GetComponent<MeshRenderer>().enabled = true;
GetComponent<Collider>().enabled = true;
Debug.Log(boosting);
// Destroy(gameObject);
}
}
}
void reset()
{
//TankMovement.m_Speed = 12f;
TankMovement collidedMovement = Tank.gameObject.GetComponent<TankMovement>();
collidedMovement.m_Speed = 12f;
//TankMovement1.m_Speed1 = 12f;
}
}
}
Trying to call on my m_Speed float in the player script to boost the speed of my player when he collides with it. How would you get a proper reference since my player is a prefab.
Tank script
using UnityEngine;
public class TankMovement : MonoBehaviour
{
public int m_PlayerNumber = 1;
public float m_Speed = 12f;
public float m_TurnSpeed = 180f;
public AudioSource m_MovementAudio;
public AudioClip m_EngineIdling;
public AudioClip m_EngineDriving;
public float m_PitchRange = 0.2f;
private string m_MovementAxisName;
private string m_TurnAxisName;
private Rigidbody m_Rigidbody;
private float m_MovementInputValue;
private float m_TurnInputValue;
private float m_OriginalPitch;
private void Awake()
{
m_Rigidbody = GetComponent<Rigidbody>();
}
private void OnEnable ()
{
m_Rigidbody.isKinematic = false;
m_MovementInputValue = 0f;
m_TurnInputValue = 0f;
}
private void OnDisable ()
{
m_Rigidbody.isKinematic = true;
}
private void Start()
{
m_MovementAxisName = "Vertical" + m_PlayerNumber;
m_TurnAxisName = "Horizontal" + m_PlayerNumber;
m_OriginalPitch = m_MovementAudio.pitch;
}
private void Update()
{
// Store the player's input and make sure the audio for the engine is playing.
m_MovementInputValue = Input.GetAxis(m_MovementAxisName);
m_TurnInputValue = Input.GetAxis(m_TurnAxisName);
EngineAudio();
}
private void EngineAudio()
{
// Play the correct audio clip based on whether or not the tank is moving and what audio is currently playing.
if (Mathf.Abs(m_MovementInputValue) < 0.1f && Mathf.Abs(m_TurnInputValue) < 0.1f)
{
if (m_MovementAudio.clip == m_EngineDriving)
{
m_MovementAudio.clip = m_EngineIdling;
m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
m_MovementAudio.Play();
}
}
else
{
if (m_MovementAudio.clip == m_EngineIdling)
{
m_MovementAudio.clip = m_EngineDriving;
m_MovementAudio.pitch = Random.Range(m_OriginalPitch - m_PitchRange, m_OriginalPitch + m_PitchRange);
m_MovementAudio.Play();
}
}
}
private void FixedUpdate()
{
// Move and turn the tank.
Move();
Turn();
}
private void Move()
{
// Adjust the position of the tank based on the player's input.
Vector3 movement = transform.forward * m_MovementInputValue * m_Speed * Time.deltaTime;
m_Rigidbody.MovePosition(m_Rigidbody.position + movement);
}
private void Turn()
{
// Adjust the rotation of the tank based on the player's input.
float turn = m_TurnInputValue * m_TurnSpeed * Time.deltaTime;
Quaternion turnRotation = Quaternion.Euler(0f, turn, 0);
m_Rigidbody.MoveRotation(m_Rigidbody.rotation * turnRotation);
}
}
Since the TankMovement component you need to access is attached to the GameObject that is colliding with the power, you can get the TankMovement component you need to change by using other.gameObject.GetComponent<TankMovement>():
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag("Player"))
{
if (!boosting)
{
// stuff
TankMovement collidedMovement = other.gameObject.GetComponent<TankMovement>();
collidedMovement.m_Speed = 20f;
// more stuff
}
}
}
I am new to C# and am trying to make a basic game in Unity. I am trying to add bullet gameObject to an array. I have researched how to add elements to an array in C# and have found the Add method. However, when I try to use this MonoDevelop doesn't highlight the method as if the method doesn't exist and I get an error. Here is is the error message:
Assets/Scripts/SpaceShipController.cs(126,25): error CS0118:
SpaceShipController.gameManager' is afield' but a `type' was
expected
Here is the line of code which trips the error:
gameManager.bullets[].Add(bulletObject);
Here is the rest of my code. The class called SpaceShipController trips the error when it tries to add bullet objects to an array in a GameManager objects with the script GameManager attached. Finally the BulletBehaviour class just makes the bullet move forward. The code is labelled by class:
SpaceShipController:
using UnityEngine;
using System.Collections;
public class SpaceShipController : MonoBehaviour {
public GameObject bulletObject;
public GameManager gameManager;
//private GameObject[] bullets;
public float shipSpeed;
public float bulletSpeed = 1;
private Vector3 spaceShip;
private Quaternion spaceShipRotation;
private Vector3 bulletPosition;
private int coolDown = 10;
private bool moveRight = false;
private bool moveLeft = false;
private bool fire = false;
// Use this for initialization
void Start () {
spaceShip = transform.position;
spaceShipRotation = transform.rotation;
bulletObject.transform.position = bulletPosition;
}
// Update is called once per frame
void Update () {
coolDown--;
inputHandler();
this.transform.position = spaceShip;
}
void inputHandler() {
if (Input.GetKeyDown(KeyCode.RightArrow)) {
moveRight = true;
}
if (Input.GetKeyDown(KeyCode.LeftArrow)) {
moveLeft = true;
}
if (Input.GetKeyUp(KeyCode.RightArrow)) {
moveRight = false;
}
if (Input.GetKeyUp(KeyCode.LeftArrow)) {
moveLeft = false;
}
if (Input.GetKeyDown(KeyCode.Space)) {
fire = true;
}
if (Input.GetKeyUp(KeyCode.Space)) {
fire = false;
}
if (moveRight == true) {
spaceShip.x += shipSpeed;
}
if (moveLeft == true) {
spaceShip.x -= shipSpeed;
}
if (coolDown <= 0) {
if (fire == true) {
Fire ();
coolDown = 10;
}
}
}
void Fire () {
for (var i = 0; i < 2; i++) {
if (i == 0) {
spaceShip = new Vector3 (transform.position.x + 0.9f, transform.position.y + 0.9f, transform.position.z);
}
else if (i == 1) {
spaceShip = new Vector3 (transform.position.x - 0.9f, transform.position.y + 0.9f, transform.position.z);
}
Instantiate(bulletObject, spaceShip, spaceShipRotation);
bulletObject.AddComponent<BulletBehaviour>();
gameManager.bullets[].Add(bulletObject);
spaceShip = this.transform.position;
}
}
}
GameManager:
using UnityEngine;
using System.Collections;
public class GameManager : MonoBehaviour {
public GameObject[] bullets;
public Camera cam;
private Vector2 cameraBounds;
// Use this for initialization
void Start () {
cameraBounds = new Vector2 (cam.orthographicSize * Screen.width/Screen.height, cam.orthographicSize);
}
// Update is called once per frame
void Update () {
/*for (int i = 0; i < bullets.Length; i++) {
if (bullets[i].transform.position.y >= cameraBounds.y) {
Destroy(bullets[i]);
}
}*/
}
}
BulletBehaviour:
using UnityEngine;
using System.Collections;
public class BulletBehaviour : MonoBehaviour {
public SpaceShipController ship;
private Vector3 shipPosition;
// Use this for initialization
void Start () {
shipPosition = transform.position;
}
// Update is called once per frame
void Update () {
shipPosition.y += 1;
transform.position = shipPosition;
}
}
As always any help would be greatly appreciated. Thanks in advance for any help you can provide.
Arrays are fixed-size. This means that, once they have been initialized with a certain length (e.g., bullets = new GameObject[10]), its length can no longer change.
In order to "add" an item to a array, you have to specify in which position you'd like the item to be. By default, arrays' indexing is 0-based. For example, to insert an element in the first position:
bullets[0] = myItem;
If you don't know how many items you'll have beforehand, and want to add/remove items at will, you should use a resizable collection, such as List<T>.
public List<GameObject> Bullets {get; set;}
You can use it like so:
//initialize with 0 items
Bullets = new List<GameObject>();
//add a new item at the end of the list
Bullets.Add(item);
Read also:
Arrays Tutorial
List<T> class
C# Collections