No worries, give it a go and see what happens, best way to learn
Hi Rob, I hope you had a good rest? I 'v been doing research I canāt seem to find anything in forums, youtube for what I trying to do. I would like the game once all the enemies objects die the game gives a message (Game Over!) I also want to have the key letter Ā® restart the game. Would you mind looking over some c# for me I got rid of the syntax error btw? I had t tag the GameController in the inspector I also tagged the enemies to a enemies tag.
I found some credible #c and worked with it but the game still doesnāt respond to the code I think is due to, I need one of the scripts possible the DestroyByContact, GameController or ObjectiveManager script find the EnemyScript this is just my theory. I created to new scripts ObjectiveManager and KillEnemy these two combined are supposed to count enemies until they are dead and state (Game Over!) I hope you can look over the work I lost donāt know if Iām on the right track could use some guidance. Thank you
Hi Martin,
Happy to take a look. Can you zip the project files up again for me, as they are at this time. Before you do though, if you take a copy of the working directory, and then delete the library folder, and then zip, this will reduce the size of the download by approximately 50%.
Rob, Good Morning btw, where are you located in the world? I will remove the library and send it to you. Thank you
Hi Martin,
Only remove it from the copy, keep the library folder in your own main working directory.
Iām in the UK.
/waves from other side of the pond
UK, Nice!! politics is wacky like in the US out there now. I just done with the copying the file give me a moment.
Zipping it now.
Hi Rob, Let me know if you are able to DL. Thank you
https://drive.google.com/file/d/1Yc8oLe6csEZs5q0AW_BfB2G_8V_Y_usx/view?usp=sharing
Hi Martin,
Yes, Iāve downloaded the project files successfully.
Ok, working through the project Iāve created as set of steps for you to follow, itās a lengthy post, please be careful not to miss anything!
Canvas
-
Canvas - your child GameObjects under the canvas are all over the place, mostly outside of the canvas, needless to say, they donāt render in the game.
I disabled your existing Canvas and recreated it, as follows;
- right-click in the Hierarchy, select UI / Canvas
- select the new Canvas
- right-click, UI / Text
- select the new Text and duplicate it twice (CTRL + D)
- name the three Text GameObjects, āScore Boardā, āGame Overā and āRestartā
You should have this;
I normally find it easier to work in 2D mode for UI related tasks. Itās also very useful to hide all of the other things in the scene so you can see the canvas and the UI objects you are working with. You can hide the other GameObjects by using the Layers (top right of the editor);
Click on the Eye icon next to Default and everything other than your canvas and UI Text GameObjects will be hidden.
It will be up to you to determine what size you want your fonts and which colours, but Iāll run through what I selected which will fit;
-
select the Score Board GameObject
-
set the rect transform as follows;
-
set the text component as follows;
The shade of green I took from your previous UI Text objects, its Hex value is: 7CFB78Note the font size and alignment options.
-
-
select the Game Over GameObject
-
set the rect transform as follows;
-
set the text component as follows;
I chose white instead of green just to make it stand out a bit more.Again, note the font size and the alignment options.
-
-
select the Restart GameObject
-
set the _rect transform as follows;
-
set the text component as follows;
I used the same shade of green as above.Again, note the font size and alignment options.
NOTE: One thing to be aware of also at this stage, Restart is only Text at this time, it isnāt a Button, Iāve basically replicated what you had but it is now visible.
The scene view should look like this;
If you run the game now, you should see all of your UI GameObjects over the top of the game play;
-
-
Click on Layers
-
Click on the eye icon next to the Default layer to show all of the other GameObjects in the scene again
-
Click on the 2D button to return to a 3D view
-
Delete the original Canvas you had created
Enemy.cs
Currently, the Enemy.cs script tries to find a GameObject of type ScoreBoard, this would fail as you do not have the ScoreBoard.cs script as a script component on the Score Board GameObject, you would see a NullReferenceException
error. You have also moved the code to increment the playerās score to your GameController.cs.
-
Replace the member variable;
ScoreBoard scoreBoard;
with
private GameController gameController;
-
Update the Start method as follows;
void Start() { AddBoxCollider(); gameController = FindObjectOfType<GameController>(); }
-
Update the ProcessHit method as follows;
private void ProcessHit() { gameController.AddScore(scorePerHit); hits = hits - 1; // todo consider hit FX }
-
The ScoreBoard.cs script is no longer used and you could consider deleting it.
Game Controller
-
The Game Controller GameObject has a space preceding its name;
Itās not a huge issue, but if you were to ever try and find it by name this would probably cause you a headache - remove the space, save yourself the pain later.
-
As we deleted the original Canvas, the references to the three UI Text GameObjects will now be missing in the GameController.cs script component;
Recreate these references by dragging the corresponding UI Text GameObjects to the exposed fields in the script component from the new Canvas -
Run the game, you should now see the score at the top of the screen. Both Game Over and Restart appear to be hidden, this is because in your GameController.cs script you are setting the text property to an empty string.
-
Shoot some enemies and youāll see the score increases.
CollisionHandler.cs
You mentioned that you want to be able to show āGame Over!ā and have the player press R to restart the game, currently though the CollisionHandler.cs script component attached to the PlayerShip GameObject prevents this from happening, as soon as there is a collision you are invoking the ReloadScene method.
-
Update the OnTriggerEnter method as follows;
void OnTriggerEnter(Collider other) { StartDeathSequence(); deathFX.SetActive(true); }
-
Delete the ReloadScene method entirely
This removes the automatic reloading of the scene.
-
add the following member variable;
private GameController gameController;
-
add a Start method as follows;
private void Start() { gameController = FindObjectOfType<GameController>(); }
-
Run the game and crash your ship, you will see now that the āGame Over!ā and āRestartā text appear.
However, the ship is still in the scene and the player rig is still moving along the rail though.
GameController.cs
-
add a new namespace directive;
using UnityEngine.Playables;
-
add a new member variable;
[SerializeField] private PlayableDirector masterTimelinePlayableDirector;
-
update the GameOver method as follows;
public void GameOver() { gameOverText.text = "Game Over!"; gameOver = true; masterTimelinePlayableDirector.Stop(); }
The above will stop the movement of the player ship along the rail. You need to give some consideration to how you want to remove the player ship from the scene. You could simply Destroy
the GameObject, doing so would remove it from the scene, however, when you restart your game you will then need to re-instantiate the player ship and parent it to the player rig. It would also mean extra calls to create/destroy the object(s) which, where possible, is better avoided.
For now, weāll get a reference to the PlayerShip GameObject and set it to disabled;
-
add a member variable as follows;
[SerializeField] private GameObject playerShip;
-
update the GameOver method as follows;
public void GameOver() { gameOverText.text = "Game Over!"; gameOver = true; masterTimelinePlayableDirector.Stop(); playerShip.SetActive(false); }
The above will now disable the PlayerShip GameObject and hide it in the scene. You will need to use SetActive(true)
in order to bring it back should the player restart the game.
GameController
-
select the GameController GameObject
-
drag the Master Timeline GameObject into the Master Timeline Playable Director exposed field in the Inspector
-
drag the PlayerShip GameObject into the Player Ship exposed field in the Inspector
Ok, so this is a lengthy post with lots of steps, if you follow them all carefully the end result should be;
- score displayed
- score updates
- player movement along rail stops when the player crashes
- āGame Over!ā text appears
There is still some additional refinements that could be done here;
- enemy ship that collides with player could/should be destroyed
- particle effects from PlayerShip are disabled when the PlayerShip is disabled, so no deathFX are shown
-
Restart needs some consideration;
- do you want it to be a button press, e.g. R or a mouse click on the Restart text?
- is the Game scene going to be simply reloaded, or, does the PlayerShip need to be re-activated and moved back to the original spawn location (the former will be easier)
- size of UI elements
Hope the above helps.
Ahh!! you are Awesome I Thank you I will make these changes
Work through the above, carefully, and then if you end up with the same result I display in that video we can have a chat about the restart functionality.
Note, I may not be online as much over the next few days but will respond as and when I can.
Hi Rob, I want to Thank you again I was following your instructions when the player crashes it only freezes. The game over message and restart message does not appear. I will contact you if I do figure it out after the holidays. Have a Happy Holiday
Hi,
Youāve possibly missed a step in the above then, I wrote the instructions after I performed each step.
Happy holidays to you also Martin and thank you
Hi Rob, After the holidays can you guide me where this line of code belongs I tried putting in the enemy.cs but the player continues shooting and enemies donāt explode when I hit them I believe I missing some other lines of code to get this to work and keep this code in the enemy.cs . I still can figure out why the (Game Over) message doesnāt work with your instructions. I re-did the instructions over twice but receive the same results. I tried adding this line of code to the killEnemy.cs this is suppose to find and count the enemies then end the game with the (Game Over) message . I posted how I added the line of code to the enemy.cs and the killEnemy.cs below:
This is the line of code I discussing:
if (GameObject.FindGameObjectsWithTag("Enemies").Length > 13)
{
Destroy(gameObject);
}
This is where I place the coe in the killEnemy.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class KillEnemy : MonoBehaviour
{
public int enemyCount;
public void EnemyDestroyed()
{
enemyCount--;
if (enemyCount <= 0)
{
AllEnemiesDestroyed();
}
}
public void AllEnemiesDestroyed()
{
if (GameObject.FindGameObjectsWithTag("Enemies").Length > 13)
{
Destroy(gameObject);
}
}
}
This is where I place it in the Enemy.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Enemy : MonoBehaviour
{
[SerializeField] GameObject deathFX;
[SerializeField] Transform parent;
[SerializeField] int scorePerHit = 100;
[SerializeField] int hits = 6;
private GameController gameController;
void Start()
{
AddBoxCollider();
gameController = FindObjectOfType<GameController>();
}
private void AddBoxCollider()
{
Collider boxCollider = gameObject.AddComponent<BoxCollider>();
boxCollider.isTrigger = false;
}
void OnParticleCollision(GameObject other)
{
ProcessHit();
if (hits <= 1)
{
KillEnemy();
}
}
private void ProcessHit()
{
gameController.AddScore(scorePerHit);
hits = hits - 1;
// todo consider hit FX
}
private void KillEnemy()
{
GameObject fx = Instantiate(deathFX, transform.position, Quaternion.identity);
fx.transform.parent = parent;
if (GameObject.FindGameObjectsWithTag("Enemies").Length > 13)
{
Destroy(gameObject);
}
}
}
Thank for all your help in this project.
Hi Martin,
The line of code in question is going to search through the entire scene, I terrogating every GameObject, check its tag and see if its tagged āenemiesā. Then, when itās finished, assuming there are more than 13 (?) references in that array, youāre going to destory a GameObject?
Are you trying to determine how many enemies are left, or how many have been destroyed?
Iām trying to determine how many enemies have been destroyed. then give the game over message and all the enemies are tag with the enemies tag. did I do that correct? so then instead of 13 I should put 14 correct?
If you have destroyed the enemy then it isnāt going to be returned in the count of active GameObject with the tag.
I suspect the reason you are not seeing the enemy GameObjects being destroyed is because your if
statement is never true.
To test the theory, where you have the check to see if you return more than 13 active enemy GameObjects, above that, outside of theif
statement, just output using Debug.Log
how many there are with the tag.
Hi Rob, sorry for the lengthily post. So then I should determine how many enemies are left to end the game then show the (You win Game Over!!) message correct? Or Iām going about all the wrong way? I thought I need to count and tag all the enemies with enemies tag so I can end of game with the (You Win Game Over!) message. If the player does not shoot all the enemies at the end of the timeline (player rig) then a message should say (You lose try again!) I havenāt worked on the (You lose try again!) message because I donāt have the the count working to see how many enemies are left to end the game with the (You win Game Over!!) So this is want I want to do before I upgrade the ships in the asset store and by other items to make the game look and feel even better besides work on how the player movement to make it smooth out in the turns. My goal is to make it complete mine and sell it for PC and handle Devices this game I will introduce my game (Latmian of Ra) read more about the game at my websites https://www.dmmsdi.com. I going to the messages idea during the game like Rick showed use with( admiral fish head) to point out caves I will add to the terrain that the player will see during is attack and defense. At the end make another splash screen with the player landing and coming out of the ship to to investigate. I hoping you can guide me or send me to the correct Unity forums that can help me complete Portal Reign the way I want to. So I can start creating (Latmian of Ra) its a first person shooter game. I Thank you for all your guidance BTW. Merry Christmas Pal
So, did you try the Debug.Log
statement like I suggested so you could output how many tagged enemies there were in the scene before you run the if
statement?
Merry Christmas to you also Martin, and thank you
Hi Rob, Thanks for staying in touch, Iām still stuck on where this: code belongs in the enemy.cs or in the killEnemy.cs I created.
I canāt get the count to happen in debug because I donāt no where to make the if statement (true). Should I create new text objects on the canvas for (You Win!) and (You Lose!) messages
In the GameController.cs Should I add this for the You Win & You Lose messages to work like this:
void Start()
{
youWin = false;
youLose = false;
gameOver = false;
restart = false;
youWinText.text = āā;
youLoseText.text = āā;
restartText.text = āā;
gameOverText.text = āā;
score = 0;
UpdateScore();
StartCoroutine(SpawnWaves());
}
public void YouWin()
{
youWinText.text = " You Win Game Over!";
youWin = true;
masterTimelinePlayableDirector.Stop();
enemies.SetActive(false);
}
public void YouLose()
{
youLoseText.text = " You Win Game Over!";
youLose = true;
masterTimelinePlayableDirector.Stop();
enemies.SetActive(false);
}
}
Should the if statement you discuss look like this? Which .cs does it belong to Enemy.cs or kilEnemy.cs? and do iI attach it to a object in the inspector like the player ship or the enemies?
if (GameObject.FindGameObjectsWithTag(āEnemiesā).Length > 14)
{
Destroy(gameObject);
public void YouWin()
{
youWinText.text = " You Win Game Over!";
youWin = true;
masterTimelinePlayableDirector.Stop();
enemies.SetActive(false);
}
public void YouLose()
{
youLoseText.text = " You Win Game Over!";
youLose = true;
masterTimelinePlayableDirector.Stop();
enemies.SetActive(false);
}
``}
}
:santa: