Updates to my Skybox Portal Reign Game

Hi I made some changes to the look and feel I also fixed the guns aiming Sample to a bigger game I’m going to work on Ftp type ( Portal_Reign_ Realm_Investigation ) Any insight is appreciated :slight_smile:

URL: https://www.dmmsdi.com/prweb/index.html

primg

1 Like

Hi Rob long time I would appreciate your input I’m trying to add a crosshair for better aiming but I receive this syntax error below: I created a new script left every other script untouched to let you know. Thank you :slight_smile:

using System. Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;

public class CrossHair: MonoBehaviour
{
   private GameObject standardCross;
   private GameObject redCross;
   private hit RaycastHit { get => RaycastHit; set => RaycastHit = value; }

    void Start()
    {
        standardCross.gameObject.SetActive(true);
    }


   void Update()
    {


        if (Physics.Raycast(transform.position, transform.forward, hit, 100))
        {
            if (hit.transform.tag == "Enemies")
            {
                redCross.gameObject.SetActive(true);
                standardCross.gameObject.SetActive(false);
            }
        }
        else
        {
            redCross.gameObject.SetActive(false);
            standardCross.gameObject.SetActive(true);
        }
    }
}

Hi Martin,

At a very quick glance, I’d suggest this is wrong;

private hit RaycastHit { get => RaycastHit; set => RaycastHit = value; }

it should be the type before the name, it looks like you have them around the other way. So your error is stating that it cannot find the type hit because it isn’t a class.

Thank you I believe I fixed this but I get one more error below: I’m a far off or on the right track?

Assets\Scripts\CrossHair.cs(24,68): error CS1503: Argument 3: cannot convert from ‘UnityEngine.RaycastHit’ to ‘float’

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;

public class CrossHair : MonoBehaviour
{
   private GameObject standardCross;
   private GameObject redCross;

   public RaycastHit RaycastHit { get; private set; }

   private RaycastHit Hit { get { return RaycastHit; } set => RaycastHit = value; }

   void Start()
   {
       standardCross.gameObject.SetActive(true);
   }


   void Update()
   {


       if (Physics.Raycast(transform.position, transform.forward, Hit, 100))
       {
           if (Hit.transform.tag == "Enemies")
           {
               redCross.gameObject.SetActive(true);
               standardCross.gameObject.SetActive(false);
           }
       }
       else
       {
           redCross.gameObject.SetActive(false);
           standardCross.gameObject.SetActive(true);
       }
   }
}

Now you are re-using the same variable name.

The best thing you could do is to start using/following some best practices for naming conventions. Currently you have a property and a field using the same name, with the same capitalisation. People will have difficulties reading your code, as does the compiler.

Typically, classes, properties and methods should use PascalCase, variable names should use camelCase.

Example;

using UnityEngine;

public class Human : MonoBehaviour
{
    // fields
    private string name;
    private int age;

    // properties
    public string Name
    { 
        get { return name; } 
        set { name = value; } 
    } 

    public int Age
    { 
        get { return age; } 
        set { name = value; } 
    }  

    private void Jump() 
    {
        //... 
    } 
} 

In the above the class name is capitalised, as are the two properties (written out in the longer way), and as is the Jump method.

The fields, the variables holding the data, are using camelCase but are single words so appear as just lowercase letters. Now when you want to return a value using the properties its very clear as to what you are returning.

If you have a field/variable which is made up from more than one word then it would appear as;

private string fullName;

Note the lower case letter for the first word, followed by the uppercase letter for the second word, camelCase.

Note, you may also come across fields being written like this;

private int m_age;

or, in its shorter form;

private int _age;

Just two more ways of indicating member variables (fields). The former is fairly old school and often approaches that are taken will depend on where people were taught.

By getting into the habit of formatting your code correctly you will avoid issues like the above.

Incidentally, if the class doesn’t need to share its data with other classes then you don’t need the property. If you are using this classes data elsewhere then it may make sense to have it.

Hope the above helps. :slight_smile:

I believe I getting closer?btw do I attach this .cs to the main camera or to both the standardCross and redCross?

Assets\Scripts\CrossHair.cs(24,21): error CS1061: ‘int’ does not contain a definition for ‘transform’ and no accessible extension method ‘transform’ accepting a first argument of type ‘int’ could be found (are you missing a using directive or an assembly reference?)

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;

public class CrossHair: MonoBehaviour
{
    private GameObject standardCross;
    private GameObject redCross;
    private string RaycastHit;
    public int Hit;
    void Start()
    {
        standardCross.gameObject.SetActive(true);
    }


    void Update()
    {


        if (Physics.Raycast(transform.position, transform.forward, Hit, 100))
        {
            if (Hit.transform.tag == "Enemies")
            {
                redCross.gameObject.SetActive(true);
                standardCross.gameObject.SetActive(false);
            }
        }
        else
        {
            redCross.gameObject.SetActive(false);
            standardCross.gameObject.SetActive(true);
        }
    }
}

At the moment Martin it isn’t going to make a lot of difference where you attach it.

