C# Help with 2D project

Hello guys can any of you help me please? This is my first attempt at C# scripting and I'm having a bit of trouble with the script between the /* */. It should instantiate a cannon ball with a smoke effect, and according to my knowledge of JavaScript this script should work (if I'm converting it right). Also how can I stop the rotation on a key press?

using UnityEngine;
using System.Collections;

public class StartingPoint : MonoBehaviour {

public float rotSpeed = 80;
public GameObject cannon;
public float launchForce = 100;
//public GameObject fireEffect;
public GameObject spawn;
public GameObject bullet;

private GameObject reFire;
private GameObject spawnedObject;
private Rigidbody2D body;
//private float startTime;

void Start () {

//startTime = Time.time;

}

void Update () {

cannon.transform.localEulerAngles = new Vector3(0, 0,
Mathf.PingPong(Time.time * rotSpeed, 90));

if (Input.GetKeyDown(KeyCode.Space) == true) {
Debug.Log("Fire Gun");
/*reFire = Instantiate (fireEffect, spawn.transform.position,
spawn.transform.rotation);
spawnedObject = Instantiate (bullet, spawn.transform.position,
spawn.transform.rotation);
body = spawnedObject.GetComponent(Rigidbody2D);
body.AddForce (spawn.transform.position * launchForce, ForceMode2D.Impulse);*/
}

}

}

Any help would be great.

Comments

  • edited
    body = spawnedObject.GetComponent(Rigidbody2D)
    That's the problem.
    C# is strongly typed.
    Use:
    body = spawnedObject.GetComponent<Rigidbody2D>();
    The text between the angle brackets tells the GetComponent method what component type you're looking for.
    You can also do spawnedObject.GetComponent(typeof(Rigidbody2D)) as Rigidbody2D; but that is ugly.

    To stop rotation, goto your prefab with the Rigidbody2D component, and look in the "constraints" section. Tick the "Freeze Rotation" box. This can also be done through code.
  • roguecode said:
    Use:
    body = spawnedObject.GetComponent<Rigidbody2D>();
    The text between the angle brackets tells the GetComponent method what component type you're looking for.
    You can also do spawnedObject.GetComponent(typeof(Rigidbody2D)) as Rigidbody2D; but that is ugly.
    Another option would be an explicit cast, seeing as the non-templated GetComponent() returns a straight-up GameObject:

    body = (RigidBody2D)spawnedobject.GetComponent(RigidBody2D);
  • edited
    True.
    Although sometimes you don't know if the component you're looking for is there. The (type) cast with throw an exception, so you can do this instead:
    var body = spawnedObject.GetComponent(typeof(Rigidbody2D)) as Rigidbody2D;
    if (body != null)
    {
    // Stuff with body
    }

    And the null check will be much faster than handling an exception.

    That being said, I'm not sure of any reason to ever not use
    GetComponent<T>()
    Thanked by 1Eric
  • As for the smoke effect, you could also rather use a particle system, and then just play that everytime space is hit. That way you only have to instantiate the bullet. There are some neat smoke puffs and fire in the standard assets pack, or you can make your own to fit in with your art style.
  • Ok thanks for the help. With regards to the rotation, I want the ping pong rotation to stop when I press a button. Any ideas?
  • edited
    Sorry, didn't see this earlier.

    Rigidbody2D body;
    
      void Start()
      {
        body = GetComponent<Rigidbody2D>();
      }
    
      void Update()
      {
        if (Input.GetKeyDown(KeyCode.Space))
          body.freezeRotation = true;
      }

    Side note, notice that you don't need == true in your if statement since GetKeyDown already returns a bool.
    So by adding == true what you're really saying is if (true == true) which is always redundant since it always equates to what GetKeyDown returned anyway.
  • I've attached my whole script for you to look at and maybe help me with my problem. I've commented in my questions.

    using UnityEngine;
    using System.Collections;

    public class StartingPoint : MonoBehaviour {

    public float rotSpeed = 80;
    public GameObject cannon;
    public float launchForce;
    public GameObject spawn;
    public GameObject bullet;
    public Rigidbody cannonBody;

    private GameObject spawnedObject;
    private Rigidbody body;
    private float tel;
    //private float startTime;
    private int launchUpgrade;

    void Start () {

    //startTime = Time.time;
    tel = 0;

    }

    void Update () {
    // This object rotates and I want it to stop when I press space.
    // How can I tell the mathf.pingpong to rotate between 2 set rotations?
    cannon.transform.localEulerAngles = new Vector3(0, 0,
    Mathf.PingPong(Time.time * rotSpeed, 90));

    if (Input.GetKeyDown(KeyCode.Space) && tel == 0) {
    Debug.Log("Fire Gun");
    spawnedObject = (GameObject)Instantiate (bullet, spawn.transform.position,
    spawn.transform.rotation);
    body = spawnedObject.GetComponent<Rigidbody>();
    body.AddForce ( - spawn.transform.position * launchForce,
    ForceMode.Impulse);
    tel = 1;
    //attempt at implamenting the freezeRotation.
    cannonBody.freezeRotation = true;
    }

    }

    }
  • You can have your rotation move between two set angles by adding an offset, or by rotating the entire gameobject. At the moment you're pingponging between 0 and 90 degrees around Z. To make that 90 and 180 degrees around Z, your code would look like this:
    cannon.transform.localEulerAngles = new Vector3(0, 0, 90f + Mathf.PingPong(Time.time * rotSpeed, 90f));


    It should be trivial to change the offset to a variable and set it to whatever you want. Alternatively, you can simply rotate the StartingPoint gameobject, provided that Cannon is a child of it in the hierarchy. Because you're using localEulerAngles it'll rotate relative to its parent transform and you'll be good to go.

    Finally, the logic of making the cannon stop rotating isn't too complex: Just don't tell it to rotate if you don't want it to!

    private bool cannonRotating;
    
    void Start()
    {
        cannonRotating = true;
    }
    
    void Update()
    {
        if (cannonRotating)
        {
            cannon.transform.localEulerAngles = new Vector3(0, 0, 90f + Mathf.PingPong(Time.time * rotSpeed, 90f));
        }
    }


    Now you can just set cannonRotating to false and the cannon will stop rotating completely. When and how you set cannonRotating is entirely up to you :) Messing with rotation freezing on a rigidbody is only really useful if that gameobject's movement is being controlled by the rigidbody, in your example you're setting rotation manually and bypassing the rigidbody completely.
  • How do I stop this loop from crashing unity?

    while (launchUpgrade > 0){
    cannonRotating = true;
    cannon.transform.localEulerAngles = new Vector3(0, 0, - 90 +
    Mathf.PingPong(Time.time * rotSpeed, 60));
    }
  • Just a design pattern suggestion that will help you in the long run: ideally you want to create a "rotator" behaviour (instead of using a boolean and if statement) that you can enable/disable as needed, which would get rid of unnecessary update calls when rotating is false.
  • How do I stop this loop from crashing unity?

    while (launchUpgrade > 0){
    cannonRotating = true;
    cannon.transform.localEulerAngles = new Vector3(0, 0, - 90 +
    Mathf.PingPong(Time.time * rotSpeed, 60));
    }
    Your while loop is always running, there's no way for it to exit the loop. If launchUpgrade is larger than 0 (which it presumably is) nothing inside the loop will change that, so the loop will never end. A while loop is designed to test some value or state that the loop actually interacts with. What are you trying to make happen here? I suspect a while loop isn't a good fit for the problem.
  • farsicon said:
    Just a design pattern suggestion that will help you in the long run: ideally you want to create a "rotator" behaviour (instead of using a boolean and if statement) that you can enable/disable as needed, which would get rid of unnecessary update calls when rotating is false.
    While that may be useful thinking later on, perhaps this sort of thing should only be brought up when control flow logic is understood? That way it doesn't derail understanding with more complexity right now.
  • dislekcia said:
    farsicon said:
    Just a design pattern suggestion that will help you in the long run: ideally you want to create a "rotator" behaviour (instead of using a boolean and if statement) that you can enable/disable as needed, which would get rid of unnecessary update calls when rotating is false.
    While that may be useful thinking later on, perhaps this sort of thing should only be brought up when control flow logic is understood? That way it doesn't derail understanding with more complexity right now.
    rotator.enabled = launchupgrade > 0;

    Also has the benefit of reducing logical complexity.
  • farsicon said:
    rotator.enabled = launchupgrade > 0;

    Also has the benefit of reducing logical complexity.
    If @RubberDucky were to type that in right now, it wouldn't work. You've assumed the writing (and referencing) of an entire "rotator" behaviour, with no explanation of how that would be done or what that code would look like. Like I said before: Yes, this might be a great approach, but there's no indication that @RubberDucky is at a point where simply saying "write a behaviour" is going to be any help at all, not with while loops being as dangerous as they are.

    This is very typical programmer "help" - pithy 1 liners that show off how the writer knows more than someone else, full of technically correct information with zero context for the person experiencing the problem :(

    This is why we can't have nice things. But yes, you're 100% technically right, well done, etc.
  • @rubberducky, rather PM me instead. I would gladly spend time with you to help you in the right direction.

    @dislekcia, nice job man.
Sign In or Register to comment.