Can you give provide feedback/insight on the gameplay of my game Portal Reign?

lol I so grateful Pal sleep well :slight_smile:

Classes start tomorrow for me I will get rest to.

I’m going to take a c# beginners course in UDemy will look for Ben class on the subject I remember he mentioned he had one.

Ok, so that delivers on the first of the three items we initially outlined above;

  • player crashes (either into scenery or into an enemy)
    • outcome = Game Over - You Lose
  • player follows rail to the end but hasn’t killed all enemies
    • outcome = Game Over - You Lose
  • player follows rail to the end and has killed all enemies
    • outcome = Game Over - You Win

Bonus content for you…

You mentioned earlier about re-scaling the text on the Splash screen, I’m sure you spotted the red cross through it, again it was hugely oversized and outside of the canvas.

I’ve re-aligned the text and image and have the screenshots of what I’ve setup below, additionally, I’ve given you a little drop-shadow on the title text so that you can actually read it - I personally find the green on yellow quite hard to see. So I’ll show you the technique, without using Text Mesh Pro, and you can see what you think…

image

If you want to create this, then try the following;

  • Open the Splash scene
  • Rename your Text UI Text GameObject to Title
  • Set the anchor preset to centre/middle
  • Set its transform and text properties as follows;
  • Duplicate the Title UI Text GameObject and name it TitleShadow
  • Set its transform and text properties as follows;
  • Order the Canvas hierarchy as follows;
    image
  • Set the transform of the Image GameObject as follows;
    image
  • Save the scene
  • Run the game

You should see a drop shadow on the text which will make it a little easier to read. You can of course move these items around the scene as you wish and change the colours and so on. Be careful when you move them so you don’t end up with the same issue as before, e.g. the red-crosses.

You’re taking it.

There’s the Unity 2D course and the Unity 3D course, both teach similar principles from the perspective of C#.

Okay will work on the text in the splash screen btw, did you read the post for the ideas I have to update this game? I will tell you more about another time its going to be great.

I did read it yes. I have to draw a line under how much more time I can invest personally on your project though, my support for yourself far exceeds anyone else I’ve helped on the forum. If I end up doing too much you run the risk of not learning by making mistakes yourself.

It probably would have been good for you to have tried extending some of the other games before this one, especially those in the 2D course, like Block Breaker / Laser Defender etc. You have some good ideas for your game but there are some fundamentals I think you should try to cover before reaching too far. Not least of which are “backups”! Followed by getting your project in order, e.g. we’ve deleted at least one script that wasn’t being used this evening, we removed one previously when I helped you too, leaving a trail of stuff you’re not using is bad practice and just makes it harder to understand the project. So a good session on “housekeeping” would be beneficial here.

You will have noticed we removed at least three bools this evening too, the code still does what it needs to do but doesn’t rely on the tanglement of boolean switches. So if you find yourself adding those again in the future, stop and have a think about the design and if there are other/better/cleaner approaches.

Regarding the last two issues, I’m happy to help you resolve those - BUT - I don’t want to have to download this project again and experience the pain of opening it/compiling it/recreating the assets database etc. I can spare a little bit of time tomorrow to try and resolve the last two issues but if you make a lot of changes in between then the copy of the project you have and I have will differ and that could cause problems as the results of what we do at either end may be different.

So, if you can hold fire making any further changes until we resolve these last two items that would be great and I’ll help you get through them. :slight_smile:

Rob, you are amazing I commend you for all you do. I will only want guidance after we get these last few update done for researching info. on google for my other projects on this game. I understand if you have limited time . But from time to time if you could guide me to what key words I can use to get my work done I would appreciate it. Sleep well I will leave the game as is until tomorrow when you reach out to me. :slight_smile:

Hi Martin,

A fairly long post coming up - please ensure you work through carefully step-by-step, it will be incredibly difficult to unpick any issues half way through…

Before you start - take a backup of your project as it was when we wrapped up last night, so if any of the following goes wrong you can easily return to that specific point.


We’ll tackle the second issue next;

  • player crashes (either into scenery or into an enemy)
    • outcome = Game Over - You Lose
  • player follows rail to the end but hasn’t killed all enemies
    • outcome = Game Over - You Lose
  • player follows rail to the end and has killed all enemies
    • outcome = Game Over - You Win

Before we start we need to look at and resolve an existing problem. As it is, when your game runs you have the player ship following the rail and there are the enemies in waves 1 to 5, these are all being controlled via the Timeline. In total there are 13 enemies in the Timeline and we see those as we fly through your game.

