public class playerAttack : MonoBehaviour {
public bool attacking = false;
public Transform Player;
public Transform swordObject_prefab;
Animator anim;
GameObject clone = null;
// Use this for initialization
void Start () {
anim = GetComponent<Animator> ();
}
// Update is called once per frame
void Update () {
if (!attacking && !anim.GetBool ("isSwimming"))
attackCode ();
if (attacking)
coolDown ();
}
void attackCode(){
if (Input.GetButtonDown ("AttackA")) {
Debug.Log ("ATTACK_A");
anim.SetBool ("isAttackingA", true);
attacking = true;
clone = (GameObject)Instantiate(swordObject_prefab, Player.position, Quaternion.identity);
Destroy(clone);
}
if (Input.GetButtonDown ("AttackB")) {
anim.SetBool ("isAttackingB", true);
}
}
void coolDown(){
if (!anim.GetCurrentAnimatorStateInfo(0).IsName ("SwordSwing")) {
attacking = false;
anim.SetBool ("isAttackingA", false);
}
}
Here's my code.
Im trying to get it so when the player presses a button, he swings a sword spawning at the players location. that all works fine, but when i try to remove the sword I get this error in Unity:
InvalidCastException: Cannot cast from source type to destination type.
playerAttack.attackCode () (at Assets/Scripts/Player/playerAttack.cs:33)
playerAttack.Update () (at Assets/Scripts/Player/playerAttack.cs:22)
Thanks for the advice.
By the way, if anyone knows of a better way to use weapons in Unity2D I will be open to suggestions if this way is a cumbersome way of doing things.
You must instantiate prefabs like this.
PrefabTypeObject obj = (TypeOfPrefab)Instantiate(prefab, position, rotation);
or
PrefabTypeObject obj = Instantiate(prefab, position, rotation) as TypeOfPrefab;
otherwise you will get null object or InvalidCastException like now.
Your solution is`
clone = (GameObject)Instantiate(swordObject_prefab.gameObject, Player.position, Quaternion.identity);
Change this line:
public Transform swordObject_prefab;
To this:
public GameObject swordObject_prefab;
But I'm not sure what instantly destroying an object that has been just created is for... Maybe you want to use a delay?
Destroy(clone, 2f); // Destroy clone 2 seconds from now
Related
I've searched around and I just can't get this to work. I think I just don't know the proper syntax, or just doesn't quite grasp the context.
I have a BombDrop script that holds a public int. I got this to work with public static, but Someone said that that is a really bad programming habit and that I should learn encapsulation. Here is what I wrote:
BombDrop script:
<!-- language: c# -->
public class BombDrop : MonoBehaviour {
public GameObject BombPrefab;
//Bombs that the player can drop
public int maxBombs = 1;
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space)){
if(maxBombs > 0){
DropBomb();
//telling in console current bombs
Debug.Log("maxBombs = " + maxBombs);
}
}
}
void DropBomb(){
// remove one bomb from the current maxBombs
maxBombs -= 1;
// spawn bomb prefab
Vector2 pos = transform.position;
pos.x = Mathf.Round(pos.x);
pos.y = Mathf.Round(pos.y);
Instantiate(BombPrefab, pos, Quaternion.identity);
}
}
So I want the Bomb script that's attached to the prefabgameobject Bombprefab to access the maxBombs integer in BombDrop, so that when the bomb is destroyed it adds + one to maxBombs in BombDrop.
And this is the Bomb script that needs the reference.
public class Bomb : MonoBehaviour {
// Time after which the bomb explodes
float time = 3.0f;
// Explosion Prefab
public GameObject explosion;
BoxCollider2D collider;
private BombDrop BombDropScript;
void Awake (){
BombDropScript = GetComponent<BombDrop> ();
}
void Start () {
collider = gameObject.GetComponent<BoxCollider2D> ();
// Call the Explode function after a few seconds
Invoke("Explode", time);
}
void OnTriggerExit2D(Collider2D other){
collider.isTrigger = false;
}
void Explode() {
// Remove Bomb from game
Destroy(gameObject);
// When bomb is destroyed add 1 to the max
// number of bombs you can drop simultaneously .
BombDropScript.maxBombs += 1;
// Spawn Explosion
Instantiate(explosion,
transform.position,
Quaternion.identity);
In the documentation it says that it should be something like
BombDropScript = otherGameObject.GetComponent<BombDrop>();
But that doesn't work. Maybe I just don't understand the syntax here. Is it suppose to say otherGameObject? Cause that doesn't do anything. I still get the error : "Object reference not set do an instance of an object" on my BombDropScript.maxBombs down in the explode()
You need to find the GameObject that contains the script Component that you plan to get a reference to. Make sure the GameObject is already in the scene, or Find will return null.
GameObject g = GameObject.Find("GameObject Name");
Then you can grab the script:
BombDrop bScript = g.GetComponent<BombDrop>();
Then you can access the variables and functions of the Script.
bScript.foo();
I just realized that I answered a very similar question the other day, check here:
Don't know how to get enemy's health
I'll expand a bit on your question since I already answered it.
What your code is doing is saying "Look within my GameObject for a BombDropScript, most of the time the script won't be attached to the same GameObject.
Also use a setter and getter for maxBombs.
public class BombDrop : MonoBehaviour
{
public void setMaxBombs(int amount)
{
maxBombs += amount;
}
public int getMaxBombs()
{
return maxBombs;
}
}
use it in start instead of awake and dont use Destroy(gameObject); you are destroying your game Object then you want something from it
void Start () {
BombDropScript =gameObject.GetComponent<BombDrop> ();
collider = gameObject.GetComponent<BoxCollider2D> ();
// Call the Explode function after a few seconds
Invoke("Explode", time);
}
void Explode() {
//..
//..
//at last
Destroy(gameObject);
}
if you want to access a script in another gameObject you should assign the game object via inspector and access it like that
public gameObject another;
void Start () {
BombDropScript =another.GetComponent<BombDrop> ();
}
Can Use this :
entBombDropScript.maxBombs += 1;
Before :
Destroy(gameObject);
I just want to say that you can increase the maxBombs value before Destroying the game object. it is necessary because, if you destroy game object first and then increases the value so at that time the reference of your script BombDropScript will be gone and you can not modify the value's in it.
I am working on a tutorial and the "Side objectives" that they don't walk you through to try and get a feel for it.
So, the way things work at this time is that there is the Player object. The player object has the player script.
public class Player : MonoBehaviour {
private Animator anim;//reference for animator component
private Rigidbody rigidBody;//reference to component for rigidbody
private AudioSource audioSource;
[SerializeField] private float force = 100f;
[SerializeField] private AudioClip sfxJump;
[SerializeField] private AudioClip sfxDeath;
}
void Awake() {//these are assertions that will ensure when writing the cocde that you wont miss them. use for team work.
Assert.IsNotNull (sfxJump);
Assert.IsNotNull (sfxDeath);
}
private bool jump = false; //check for jump
// Use this for initialization
void Start () {//all these are getting components at the start to update them as the code goes onwards.
anim = GetComponent<Animator> ();
rigidBody = GetComponent<Rigidbody> ();
audioSource = GetComponent<AudioSource> ();
positionStart = GetComponent<Transform> ();
}
// Update is called once per frame
void Update () {
if (!GameManager.instance.GameOver && GameManager.instance.GameStarted) {
if (Input.GetMouseButtonDown (0)) {//if press mouse key
GameManager.instance.PlayerStarted ();
rigidBody.useGravity = true;//turn gravity on for component so it goes back down.
audioSource.PlayOneShot (sfxJump);
anim.Play ("jump");//play the animation jump
jump = true;
}
}
}
//Fixed update for physics
void FixedUpdate() {//use this for any physics due to frame rate. time.deltatime wont cut it.
if (jump == true) {//if we are jumping, turn the jump off.
jump = false;
rigidBody.velocity = new Vector2 (0, 0);//turn velocity to 0 so speed doesnt increase while falling
rigidBody.AddForce (new Vector2 (0, force), ForceMode.Impulse);//give a impulse upwards.
}
//print (rigidBody.velocity.y);//print velocity. turn this shit off.
}
//Code to create collision with obstacles and then die and fall through the floor.
void OnCollisionEnter (Collision collision) {//call collision component
if (collision.gameObject.tag == "obstacle") {//if you slap a tagged object called obstacle
rigidBody.AddForce (new Vector2 (-50, 20), ForceMode.Impulse);//add force to push back cause you ded
rigidBody.detectCollisions = false;//turn off the ability to detect collisions
audioSource.PlayOneShot (sfxDeath);//play ded noise
GameManager.instance.PlayerCollided ();
GameManager.instance.Restart ();
}
}
}
The game manager, of course exists in the camera to control the states of the game.
public static GameManager instance = null;//only one in memory. only one gamemanager ever.
[SerializeField] private GameObject mainMenu;
[SerializeField] private GameObject replayBtn;
[SerializeField] private GameObject playBtn;
private bool gameEnd = false;
private bool gameStarted = false;
private bool playerActive = false;
private bool gameOver = false;
//getters setters start
public bool PlayerActive {
get { return playerActive; }
}
public bool GameOver {
get { return gameOver; }
}
public bool GameStarted {
get { return gameStarted; }
}
//to create a state between gameover and main menu
public bool GameEnd {
get {return gameEnd; }
}
//getter setters end
void Awake(){
if (instance == null) {
instance = this;//this means the current instance. one instance of this class.
} else if (instance != this) {//if a seocnd one gets created destroy that bitch.
Destroy (gameObject);
}
DontDestroyOnLoad (gameObject);//allows a game object to persist between the scene. Dont need with one scene.
}
// Use this for initialization
void Start () {
replayBtn.SetActive (false);
}
// Update is called once per frame
void Update () {
}
public void PlayerCollided(){
gameOver = true;
}
public void PlayerStarted(){
playerActive = true;
}
public void EnterGame (){
mainMenu.SetActive(false);
gameStarted = true;
}
//When player dies start coroutine Hold.
public void Restart (){
StartCoroutine (Holdexit());
}
//The hole Coroutine waits 2 seconds then turns on the menu.
IEnumerator Holdexit (){
yield return new WaitForSeconds (2);
playBtn.SetActive (false);
replayBtn.SetActive (true);
mainMenu.SetActive (true);
//add character movement to location
}
}
So, When the player hits the object he dies, loses the ability to touch colliders and falls through the map, after 2 seconds the main menu comes back and the play button is replaced with a replay button. When I press replay, I need to reset the position, the state of the game, and the ability to collide.
I Tried all kinds of things. I did a get component for transform and tried to call it in the coroutine and then set it there, but I couldnt figure it out. I tried just changing the position after etc after the game managers state to restart gets called but the position change occurs before the main menu comes back on because its not being used in the coroutine.
Once thing I though would work, is i created a new method,
public void PlayerReset (){
if (GameManager.instance.Restart()){
//put new changes to player here.
}
}
The errors I came across here was I could not convert type void to bool, I assume its cause I was trying to say if the restart instance existed then function, but the way the restart function is created isn't true or false its just - is.
I really appreciate any help. I think what im going to try and do is make another script to the side and have it call the class of player to pull the components, and then manipulate them from there maybe. AUGH. So confusing. Lmao.
You can just set a public Transform variable on your object, and then in the inspector, drag the selected transform you want to call to that variable.
When that's done, you can use that transform variable in any way you want.
You can save the start position of the player in GameManager as it's a singleton. So, you set the position of the player to this saved position after restart.
You'll need to reinitialize all the variables(i.e. gameEnd,gameStarted, playerActive, gameOver etc.) on restart.
if(GameManager.instance.Restart()) will not work, as Restart() returns void not a boolean.
I'm making a Shooting game for VR in Unity and I'm unable to shoot the object. Everytime I point the object, it throws this error. I tried other posts with same error but they does not answer my problem.
ERROR-
ArgumentException: The Object you want to instantiate is null.
UnityEngine.Object.CheckNullArgument (System.Object arg, System.String message) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:239)
UnityEngine.Object.Instantiate (UnityEngine.Object original) (at /Users/builduser/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:176)
playerScript+c__Iterator0.MoveNext () (at Assets/Scripts/playerScript.cs:30)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at /Users/builduser/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)
UnityEngine.MonoBehaviour:StartCoroutine(String)
playerScript:Update() (at Assets/Scripts/playerScript.cs:61)
I'm attaching an image for better understanding of the scene. The yellow cubes are the Shooting Object.
Here's the code I'm using-
using UnityEngine;
using System.Collections;
public class playerScript : MonoBehaviour {
//declare GameObjects and create isShooting boolean.
private GameObject gun;
private GameObject spawnPoint;
private bool isShooting;
// Use this for initialization
void Start () {
//only needed for IOS
Application.targetFrameRate = 60;
//create references to gun and bullet spawnPoint objects
gun = gameObject.transform.GetChild (0).gameObject;
spawnPoint = gun.transform.GetChild (0).gameObject;
//set isShooting bool to default of false
isShooting = false;
}
//Shoot function is IEnumerator so we can delay for seconds
IEnumerator Shoot() {
//set is shooting to true so we can't shoot continuosly
isShooting = true;
//instantiate the bullet
GameObject bullet = Instantiate(Resources.Load("bullet", typeof(GameObject))) as GameObject;
//Get the bullet's rigid body component and set its position and rotation equal to that of the spawnPoint
Rigidbody rb = bullet.GetComponent<Rigidbody>();
bullet.transform.rotation = spawnPoint.transform.rotation;
bullet.transform.position = spawnPoint.transform.position;
//add force to the bullet in the direction of the spawnPoint's forward vector
rb.AddForce(spawnPoint.transform.forward * 500f);
//play the gun shot sound and gun animation
GetComponent<AudioSource>().Play ();
gun.GetComponent<Animation>().Play ();
//destroy the bullet after 1 second
Destroy (bullet, 1);
//wait for 1 second and set isShooting to false so we can shoot again
yield return new WaitForSeconds (1f);
isShooting = false;
}
// Update is called once per frame
void Update () {
//declare a new RayCastHit
RaycastHit hit;
//draw the ray for debuging purposes (will only show up in scene view)
Debug.DrawRay(spawnPoint.transform.position, spawnPoint.transform.forward, Color.green);
//cast a ray from the spawnpoint in the direction of its forward vector
if (Physics.Raycast(spawnPoint.transform.position, spawnPoint.transform.forward, out hit, 100)){
//if the raycast hits any game object where its name contains "zombie" and we aren't already shooting we will start the shooting coroutine
if (hit.collider.name.Contains("Shooting Object")) {
if (!isShooting) {
StartCoroutine ("Shoot");
}
}
}
}
}
The problem is this line
GameObject bullet = Instantiate(Resources.Load("bullet", typeof(GameObject))) as GameObject;
It can't find the resource "bullet." Make sure you've deployed it into the right folder.
I'm trying to force Unity to spawn a gameobject every second with a coroutine but I am getting the errors cs1502 & cs1503. (sorry if this is a stupid syntax error)
public class BossCannon : MonoBehaviour
{
public BossBullet BossAmmo;
public float Force;
public bool trigger = false;
void Start ()
{
}
void Update()
{
if (trigger == true)
ShootBullet();
}
void ShotPattern()
{
while (true)
{
StartCoroutine(Shoot);
}
}
public IEnumerator Shoot()
{
trigger = false;
yield return new WaitForSeconds(1f); //Waits 1 second
GameObject b = Instantiate(BossAmmo.gameObject, transform.position, transform.rotation) as GameObject;
trigger = true;
}
}
Try passing the Transform to Instantiate instead of the GameObject.
Transform b = Instantiate(BossAmmo.transform, transform.position, transform.rotation) as Transform;
You are also starting your coroutine wrong. Try this:
StartCoroutine(Shoot());
The errors you are getting are Invalid Parameter errors. A method is expecting one type, and you are passing another type.
It might be helpful to post the full errors you are getting when you compile.
One more note: while(true) is generally a terrible thing to do. When you do get this running, I suspect Unity will suddenly lock up on you.
I'm having a bit of trouble getting the Vector3 wayPointPosition to my other script called Walking and changing it into the Transform target. My troubles lie in the fact that I'm trying to grab this dynamic variable from WayPointPositioner (it changes depending on what object is clicked in the stage and whether the player overlaps with this waypoint) and import and use it in another script.
Below is the code I'm using.
WayPointPositioner
using UnityEngine;
using System.Collections;
public class WayPointPositioner : MonoBehaviour {
public Vector3 wayPointPosition = Vector3.zero;
private bool checkPlayerWaypointCollision;
void Start()
{
}
void OnTriggerStay2D (Collider2D other)
{
// Check if collision is occuring with player character.
if (other.gameObject.name == "Player")
{
checkPlayerWaypointCollision = true;
}
else
{
checkPlayerWaypointCollision = false;
}
}
//Check if object is clicked
void OnMouseDown ()
{
// If its the player, then return a new position for the player to move to for walking
// Else debug that its not so
if (checkPlayerWaypointCollision == false)
{
Debug.Log ("Object not colliding and retrieving position");
Debug.Log (wayPointPosition);
Debug.Log (gameObject.name);
wayPointPosition = new Vector3 (transform.position.x, transform.position.y, 10);
wayPointPosition = Camera.main.ScreenToWorldPoint(wayPointPosition);
}
else
{
Debug.Log ("Object is colliding, no movement needed");
}
}
}
Walking
using UnityEngine;
using System.Collections;
public class Walking : MonoBehaviour {
public Transform target;
public WayPointPositioner wayPointPosition;
public bool walkingAnimation = false;
private Animator anim;
void Awake ()
{
anim = GetComponent<Animator> ();
wayPointPosition = GameObject.FindGameObjectWithTag ("Waypoint").GetComponent<WayPointPositioner> ();
}
void Start ()
{
}
void Update ()
{
Debug.Log ("This is in Walking, WPP =" + wayPointPosition);
}
}
As you can see I'm trying to import the wayPointPosition from the seperate class which is attached to the gameobjects called "Waypoint" (In my current layout those are empty objects with circle colliders to check if they have been clicked). However when I run this, I am not getting my Vector, but I'm getting the name of the last waypoint in the hierarchy (I have currently 6 waypoints which can be clicked) and not a Vector.
I hope someone is able to help me / point out my mistake. I'm still learning C# so I might've made a strange / odd assumption which isn't working.
Kind regards,
Veraduxxz.
It looks like invoking GameObject.FindGameObjectWithTag("Waypoint").GetComponent<WayPointPositioner>(); retrieves a component from the game object which matches the specified tag, as well as a type argument T which derives from MonoBehavior.
Calling this should actually give you an instance of your WayPointPositioner class, which you can then pass to whichever methods you want, and interact with its Vector3 however you would like.