I get the null reference exception error when trying to change the boolean to right (or left in that regard). My prefab should spawn at FirepointL.
My script does recognise the prefeb as it does not return a Null for finding the prefab (tested this).
I made sure my boolean was set to Public and i had dropped all the GameObjects to their designated places in the Inspector.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMovement : MonoBehaviour
{
public GameObject bullet;
private Rigidbody2D myRigidbody;
private float speed = 15;
private bool facingRight;
private bool ground = false;
private float jump = 23;
// Start is called before the first frame update
void Start()
{
facingRight = true;
myRigidbody = GetComponent<Rigidbody2D>();
}
// Update is called once per frame
void FixedUpdate()
{
float horizontal = Input.GetAxis("Horizontal");
bullet = GameObject.FindGameObjectWithTag("Button");
Movement(horizontal);
Flip(horizontal);
if (Input.GetKey("w"))
{
if (ground)
{
GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jump);
}
}
// this is the part that returns the error
if (facingRight == true)
{
bullet.GetComponent<weapon>().right = true;
}
if (facingRight == false)
{
bullet.GetComponent<weapon>().right = false;
}
}
void OnTriggerEnter2D()
{
ground = true;
}
void OnTriggerExit2D()
{
ground = false;
}
private void Movement(float horizontal)
{
myRigidbody.velocity = new Vector2(horizontal * speed,myRigidbody.velocity.y);
}
private void Flip(float horizontal)
{
if (horizontal > 0 && !facingRight || horizontal < 0 && facingRight)
{
facingRight = !facingRight;
Vector3 theScale = transform.localScale;
theScale.x *= -1;
transform.localScale = theScale;
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class weapon : MonoBehaviour
{
// Start is called before the first frame update
public bool right;
public Transform firepointR;
public Transform firepointL;
public GameObject bulletPrefab;
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown("space"))
{
Debug.Log("It's the space key");
Shoot();
}
}
void Shoot()
{
if (right == true)
{
Instantiate(bulletPrefab, firepointR.position, firepointR.rotation);
}
if(right == false)
{
Instantiate(bulletPrefab, firepointL.position, firepointL.rotation);
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class bullet : MonoBehaviour
{
public float speed = 20;
public Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
rb.velocity = transform.right * speed;
}
// Update is called once per frame
void Update()
{
}
}
Not sure if it's the exact issue, but there's a problem in PlayerMovement class. When you retrieve bullet you assume that an object with Button tag is present.
In my opinion, you should check for it with
// this is the part that returns the error
if (bullet && facingRight == true)
{
bullet.GetComponent<weapon>().right = true;
}
if (bullet && facingRight == false)
{
bullet.GetComponent<weapon>().right = false;
}
I think there is a problem with naming conventions. You are trying to find out a bullet whose name is "Button" but when you are instantiating the gameobject, it names it to something like Button(clone).
One solution that comes in my mind:
1st step:
Make a public static variable inside PlayerMovement script.
public static PlayerMovement Instance;
private void Awake()
{
Instance = this;
}
Set its value inside the awake function so that you can call it from anywhere.
2nd step:
I modified the shoot function.
void Shoot()
{
GameObject _firePosition = right == true ? firepointR : firepointL;
PlayerMovement.Instance.bullet = Instantiate(bulletPrefab, _firePosition.position, _firePosition.rotation); // we are setting the reference on runtime whenever we spawn a new bullet.
}
3rd Step:
Remove this line from PlayerMovement script as it is not needed now.
bullet = GameObject.FindGameObjectWithTag("Button");
PS: Code will not work if you don't follow step 3. Let me know if it helps. :)
Related
So . I work at a 2d game in unity and I have some problems with some mechanics and i really need some help from you guys. All I want to do is to make my character hand to stop and grab a object. When I press E the animation of the hand start and have a collider for each frame, in case that the hand collide with a closer object, the animation to stop at that frame. I have a week since I try to figure it out. If you want to help me we can do it on discord. I will put the codes here, maybe the reason that I can't to what I want to do is very clear and I dont see it.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class showHide : MonoBehaviour
{
[SerializeField]
GameObject hand;
private Animator freeze;
public bool touch = false;
private bool ok = true;
// Start is called before the first frame update
void Start()
{
freeze = GetComponent<Animator>();
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.E) && ok == true)
{
freeze.Play("Follower");
StartCoroutine(show());
}
}
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "box")
{
StartCoroutine(colliderShow());
}
}
private IEnumerator show()
{
ok = false;
hand.SetActive(true);
yield return new WaitForSeconds(4f);
hand.SetActive(false);
ok = true;
}
private IEnumerator colliderShow()
{
touch = true;
print(touch);
yield return new WaitForSeconds(4f);
touch = false;
print(touch);
}
private void FreezeAniamtion()
{
freeze.speed = 0f;
StartCoroutine(waitTime());
}
private IEnumerator waitTime()
{
yield return new WaitForSeconds(0f);
freeze.speed = 1f;
}
}
This is the code that activate and deactivate my hand object , including the animation .
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class facingScript : MonoBehaviour
{
private SpriteRenderer render;
private Camera mainCam;
private Vector3 mousePos;
private Animator aniHand;
public bool atinge;
void Start()
{
mainCam = Camera.main;
render = GetComponent<SpriteRenderer>();
aniHand = GetComponent<Animator>();
gameObject.SetActive(false);
}
// Update is called once per frame
void Update()
{
mousePos = Input.mousePosition;
mousePos = mainCam.ScreenToWorldPoint(
new Vector3(mousePos.x, mousePos.y, mainCam.transform.position.z - transform.position.z)
);
Vector3 rotation = mousePos - transform.position;
if (rotation.x > 0)
render.flipY = true;
else
render.flipY = false;
if (atinge == false)
aniHand.speed = 1f;
Debug.Log(aniHand.speed);
}
// Collision with objects
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag == "box")
{
atinge = true;
aniHand.speed = 0f;
StartCoroutine(freezingTime());
}
}
private IEnumerator freezingTime()
{
yield return new WaitForSeconds(4f);
atinge = false;
}
// No collision with any object
private void FreezeAnimation()
{
aniHand.speed = 0f;
StartCoroutine(waitTime());
}
private IEnumerator waitTime()
{
yield return new WaitForSeconds(0f);
aniHand.speed = 1f;
}
}
This is the hand component script . When the hand don't collide with anything the object is deactivated . The FreezeAnimation() is a event at the last frame. I tryed to do a collider animation for the showHide component that will be exact with the hand animation collider for each frame to check if the hand collide in the showHide script and if it collide to have a 4 seconds of waiting with the hand at that position.
I really tryed my best but I really can't figure it out.
I have a problem in unity , the player mouvement is going good until I add an animation the player stop moving even if I press the keyboard keys,when I remove the animator compenent the player move normaly without problems !
I tried separate the animation script from the movement script and still theame problem , I don't think that the problem is comming from the code
playerAnimation code :
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerAnim : MonoBehaviour
{
Animator anim;
Rigidbody2D rb;
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
anim = gameObject.GetComponent<Animator>();
}
void FixedUpdate()
{
if (rb.velocity.x == 0)
anim.SetBool("isRunning", false);
else
anim.SetBool("isRunning", true);
if (rb.velocity.y > 0)
anim.SetBool("isJumping", true);
else
anim.SetBool("isJumping", false);
}
}
playerMovement script
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class playerControl : MonoBehaviour
{
Rigidbody2D rb;
private float horizontal;
public float runSpeed;
public float jumpPower;
public bool inTheGround;
private SpriteRenderer sp;
Animator anim;
// Start is called before the first frame update
void Start()
{
rb = gameObject.GetComponent<Rigidbody2D>();
sp = gameObject.GetComponent<SpriteRenderer>();
anim = gameObject.GetComponent<Animator>();
}
private void Update()
{
horizontal = Input.GetAxisRaw("Horizontal");
}
private void FixedUpdate()
{
rb.velocity = new Vector2(horizontal * runSpeed,
rb.velocity.y);
if (Input.GetButton("Jump")&& inTheGround)
{
rb.velocity = new Vector2(rb.velocity.x,jumpPower);
}
flipping();
Debug.Log(rb.velocity.x);
}
private void OnCollisionEnter2D(Collision2D other)
{
if (other.gameObject.CompareTag("ground"))
inTheGround = true;
}
private void OnCollisionExit2D(Collision2D other)
{
if
(other.gameObject.CompareTag("ground")&&rb.velocity.y>0.1)
inTheGround = false;
}
void flipping()
{
if (Input.GetKey(KeyCode.RightArrow))
sp.flipX = false;
if (Input.GetKey(KeyCode.LeftArrow))
sp.flipX = true;
}
}
Check if Apply Root Motion on Animator Component is set to false. This setting can overwrite your changes of the object's position over time. if not - can you please provide more information, perfectly a screenshot of your player components, and Animator Controller.
The script is attached to empty gameobject
At this line i'm using the mouse left button to fire a bullet one time.
If i'm using a break point it will shot one bullet once. but if i'm not using a break point it will shot two bullets in a row one after the other.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Cinemachine;
public class Shooting : MonoBehaviour
{
public CinemachineVirtualCamera cmf;
[Header("Main")]
public Rigidbody bulletPrefab;
public float launchForce = 700f;
public bool automaticFire = false;
public float bulletDestructionTime;
public bool go = false;
[Space(5)]
[Header("Slow Down")]
public float maxDrag;
public float bulletSpeed;
public bool bulletsSlowDown = false;
public bool overAllSlowdown = false;
[Range(0, 1f)]
public float slowdownAll = 1f;
public List<Transform> firePoints = new List<Transform>();
public Animator anim;
private void Start()
{
if (anim != null)
{
anim.SetBool("Shooting", true);
}
}
public void Update()
{
if (overAllSlowdown == true)
{
Time.timeScale = slowdownAll;
}
if (firePoints.Count > 0))
{
for (int i = 0; i < firePoints.Count; i++)
{
if (Input.GetMouseButton(0))
{
anim.SetTrigger("Shoot");
}
if (Input.GetMouseButton(1))
{
cmf.enabled = false;
}
if (go)
{
LaunchProjectile(firePoints[i]);
go = false;
}
}
}
}
private void LaunchProjectile(Transform firePoint)
{
Rigidbody projectileInstance = Instantiate(
bulletPrefab,
firePoint.position,
firePoint.rotation);
projectileInstance.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
cmf.enabled = true;
cmf.Follow = projectileInstance.transform;
cmf.LookAt = projectileInstance.transform;
projectileInstance.AddForce(new Vector3(0, 0, 1) * launchForce);
if (bulletsSlowDown == true)
{
if (projectileInstance != null)
{
StartCoroutine(AddDrag(maxDrag, bulletSpeed, projectileInstance));
}
}
}
IEnumerator AddDrag(float maxDrag, float bulletSpeed, Rigidbody rb)
{
if (rb != null)
{
float current_drag = 0;
while (current_drag < maxDrag)
{
current_drag += Time.deltaTime * bulletSpeed;
rb.drag = current_drag;
yield return null;
}
rb.velocity = Vector3.zero;
rb.angularVelocity = Vector3.zero;
rb.drag = 0;
}
}
}
This script is attached to my player with animator and i'm using this method to reference event i added to animation in the animator controller. when the event happens the variable bool flag go is set to true.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ThrowObject : MonoBehaviour
{
public Shooting shooting;
public void ThrowEvent()
{
shooting.go = true;
}
}
This is a screenshot of the animator controller.
I added a new state name Throwing with two transitions from and to the Grounded state.
The Grounded state is playing idle animation.
In the transition from the Grounded to the Throwing i added a condition name Shoot type trigger.
In the transition from the Throwing state to the Grounded there is no any conditions.
Afaik animator triggers are stackable!
So since you call this in a for loop it might happen that it adds multiple triggers at once but each transition only consumes one at a time!
What I ended up using in combination with triggers in an animator is this script
public class AnimatorTriggerResetter : StateMachineBehaviour
{
override public void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
foreach(var p in animator.parameters)
{
if (p.type == AnimatorControllerParameterType.Trigger)
{
animator.ResetTrigger(p.name);
}
}
}
}
attach this to no specific state at all but directly to the Basic layer of your AnimatorController itself => It is called for each and every state that is entered => resets all existing triggers.
In your specific case though, why not rather pull the general calls out of the loop and rather make it
if (firePoints.Count > 0 && go)
{
if (Input.GetMouseButton(0))
{
anim.SetTrigger("Shoot");
}
if (Input.GetMouseButton(1))
{
cmf.enabled = false;
}
for (int i = 0; i < firePoints.Count; i++)
{
LaunchProjectile(firePoints[i]);
}
go = false;
}
I'm working on some animations for a game I'm working on (Still in the very early stages, and new to coding). Right now I'm trying to use a bool to detect whether or not the player is jumping, and then if it returns true, then the animation will play.
Character Controller:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Character2dController : MonoBehaviour
{
public float MovementSpeed = 8;
public float JumpForce = 5;
public Transform feet;
public bool isJumping;
private Rigidbody2D rb;
public LayerMask groundLayers;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody2D>();
isJumping = false;
}
// Update is called once per frame
void Update()
{
Jump();
//LR movement
var movement = Input.GetAxis("Horizontal");
transform.position += new Vector3(movement, 0, 0) * Time.deltaTime * MovementSpeed;
isJumping = false;
}
//Jumping
void Jump()
{
if (Input.GetButtonDown("Jump") && IsGrounded())
{
isJumping = true;
rb.AddForce(new Vector2(0, JumpForce), ForceMode2D.Impulse);
}
}
//Grounding
public bool IsGrounded()
{
Collider2D groundCheck = Physics2D.OverlapCircle(feet.position, 0.5f, groundLayers);
if (groundCheck.gameObject != null)
{
return true;
}
return false;
}
}
CharacterAnimation:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CharacterAnimation : MonoBehaviour
{
private Animator anim;
private bool isJumping;
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
isJumping = GetComponent<Character2dController>().isJumping;
isJumping = false;
}
// Update is called once per frame
void Update()
{
//Walking Anim
if (Input.GetKey("a") || Input.GetKey("d"))
{
anim.SetBool("isWalking", true);
}
else
{
anim.SetBool("isWalking", false);
}
//Character flipping
if (Input.GetKey("a"))
{
transform.localScale = new Vector3(-1, 1, 1);
}
if (Input.GetKey("d"))
{
transform.localScale = new Vector3(1, 1, 1);
}
if(isJumping == true)
{
anim.SetTrigger("Up");
}
}
}
However, the isJumping bool never seems to change to true, and thus the animation will never play. I've tried putting it in a variety of places within the character controller code, but none of them seem to work. I'm wondering if there's something I'm doing wrong or if I should just use a different way to animate the player jumping.
Again I'm fairly new to coding so if there's anything that's wrong feel free to let me know. Thanks!
public class CharacterAnimation : MonoBehaviour
{
private Animator anim;
private bool isJumping;
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
isJumping = GetComponent<Character2dController>().isJumping;//assigns value
isJumping = false;
}
.
.
.
The line that I commented only assigns the value of isJumping variable in the Character2dController class, to the isJumping variable in your CharacterAnimation class. Therefore when you change the isJumping variable in the Character2dController class, the isJumping variable in the CharacterAnimation class is not updated.
So instead, you could check the isJumping variable from the Character2dController class:
public class CharacterAnimation : MonoBehaviour
{
private Animator anim;
private Character2dController character2dController;
private Rigidbody2D rb;
// Start is called before the first frame update
void Start()
{
anim = GetComponent<Animator>();
character2dController = GetComponent<Character2dController>();//now we are holding a reference to the Character2dController component
}
// your other code here
if(character2dController.isJumping == true)
{
anim.SetTrigger("Up");
}
Also, in the Character2dController, you are setting isJumping to false at every frame, which is I believe not what you want to do. Instead of setting it directly to false, you should check whether you are grounded or not, and update the isJumping accordingly.
Try to get inputs with Keycode. like this:
if (Input.GetKey(KeyCode.A)) {
Debug.LogError("A");
}
You can try to Debug.LogError("Message on key pressed") to be sure you are capturing the input.
If you are sure you are capturing your input properly you can indicate that in your question so that a possible helper knows that to dive deep into the code.
Also post any console error you might be getting.
Also be sure that the parameters that control the animation are set, for example in the anim.SetBool("isWalking", true); you are able to check in the editor itself if setting the parameter the animation takes place.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VideoSettings : MonoBehaviour
{
public GameObject VideoAudioCube;
public float speed = 5f;
public float distanceToMove;
private bool keepMoving = true;
private Vector3 startPos;
private Vector3 endPos;
private bool moveBack = false;
private void Start()
{
startPos = VideoAudioCube.transform.position;
}
private void OnMouseDown()
{
if (keepMoving == true)
{
if (transform.GetComponentInChildren<TextMesh>().text == "Video")
{
StartCoroutine(MoveVideo());
}
keepMoving = false;
}
}
private IEnumerator MoveVideo()
{
endPos = VideoAudioCube.transform.position - VideoAudioCube.transform.right * distanceToMove;
if (moveBack == false)
{
while (VideoAudioCube.transform.position != endPos)
{
VideoAudioCube.transform.position =
Vector3.MoveTowards(VideoAudioCube.transform.position, endPos, Time.deltaTime * speed);
yield return null;
}
}
keepMoving = true;
moveBack = true;
}
}
In the screenshot the script is attached to the New Game cube. And the script is moving the empty GameObject parent :
The camera is facing the Buttons :
And this is after the GameObject moved for some reason I see that all the objects under Buttons start moving to the right :
It looks like the whole Buttons object is moving to the right but it's not it's only the children under buttons that move :
If I'm not using the script at all the children objects under Buttons will not move. I can't figure out what make the objects to start moving after the GameObject has finished moving.