At some point you’ve added some code for spawning enemies, this includes a vector to indicate where which you then randomise a little, you have set the number of hazards to be 13, presumably because that was the number of enemies you already had in the Timeline. You then have a coroutine which keeps spawning enemy waves. Within the coroutine method SpawnWaves you also have a while loop which never exits, so it runs through and spawns 13 enemies, then runs through again and spawns 13 enemies and so on.

Aside from a few issues with the code itself, the bigger problem here is that you are spawning enemies that the player will never be able to shoot because the player ship has already been moved along the rail passed them. If you want to actually see this in place, remove the while(true) statement, not the code inside it, just that outer loop, then disable your Terrain GameObject, hide the Default layer via Layers,and, via the Lighting Settings window, remove your Skybox, you’ll end up with a blue background and no terrain when you run the game which makes seeing all of the enemies that are getting spawned much easier, but of course you cannot shoot them and ordinarily the player won’t even see them.

The reason this is a problem is because you want to determine the outcome when the player returns to the landing pad based on whether they have killed all the enemies, with things the way they currently are you player will only be able to lose. I’m not sure if the hazards/spawning code was just something you tried but then its got left over or if you had some other plans for it but for now I plan to strip that all out in order to achieve the items on your list.

So, let’s tear apart your GameController.cs script :slight_smile:


  • Open GameController.cs within Visual Studio
  • Remove the following lines of code;
    public GameObject hazard;
    public Vector3 spawnValues;
    public int hazardCount;
    public float spawnWait;
    public float startWait;
    public float waveWait;
    
  • Delete the SpawnWaves method
  • Update the Start method, removing this line of code;
    StartCoroutine(SpawnWaves());
    
  • Run the game

There should be no errors and in the Hierarchy you will no longer see enemy waves being spawned, but the original waves 1 to 5 are present and those 13 enemy ships will appear as you progress along the rails.


In order to know whether all of the enemies have been killed or not we need to obtain the number of enemies that are present in the scene. Because you are using Timeline you’ll notice that whilst the enemy ships in their waves are enabled in Scene view, as soon as you run the game only the first two ships are enabled, all the others are disabled. As you progress through the time of the Timeline the other enemy ship are then enabled and earlier ones are disabled.

This poses a bit of a problem because during realtime the disabled GameObjects wouldn’t be returned in any “Find” method and as they are disabled they cannot execute code that says, “Hey, I’m here” - at least not until they are enabled.

Thankfully we can grab the count of enemies before Timeline disables them. We do that using this line of code in the Start method;

enemiesLeft = GameObject.FindObjectsOfType<Enemy>().Length;

Whether it is by design or by chance that this executes before Timeline disables the GameObjects is open to interpretation at this point but for now, it works, so we’ll stick with it.

Next we need to reduce enemiesLeft each time an enemy ship is destroyed, this is currently being handled by the GameController.cs script via the DecreaseEnemyCount method, which itself is called from the KillEnemy method within Enemy.cs.

So we have the total count, and we are reducing it when enemies are killed. The next step is to determine when to evaluate the value of enemiesLeft. With both of the remaining two issues you are only interested in the outcome at the “end” of the game, this is determined by the player ship reaching the landing pad.

We can use the BoxCollider on the landing pad to determine if the ship has landed. At the beginning this would be true, when it takes off it would be false, and then when it gets to the end of the rails it would be true again.

  • Select the LandingPad GameObject/prefab;
    • Change the BoxCollider component to have its Center properties all set to zero
    • Change the BoxCollider component to have a scale of 2.5 on the Y axis

Running the game at this point would trigger a Game Over situation because the CollisionHandler.cs script component attached your the Player Ship detects the collision and ends the game, assuming you’ve crashed. Let’s address that so that the BoxCollider on the LandingPad will be ignored from the perspective of “crashing”.

  • With the LandingPad GameObject/prefab selected;
    • Add a new Script component named “LandingPad”
    • Update the code within the LandingPad.cs file as follows;
    using UnityEngine;
    
    public class LandingPad : MonoBehaviour
    {
    
    }
    
  • Save the script
  • Open CollisionHandler.cs
  • Update the OnTriggerEnter method as follows;
    void OnTriggerEnter(Collider other)
    {
        LandingPad landingPad = other.gameObject.GetComponent<LandingPad>();
    
        if(landingPad == null)
        {
            StartDeathSequence();
            deathFX.SetActive(true);
    
            gameController.GameOver();
        }
    }
    

When a collision takes place with the Player Ship the above code will try to get the LandingPad component from the GameObject it just collided with, if this is null the collision wasn’t with the landing pad, in which case, we carry on and destroy the player ship.