Aside from the error message you are receiving you are going to try to access two member variables that you have initialised, standardCross and redCross. These are going to be null and you’ll receive a NullReferenceException when you try to access them.

Where you place this script when you’ve ironed out all the issues is entirely up to you but I would personally recommend placing it where it makes the most sense.

It will need to be attached to an active GameObject and it relates to the player.

I would also ask what you believe your RaycastHit string variable and Hit variables are doing in the above.

Hi, Rob, I’m not sure what to do this is what I have done.
I apperciate you :slight_smile:

I thought by creating RaycastHit string variable and Hit variables it would get this line here to work?

if (Physics.Raycast(transform.position, transform.forward, Hit, 100))

I’m trying to make these two lines show in the Inspector

[SerializeField] private GameObject standardCross; 
[SerializeField] private GameObject redCross;

Where I’m I wrong?

using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
using UnityEngine;

public class CrossHair: MonoBehaviour
{
    
    [SerializeField] private GameObject standardCross;
    [SerializeField] private GameObject redCross;
    private string RaycastHit;

    private int Hit;
    private string standardCrossImage;
    private string redCrossImage;

    void Start()
    {
        standardCross.gameObject.SetActive(true);
        standardCrossImage = "";
        redCrossImage = "";
    }


    void Update()
    {


        if (Physics.Raycast(transform.position, transform.forward, Hit, 100))
        {
            if (Hit.transform.tag == "Enemies")
            {
                redCross.gameObject.SetActive(true);
                standardCross.gameObject.SetActive(false);
            }
        }
        else
        {
            redCross.gameObject.SetActive(false);
            standardCross.gameObject.SetActive(true);
        }
    }
}

Hi Martin,

I see you now have the two crosses using the [SerializeField] attribute, that will help you wire them up, although there may be a better way - but perhaps get this working first and then give that a try, more on that later.

private string RaycastHit;

In the above line you have declared a variable of string type, a RaycastHit is a type of its own, you can’t just throw types around arbitrarily. The name, as mentioned above, would also be better using camelCase to avoid confusion. An object of type RaycastHit will contain information related to the raycast.

For example;

private RaycastHit raycastHit;

These two lines of code don’t appear to be adding any value as they are not used, other than to set them as equal to nothing. Your variable names suggest these may have been intended for images, but again you have declared their types as string.

private string standardCrossImage;
private string redCrossImage;

Finally, you have a variable called Hit which, again, has the incorrect type. You are using it in the Physics.Raycast method, this would be the variable which needs to be of type RaycastHit. For now I would suggest deleting this also.

These two lines of code also don’t appear to be adding any value at all, as they are not used;

standardCrossImage = "";
redCrossImage = "";

So, if we tidied up a bit, the script may look like this now;

using UnityEngine.UI;
using UnityEngine;

public class CrossHair: MonoBehaviour
{    
    [SerializeField] private GameObject standardCross;
    [SerializeField] private GameObject redCross;
    
	private RaycastHit raycastHit;

    void Start()
    {
        standardCross.gameObject.SetActive(true);
    }

    void Update()
    {
        if (Physics.Raycast(transform.position, transform.forward, Hit, 100))
        {
            if (Hit.transform.tag == "Enemies")
            {
                redCross.gameObject.SetActive(true);
                standardCross.gameObject.SetActive(false);
            }
        }
        else
        {
            redCross.gameObject.SetActive(false);
            standardCross.gameObject.SetActive(true);
        }
    }
}

There’s still an issue with the Physics.Raycast statement at this point as it is still using the variable Hit which we’ve deleted. To keep that statement a little easier to read, at least for now, I’d probably opt to take out the specifics for the ray itself, create a new variable for the ray, and then pass that into one of the overloads for the Raycast method, perhaps like this;

void Update()
{
    Ray targettingRay = new Ray(transform.position, transform.forward);
	
    if (Physics.Raycast(targettingRay, out raycastHit, 100))
    {
        if (raycastHit.transform.tag == "Enemies")
        {
            Debug.Log("Raycast hit an enemy");

            redCross.gameObject.SetActive(true);
            standardCross.gameObject.SetActive(false);
        }
    }
    else
    {
        redCross.gameObject.SetActive(false);
        standardCross.gameObject.SetActive(true);
    }
}

The statement is still less than ideal as it has the value of 100 crammed in to it, but you could swap that out with a variable later that relates to the distance the player can fire perhaps, for now I’d leave it until you get this working.

With regards to where to put this script, you are currently referencing the transform position and direction when creating the origin of the ray so it would either need to be a GameObject in the scene, or you’d need to update the code to use the mouse position and then convert that position to world space, you can use the Camera’s ScreenPointToRay method for this, for example;

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

Note, there are some things you could do to make this a little more performant also, but as per the other suggestion, perhaps get it working first, then refine.

Hope this helps :slight_smile:


See also;

Hi Rob, I know it must be late by you I added some code from the links you gave me but I don’t believe its working right. Shouldn’t the cross-hair move accordingly as the player rig does to point at enemies? BTW there are no errors in the console when running the game. I apologize or the fast video and talking space is limited. I appreciate you :slight_smile:

