When bulletpool is being instantiated, I can shoot bullets. But when all the bullets are done instantiated, I can't shoot the bullet. IDK where is the porblem..
BulletPoolScript:
public class scriptBulletPool : MonoBehaviour
{
private static scriptBulletPool myInstance;
public static scriptBulletPool MyInstance
public GameObject bulletPrefab;
public List<GameObject> bulletPool;
public int poolSize;
{
get
{
return myInstance;
}
}
private void Awake()
{
if (myInstance == null)
{
myInstance = this;
} else if(myInstance != this)
{
Debug.LogError("Obj 1:", gameObject);
Debug.LogError("Obj 2:", myInstance.gameObject);
}
instantiatePool();
}
private void instantiatePool()
{
bulletPool = new List<GameObject>();
for (int i=0; i<poolSize; i++)
{
GameObject newBullet = Instantiate(bulletPrefab);
bulletPool.Add(newBullet);
newBullet.SetActive(false);
}
}
public GameObject getBullet(Vector3 targetPos, Quaternion targetRot)
{
GameObject newBullet = bulletPool[bulletPool.Count - 1];
newBullet.transform.position = targetPos;
newBullet.transform.rotation = targetRot;
newBullet.SetActive(true);
bulletPool.Remove(newBullet);
return newBullet;
}
public void returnBullet(GameObject bullet)
{
bulletPool.Add(bullet);
bullet.SetActive(false);
}
}
ShootScript:
public class scriptShoot : MonoBehaviour
{
public GameObject bulletSpawnPoint;
void Update()
{
shoot();
}
private void shoot()
{
if (Input.GetMouseButtonDown(0))
{
scriptBulletPool.MyInstance.getBullet(bulletSpawnPoint.transform.position, bulletSpawnPoint.transform.rotation);
}
}
}
BulletScript:
public class scriptBullet : MonoBehaviour
{
public GameObject bullet;
public float maxDistance;
void Update()
{
transform.Translate(Vector3.forward * 7 * Time.deltaTime);
maxDistance += 1 * Time.deltaTime;
if (maxDistance >= 5)
{
scriptBulletPool.MyInstance.returnBullet(bullet);
}
}
}
The problem is probably the scriptBullet.maxDistance.
You increment it in every update, and eventually pool the bullet.
When you need a bullet, you unpool it, but the maxDistance is never reset, resulting in the bullet being pooled again immediately.
Related
I've added a stamina system in my game, but when I try do call the function there's a few problems happening:
I can't jump when my character is sprinting and when I jump and press the sprint button my character doesn't fall anymore, he basically just flies.
PlayerController
private Vector3 playerVelocity;
private bool groundedPlayer;
private CharacterController controller;
private PlayerControls playerControls;
private InputManager inputManager;
public HealthBar healthBar;
public StaminaBar staminaBar;
public int currentHealth;
public int maxHealth = 100;
public int currentStamina;
public int maxStamina = 100;
public int staminaDrain = 10;
[SerializeField]
private float playerSpeed = 2.0f;
[SerializeField]
private float playerRunSpeed= 1f;
[SerializeField]
private float jumpHeight = 1.0f;
[SerializeField]
private float gravityValue = -9.81f;
private Transform cameraTransform;
private void Start()
{
currentHealth = maxHealth;
healthBar.SetMaxHealth(maxHealth);
currentStamina = maxStamina;
staminaBar.SetMaxStamina(maxStamina);
controller = GetComponent<CharacterController>();
inputManager = InputManager.Instance;
cameraTransform = Camera.main.transform;
//player = GameObject.Find("Player");
}
void Update()
{
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}
Vector2 movement = inputManager.GetPlayerMovement();
Vector3 move = new Vector3(movement.x, 0f, movement.y);
move = cameraTransform.forward * move.z + cameraTransform.right * move.x;
move.y = 0f;
//controller.Move(move * Time.deltaTime * playerSpeed);
if(inputManager.isRunning && currentStamina > 0)
{
controller.Move(move * playerRunSpeed * Time.deltaTime);
staminaBar.UseStamina(staminaDrain);
staminaBar.staminaSlider.value = currentStamina;
}
else
{
controller.Move(move * Time.deltaTime * playerSpeed);
}
// Changes the height position of the player..
if (inputManager.PlayerJumpedThisFrame() && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}
playerVelocity.y += gravityValue * Time.deltaTime;
controller.Move(playerVelocity * Time.deltaTime);
}
StaminaBar script
public class StaminaBar : MonoBehaviour
{
public Slider staminaSlider;
private PlayerController playerController;
private WaitForSeconds regenTick = new WaitForSeconds(0.1f);
private Coroutine regen;
public void SetMaxStamina(int stamina){
staminaSlider.maxValue = stamina;
staminaSlider.value = stamina;
}
public void SetStamina(int stamina){
staminaSlider.value = stamina;
}
public void UseStamina(int amount){
if(playerController.currentStamina - amount >= 0){
playerController.currentStamina -= amount;
staminaSlider.value = playerController.currentStamina;
Debug.Log("Losing Stamina");
if(regen != null)
StopCoroutine(regen);
regen = StartCoroutine(RegenStamina());
}
else
{
Debug.Log("NotEnoughStamina");
}
}
private IEnumerator RegenStamina()
{
yield return new WaitForSeconds(2);
while(playerController.currentStamina < playerController.maxStamina){
playerController.currentStamina += playerController.maxStamina/100;
staminaSlider.value = playerController.currentStamina;
yield return regenTick;
}
regen = null;
}
}
Input Manager
{
private StaminaBar staminaBar;
private PlayerController playerController;
[SerializeField]
private float bulletHitMissDistance = 25f;
[SerializeField]
private Transform bulletParent;
[SerializeField]
private Transform barrelTransform;
[SerializeField]
private GameObject bulletPrefab;
[SerializeField]
private float damage = 100;
public float impactForce = 30;
public float fireRate = 8f;
WaitForSeconds rapidFireWait;
public bool isRunning;
private static InputManager _instance;
public static InputManager Instance
{
get {
return _instance;
}
}
private PlayerControls playerControls;
private Transform cameraTransform;
Coroutine fireCoroutine;
private void Awake()
{
if(_instance != null && _instance != this)
{
Destroy(this.gameObject);
}
else
{
_instance = this;
}
playerControls = new PlayerControls();
//Cursor.visible = false;
rapidFireWait = new WaitForSeconds(1/fireRate);
cameraTransform = Camera.main.transform;
playerControls.Player.RunStart.performed += x => Running();
playerControls.Player.RunEnd.performed += x => RunningStop();
playerControls.Player.Shoot.started += _ => StartFiring();
playerControls.Player.Shoot.canceled += _ => StopFiring();
}
private void OnEnable()
{
playerControls.Enable();
//playerControls.Player.Shoot.performed += _ => StartFiring();
}
private void OnDisable()
{
playerControls.Disable();
//playerControls.Player.Shoot.performed += _ => StopFiring();
}
void StartFiring()
{
fireCoroutine = StartCoroutine(RapidFire());
}
void StopFiring()
{
if(fireCoroutine != null)
{
StopCoroutine(fireCoroutine);
}
}
public Vector2 GetPlayerMovement()
{
return playerControls.Player.Movement.ReadValue<Vector2>();
}
public Vector2 GetMouseDelta(){
return playerControls.Player.Look.ReadValue<Vector2>();
}
public bool PlayerJumpedThisFrame(){
return playerControls.Player.Jump.triggered;
}
public void Shooting()
{
RaycastHit hit;
//creates the bullet
GameObject bullet = GameObject.Instantiate(bulletPrefab, barrelTransform.position, Quaternion.identity, bulletParent);
BulletController bulletController = bullet.GetComponent<BulletController>();
//shoots the bullet forwards
if (Physics.Raycast(cameraTransform.position, cameraTransform.forward, out hit, Mathf.Infinity))
{
//checks if the bullet hit something
bulletController.target = hit.point;
bulletController.hit = true;
//makes enemy take damage
Enemy takingDamage = hit.transform.GetComponent<Enemy>();
if (takingDamage != null)
{
takingDamage.TakeDamage(damage);
}
//makes enemy go backwards when hit
if(hit.rigidbody != null)
{
hit.rigidbody.AddForce(-hit.normal * impactForce);
}
}
else
{
bulletController.target = cameraTransform.position + cameraTransform.forward * bulletHitMissDistance;
bulletController.hit = false;
}
}
public IEnumerator RapidFire()
{
while(true)
{
Shooting();
yield return rapidFireWait;
}
}
public void Running()
{
/* if(playerController.currentStamina > 0){
isRunning = true;
staminaBar.UseStamina(playerController.staminaDrain);
staminaBar.staminaSlider.value = playerController.currentStamina;
} */
isRunning = true;
}
public void RunningStop(){
isRunning =false;
}
}
I'm using unity new input system and tried to call the function in two different ways: in the isRunning and when I actually do the sprint function.
I was expecting the player to lose 10 stamina every time I press the sprint button, I was trying to figure that out before trying to make him lose stamina while the button is pressed.
I've seen a couple videos on YouTube, which is where I got the code from, but can't find out what I'm doing wrong when calling the function, I've had similar problems before when trying to call a TakeDamage function but I guess that's a different question.
So here is what I would do.
Instead of controlling the stamina in multiple places and hve forth and back references (=dependencies) between all your scripts I would rather keep this authority within the PlayerController.
Your StaminaBar component should be purely listening and visualizing the current value without having the authority to modify it.
Next step would be to decide for a general code structure
Who is responsible for what?
Who knows / controls what?
There are many possible answers to those but for now an this specific case
You can either say the PlayerController "knows" the StaminaBar just like it also knows the InputManager and can't live without both
Or you could decouple them and let the PlayerController work without having the visualization via the StaminaBar but rather let the StaminaBar listen to the value and just display it .. or not if you want to remove or change this later on
Personally I would go with the second so I will try and give you an example how I would deal with this:
public class PlayerController : MonoBehaviour
{
[Header("Own References")]
[SerializeField] private CharacterController _controller;
[Header("Scene References")]
[SerializeField] private Transform _cameraTransform;
[SerializeField] private InputManager _inputManager;
// In general always make you stuff as encapsulated as possible
// -> nobody should be able to change these except you via the Inspector
// (Values you are anyway not gonna change at all you could also convert to "const")
[Header("Settings")]
[SerializeField] private float _maxHealth = 100f;
[SerializeField] private float _maxStamina = 100f;
[SerializeField] private float _staminaDrainPerSecond = 2f;
[SerializeField] private float _secondsDelayBeforeStaminaRegen = 1f;
[SerializeField] private float _staminaRegenPerSecond = 2f;
[SerializeField] private float _playerSpeed = 1f;
[SerializeField] private float _playerRunSpeed = 2f;
[SerializeField] private float _jumpHeight = 1f;
[SerializeField] private float _gravityValue = -9.81f;
// Your runtime valus
private float _staminaRegenDelayTimer;
private float _currentHealt;
private float _currentStamina;
// You only need a single float for this
private float _currentYVelocity;
// EVENTS we expose so other classes can react to those
public UnityEvent OnDeath;
public UnityEvent<float> OnHealthChanged;
public UnityEvent<float> OnStaminaChanged;
// Provide public read-only access to the settings so your visuals can access those for their setup
public float MaxHealth => _maxHealth;
public float MaxStamina => _maxStamina;
// And then use properties for your runtime values
// whenever you set the value you do additional stuff like cleaning the value and invoke according events
public float currentHealth
{
get => _currentHealt;
private set
{
_currentHealt = Mathf.Clamp(value, 0, _maxHealth);
OnHealthChanged.Invoke(_currentHealt);
if (value <= 0f)
{
OnDeath.Invoke();
}
}
}
public float currentStamina
{
get => _currentStamina;
private set
{
_currentStamina = Mathf.Clamp(value, 0, _maxStamina);
OnStaminaChanged.Invoke(_currentStamina);
}
}
private void Awake()
{
// As a thumb rule to avoid issues with order I usually initialize everything I an in Awake
if (!_controller) _controller = GetComponent<CharacterController>();
currentHealth = MaxHealth;
currentStamina = MaxStamina;
}
private void Start()
{
// in start do the things were you depend on others already being initialized
if (!_inputManager) _inputManager = InputManager.Instance;
if (!_cameraTransform) _cameraTransform = Camera.main.transform;
}
private void Update()
{
UpdateStamina();
UpdateHorizontalMovement();
UpdateVerticalMovement();
}
private void UpdateStamina()
{
if (_inputManager.IsRunning)
{
// drain your stamina -> also informs all listeners
currentStamina -= _staminaDrainPerSecond * Time.deltaTime;
// reset the regen timer
_staminaRegenDelayTimer = _secondsDelayBeforeStaminaRegen;
}
else
{
// only if not pressing run start the regen timer
if (_staminaRegenDelayTimer > 0)
{
_staminaRegenDelayTimer -= Time.deltaTime;
}
else
{
// once timer is finished start regen
currentStamina += _staminaRegenPerSecond * Time.deltaTime;
}
}
}
private void UpdateHorizontalMovement()
{
var movement = _inputManager.PlayerMovement;
var move = _cameraTransform.forward * movement.y + _cameraTransform.right * movement.x;
move.y = 0f;
move *= _inputManager.IsRunning && currentStamina > 0 ? _playerRunSpeed : _playerSpeed;
_controller.Move(move * Time.deltaTime);
}
private void UpdateVerticalMovement()
{
if (_controller.isGrounded)
{
if (_inputManager.JumpedThisFrame)
{
_currentYVelocity += Mathf.Sqrt(_jumpHeight * -3.0f * _gravityValue);
}
else if (_currentYVelocity < 0)
{
_currentYVelocity = 0f;
}
}
else
{
_currentYVelocity += _gravityValue * Time.deltaTime;
}
_controller.Move(Vector3.up * _currentYVelocity * Time.deltaTime);
}
}
And then your StaminaBar shinks down to really only being a display. The PlayerController doesn't care/even know it exists and can fully work without it.
public class StaminaBar : MonoBehaviour
{
[SerializeField] private Slider _staminaSlider;
[SerializeField] private PlayerController _playerController;
private void Awake()
{
// or wherever you get the reference from
if (!_playerController) _playerController = FindObjectOfType<PlayerController>();
// poll the setting from the player
_staminaSlider.maxValue = _playerController.MaxStamina;
// attach a callback to the event
_playerController.OnStaminaChanged.AddListener(OnStaminaChanged);
// just to be sure invoke the callback once immediately with the current value
// so we don't have to wait for the first actual event invocation
OnStaminaChanged(_playerController.currentStamina);
}
private void OnDestroy()
{
if(_playerController) _playerController.OnStaminaChanged.RemoveListener(OnStaminaChanged);
}
// This will now be called whenever the stamina has changed
private void OnStaminaChanged(float stamina)
{
_staminaSlider.value = stamina;
}
}
And just for completeness - I also refactored your InputManager a bit on the fly ^^
public class InputManager : MonoBehaviour
{
[Header("Own references")]
[SerializeField] private Transform _bulletParent;
[SerializeField] private Transform _barrelTransform;
[Header("Scene references")]
[SerializeField] private Transform _cameraTransform;
// By using the correct component right away you can later skip "GetComponent"
[Header("Assets")]
[SerializeField] private BulletController _bulletPrefab;
[Header("Settings")]
[SerializeField] private float _bulletHitMissDistance = 25f;
[SerializeField] private float _damage = 100;
[SerializeField] private float _impactForce = 30;
[SerializeField] private float _fireRate = 8f;
public static InputManager Instance { get; private set; }
// Again I would use properties here
// You don't want anything else to set the "isRunning" flag
// And the others don't need to be methods either
public bool IsRunning { get; private set; }
public Vector2 PlayerMovement => _playerControls.Player.Movement.ReadValue<Vector2>();
public Vector2 MouseDelta => _playerControls.Player.Look.ReadValue<Vector2>();
public bool JumpedThisFrame => _playerControls.Player.Jump.triggered;
private Coroutine _fireCoroutine;
private PlayerControls _playerControls;
private WaitForSeconds _rapidFireWait;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
}
else
{
Instance = this;
}
_playerControls = new PlayerControls();
//Cursor.visible = false;
_rapidFireWait = new WaitForSeconds(1 / _fireRate);
_cameraTransform = Camera.main.transform;
_playerControls.Player.RunStart.performed += _ => Running();
_playerControls.Player.RunEnd.performed += _ => RunningStop();
_playerControls.Player.Shoot.started += _ => StartFiring();
_playerControls.Player.Shoot.canceled += _ => StopFiring();
}
private void OnEnable()
{
_playerControls.Enable();
}
private void OnDisable()
{
_playerControls.Disable();
}
private void StartFiring()
{
_fireCoroutine = StartCoroutine(RapidFire());
}
private void StopFiring()
{
if (_fireCoroutine != null)
{
StopCoroutine(_fireCoroutine);
_fireCoroutine = null;
}
}
private void Shooting()
{
var bulletController = Instantiate(_bulletPrefab, _barrelTransform.position, Quaternion.identity, _bulletParent);
if (Physics.Raycast(_cameraTransform.position, _cameraTransform.forward, out var hit, Mathf.Infinity))
{
bulletController.target = hit.point;
bulletController.hit = true;
if (hit.transform.TryGetComponent<Enemy>(out var enemy))
{
enemy.TakeDamage(_damage);
}
if (hit.rigidbody != null)
{
hit.rigidbody.AddForce(-hit.normal * _impactForce);
}
}
else
{
bulletController.target = _cameraTransform.position + _cameraTransform.forward * _bulletHitMissDistance;
bulletController.hit = false;
}
}
private IEnumerator RapidFire()
{
while (true)
{
Shooting();
yield return _rapidFireWait;
}
}
private void Running()
{
IsRunning = true;
}
private void RunningStop()
{
IsRunning = false;
}
}
You're decreasing and increasing the stamina in the same scope. I think you should let the stamina to be drained when sprint is pressed and start regenerating only if it is released.
I have been following a tutorial on a unity 2d game. The player and the enemy inherit from a base class known as MovingObject. Everything in the game works fine except that the player and the enemy can't move. Here are the scripts. The movement happens in a gridlike tile system.
This is the original tutorial series. Try going over the moving object, player, and enemy tutorials.
https://www.youtube.com/playlist?list=PLX2vGYjWbI0SKsNH5Rkpxvxr1dPE0Lw8F
Base MovingObject class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public abstract class MovingObject : MonoBehaviour {
public float moveTime = 0.1f;
public LayerMask blockinglayer;
private BoxCollider2D boxCollider;
private Rigidbody2D rb2D;
private float inverseMoveTime;
// Use this for initialization
protected virtual void Start () {
boxCollider = GetComponent<BoxCollider2D>();
rb2D = GetComponent<Rigidbody2D>();
inverseMoveTime = 1f / moveTime;
}
protected bool Move(int xDir, int yDir, out RaycastHit2D hit)
{
Vector2 start = transform.position;
Vector2 end = start + new Vector2(xDir, yDir);
boxCollider.enabled = false;
hit = Physics2D.Linecast(start, end, blockinglayer);
boxCollider.enabled = true;
if (hit.transform == null)
{
StartCoroutine(SmoothMovement(end));
return true;
}
return false;
}
protected IEnumerator SmoothMovement(Vector3 end)
{
float sqrRemainingDistance = (transform.position - end).sqrMagnitude;
while (sqrRemainingDistance > float.Epsilon)
{
Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime);
rb2D.MovePosition(newPosition);
sqrRemainingDistance = (transform.position - end).sqrMagnitude;
yield return null;
}
}
protected virtual void AttemptMove<T>(int xDir, int yDir)
where T : Component
{
RaycastHit2D hit;
bool canMove= Move(xDir, yDir, out hit);
if (hit.transform == null)
{
return;
}
T hitComponent = hit.transform.GetComponent<T>();
if(!canMove && hitComponent != null)
{
OnCantMove(hitComponent);
}
}
protected abstract void OnCantMove<T>(T component)
where T : Component;
// Update is called once per frame
}
Player Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class Player : MovingObject {
public int wallDamage = 1;
public int pointsPerFood = 10;
public int pointsPerSoda = 20;
public float restartLevelDelay = 1f;
private Animator animator;
private int food;
// Use this for initialization
protected override void Start () {
animator = GetComponent<Animator>();
food = GameManager.instance.playerFoodPoints;
base.Start();
}
private void OnDisable()
{
GameManager.instance.playerFoodPoints = food;
}
// Update is called once per frame
void Update () {
if (GameManager.instance.playersTurn)
{
return;
}
int horizontal = 0;
int vertical = 0;
horizontal = (int)Input.GetAxisRaw("Horizontal");
vertical = (int)Input.GetAxisRaw("Vertical");
if (horizontal != 0)
{
vertical = 0;
}
if(horizontal!=0 || vertical != 0)
{
AttemptMove<Wall>(horizontal, vertical);
}
}
protected override void OnCantMove<T>(T component)
{
Wall hitwall = component as Wall;
hitwall.damageWall(wallDamage);
animator.SetTrigger("playerChop");
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
food--;
base.AttemptMove<T>(xDir, yDir);
RaycastHit2D hit;
CheckIfGameOver();
GameManager.instance.playersTurn = false;
}
public void LoseFood(int loss)
{
animator.SetTrigger("playerHit");
food -= loss;
CheckIfGameOver();
}
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Exit")
{
Invoke("Restart", restartLevelDelay);
enabled = false;
}
else if (other.tag == "Food")
{
food += pointsPerFood;
other.gameObject.SetActive(false);
}
else if (other.tag == "Soda")
{
food += pointsPerSoda;
other.gameObject.SetActive(false);
}
}
private void Restart()
{
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
private void CheckIfGameOver()
{
if (food <= 0)
{
GameManager.instance.GameOver();
}
}
}
Enemy Script:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MovingObject {
public int playerDamage;
private Animator animator;
private Transform target;
private bool skipmove;
// Use this for initialization
protected override void Start () {
GameManager.instance.AddEnemyToList(this);
animator = GetComponent<Animator>();
target = GameObject.FindGameObjectWithTag("Player").transform;
base.Start();
}
protected override void AttemptMove<T>(int xDir, int yDir)
{
if (skipmove)
{
skipmove = false;
return;
}
base.AttemptMove<T>(xDir, yDir);
}
public void MoveEnemy()
{
int xDir = 0;
int yDir = 0;
if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
{
yDir = target.position.y > transform.position.y ? 1 : -1;
}
else
{
xDir = target.position.x > transform.position.x ? 1 : -1;
AttemptMove<Player>(xDir,yDir);
}
}
protected override void OnCantMove<T>(T component)
{
Player hitplayer = component as Player;
animator.SetTrigger("enemyAttack");
hitplayer.LoseFood(playerDamage);
}
}
I'm not sure which whether the player or enemy have an issue of the base script. Can anyone help.
A few Observations (Hopefully it helps):
MovingObject.cs - Inside of Update(), should it not be this?
if (!GameManager.instance.playersTurn)
Note I added a "!" before GameManager
Player.cs - in AttemptMove(), you need to call Move()... like this
Move (xDir, yDir, out hit);
Enemy.cs
1) At the end of AttemptMove(), there should be:
skipMove = true;
2) In MoveEnemy(), at the end, this code should NOT be in the else, but after the else:
AttemptMove<Player>(xDir,yDir);
I'm converting a simple platformer game into a multiplayer game(my first ever attempt at a multiplayer game), and i have these objects that if the player touches them, the player gets damaged. I'm having slight problems with server registering damage that shouldn't be, so to avoid all future problems i wanted to make damage client-sided.
I want to make it so all damage is client sided and the clients health gets sent to the server.
Edit: Made question less confusing.
public class EnemyTrigger : MonoBehaviour
{
private PlayerStats player;
private CharacterController2D controller;
public int Damage;
public float horizontal;
public float vertical;
private void Start()
{
}
private void OnTriggerStay2D(Collider2D collider)
{
if (collider.tag == "Player" && collider.GetComponent<PlayerStats>().DamageTimer <= 0 && collider.GetComponent<PlayerStats>().isDashing == false)
{
player = collider.GetComponent<PlayerStats>();
controller = player.GetComponent<CharacterController2D>();
player.TakeDamage(Damage);
if (this.transform.position.x - player.transform.position.x > 0)
{
controller.KnockBackRight(horizontal);
}
else
{
controller.KnockBackLeft(horizontal);
}
controller.KnockBackDown(vertical);
}
}
}
public class PlayerStats : NetworkBehaviour {
[SyncVar] public int Health;
public GameObject BloodEffect;
public Transform HealthBar;
public float DefDamageTimer;
public float DamageTimer;
public bool isDashing;
public int facingDirection;
private Rigidbody2D m_Rigidbody2D;
private CharacterController2D controller;
public AnimationPlayer anim;
private void Awake()
{
m_Rigidbody2D = GetComponent<Rigidbody2D>();
controller = GetComponent<CharacterController2D>();
}
private void Update()
{
HealthBar.localScale = new Vector3(Health / 10f, 1f);
if (DamageTimer > 0)
{
DamageTimer -= Time.deltaTime;
}
CmdSendDashing(isDashing);
}
public void TakeDamage(int Damage)
{
Health -= Damage;
Instantiate(BloodEffect, transform.position, Quaternion.identity);
anim.Damaged();
Debug.Log("Player Has Taken " + Damage + " Damage");
DamageTimer = DefDamageTimer;
if (Health <= 0)
{
Destroy(gameObject);
}
CmdSendHealth(Health);
}
void CmdSendHealth(int health)
{
Health = health;
}
void CmdSendDashing(bool isdashing)
{
isDashing = isdashing;
}
}
I have made a breakout game using unity tutorials and everything seemed to work well, but when I played it in the game mode there were some errors. So after I tried fixing the errors, the bricks wont get destroyed anymore. I tried undoing it, writing the code anew or even writing the same project anew but nothing works. What can I do?
These are the codes for my game which are exactly like the codes in the tutorial!
Paddle:
public class Paddle : MonoBehaviour {
public float paddleSpeed = 1f;
private Vector3 playerPos = new Vector3(0, -9f, 0);
void Update ()
{
float xPos = transform.position.x + (Input.GetAxis("Horizontal")*paddleSpeed);
playerPos = new Vector3(Mathf.Clamp(xPos, -7.5f, 7.5f), -9f, 0f);
transform.position = playerPos;
}
}
Ball:
public class Ball : MonoBehaviour {
private float ballInitialVelocity = 600f;
private Rigidbody rb;
private bool ballInPlay;
void Awake ()
{
rb = GetComponent<Rigidbody>();
}
void Update ()
{
if(Input.GetButtonDown("Fire1") && ballInPlay==false)
{
transform.parent = null;
ballInPlay = true;
rb.isKinematic = false;
rb.AddForce(new Vector3(ballInitialVelocity, ballInitialVelocity, 0));
}
}
}
GM:
using UnityEngine; using System.Collections;
public class deathZone : MonoBehaviour {
void OnTriggerEnter(Collider col)
{
GM.instance.loseLife();
}
}
public class GM : MonoBehaviour {
public int Lives = 3;
public int bricks = 16;
public float resetDelay = 1f;
public Text livesText;
public GameObject gameOver;
public GameObject bricksPrefab;
public GameObject youWon;
public GameObject paddle;
public GameObject deathParticles;
public static GM instance = null;
private GameObject clonePaddle;
void Start()
{
if (instance == null)
instance = this;
else if (instance != this)
instance = null;
setup();
}
public void setup()
{
clonePaddle = Instantiate(paddle, new Vector3(0, -9,0), Quaternion.identity) as GameObject;
Instantiate(bricksPrefab, new Vector3((float)18.5, (float)-61.14095, (float)238.4855), Quaternion.identity);
}
void checkGameOver()
{
if (bricks < 1)
{
youWon.SetActive(true);
Time.timeScale = .25f;
Invoke("Reset", resetDelay);
}
if (Lives < 1)
{
gameOver.SetActive(true);
Time.timeScale = .25f;
Invoke("Reset", resetDelay);
}
}
void Reset()
{
Time.timeScale = 1f;
Application.LoadLevel(Application.loadedLevel);
}
public void loseLife()
{
Lives--;
livesText.text = "Lives: " + Lives;
Instantiate(deathParticles, clonePaddle.transform.position, Quaternion.identity);
Destroy(clonePaddle);
Invoke("SetupPaddle", resetDelay);
checkGameOver();
}
void SetupPaddle()
{
clonePaddle = Instantiate(paddle, new Vector3(0, -9, 0), Quaternion.identity) as GameObject;
}
public void destroyBrick()
{
bricks--;
checkGameOver();
}
}
Bricks:
public class Bricks : MonoBehaviour {
public GameObject brickParticle;
void OnCollisionEnter(Collision other)
{
Instantiate(brickParticle, transform.position, Quaternion.identity);
GM.instance.destroyBrick();
Destroy(gameObject);
}
}
deathZone:
public class deathZone : MonoBehaviour {
void OnTriggerEnter(Collider col)
{
GM.instance.loseLife();
}
}
In this tutorial you have to make sure all of the bricks GameObject have both the Bricks script and a BoxCollider components. Also the ball should have a Rigidbody and a SphereCollider components.
An easy way to debug Collisions or Triggers is to simply use a Debug.Log("something"); as a first command in the OnCollisionEnter/OnTriggerEnter/... methods.
It seems that the issue is with colliders. You should check them in Editor if they are placed right ( since no debug.log on collision is written). Also make sure that you are using Colliders and not colliders2D ( collision is called by diffrent method)
so I was wondering if there was a way to make a spawned object gradually moves/go faster after the player (you the user) collects 10 points. And faster when the player collects another 10 points and so on and so on?
This is my movement script attach to my objects that get spawned in:
public class Movement : MonoBehaviour
{
public static int movespeed = 20;
public Vector3 userDirection = Vector3.right;
public void Update()
{
transform.Translate(userDirection * movespeed * Time.deltaTime);
}
}
This is my score script attach to my player
public int Score;
public Text ScoreText;
void Start ()
{
Score = 0;
SetScoreText ();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag ("Pick Up"))
{
other.gameObject.SetActive (false);
Score = Score + 1;
SetScoreText ();
}
}
void SetScoreText ()
{
ScoreText.text = "Score: " + Score.ToString ();
}
And this is my generateEnemy script:
public GameOverManager gameOverManager = null;
[HideInInspector]
public float minBlobSpawnTime = 2;
[HideInInspector]
public float maxBlobSpawnTime = 5;
[HideInInspector]
public bool generateBlobs = true;
[HideInInspector]
public GameObject blobPrefab = null;
[HideInInspector]
public GameObject blobRoot = null;
[HideInInspector]
public float minimumYPosition = -0.425f;
[HideInInspector]
public float maximumYPosition = 0.35f;
[HideInInspector]
public float minDaggerSpawnTime = 2;
[HideInInspector]
public float maxDaggerSpawnTime = 5;
[HideInInspector]
public bool generateDaggers = true;
[HideInInspector]
public GameObject daggerPrefab = null;
[HideInInspector]
public GameObject daggerRoot;
[HideInInspector]
public float minimumXPosition = -11.5f;
[HideInInspector]
public float maximumXPosition = 11.5f;
public Camera camera = null;
// Use this for initialization
void Start ()
{
generateBlobs = ((generateBlobs) && (blobPrefab != null) && (blobRoot != null));
generateDaggers = ((generateDaggers) && (daggerPrefab != null) && (daggerRoot != null));
if (camera == null)
{
Debug.LogError("GenerateEnemy: camera is not set in the inspector. Please set and try again.");
camera = Camera.main;
}
if (gameOverManager == null)
{
Debug.LogError("GenerateEnemy: gameOverManager not set in the inspector. Please set and try again.");
}
if (generateBlobs)
{
StartCoroutine(GenerateRandomEnemy(true, blobPrefab, blobRoot, minBlobSpawnTime, maxBlobSpawnTime));
}
if (generateDaggers)
{
StartCoroutine(GenerateRandomEnemy(false, daggerPrefab, daggerRoot, minDaggerSpawnTime, maxDaggerSpawnTime));
}
}
// Update is called once per frame
void Update ()
{
DestroyOffScreenEnemies();
}
// Spawn an enemy
IEnumerator GenerateRandomEnemy(bool generateOnYAxis, GameObject prefab, GameObject root, float minSpawnTime, float maxSpawnTime)
{
if ((prefab != null) && (gameOverManager != null))
{
if (!gameOverManager.GameIsPaused())
{
GameObject newEnemy = (GameObject) Instantiate(prefab);
newEnemy.transform.SetParent(root.transform, true);
// set this in the prefab instead
// newEnemy.transform.position = new Vector3(newEnemy.transform.parent.position.x, 0.5f, newEnemy.transform.parent.position.z);
// or if you want the y position to be random you need to do something like this
if (generateOnYAxis)
{
newEnemy.transform.position = new Vector3(newEnemy.transform.parent.position.x, Random.Range(minimumYPosition, maximumYPosition), newEnemy.transform.parent.position.z);
}
else
{
newEnemy.transform.position = new Vector3(Random.Range(minimumXPosition, maximumXPosition), newEnemy.transform.parent.position.y, newEnemy.transform.parent.position.z);
}
}
}
yield return new WaitForSeconds(Random.Range(minSpawnTime, maxSpawnTime));
StartCoroutine(GenerateRandomEnemy(generateOnYAxis, prefab, root, minSpawnTime, maxSpawnTime));
}
public void DestroyOffScreenEnemies()
{
GameObject[] enemies = GameObject.FindGameObjectsWithTag("enemy");
if ((enemies.Length > 0) && (camera != null))
{
for (int i = (enemies.Length - 1); i >= 0; i--)
{
// just a precaution
if ((enemies[i] != null) && ((camera.WorldToViewportPoint(enemies[i].transform.position).x > 1.03f) ||
(enemies[i].transform.position.y < -6f)))
{
Destroy(enemies[i]);
}
}
}
}
}
(This script has an generateEnemyCustomEditor script that references it, to show in the inspector)
Thank you :)
First of all, remove the static keyword from public static int movespeed = 20; and use GameObject.Find("ObjectMovementIsAttachedTo").GetComponent<Movement>(); to get the script instance if you want to modify movespeed variable from another script.
And faster when the player collects another 10 points and so on and so
on?
The solution is straight on. Use
if (Score % 10 == 0){
//Increement by number (4) movespeed from Movement script
movement.movespeed += 4;
}
to check if the Score is increased by 10 then increment movespeed by any value you want if that condition is true. It makes sense to put that in the OnTriggerEnter2D function after Score is incremented by 1.
Your new score script:
public class score : MonoBehaviour
{
public int Score;
public Text ScoreText;
private int moveSpeed;
void Start()
{
Score = 0;
SetScoreText();
}
void OnTriggerEnter2D(Collider2D other)
{
if (other.gameObject.CompareTag("Pick Up"))
{
other.gameObject.SetActive(false);
Score = Score + 1;
if (Score % 10 == 0)
{
//Increement by number (4) movespeed from Movement script
moveSpeed += 4;
}
SetScoreText();
}
}
public int getMoveSpeed()
{
return moveSpeed;
}
void SetScoreText()
{
ScoreText.text = "Score: " + Score.ToString();
}
}
Since your Movement script will be instantiated, when you instantiate it, you send its reference to the Player script.
public class Movement : MonoBehaviour
{
public int movespeed = 20;
public Vector3 userDirection = Vector3.right;
score mySpeed;
void Start()
{
//Send Movement instance to the score script
GameObject scoreGameObject = GameObject.Find("GameObjectScoreIsAttachedTo");
mySpeed = scoreGameObject.GetComponent<score>();
}
public void Update()
{
transform.Translate(userDirection * mySpeed.getMoveSpeed() * Time.deltaTime);
}
}