Running the game now will return us back to where we were, the Player Ship won’t trigger a “Game Over” condition as soon as it starts but we now have the ability to determine if the player is on the LandingPad or not.

I’m not a fan of the architecture in the Argon Assault game, but at the same time I can’t really go through and re-write your entire project, so I’ll offer the following which is “in-line” with the approach used in the course content, specifically around the use of SendMessage.

Currently we are only carry if the player is “not” on the LandingPad, let’s update the OnTriggerEnter method again to cater for when they are;

  • Update the OnTriggerEnter method as follows;
    void OnTriggerEnter(Collider other)
    {
        LandingPad landingPad = other.gameObject.GetComponent<LandingPad>();
    
        if(landingPad == null)
        {
            StartDeathSequence();
            deathFX.SetActive(true);
    
            gameController.GameOver();
        }
        else
        {
            SendMessage("OnPlayerLanding");
        }
    }
    

We also want to know when the player was in contact with the LandingPad but no longer is, we can use the OnTriggerExit method for that;

  • Add the following method to the CollisionHanlder.cs script;

    private void OnTriggerExit(Collider other)
    {
        LandingPad landingPad = other.gameObject.GetComponent<LandingPad>();
    
        if(landingPad != null)
        {
            SendMessage("OnPlayerTakeOff");
        }
    }
    

    At any point when the Player Ship leaves a trigger collider this method will get a reference to the LandingPad component, if it isn’t null then we know that the player was on the LandingPad and no longer is, therefore they must have taken off.

Using the SendMessage approach above we are making calls to two new methods on the PlayerController.cs script which we haven’t yet created, let’s add those;

  • Open the PlayerController.cs script
  • Add the following methods;
    void OnPlayerLanding()
    {
        isControlEnabled = false;
    
        if (!landed)
        {
            Debug.Log("Landing");
        }
    }
    
    void OnPlayerTakeOff()
    {
        isControlEnabled = true;
        landed = false;
        Debug.Log("Take Off");
    }
    
  • Add a member variable as follows;
    private bool landed = true;
    

Running the game now prevents the player from controlling the Player Ship until it has taken off, a “Take Off” message is displayed to the console once the Player Ship’s BoxCollider leaves the BoxCollider of the LandingPad. When you return to the Landing Pad and descend again the player controls are disabled and the ship lands. A “Landing” message is displayed to the console.


Now we have determine that the player has landed we can trigger the game over state.

Before we do, let’s just clear up a few more things. Your GameController.cs script has an OnGUI method, this is called several times per frame and you have again added a “Find” method in there which is getting a count of all of the enemy ships. We know that this count will be wrong once the game is running because some of the enemy ship may be disabled. If you look at the code you have in there, the reason your “You Lose” message appears when there’s ONE enemy left should be fairly obvious. Regardless of how good the player is, as they kill each enemy, at some point there will ALWAYS be one enemy left, right before killing it, so your code would always display this message as it stands at the moment.

  • Open GameController.cs
  • Remove the OnGUI method
  • Remove the endGame method
  • Remove this line of code;
    private bool killedAllEnemies = false;
    
  • Remove these lines of code from the Update method;
    if (enemiesLeft == 0)
    {
      endGame();
    }
    

Once the player ship has landed we can call the GameOver method from the PlayerController.cs script;

  • Open the PlayerController.cs script
  • Add the following member variable;
    private GameController gameController;
    
  • Add a Start method as follows;
    private void Start()
    {
        gameController = FindObjectOfType<GameController>();
    }
    
  • Update the OnPlayerLanding method as follows;
    void OnPlayerLanding()
    {
        isControlEnabled = false;
    
        if (!landed)
        {
            gameController.GameOver();
        }
    }
    
  • Remove the following line of code from OnPlayerTakeOff;
    Debug.Log("Take Off");
    
  • Update the OnPlayerDeath method as follows;
    void OnPlayerDeath()
    {
        isControlEnabled = false;
        gameController.GameOver();
    }
    

Now that PlayerController.cs has a reference to GameController.cs and we’ve added the call to the GameOver method within OnPlayerDeath we can remove all the references to GameController from within CollisionHandler.cs as they are no longer required.

  • Open CollisionHandler.cs
  • Remove this line of code;
    private GameController gameController;
    
  • Remove the Start method
  • Remove this line of code from the OnTriggerEnter method;
    gameController.GameOver();
    

Whilst we are here, the method ReloadScene and the member variable levelLoadDelay are not being used at all by any of your code;

  • Remove the method ReloadScene
  • Remove this line of code;
    [Tooltip("In seconds")] [SerializeField] float levelLoadDelay = 1f;
    

We now have all avenues pointing to the GameOver method within GameController.cs but currently it isn’t doing anything to check how many enemies are left and as such is displaying an inaccurate outcome.

  • Open GameController.cs
  • Update the GameOver method as follows;
    public void GameOver()
    {
        gameOver = true;
        gameOverText.text = "Game Over!";
    
        if (enemiesLeft > 0)
        {
            outcome.text = "You Lose";
        }
        else
        {
            outcome.text = "You Win";
        }
    
        restartText.text = "Press 'R' for Restart";
    
        masterTimelinePlayableDirector.Stop();
        playerShip.SetActive(false);
    }
    

Run the game and you will now find that if you shoot all of the enemies and don’t crash you see “Game Over” and “You Win” when you land, but if you miss any of the enemies you’ll see “Game Over” and “You Lose” when you land. If you crash at any point during the game you’ll see “Game Over” and “You Lose”. In all cases there is an option to restart by press R.

Due to the positions of your enemies and their animations/movements and the angle of the player ship I don’t find it easy to shoot them all which makes testing a real pain. To make it easier, if you disable Wave 2, 3, 4, and 5, AND the Enemy Ships within each wave, when you run the game the Timeline will only give you the two ships in Wave 1 to shoot, the enemy count will be 2, you’ll stand a good chance of shooting both. You can then just fly to the end and see the win message, or, deliberately miss one or both and fly to the end to see the lose message.


That’s it, all three items delivered;

  • player crashes (either into scenery or into an enemy)
    • outcome = Game Over - You Lose
  • player follows rail to the end but hasn’t killed all enemies
    • outcome = Game Over - You Lose
  • player follows rail to the end and has killed all enemies
    • outcome = Game Over - You Win

I hope I have explained things well enough as I’ve given the instructions above and that the code I’ve added makes sense to you.

There is still a lot of housekeeping that could take place in this code base at the moment, it really could do with a good tidy up. I’d also move to not specifically set text properties of UI Text GameObjects where you don’t need to. If you’ve already set “Game Over” in the Inspector, to change it to an empty string and then re-populate it seems a bit unnecessary, you could just get a refernce to the UI Text GameObject and then enable/disable it from code to show/hide it. The exception would be your Outcome UI Text GameObject which you do want to change to either win/lose.

If you’ve followed all of the above and got to this part I would strongly urge you to take a backup of your project right now and keep it somewhere safe so that if you make some changes but then need to return to this point it is easy to do so.

I would then suggest working your way through the code and determine which scripts are not being used and remove them, which variables in scripts are not being used and remove them, which methods in scripts are not being used and remove them. Do the same for any of the assets as well, if there are things there that are not being used, clear them out, add them when you need them. Once you’re on top of all of the housekeeping and have run successful tests, make a fresh backup so you have a “clean” version of the project.

Hope this helps. :slight_smile:

Rob Thank you, I will work on this now I was up early getting school assignments done your the best Pal :slight_smile:

1 Like

No worries, enjoy :slight_smile:

Rob, all done now I will adjust the movement of the Player ship then the enemies movements. I can’t thank you enough Pal :slight_smile:

I like to give some compensation when I get paid from school.

I plan to update asset for the ships and create a video splash screen to link to the second scene. In the second scene, the player walks around as an fps game killing enemies. Should the player have a choice of payer ships to choose from? considering it’s a short scene I don’t think is necessary. what do you think?

Rob, My player ship is frozen I can’t move it just flies through the time line I can move with the controls anymore I went back to work on the movement but test one last before working on it - it wont move anymore. There are no errors in the console.

  • Pause the game
  • Run the game
  • Select the Player Ship GameObject in the Hierarchy
  • Right-click on the Inspector and select Debug
  • Scroll down to the Player Controller script component
  • View the isControlEnabled field
  • Un-pause the game

Does it remain set to false?

hold on

This is what I have, at the end of the game the messages show even if I kill all enemies or not.

I’d suggest going back through the instructions one-by-one carefully and see if there’s a step that got missed.

Yeah that’s what I going to do. Thank you

The land pad was not sized or aligned correctly that fixed the issue once I aligned it. :slight_smile:

1 Like

Rob, are you busy?
I tried to build the game when it completed the enemies and player ship fx explosion has no sound.
I made some changes to the enemy script below but still no sound after building the game

[SerializeField] GameObject enemyDeathFX;

GameObject fx = Instantiate(enemyDeathFX, transform.position, Quaternion.identity);
        fx.transform.parent = parent;

Privacy & Terms