using UnityEngine.UI;
using UnityEngine;

public class CrossHair : MonoBehaviour

{

    [SerializeField] private GameObject standardCross;
    [SerializeField] private GameObject redCross;

    float moveForce = 1.0f;
    float rotateTorque = 1.0f;
    float hoverHeight = 4.0f;
    float hoverForce = 5.0f;
    float hoverDamp = 0.5f;

    Rigidbody rb;

    private RaycastHit raycastHit;

    void Start()

    {

        standardCross.gameObject.SetActive(true);
         rb = GetComponent<Rigidbody>();

        // Fairly high drag makes the object easier to control.
        rb.drag = 0.5f;
        rb.angularDrag = 0.5f;
    }

    void Update()

    {
        // Push/turn the object based on arrow key input.
        rb.AddForce(Input.GetAxis("Vertical") * moveForce * transform.forward);
        rb.AddTorque(Input.GetAxis("Horizontal") * rotateTorque * Vector3.up);

        RaycastHit hit;
        Ray downRay = new Ray(transform.position, -Vector3.up);

        if (Physics.Raycast(downRay, out hit))
        {
            // The "error" in height is the difference between the desired height
            // and the height measured by the raycast distance.
            float hoverError = hoverHeight - hit.distance;

            // Only apply a lifting force if the object is too low (ie, let
            // gravity pull it downward if it is too high).
            if (hoverError > 0)
            {
                // Subtract the damping from the lifting force and apply it to
                // the rigidbody.
                float upwardSpeed = rb.velocity.y;
                float lift = hoverError * hoverForce - upwardSpeed * hoverDamp;
                rb.AddForce(lift * Vector3.up);
            }
    }
    Ray targettingRay = new Ray(transform.position, transform.forward);



        if (Physics.Raycast(targettingRay, out raycastHit, 100))

        {

            if (raycastHit.transform.tag == "Enemies")

            {

                Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

                redCross.gameObject.SetActive(true);

                standardCross.gameObject.SetActive(false);

            }

        }

        else

        {

            redCross.gameObject.SetActive(false);

            standardCross.gameObject.SetActive(true);

        }
    }
}

Hi Rob, do you have time to provide me some guidance today? for above work.

Hi Martin,

My time is fairly limited at the moment.

Have you considered adding your crosshair to the player rig/ship itself and just placing it a certain distance in front of the ship?

Hi Rob, Thank you for responding I’m currently extracting the game I was trying to work on the player movement. Just to give the game a better feel when playing but what I tried to didn’t work out as soon as my saved version extracts I will try your advise. :slight_smile:

If I were you I would put a hold on Portal Reign for a couple of weeks and start learning Git, you’ll get around all of these issues with backups by doing so.

Your right I will do that.

56% done

It didn’t work so I put back in the canvas. I get an error message now about adding a Rigidbody. So I added the Rigidbody now the crosshair wont stay in the center of the scene it falls straight down out of the scene
I going to just remove this code for now I can’t figure it out.

I’m not entirely sure what you thought that code was going to do, or where you got it from, but you need to move away from arbitrarily dumping code into a file and expecting successful results.

After I had spent time the other night removing all of the other issues, unnecessary code and wrong types I was somewhat surprised you then added another tonne of code into that script.

I know you want to proceed with your game but I think often you are trying to run before you can walk so to speak and taking a more gradual approach would, I believe, serve you better in the long term.

Just try something simple, just add a sphere for example as a child of the player ship and position it away from the ship, e.g in front of it a certain distance and run the game. If its a child of the ship it will move when the ship moves.

Yeah, I got that code from the links you provide for ray cast no worries. I learn more about it later, for now, I removed the code like you said I need to walk before I run. I don’t believe the game needs the crosshair that bad anyways what are your thoughts? can you play the game and let me know if the game will benefit from it. If you decide to can you wait until I upload a new version I added two more enemies give me a good 10 minutes? Your right it was a lot to take in I was over my head. Thank you :slight_smile:

I don’t recall seeing any of that code in those links I provided you with?

I won’t be available to look at in until later.

You have many areas of refinement you can work on with the skills you have already learnt.

With regards to the crosshair, does the game need it, no. Would it be a nice feature to add, yes. But you need to think that feature through fully before diving into the code.

Initial thoughts I had when I read your original post were along these lines;

  • will the cross hair be hidden by other objects moving in front of the player?
  • if the cross hair is in the centre, how will that be a big benefit to the player when the lasers are firing either side and parallel to each other, rather than towards to central point of the crosshair
  • what is the range of the lasers? You are playing with an arbitrary value of 100 for the raycast to indicate what is “in range”, yet your projectiles just gone on for a long time, potentially further than the range of the crosshair

These are just a few of the thoughts I had, and that’s how you start thinking and dissecting a feature. Look for the benefits, the reasons why the feature is a good idea or a benefit. Then look at all of the challenges and determine how you will overcome them.

Privacy & Terms