Awesome, awesome tutorial! Here's a little tip to clean up some of the UnitSelection code, functionalize adding and removing units from your selection like this: private void addSelection(GameObject unitToAdd) { unitsSelected.Add(unitToAdd); unitToAdd.transform.GetChild(0).gameObject.SetActive(true); unitToAdd.GetComponent().enabled = true; } private void removeSelection(GameObject unitToRemove) { unitsSelected.Remove(unitToRemove); unitToRemove.transform.GetChild(0).gameObject.SetActive(false); unitToRemove.GetComponent().enabled = false; } And then your other functions get a little cleaner like so: public void ClickSelect(GameObject unitToAdd) { DeselectAll(); addSelection(unitToAdd); } public void ShiftClickSelect(GameObject unitToAdd) { if (unitsSelected.Contains(unitToAdd)) { removeSelection(unitToAdd); } else { addSelection(unitToAdd); } } public void DragSelect(GameObject unitToAdd) { if (!unitsSelected.Contains(unitToAdd)) { addSelection(unitToAdd); } }
Awesome, mate! I always run into this.. I finish a tutorial and then look back and find better methods of doing it lol.. Thanks for taking the time to refactor some of it :)
I've watched a bunch of these systems explained and this one was the clearest and easiest to follow. I fucking LOVE the way that you outline something like a conditional as a whole before you start filling in the conditions, and how you add comments in the script. It's so much easier for a noob like me to follow what you're doing when you say "here we have a few conditions, here's what they all are and what they need to do. Ok, now lets do the first one". So many tutorials just tell you a condition, fill it out, then tell you the next one. Awesome content.
I AM having issues. I tried capsule collider and mesh collider but still can click select anything. Could you please give me some more hint? I'm using empty game object, then multiple cubes in the object, I added the colliders to the empty game object. Is this not the way?
I know this is an old video, but it is a *W*. It is simple enough to follow that I easily refactored the logic to fit my project. You just got yourself a subscriber.
+1 sub, thank you, we (I'm not the only one I think) want more RTS tutorials, like "give orders to selected units", "building", "ressources", "skills" :)
Wow ! This was SO useful ! Thank you a lot man ! I'm currently learning Unity for fun and that was a clear and thorough explanation. I'm really looking forward to your next RTS tutorial. Maybe unit movement ? I am struggling with this one.
This video was exactly what I was looking for, and you do a great job of explaining things. I come from a JavaScript background, and the way you teach things is great
Diablo? Where is Warcraft? xD This tutorial is a treasure xD It was hard to find one good working or not having outside scripts ... So Thank You :) Hail to the RTS!! xD
I have got a problem :( I'am at 9:00 and testing UnitList and Units Selected, I have the number of units on my scene but not the selected units, I think it's not working when I click on them EDIT : found the problem, I have setup my GameObject (soldier/unit) and change the "default" layer to "Clickable"
Thanks for the tutorial! I followed it step by step, but I got stuck at 9:20, but when I click on the units, they are not added to the "Units Selected" list. Any idea what I might be missing? edit: got it to work! I had a typo where it assigned the camera
Great tutorial! I love the way you code and of explaining. The only really small thing is i don't understand why you didn't set the Deselect() function since you created it. Apart this really nice tutorial!
Wrote the same code, but it doesn't work for me, the raycast just doesn't hit the clickable layer. Any idea what's wrong? Followed the steps in the video, except I used cubes instead of capsules...
1) On the right corner of Unity click on "Layers" (just between "Account" and "Layout") 2) Edit a new layer and use the same name "Clickable" 3) On the inspector of your Units/Soldiers/Capsusles... 4) Change the layer default to your new Layer you have created before
so I ran into an issue at the end. The groundMarker appears on the ground whenever I click, not only when units are selected. I wanted to add an if() statement into the part of unitClick.cs that checks if unitsSelected from UnitSelections.cs has members or not. if its empty, no groundmarker appears. However, Im not able to reference the unitSelected list in the unitClick.cs script. Any ideas? Im a complete fish-out-of-water so the answer is probably painfuly obvious.
sure u can.. you can use the instance reference to it.. if (Input.GetMouseButtonDown(1)) { RaycastHit hit; Ray ray = myCam.ScreenPointToRay(Input.mousePosition); if(Physics.Raycast(ray, out hit, Mathf.Infinity, ground) && UnitSelections.Instance.unitsSelected.Count > 0) { groundMarker.transform.position = hit.point; groundMarker.SetActive(false); groundMarker.SetActive(true); } } so you could add the " && UnitSelections.Instance.unitsSelected.Count > 0 " and then set the marker if u want to
I Have error like below : "SetDestination" can only be called on an active agent that has been placed on a NavMesh. UnityEngine.AI.NavMeshAgent:SetDestination(Vector3) UnitMovement:Update() (at Assets/Scripts/UnitMovement.cs:25) any idea ? thanks.
Great video, was a little fast, but that is perfectly fine when you get such a great outcome like what I got. I have two questions though. Anyway to make it so the units make a formation when you click so they don't try and push into each other all the time when trying to get to the destination? And is there a reason for the Deselect function in the UnitSelections script, there is nothing in it?
First question: Yes I am still currently trying to work out a good way to avoid clumping.. Currently I have something like finding the center point of all units and added that as an offset to each units destination.. it works sorta but not what I want.. When I come up with a good system I'll make a part 2.. 2nd: Yes that was intended to be the deselection method but the setup ended up not using it. Sorry I left it in there.. :P
Sorry Its so fast.. I try to keep my videos under 20 minutes long.. I try to explain everything the best I can so you can pause and copy things down.. and *know* what your copying..
Thanks for this. I know it's been a while, but I was wondering if you had any thoughts on how to ignore enemy units. I tried to add this myself by putting enemy units in a new layer called "enemy", which works great for click and shift-click select, but I this is when I realized drag select doesn't check if units are in the clickable layer. I cannot for the life of me figure out how to check the unit's layer when doing drag select. Any tips would be great!
For anyone stuck on this. First create another type of unit and assign it a different layer other than "Clickable." In the SelectUnits() method of the UnitDrag script, modify it as such: void SelectUnits() { // loop through all the units foreach (var unit in UnitSelections.Instance.unitList) { // if unit is with the dragged rectangle if(selectionBox.Contains(myCam.WorldToScreenPoint(unit.transform.position))) { if(unit.layer == 8) // if any unit is within the dragged area, then add the units UnitSelections.Instance.DragSelect(unit); } } } There's an added if statement that checks the unit's layer. The layers are assigned a value between 0 and 31, my clickable layer was 8. Just match your clickable layer to its number in your layer list.
Yep! You're ray-casting into the world and just getting positions when it collides with something. The camera is just a position where we start our ray from. It will work in Ortho and Perspective
if u mean the actual image i just used photoshop / could use gimp and i just drew out with my mouse a circle.. and then a smaller one inside and deleted it.. leaving a stylized little ring.. in unity i think i may have used a 3d Quad rotate it the right way up and dragged the imported 2D sprite onto it, creating a material.. then i may have changed some transparency settings and made prefab out of it..
You may have got the code when the calculations are made to determine if you are dragging a certain way wrong. Maybe review that part of the video and see what you messed up on
Man thanks for that tutorial im newbie...So i have questions...I don't know why but my character at start of game use navmesh without selecting them. so I don't need to select them and they move when I click on ground... Some chance to help how to fix it? thank you.
I have random amounts of success with adding/removing units from the Unit List when shift clicking. Sometimes I can shift click them and they are added or removed right away, and sometimes I need to double/triple/quad click a unit for it to add or remove. Regular clicks select the units properly and responsively. If anyone has a suggestion as to why I'd appreciate it!
In case anyone else has this issue, I used GetMouseButton instead of GetMouseButtonDown and it was registering multiple clicks from one mouse press because the frames are so fast.
thats the tricky part.. i still havent found a great solution but so far i been experimenting with offsets.. so i loop thru the unitsSelected and find the center point of all the units.. then i assign the unit an offset to that center point and move it towards the destination + offset it looks something like this.. but this still needs alot of work foreach (var unit in UnitSelection_og.Instance.unitsSelected) { centerPointOfUnits += unit.transform.position; } centerPointOfUnits /= UnitSelection_og.Instance.unitsSelected.Count; offset = transform.position - centerPointOfUnits; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, Mathf.Infinity, ground)) { theAgent.SetDestination(hit.point + offset / 3); }
@@SpawnCampGames but wouldnt that set it to never reach its real destination? even from the first unit that gets there, its not going to arrive at the hit point of your ray. i think the foreach statement has to be rethought. like keeping track of how many units were sent to a location. and then we feed that information to every AI that is heading to the same destination. for every AI that has already reached its destination, we set an offset to every ai that follows. ima game dev myself and maybe we could work on something (41k subs here). the only time we would use the foreach statement, is when we want to know how many units has already reached its designated destination, right?
Hey, grat vid! I was wondering, I'm trying to translate this to the new input system, is there a way to do it or should try a totally different approach?
Sorry mate, I haven't used the new input system yet. I tried it out once and I couldn't get the mouse deltas to update correctly.. might be time for me to revisit it.
@@SpawnCampGames don't worry! Ended up merging like 4 tutorials in one script and finally got it working, only thing left is selecting units when you release the drag selection, but I think it's a layermask thing
@@Jeamar glad u got it working... it wasn't too difficult to swap to the new input system was it? im curious if i should start learning it now or wait until the old system is closer to being deprecated
@@SpawnCampGames I'd say to start now and swap to the new input system, imo it's harder to work around some stuff with it but in the end you can make better and more readable code with it, and also a lot of QOL stuff it brings I still can't make the drag selection work tho lmao EDIT: I was too dumb to realize I wasn't enabling the child representing the unit was selected, so TLDR I made it work lol
I cant get my units to become selected, I've been working on it for hours. I'm thinking it has something to do with my camera, I'm pretty sure my script is the same as yours. I started a fresh project and went through your tutorial again and still couldn't get them to select. Here's my UnitClick Script just incase it is something I'm overlooking: using UnityEngine; public class UnitClick : MonoBehaviour { private Camera myCam;
public LayerMask clickable; public LayerMask ground;
} else { //if we didn't && we're not shift clicking
if(!Input.GetKey(KeyCode.LeftShift)) { UnitSelections.Instance.DeselectAll(); } } } } } I have been looking up how to use debugging to check if my camera is actually sending the raycast but I'm new to all of this some I'm not sure how to add it into my code. Also to note my ground and units are on the correct layers and the units are coming up in the "unit list" just not the "units selected" when clicked on. Any help would be much appreciated :)
@@arickthompson9833 I'm guessing you don't need this info anymore since it was 1 year ago but I forgot to assign the layer masks in the unity window lol
My units are being added when I hold shift and click, if i just click on them it doesn't work. I wrote a debug.log in both the update method in the unit click script and a debug.log in the unit selection after unitsSelected.Add(unitToAdd); and I get the debug message so it's not throwing errors and it's calling the ClickSelect(GameObject unitToAdd). and it's just not adding to the list. Makes no sense that it's working when i hold shift but not just normal clicking. UnitClick script void Update() { if (Input.GetMouseButtonDown(0)) { RaycastHit hit; Ray ray = myCam.ScreenPointToRay(Input.mousePosition); if(Physics.Raycast(ray,out hit, Mathf.Infinity, AiVisibility)) { // If we hit a target if (Input.GetKey(KeyCode.LeftShift)) { UnitSelections.Instance.ShiftClickSelect(hit.collider.gameObject); } else { UnitSelections.Instance.ClickSelect(hit.collider.gameObject); Debug.Log("Unit Selected"); } } UnitSelection script public void ClickSelect(GameObject unitToAdd) { DeselectAll(); unitsSelected.Add(unitToAdd); Debug.Log("Should be working"); } Any help would be appreciated
@@SpawnCampGames Same Problem. Shift works, but without shift it just execute the -> if (!Input.GetKey(KeyCode.LeftShift)) { UnitSelections.Instance.DeselectAll(); } -> in UnitClick. No clue why.
Edit: So i think its all a little bit buggy, I tried this code here for debugging -> if (Physics.Raycast(ray, out hit, 2000, unit)) { Debug.Log("YEP"); if (Input.GetKey(KeyCode.LeftShift)) { UnitSelections.Instance.ShiftClickSelect(hit.collider.gameObject); } else { UnitSelections.Instance.ClickSelect(hit.collider.gameObject); } } else { Debug.Log("NOPE"); if (!Input.GetKey(KeyCode.LeftShift)) { UnitSelections.Instance.DeselectAll(); } } } -> And the Output was NOPE YEP NOPE NOPE NOPE -> for just one click. So the raycasting or something is very buggy here. And when I do shift, it does the same, but it doesnt delete the list because of the shift if statement "if (!Input.GetKey(KeyCode.LeftShift))"
@@xamexer Thanks for beginning to debug.. I never noticed this and I'll take a look this afternoon w/ ur example from above to try to work out whats going on..
@@SpawnCampGames Oh no, I found the issue and I feel ashamed xDDD. My Soldier had Unit Click on them for some reason, thats why the script played multiple times. Dont know how that happend. Thank you so much for the vid haha
I found this video really helpfull but I'm new to unity and like the animations that u made and u cutted the video I did not understand nor I found how to make, and I believe that is giving me some errors because my code is the same as your's but some stuff doesn't happen, could you possibly help me?
Sure, just let me know.. what Error is displayed in the Editor Console Window.. What line numbers does it point to.. And what part of the script.. C# is a strongly typed language.. meaning capitalizations, and punctuations are very important..
Do you have a discord server that maybe I could enter so I can show you what the problem is? But in short words is basically when I drag, the units are not getting selected. And I reviewed the code 3 times and I did not find any diference.
if theres no errors in the console.. then most likely. it is a code issue.. its probably an issue where the gameobject / components aren't set correctly @@tiagopetinga6496
Gonna comment this for anyone in the future because I was stuck on this for ages: If your drag select code is correct but the UI is acting all weird, change it to a raw image instead of an image. Don't know why this works, maybe because this video is 2 years old.
hey. i really like your channel . could you help me ! i want make a 2D PUZZLE GAME like LIMBO . so i dont know how i can start. i have many problems about physics and creating 2d layers for scenes .. so could you make a tutorial video ? :(
Its a bad idea to setup everything before you start showing the code. People wanting to learn need to see why things are being added and what they are as they are needed.
did you bake the navmesh? the unit has a navmeshagent.. and then making sure you set a destination of ur navmesh agent? docs.unity3d.com/ScriptReference/AI.NavMeshAgent.SetDestination.html
I had a problem and it was because UnitSelection.DeselectAll() was throwing a NullReferenceException. (What was very odd was that *the editor was not showing this exception* it only appeared when I tried debugging). On a whim I tried changing the contents of DeselectAll() to this: public void DeslectAll() { if(unitsSelected.Any()) { unitsSelected.ForEach(unit => unit.transform.GetChild(0).gameObject.SetActive(false)); unitsSelected.Clear(); } } Protecting the ForEach from trying to set the set the Quad to inactive fixed it for me. Hope this helps you. P.S you will need to add using System.Linq; to the file to use .Any()
if u guys have problem with select a object just change if statment this way : if(Mouse.current.leftButton.wasPressedThisFrame) with this its only works just 1 time and selected object is not removing immediately
Hi there! First of all thank you so much for the video! It helped me a lot. I am currently stuck with the Drag Function and I think my problem is with these last few lines void DrawSelection() { if (Input.mousePosition.x < startPosition.x) { selectionBox.xMin = Input.mousePosition.x; selectionBox.xMax = startPosition.x; } else { selectionBox.xMin = startPosition.x; selectionBox.xMax = Input.mousePosition.x; } if (Input.mousePosition.y < startPosition.y) { selectionBox.yMin = Input.mousePosition.y; selectionBox.yMax = startPosition.y; } else { selectionBox.yMin = startPosition.y; selectionBox.yMax = Input.mousePosition.y; } } void SelectedUnits() { foreach (var unit in UnitSelection.Instance.unitList) { if (selectionBox.Contains(myCam.WorldToScreenPoint(unit.transform.position))) { UnitSelection.Instance.DragClickSelect(unit); } } } I made sure that everything is correct but it seems like none of my units are being selected.
Had the same issue, I forgot to place an exclamation mark in UnitSelections script: public void DragSelect(GameObject unitToAdd) { if (!unitsSelected.Contains(unitToAdd)) //
it keeps coming up with selectionBox does not exist in current context using UnityEngine; public class UnitDrag : MonoBehaviour { Camera myCam; [SerializeField] RectTransform boxVisual; Vector2 startPosition; Vector2 endPosition; void Start() { myCam = Camera.main; startPosition = Vector2.zero; endPosition = Vector2.zero; DrawVisual(); }
No instant codespaming, just make sure, the viewer understands, what will going on in a minute. I LOVE IT! THANK YOU!
No, Thank you! :)
Awesome, awesome tutorial!
Here's a little tip to clean up some of the UnitSelection code, functionalize adding and removing units from your selection like this:
private void addSelection(GameObject unitToAdd) {
unitsSelected.Add(unitToAdd);
unitToAdd.transform.GetChild(0).gameObject.SetActive(true);
unitToAdd.GetComponent().enabled = true;
}
private void removeSelection(GameObject unitToRemove) {
unitsSelected.Remove(unitToRemove);
unitToRemove.transform.GetChild(0).gameObject.SetActive(false);
unitToRemove.GetComponent().enabled = false;
}
And then your other functions get a little cleaner like so:
public void ClickSelect(GameObject unitToAdd) {
DeselectAll();
addSelection(unitToAdd);
}
public void ShiftClickSelect(GameObject unitToAdd) {
if (unitsSelected.Contains(unitToAdd)) {
removeSelection(unitToAdd);
} else {
addSelection(unitToAdd);
}
}
public void DragSelect(GameObject unitToAdd) {
if (!unitsSelected.Contains(unitToAdd)) {
addSelection(unitToAdd);
}
}
Awesome, mate! I always run into this.. I finish a tutorial and then look back and find better methods of doing it lol.. Thanks for taking the time to refactor some of it :)
I've watched a bunch of these systems explained and this one was the clearest and easiest to follow. I fucking LOVE the way that you outline something like a conditional as a whole before you start filling in the conditions, and how you add comments in the script. It's so much easier for a noob like me to follow what you're doing when you say "here we have a few conditions, here's what they all are and what they need to do. Ok, now lets do the first one". So many tutorials just tell you a condition, fill it out, then tell you the next one.
Awesome content.
Thank you very much.. I'm still pretty new myself, relatively speaking.. I remember what its like. The struggle is real lol. I'm glad I could help! :)
Underrated channel, splendid video regarding such a classic RTS issue. I highly recommend you continue your awesome work, especially in the RTS genre.
Just wanted to say thank you very much for this tutorial, very useful and manages to combine all the basic rts fundamentals into one video :)
Amazing tutorial! If anyone has issues at around 9:00 when using a custom model, make sure to add a capsule collider to it!
I AM having issues. I tried capsule collider and mesh collider but still can click select anything. Could you please give me some more hint? I'm using empty game object, then multiple cubes in the object, I added the colliders to the empty game object. Is this not the way?
Great tutorial... worked perfectly! That must've taken you a minute to work out. Definitely a time saver for me. Thanks for sharing!
very welcome
I know this is an old video, but it is a *W*. It is simple enough to follow that I easily refactored the logic to fit my project. You just got yourself a subscriber.
Been meaning to make newer videos.. I have a full itinerary for the new couple of months.. Thanks for the subscription!
Love your voice and accent. Friendly regards from South Africa.
+1 sub, thank you, we (I'm not the only one I think) want more RTS tutorials, like "give orders to selected units", "building", "ressources", "skills" :)
yeah
Yes more RTS!
Actually one of the best unity tutorials i've seen lately :)
Wow, thanks!
Well donee, amazing explanation with clean code and amazing concept explanation, best of luck!!
Wow ! This was SO useful ! Thank you a lot man !
I'm currently learning Unity for fun and that was a clear and thorough explanation.
I'm really looking forward to your next RTS tutorial. Maybe unit movement ? I am struggling with this one.
This video was exactly what I was looking for, and you do a great job of explaining things. I come from a JavaScript background, and the way you teach things is great
Happy I could help
Diablo? Where is Warcraft? xD This tutorial is a treasure xD It was hard to find one good working or not having outside scripts ... So Thank You :)
Hail to the RTS!! xD
Simple, clair et précis. Superbe travail!
I have got a problem :( I'am at 9:00 and testing UnitList and Units Selected, I have the number of units on my scene but not the selected units, I think it's not working when I click on them
EDIT : found the problem, I have setup my GameObject (soldier/unit) and change the "default" layer to "Clickable"
Nice Video thanks man. A video about unit formations and moving them to differnet positions would be pretty helpfull. Keep up with this good content
I agree.. this I'm looking into right at this moment. Sorry trying to juggle the channel and making my own game hehe :)
@@SpawnCampGames oh nice okay. No problem thank you for the awesome videos :)
Thank you! Not only did your tutorial make the selection system but also the movement system (im making a topdown managment game)
You're legit a unit. Subscriber earned by you, man.
Thank you for this video. Very neatly done and nicely explained.
Good tutorial, More RTS vidoes will be great ! keep up.
one of the best tutorials i really nedded
Awesome tutorial :') everything is explained and everything is logic Wow man thank you! 😊
Thank you very much, First Tutorial on RTS That is this informative and Good, Well Done. +1 Subscriber, +1 Like
Thanks for the tutorial! I followed it step by step, but I got stuck at 9:20, but when I click on the units, they are not added to the "Units Selected" list. Any idea what I might be missing?
edit: got it to work! I had a typo where it assigned the camera
This dude sounds like some of my drinking buddies xD
I keep waiting for him to talk about cold beer and fishing
Thank you so much. Very helpful, clear, concise, and no issues or errors of any kind!
Awesome video! Thank you for your hard work.
Great tutorial! I love the way you code and of explaining. The only really small thing is i don't understand why you didn't set the Deselect() function since you created it. Apart this really nice tutorial!
thank you very good tutorial and informative not only copy paste
Wrote the same code, but it doesn't work for me, the raycast just doesn't hit the clickable layer. Any idea what's wrong?
Followed the steps in the video, except I used cubes instead of capsules...
Its easy buddy!! I can help you if you want 😋 i could understand this tutorial well
Look for a mistake
1) On the right corner of Unity click on "Layers" (just between "Account" and "Layout")
2) Edit a new layer and use the same name "Clickable"
3) On the inspector of your Units/Soldiers/Capsusles...
4) Change the layer default to your new Layer you have created before
Damn, verry good tutorial!!
Thank you for watching..
Why don't you have to account to negative vectors? Why does Abs work? Is it because the anchors make it bigger regardless of directionality?
perfect, thank you for this very good video!!
Awesome video, thank you a lot ! :)
so I ran into an issue at the end. The groundMarker appears on the ground whenever I click, not only when units are selected. I wanted to add an if() statement into the part of unitClick.cs that checks if unitsSelected from UnitSelections.cs has members or not. if its empty, no groundmarker appears.
However, Im not able to reference the unitSelected list in the unitClick.cs script. Any ideas?
Im a complete fish-out-of-water so the answer is probably painfuly obvious.
sure u can.. you can use the instance reference to it..
if (Input.GetMouseButtonDown(1))
{
RaycastHit hit;
Ray ray = myCam.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit, Mathf.Infinity, ground) && UnitSelections.Instance.unitsSelected.Count > 0)
{
groundMarker.transform.position = hit.point;
groundMarker.SetActive(false);
groundMarker.SetActive(true);
}
}
so you could add the " && UnitSelections.Instance.unitsSelected.Count > 0 "
and then set the marker if u want to
I Have error like below :
"SetDestination" can only be called on an active agent that has been placed on a NavMesh.
UnityEngine.AI.NavMeshAgent:SetDestination(Vector3)
UnitMovement:Update() (at Assets/Scripts/UnitMovement.cs:25)
any idea ? thanks.
The component needs a NavmeshAgent.. also make sure the ground is set to static and you have baked the navmesh in the Window > Navigation tab
@@SpawnCampGames thanks and it's work, I check your video in 00:40 very helpful.
Great video, was a little fast, but that is perfectly fine when you get such a great outcome like what I got. I have two questions though. Anyway to make it so the units make a formation when you click so they don't try and push into each other all the time when trying to get to the destination? And is there a reason for the Deselect function in the UnitSelections script, there is nothing in it?
First question: Yes I am still currently trying to work out a good way to avoid clumping..
Currently I have something like finding the center point of all units and added that as an offset to each units destination.. it works sorta but not what I want.. When I come up with a good system I'll make a part 2..
2nd: Yes that was intended to be the deselection method but the setup ended up not using it. Sorry I left it in there.. :P
Sorry Its so fast.. I try to keep my videos under 20 minutes long.. I try to explain everything the best I can so you can pause and copy things down.. and *know* what your copying..
Thanks for this. I know it's been a while, but I was wondering if you had any thoughts on how to ignore enemy units. I tried to add this myself by putting enemy units in a new layer called "enemy", which works great for click and shift-click select, but I this is when I realized drag select doesn't check if units are in the clickable layer. I cannot for the life of me figure out how to check the unit's layer when doing drag select. Any tips would be great!
For anyone stuck on this. First create another type of unit and assign it a different layer other than "Clickable." In the SelectUnits() method of the UnitDrag script, modify it as such:
void SelectUnits()
{
// loop through all the units
foreach (var unit in UnitSelections.Instance.unitList)
{
// if unit is with the dragged rectangle
if(selectionBox.Contains(myCam.WorldToScreenPoint(unit.transform.position)))
{
if(unit.layer == 8)
// if any unit is within the dragged area, then add the units
UnitSelections.Instance.DragSelect(unit);
}
}
}
There's an added if statement that checks the unit's layer. The layers are assigned a value between 0 and 31, my clickable layer was 8. Just match your clickable layer to its number in your layer list.
Would this work on an orthographic screen. The rays tell me otherwise, but that may be my inexperience talking.
Yep! You're ray-casting into the world and just getting positions when it collides with something.
The camera is just a position where we start our ray from. It will work in Ortho and Perspective
How did you create that ground marker?
if u mean the actual image i just used photoshop / could use gimp and i just drew out with my mouse a circle.. and then a smaller one inside and deleted it.. leaving a stylized little ring..
in unity i think i may have used a 3d Quad rotate it the right way up and dragged the imported 2D sprite onto it, creating a material.. then i may have changed some transparency settings and made prefab out of it..
hi i have problem with private camera.main he cant find it exapt if i set it to public
i need help. drag seletion in only working from right to left bottom.
You may have got the code when the calculations are made to determine if you are dragging a certain way wrong. Maybe review that part of the video and see what you messed up on
Man thanks for that tutorial im newbie...So i have questions...I don't know why but my character at start of game use navmesh without selecting them. so I don't need to select them and they move when I click on ground... Some chance to help how to fix it? thank you.
I have random amounts of success with adding/removing units from the Unit List when shift clicking. Sometimes I can shift click them and they are added or removed right away, and sometimes I need to double/triple/quad click a unit for it to add or remove. Regular clicks select the units properly and responsively. If anyone has a suggestion as to why I'd appreciate it!
In case anyone else has this issue, I used GetMouseButton instead of GetMouseButtonDown and it was registering multiple clicks from one mouse press because the frames are so fast.
@@cpt.flapjack9287 glad u worked it out!
loved this. how can you avoid the AI clumping up to eachother?
thats the tricky part.. i still havent found a great solution but so far i been experimenting with offsets.. so i loop thru the unitsSelected and find the center point of all the units.. then i assign the unit an offset to that center point and move it towards the destination + offset
it looks something like this.. but this still needs alot of work
foreach (var unit in UnitSelection_og.Instance.unitsSelected)
{
centerPointOfUnits += unit.transform.position;
}
centerPointOfUnits /= UnitSelection_og.Instance.unitsSelected.Count;
offset = transform.position - centerPointOfUnits;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit, Mathf.Infinity, ground))
{
theAgent.SetDestination(hit.point + offset / 3);
}
@@SpawnCampGames
but wouldnt that set it to never reach its real destination? even from the first unit that gets there, its not going to arrive at the hit point of your ray. i think the foreach statement has to be rethought. like keeping track of how many units were sent to a location. and then we feed that information to every AI that is heading to the same destination. for every AI that has already reached its destination, we set an offset to every ai that follows. ima game dev myself and maybe we could work on something (41k subs here). the only time we would use the foreach statement, is when we want to know how many units has already reached its designated destination, right?
Hey, grat vid! I was wondering, I'm trying to translate this to the new input system, is there a way to do it or should try a totally different approach?
Sorry mate, I haven't used the new input system yet. I tried it out once and I couldn't get the mouse deltas to update correctly.. might be time for me to revisit it.
@@SpawnCampGames don't worry! Ended up merging like 4 tutorials in one script and finally got it working, only thing left is selecting units when you release the drag selection, but I think it's a layermask thing
@@Jeamar glad u got it working... it wasn't too difficult to swap to the new input system was it? im curious if i should start learning it now or wait until the old system is closer to being deprecated
@@SpawnCampGames I'd say to start now and swap to the new input system, imo it's harder to work around some stuff with it but in the end you can make better and more readable code with it, and also a lot of QOL stuff it brings
I still can't make the drag selection work tho lmao
EDIT: I was too dumb to realize I wasn't enabling the child representing the unit was selected, so TLDR I made it work lol
I cant get my units to become selected, I've been working on it for hours.
I'm thinking it has something to do with my camera, I'm pretty sure my script is the same as yours. I started a fresh project and went through your tutorial again and still couldn't get them to select. Here's my UnitClick Script just incase it is something I'm overlooking:
using UnityEngine;
public class UnitClick : MonoBehaviour
{
private Camera myCam;
public LayerMask clickable;
public LayerMask ground;
void Start()
{
myCam = Camera.main;
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = myCam.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hit, Mathf.Infinity, clickable))
{
//if we hit a clickable object
if (Input.GetKey(KeyCode.LeftShift))
{
//shift clicked
UnitSelections.Instance.ShiftClickSelect(hit.collider.gameObject);
}
else
{
//normal clicked
UnitSelections.Instance.ClickSelect(hit.collider.gameObject);
}
}
else
{
//if we didn't && we're not shift clicking
if(!Input.GetKey(KeyCode.LeftShift))
{
UnitSelections.Instance.DeselectAll();
}
}
}
}
}
I have been looking up how to use debugging to check if my camera is actually sending the raycast but I'm new to all of this some I'm not sure how to add it into my code. Also to note my ground and units are on the correct layers and the units are coming up in the "unit list" just not the "units selected" when clicked on.
Any help would be much appreciated :)
Have you fixed it? I'm having the same issue. Only drag select works.
No sorry
@@arickthompson9833 I'm guessing you don't need this info anymore since it was 1 year ago but I forgot to assign the layer masks in the unity window lol
My units are being added when I hold shift and click, if i just click on them it doesn't work. I wrote a debug.log in both the update method in the unit click script and a debug.log in the unit selection after unitsSelected.Add(unitToAdd); and I get the debug message so it's not throwing errors and it's calling the ClickSelect(GameObject unitToAdd). and it's just not adding to the list.
Makes no sense that it's working when i hold shift but not just normal clicking.
UnitClick script
void Update()
{
if (Input.GetMouseButtonDown(0))
{
RaycastHit hit;
Ray ray = myCam.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray,out hit, Mathf.Infinity, AiVisibility))
{
// If we hit a target
if (Input.GetKey(KeyCode.LeftShift))
{
UnitSelections.Instance.ShiftClickSelect(hit.collider.gameObject);
}
else
{
UnitSelections.Instance.ClickSelect(hit.collider.gameObject);
Debug.Log("Unit Selected");
}
}
UnitSelection script
public void ClickSelect(GameObject unitToAdd)
{
DeselectAll();
unitsSelected.Add(unitToAdd);
Debug.Log("Should be working");
}
Any help would be appreciated
ill look it over, asap and see if I can catch anything out of the ordinary
@@SpawnCampGames Same Problem. Shift works, but without shift it just execute the ->
if (!Input.GetKey(KeyCode.LeftShift))
{
UnitSelections.Instance.DeselectAll();
}
-> in UnitClick. No clue why.
Edit: So i think its all a little bit buggy, I tried this code here for debugging ->
if (Physics.Raycast(ray, out hit, 2000, unit))
{
Debug.Log("YEP");
if (Input.GetKey(KeyCode.LeftShift))
{
UnitSelections.Instance.ShiftClickSelect(hit.collider.gameObject);
}
else
{
UnitSelections.Instance.ClickSelect(hit.collider.gameObject);
}
}
else
{
Debug.Log("NOPE");
if (!Input.GetKey(KeyCode.LeftShift))
{
UnitSelections.Instance.DeselectAll();
}
}
}
-> And the Output was
NOPE
YEP
NOPE
NOPE
NOPE
-> for just one click. So the raycasting or something is very buggy here.
And when I do shift, it does the same, but it doesnt delete the list because of the shift if statement "if (!Input.GetKey(KeyCode.LeftShift))"
@@xamexer Thanks for beginning to debug.. I never noticed this and I'll take a look this afternoon w/ ur example from above to try to work out whats going on..
@@SpawnCampGames Oh no, I found the issue and I feel ashamed xDDD. My Soldier had Unit Click on them for some reason, thats why the script played multiple times. Dont know how that happend. Thank you so much for the vid haha
Where's the second part is this video?
Do u want a second part
@@SpawnCampGames yes. Make more episodes
soo good !!! thank you very much !
nice tutorial
thanks mate.. I got a RTS camera tutorial coming out soon as well.
I found this video really helpfull but I'm new to unity and like the animations that u made and u cutted the video I did not understand nor I found how to make, and I believe that is giving me some errors because my code is the same as your's but some stuff doesn't happen, could you possibly help me?
Sure, just let me know.. what Error is displayed in the Editor Console Window.. What line numbers does it point to.. And what part of the script.. C# is a strongly typed language.. meaning capitalizations, and punctuations are very important..
Do you have a discord server that maybe I could enter so I can show you what the problem is?
But in short words is basically when I drag, the units are not getting selected. And I reviewed the code 3 times and I did not find any diference.
I forgot to say, I dont have any errors in the console nor in the code
if theres no errors in the console.. then most likely. it is a code issue.. its probably an issue where the gameobject / components aren't set correctly
@@tiagopetinga6496
Found the issue, thx for the help@@SpawnCampGames
Gonna comment this for anyone in the future because I was stuck on this for ages: If your drag select code is correct but the UI is acting all weird, change it to a raw image instead of an image. Don't know why this works, maybe because this video is 2 years old.
can you make more RTS tutorials?
what would u like to see?
@@SpawnCampGames like how to give orders or spawning units method
Thanks for tutorial!
hey. i really like your channel . could you help me ! i want make a 2D PUZZLE GAME like LIMBO . so i dont know how i can start. i have many problems about physics and creating 2d layers for scenes .. so could you make a tutorial video ? :(
I'll look into it :)
@@SpawnCampGames thank you so much sir
hey man...any chance you could upload the scripts somewhere?
i'll have to re-do it as i dont have it anymore but i can if you really need it
Thank you!
Why not putting all thing that has to do with unit selection in one class? for every single function a new script is mess I think.
merci beaucoup !
Thanks man !!!
THANK YOU! ❤
Nope, thank you for watching 👀
Its a bad idea to setup everything before you start showing the code. People wanting to learn need to see why things are being added and what they are as they are needed.
Thx for the video
There is no unit selection in Diablo games. Anyway thank you for the tutorial ^_^
Ohh snap! You right. Lmao! && thanks!
wait my unit doesn't move
did you bake the navmesh?
the unit has a navmeshagent..
and then making sure you set a destination of ur navmesh agent?
docs.unity3d.com/ScriptReference/AI.NavMeshAgent.SetDestination.html
@@SpawnCampGames I thanks really much
@@SpawnCampGames oh no wait it was all correct
mega cool!
Can you share a link to your code?
Youre a god
thanks
The best one
my drag select aint working
Same
@@jozefhudec3028 i did a very dumb mistake . i used " > " instead of " < "
I had a problem and it was because UnitSelection.DeselectAll() was throwing a NullReferenceException. (What was very odd was that *the editor was not showing this exception* it only appeared when I tried debugging).
On a whim I tried changing the contents of DeselectAll() to this:
public void DeslectAll()
{
if(unitsSelected.Any())
{
unitsSelected.ForEach(unit => unit.transform.GetChild(0).gameObject.SetActive(false));
unitsSelected.Clear();
}
}
Protecting the ForEach from trying to set the set the Quad to inactive fixed it for me.
Hope this helps you.
P.S you will need to add using System.Linq; to the file to use .Any()
@@BobBobBob445 Amazing! Thank you so much!
please add the subtitles for those of us who don't know English to better understand what you are saying. Thank you very much
I love you.
thanks :)
Ilysm you dont understand
if u guys have problem with select a object just change if statment this way : if(Mouse.current.leftButton.wasPressedThisFrame)
with this its only works just 1 time and selected object is not removing immediately
Hi there! First of all thank you so much for the video! It helped me a lot. I am currently stuck with the Drag Function and I think my problem is with these last few lines
void DrawSelection()
{
if (Input.mousePosition.x < startPosition.x)
{
selectionBox.xMin = Input.mousePosition.x;
selectionBox.xMax = startPosition.x;
}
else
{
selectionBox.xMin = startPosition.x;
selectionBox.xMax = Input.mousePosition.x;
}
if (Input.mousePosition.y < startPosition.y)
{
selectionBox.yMin = Input.mousePosition.y;
selectionBox.yMax = startPosition.y;
}
else
{
selectionBox.yMin = startPosition.y;
selectionBox.yMax = Input.mousePosition.y;
}
}
void SelectedUnits()
{
foreach (var unit in UnitSelection.Instance.unitList)
{
if (selectionBox.Contains(myCam.WorldToScreenPoint(unit.transform.position)))
{
UnitSelection.Instance.DragClickSelect(unit);
}
}
}
I made sure that everything is correct but it seems like none of my units are being selected.
i have the same problem. Did you figure it out?
Had the same issue, I forgot to place an exclamation mark in UnitSelections script:
public void DragSelect(GameObject unitToAdd)
{
if (!unitsSelected.Contains(unitToAdd)) //
it keeps coming up with selectionBox does not exist in current context
using UnityEngine;
public class UnitDrag : MonoBehaviour
{
Camera myCam;
[SerializeField]
RectTransform boxVisual;
Vector2 startPosition;
Vector2 endPosition;
void Start()
{
myCam = Camera.main;
startPosition = Vector2.zero;
endPosition = Vector2.zero;
DrawVisual();
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
startPosition = Input.mousePosition;
selectionBox = new Rect();
}
if (Input.GetMouseButton(0))
{
endPosition = Input.mousePosition;
DrawVisual();
DrawSelection();
}
if (Input.GetMouseButtonUp(0))
{
SelectUnits();
startPosition = Vector2.zero;
endPosition = Vector2.zero;
DrawVisual();
}
}
void DrawVisual()
{
Vector2 boxStart = startPosition;
Vector2 boxEnd = endPosition;
Vector2 boxCenter = (boxStart + boxEnd) / 2;
boxVisual.position = boxCenter;
Vector2 boxSize = new Vector2(Mathf.Abs(boxStart.x - boxEnd.x), Mathf.Abs(boxStart.y - boxEnd.y));
boxVisual.sizeDelta = boxSize;
}
void DrawSelection()
{
if(Input.mousePosition.x < startPosition.x)
{
selectionBox.xMin = Input.mousePosition.x;
selectionBox.xMax = startPosition.x;
}
else
{
selectionBox.xMin = startPosition.x;
selectionBox.xMax = Input.mousePosition.x;
}
if(Input.mousePosition.y < startPosition.y)
{
selectionBox.yMin = Input.mousePosition.y;
selectionBox.yMax = startPosition.y;
}
else
{
selectionBox.yMin = startPosition.y;
selectionBox.yMax = Input.mousePosition.y;
}
}
void SelectUnits()
{
foreach (var unit in UnitSelections.Instance.unitList)
{
if (selectionBox.Contains(myCam.WorldToScreenPoint(unit.transform.position)))
{
UnitSelections.Instance.DragSelect(unit);
}
}
}
}
Update: I Found the error :D