I can't believe something like this isn't behind a paywall. Fantastic work!
@SebastianLague9 жыл бұрын
Episode two - creating the FOV visualisation. Let me know if there's anything more you'd like to see from this series. Hope you enjoy :) You can support my videos on patreon over here: bit.ly/sebPatreon
@leloctai9 жыл бұрын
That would be very cool if you add a stencil buffer shader, you can make everything unseen by the character invisible.
@SebastianLague9 жыл бұрын
+Lê Tài Good idea, I'll experiment with that.
@Mikekan139 жыл бұрын
+Sebastian Lague omg if you can make it so everything is black when the character can't see it It would be amazing!!!!!!!!
@SebastianLague9 жыл бұрын
+Michael Kantack I've got it working, will upload an episode on it later :)
@Mikekan139 жыл бұрын
+Sebastian Lague Then you sir are my hero.
@Mixtrate9 жыл бұрын
I love these small supplement type tutorials. They go over some great math and good programming for a rapid prototype of a system. Awesome to follow along then tinker and learn from the entire process.
@BlackoutGamingChannel2 жыл бұрын
I started learning unity 6 years ago. You were the person who taught me how to code. I still find myself coming back time and time again just to watch your videos either because I remembered you doing a specific thing or just because I really enjoy watching them. I just want you to know how much I've appreciated your content over the years.
@asliniarayanadam2 жыл бұрын
After 7 years this video can be still helpful as its very first day. You are great Sebastian! Thanks a lot!
@connorheyz92303 жыл бұрын
Sebastian, just know how many future game designers you are helping to foster with these fantastic tutorials. What a blessing you are
@NFMynster9 жыл бұрын
Great tutorials man, I can't believe how much work you put into each tutorial. Really great job man, I'm really hoping the best for you!
@SebastianLague9 жыл бұрын
+NFMynster Thank you!
@prod.jakekarno17652 жыл бұрын
FULL 2D script Converting these scripts to 2D for Unity 2021 was an absolute nightmare. Other people have already shared scripts but none of them seemed to work for me entirely. So here are both the scripts, converted to 2D, with a rotation variable added so that you can choose which direction it faces in if you need that and a bool targetAquired to use for enemy actions. Hope it helps. FIELD OF VIEW SCRIPT ( I renamed mine to FOV) public class FOV : MonoBehaviour { public float viewRadius; [Range(0,360)] public float viewAngle; [Range(0,360)] public float fovRotation; public LayerMask targetMask; public LayerMask obstacleMask; ///[HideInInspector] public List visibleTargets = new List(); public float meshResolution; public int edgeResolveIterations; public float edgeDstThreshold; public MeshFilter viewMeshFilter; private Mesh viewMesh; public bool targetAquired = false; void Start() { viewMesh = new Mesh (); viewMesh.name = "View Mesh"; viewMeshFilter.mesh = viewMesh; StartCoroutine ("FindTargetsWithDelay", .2f); } IEnumerator FindTargetsWithDelay(float delay) { while (true) { yield return new WaitForSeconds (delay); FindVisibleTargets (); } } void LateUpdate() { DrawFieldOfView(); } void FindVisibleTargets() { visibleTargets.Clear (); targetAquired = false; Collider2D[] targetsInViewRadius = Physics2D.OverlapCircleAll (new Vector2(transform.position.x, transform.position.y), viewRadius, targetMask); for (int i = 0; i < targetsInViewRadius.Length; i++) { Transform target = targetsInViewRadius [i].transform; Vector2 dirToTarget = (target.position - transform.position).normalized; if (Vector2.Angle(new Vector2(Mathf.Sin(fovRotation * Mathf.Deg2Rad), Mathf.Cos(fovRotation * Mathf.Deg2Rad)), dirToTarget) < viewAngle / 2) { float dstToTarget = Vector3.Distance (transform.position, target.position); if (!Physics2D.Raycast (transform.position, dirToTarget, dstToTarget, obstacleMask)) { visibleTargets.Add (target); targetAquired = true; } } } } void DrawFieldOfView() { int rayCount = Mathf.RoundToInt(viewAngle * meshResolution); float stepAngleSize = viewAngle / rayCount; List viewPoints = new List(); ViewCastInfo oldViewCast = new ViewCastInfo (); for (int i = 0; i < rayCount; i++) { float angle = fovRotation - viewAngle / 2 + stepAngleSize * i; ViewCastInfo newViewCast = ViewCast(angle); if (i > 0) { bool edgeDstThresholdExceeded = Mathf.Abs(oldViewCast.dst - newViewCast.dst) > edgeDstThreshold; if (oldViewCast.hit != newViewCast.hit || (oldViewCast.hit && newViewCast.hit && edgeDstThresholdExceeded)) { EdgeInfo edge = FindEdge(oldViewCast, newViewCast); if (edge.pointA != Vector3.zero) { viewPoints.Add(edge.pointA); } if (edge.pointB != Vector3.zero) { viewPoints.Add(edge.pointB); } } } viewPoints.Add(newViewCast.point); oldViewCast = newViewCast; } int vertexCount = viewPoints.Count + 1; Vector3[] vertices = new Vector3[vertexCount]; int[] triangles = new int[(vertexCount -2) * 3]; vertices[0] = Vector3.zero; for (int i = 0; i < vertexCount - 1; i++) { vertices[i + 1] = transform.InverseTransformPoint(viewPoints [i]); if (i < vertexCount - 2) { triangles[i * 3] = 0; triangles[i * 3 + 1] = i + 1; triangles[i * 3 + 2] = i + 2; } } viewMesh.Clear (); viewMesh.vertices = vertices; viewMesh.triangles = triangles; viewMesh.RecalculateNormals (); } EdgeInfo FindEdge(ViewCastInfo minViewCast, ViewCastInfo maxViewCast) { float minAngle = minViewCast.angle; float maxAngle = maxViewCast.angle; Vector3 minPoint = Vector3.zero; Vector3 maxPoint = Vector3.zero; for (int i = 0; i < edgeResolveIterations; i++) { float angle = (minAngle + maxAngle) / 2; ViewCastInfo newViewCast = ViewCast (angle); bool edgeDstThresholdExceeded = Mathf.Abs(minViewCast.dst - newViewCast.dst) > edgeDstThreshold; if (newViewCast.hit == minViewCast.hit && !edgeDstThresholdExceeded) { minAngle = angle; minPoint = newViewCast.point; } else { maxAngle = angle; maxPoint = newViewCast.point; } } return new EdgeInfo(minPoint, maxPoint); } ViewCastInfo ViewCast(float globalAngle) { Vector3 dir = DirFromAngle(globalAngle, true); RaycastHit2D hit; hit = Physics2D.Raycast(transform.position,dir, viewRadius, obstacleMask); if (hit.collider!=null) { return new ViewCastInfo(true, hit.point, hit.distance, globalAngle); } else { return new ViewCastInfo(false, transform.position + dir * viewRadius, viewRadius, globalAngle); } } public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal) { if (!angleIsGlobal) { angleInDegrees += fovRotation; } return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), Mathf.Cos(angleInDegrees * Mathf.Deg2Rad), 0); } public struct ViewCastInfo { public bool hit; public Vector3 point; public float dst; public float angle; public ViewCastInfo(bool _hit, Vector3 _point, float _dst, float _angle) { hit = _hit; point = _point; dst = _dst; angle = _angle; } } public struct EdgeInfo { public Vector3 pointA; public Vector3 pointB; public EdgeInfo(Vector3 _pointA, Vector3 _pointB) { pointA = _pointA; pointB = _pointB; } } } EDITOR SCRIPT [CustomEditor (typeof (FOV))] public class FOVEditor : Editor { void OnSceneGUI(){ FOV fow = (FOV)target; Handles.color = Color.white; Handles.DrawWireArc(fow.transform.position, Vector3.forward, Vector3.right, 360, fow.viewRadius); Vector3 viewAngleA = fow.DirFromAngle(-fow.viewAngle / 2, false); Vector3 viewAngleB = fow.DirFromAngle(fow.viewAngle / 2, false); Handles.DrawLine(fow.transform.position, fow.transform.position + viewAngleA * fow.viewRadius); Handles.DrawLine(fow.transform.position, fow.transform.position + viewAngleB * fow.viewRadius); Handles.color = Color.red; foreach (Transform visibleTarget in fow.visibleTargets) { Handles.DrawLine (fow.transform.position, visibleTarget.position); } } }
@Ir0nma1den Жыл бұрын
Mate, you're a hero. I was struggling with the same thing!
@prod.jakekarno1765 Жыл бұрын
@@Ir0nma1den Glad I could help, converting it's quite tricky when you're starting out
@LucasJCockburn Жыл бұрын
Thank You! this is epic
@prod.jakekarno1765 Жыл бұрын
@@LucasJCockburn Np, glad I could help
@BusCaseList9 ай бұрын
The world in the hands of heroes like you!
@susi26223 жыл бұрын
even in 6 years after, the quality of the video is utmost. due to the lack of my intellectual comprehension, I can't fully absorb the content. but absolutely helpful video!
@adameisfeld87094 жыл бұрын
I enjoy the style and detail of these videos. You explain the problem and goal first allowing us to think about how we might solve the problem before seeing your solution. I’m a mobile engineer (iOS apps, primarily Swift), I’ve not used Unity yet but I’m glad to see how nicely it plays with custom code, seems very intuitive.
@CodeBlues-TimeisGold7 жыл бұрын
이런건 돈 내고 학원가야 가르쳐 줄까 말까 할 정도로 퀄리티 상급의 강의네요. 대단하단 말밖에 안 나오네요. 애청자 됐어요 ^^ 알아들을지는 모르지만 .. 최곱니다!!!
@florentmougenotaliasdafthu62279 жыл бұрын
God a huge thanks from France for this series ! :D I have learn so much from it and I apply a lot of your tips when I'm making games so please don't stop it this soon :) A good learning can be the AI part if your are motivated :p
@quantumcookie644 жыл бұрын
17:17 I didn't imagine binary search would come in handy in something like this. Wow
@pureatheistic2 ай бұрын
At around 11:40 when writing the for loop, you dont have to artificially adsust the index count by adding one inside the loop. You can just set i=1 as the start of the for loop. Kinda the whol point of defining the iterating variable in the first place. I know you probably know this by now, but other people might find this bit of info helpful as it's a tutorial aimed at beginners.
@telamontgamedev76527 жыл бұрын
I have to say, your videos are absolutely excellent, clear voice, perfect pace, never wasting time trying to figure things out, clearly very well prepared. Your skills are also quite remarkable. Have you made any games commercially available? I'd be curious to see what have you come up with.
@AlanAlan-bv9yg3 жыл бұрын
Sebestian is the best of the best Unity teacher in the world !
@scootergem2 жыл бұрын
at first i was lost, but now i'm beginning to get it. very good stuff. i want more - please... ..sir
@cutsceneentertainment67063 жыл бұрын
FOR US NOOBS - visibleTargets.Count will give you an integer for how many targets are in the field of view. You can use this integer for actually having something happen when when a target is detected. For ex. If visibleTargets.Count >= 1, set off the alarm.
@brendon500494 жыл бұрын
Thank you, this was fantastic. This was also my first time generating a mesh at runtime and you made it incredibly simple.
@Runalotski9 жыл бұрын
This was a nice tutorial, I enjoy the one off short tuts on a specific feature or mechanic to play with in-between my own projects, keep up the good work!
@beratcan94375 жыл бұрын
Awesome tutorial, thank you so much. I implemented this radial raycasting method to my project, it's worked correctly.
@tomtatlichsu28787 жыл бұрын
I love this guys so much! he made the best of the best tutorials.
@boncret3 жыл бұрын
Thank you so much, this series was exactly what i were looking for!
@TheBalalaikaVision8 жыл бұрын
Sebastian Wow, amazing tutorial, everything is explained, I will be using this in my game, excellent work of my friend
@Gonzalo_1054 жыл бұрын
thanks, your one of the best unity youtubers out there.
@lDeath4899 жыл бұрын
You call that miniseries , evil T_T. This will take me a week to fully understand it lol. Your torture is very lovely and welcomed xP. Thank you so much for doing something very useful. I have a note for you though if you don't mind feedback ...
@SebastianLague9 жыл бұрын
+S Al Always happy to receive feedback!
@lDeath4899 жыл бұрын
+Sebastian Lague If you are aiming to teach inexperienced people too then i think you can do it in a better way. If not then no need to read the rest. For example: The moment you want to put a new feature to the script put the main goal without deep details first so that they know why they are doing this then write the code : if (!angleIsGlobal) { angleInDegrees += transform.eulerAngles.y; } [Read the code in an easy way] // if the angle Is not Global then we will convert it to a global angle ( by adding the angle to the transform own rotation ). [Explain why you created it] // This function will set the variable angleIsGlobal to a global angle so that we can make it false when we apply boolean to the editor and that will give us an angle that stays relative to character rotation. You can do this in the video which will make it longer with more work or just write it in a note while you are creating the video and upload it with the files. This will make it very simple to anyone.
@SebastianLague9 жыл бұрын
+S Al Thanks, I will work at this.
@arturoalcibia39899 жыл бұрын
+Sebastian Lague Great tutorials!! but if you could be able to do this for your scripts would be awesome!! I'm a beginner in this and it's really hard to understand most of these concepts even if I look up for them, but great work!
@ShadyCastKittyKai8 жыл бұрын
I would really love if you made a tutorial on how to do a 3d version of this, so it's like a 3d spotlight rather than a flat cone
@Justinjaro4 жыл бұрын
Make a cone 3d object and make it a child of the camera? Nothing really confusing on that one
@HandsOnKnowledge4 жыл бұрын
This was amazing Sebastian, great work and I did learn a lot from it
@MaltProgrammer4 жыл бұрын
Thanks a lot! This is amazing tutorial. I will update my stealth game now!
@gabrielrej8349 жыл бұрын
There is one technique for more realistic visibility detection, for both 3d and 2d. Namely pick a random point within characters volume (like a vertex of the model), use that as a point you cast a ray to, pick another random point and another one and another etc. If a certain percentage of those rays return true, character is visible. If only a f.e. a hand is visible, there would be no way you'd get detected.
@TheOriginalMomos6 жыл бұрын
Hello, hello! Dunno if you'll see this, but could you give an example on how I'd do that in 2D and maybe 3D? 'cause right now I'm concluding that while the representation of the FOV and all is pretty darn great, the fact that it checks only the very center of the sprite before concluding that it sees it is kinda iffy at best.
@paularbas24449 жыл бұрын
Amazing. Was waiting for the 2nd part and it didn't disappoint :) thank you for all the hard work. Was also wondering if you ever considered doing a series on character cameras for different game modes? For example a strategy game, which allows you to select units with a drag box. A camera that has the very rough basics of what you see in 3rd person games. Be it mmos, adventure games, over the shoulder and so on. Another series that would be interesting is a mini series on basic programming concepts and optimizations, like object pooling, mesh and material merging and separating between objects of same type, saving/loading system. Maybe more topics on procedural generation, especially when it comes to generating terrain. Heightmap and nonheightmap based generation? Or maybe just play around and explain different noise methods, like perlin noise, voronoi and so on? Well whatever the case, hope to see more interesting topics from you in the near future :)
@ashleytwo8 жыл бұрын
Fantastic series that really has helped, both the scripting side and the general maths/geometry pointers were great. Having problems trying to convert this to 2D. I can get it working to display the Debuged lines (around 3 minutes) but by the time we get to the mesh (15 minutes) it's not working. I can attach a mesh, but rather than clipping around obstacles it's simply not drawing on top of them. If I have a small obstacle the FOV still shows, but it just looks like the FOV is a layer underneath rather than working around it. If that makes sense. If anyone has any suggestions I'd be much obliged!
@MrNathanShow6 жыл бұрын
I was able to follow along well, just most of the transformations are Vector2 based now. Also, 2D collisions do not work with 3D collisions, 2D is done with Box2D and 3D is done with PhysX (so they are completely different systems). Physics2D is going to be needed to correctly convert this to 2D.
@TheOriginalMomos6 жыл бұрын
Hello, hello! Got a question for you: By "most of the transformations are Vector2 based now", do you mean stuff like transformation.position? Right now what I'm struggling with is to get the required infos out for the Physics2D.Raycast.
@thatcreepyguyinthecorner33645 жыл бұрын
To make it work in 2d just replace RaycastHit2D hit; if (Physics2D.Raycast(transform.position, dir, hit, viewRadius, SightBlocker)) { return new ViewCastInfo(true, hit.point, hit.distance, globalAngle); } else { return new ViewCastInfo(false, transform.position + dir * viewRadius, viewRadius, globalAngle); } With RaycastHit2D hit = Physics2D.Raycast(transform.position, new Vector2(dir.x, dir.y), viewRadius, SightBlocker); if (hit != null && hit.collider != null) { return new ViewCastInfo(true, hit.point, hit.distance, globalAngle); } else { return new ViewCastInfo(false, transform.position + dir * viewRadius, viewRadius, globalAngle); } Hope That Helps!
@ToastandBananas4 жыл бұрын
@@thatcreepyguyinthecorner3364 My saviour!
@ForgottenMovieGems5 жыл бұрын
This is incredibly helpful for a university project that I'm working on! You may have just saved my butt :P
@cedricodigital9 жыл бұрын
Incredible material, as usual ;-) Bravo!
@nickngafook9 жыл бұрын
Amazing tutorial series! Thanks for the hard work
@123dgriffin2 ай бұрын
This is amazing work. Curious if you have any content to handle this same type of thing but with uneven terrain
@keithtai79455 жыл бұрын
Great tutorial! May I know how you turn those blue capsule to red when it get detected?
@casvanmarcel9 жыл бұрын
Fantastic work Sebastian
@gotbaka3 Жыл бұрын
Amazing, you are a life saver
@stefan4294 жыл бұрын
i really appreciate all the explanations, i sort of understand all this! :D
@Elledan31016 жыл бұрын
Great material. thank you so much! :)
@Secretlycat313 жыл бұрын
This helped so much. Thank you very much
@mAeX1353 жыл бұрын
I LOVE YOU FOR THIS TUTORIAL!
@永泽秦 Жыл бұрын
very nice work man
@ronnieth3bear8 жыл бұрын
This is a fantastic tutorial. Thank you so much!
@bytestream649 жыл бұрын
Gread mini series. One question though: How does this react to rather small obstacles? Wouldn't it simply ignore them if they are small enough to completely fit between two rays?
@flat6_music8 жыл бұрын
Although your comment is ten menths old, look at this: ncase.me/sight-and-light/ Basically you cast a ray to the edges of the Object and then cast two additional rays, wich are rotatet by a tiny amount so that they hit the wall or whatever behind the edge. You can find this explained a little bit better when you look at the link I just gave you :)
@Psyhogenesis6 жыл бұрын
Thank you very much, sir, for your tutorial.
@johncruel45648 жыл бұрын
thank you for making this very good tutorial.
@timadams16623 жыл бұрын
I was messing around after completing the tutorial and polishing/optimizing more and I found a piece of functionality that I wanted in and figured it out. When the ViewAnglew is set to 360 there was always a small gap in the back of the view. Now this could be because I calculated things wrong or just by design, but I wanted to support the 360 view. Here's the code for it: ============================================ int vertexCount = viewPoints.Count + 1; Vector3[] vertices = new Vector3[vertexCount]; int triangleCount = (vertexCount - 2) * 3; if (viewAngle == 360) { triangleCount += 3; } int[] triangles = new int[triangleCount]; vertices[0] = Vector3.zero; for (int i = 0; i < vertexCount-1; i++) { vertices[i + 1] = transform.InverseTransformPoint(viewPoints[i]); if (i < vertexCount - 2) { triangles[i * 3] = 0; triangles[i * 3 + 1] = i + 1; triangles[i * 3 + 2] = i + 2; } } if (viewAngle == 360) { triangles[(vertexCount - 1) * 3 - 3] = 0; triangles[(vertexCount - 1) * 3 - 2] = vertexCount - 1; triangles[(vertexCount - 1) * 3 - 1] = 1; } ============================================ Starting where you calculate the VertextCount and all the way till before you RecalculateNormals this adds 3 to the triangleCount if the viewAngle is 360. Because we need to add 3 more points for a triangle into it. After the for loop we have to use different functionality for the indices of the last triangle. Instead of increasing by 1 and 2 at an index we start from the end and count backwards. Using the center point for the first slot (as always), the vertexCount-1 (the Length) for the second, and 1 for the last as we're reconnecting to the first index always. I hope this helps anyone who was figuring this out to get trucking and find the answer/just copy paste :P
@elronman4 жыл бұрын
Accidentally had my viewvisualization mesh scaled to 2 for some reason. Spent like an hour trying to figure out what was doubling it in the script.
@eggsscramblerzz47116 жыл бұрын
this coding is so satisfying to watch (y)
@cschott9 жыл бұрын
Great work! The effekt looks damn nice :D And happy new year! ( nearly there ;) )
@SebastianLague9 жыл бұрын
+Mr3D Thanks, happy new year :D
@Catequil4 жыл бұрын
I wonder whether the edge detection could be solved by drawing a line from the impact point alongside the normal of the impacted object, until it exists the object. This could reduce the ammount of rays, but idk whether the calculation would be much lighter in the grand scheme of things, as it would be difficult with spheres etc.
@sadekmaghzili27488 жыл бұрын
How I can make a condition when the player see the target please ?
@romeogaming64243 жыл бұрын
EXCELENT, thank you very much!
@PS3centere9 жыл бұрын
love the new diagrams
@doshirts-77018 жыл бұрын
HOW TO DO IF IN VISIBLE SECTOR, for example to change the color of the object ?
@MrBalinSuperTV4 жыл бұрын
Bug fix: public Vector3 DirectionFromAngle(float angleInDegrees, bool angleIsGlobal) { if (angleIsGlobal) angleInDegrees += transform.localRotation.eulerAngles.y; return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), 0, Mathf.Cos(angleInDegrees * Mathf.Deg2Rad)); } Where need to get LOCAL rotation euler angle for Y.
@cyco3oy8 жыл бұрын
Keeping performance in mind, can i run this attached to 20 or more enemies?
@daveroydun118 жыл бұрын
Impressive presentation. and it works! Still trying to figure out how you can type and speak so effortlessly without losing your train of thought or having to backtrack your explanation!
@SebastianLague8 жыл бұрын
+Dave Dunbar Movie magic!
@86lufe3 жыл бұрын
damn, man... you are too good.
@omniges2 жыл бұрын
is createEmptyChild() a method of disfunctionalHousehold() ?
@Aaaalfaroeo4 жыл бұрын
How can I convert if (Physics.Raycast(transform.position, dir, out hit, Radius, obstacleMask)) to Physics2D?
@Slymp04 жыл бұрын
There is a Physics2D.Raycast() equivalent
@igortelepenko25723 жыл бұрын
this is how I've done this: ViewCastInfo ViewCast(float globAngle) { Vector3 dir = DirFromAngle(globAngle, true); RaycastHit2D hit = Physics2D.Raycast(transform.position,dir, viewRadius, obstacleMask); if (hit!=null && hit.collider!=null) { return new ViewCastInfo(true, hit.point, hit.distance, globAngle); } else { return new ViewCastInfo(false, transform.position + dir * viewRadius, viewRadius, globAngle); } }
@perendi55838 жыл бұрын
Great tutorial, thanks alot!
@lachee30557 жыл бұрын
some could argue that the edge problem is really just..... a edge case *ba dum tish*...... I will walk myself out.
@glorkeShprork3 жыл бұрын
I've watched to 15:24 and my view cone goes through obstacles, where did I go wrong?
@wilcorelow2 жыл бұрын
Maybe your obstacles are not quite on the ground and the view cone is passing under them.
@glorkeShprork2 жыл бұрын
@@wilcorelow Thanks Man!
@akmaludddin9281 Жыл бұрын
i Hope i found this sooner :( 2023 now and finally i found this video
@rodolforubens9 жыл бұрын
This is amazing, thank you!
@jthespacec9 жыл бұрын
Awesome, dude. Thanks
@anonyanony74696 жыл бұрын
Love your vids.
@Blacksoul4445 жыл бұрын
Nice Tutorial man, thanks! Wouldn't it be more performant and smoother to save the vertices of the obstacles and construct a triangulated mesh incorporating the exact vertices? That way you wouldn't have to guess where to find the edge of an obstacle in view and would not have to deal with the jitter. Of course, it would require a little preliminary work, like adding 2D-Colliders to the obstacles and taking their vertices.
@Blacksoul4445 жыл бұрын
@Luc Bloom You're right.
@lightswitch26222 жыл бұрын
what if there is many objec
@jakubkadlec42854 жыл бұрын
Very nice tutorial, that's right .. but I'm little bit struggling in how to work with visible targets. I have this field of view script on enemy and whenever the player is in fov of enemy, the enemy should look at player.. But he don't want to look at him. I tried everything..write it in FieldOfViewEditor script where red line is created, i tried to call it from another script but nothing work .. would it be possible to explain how it's done ..? i would be really grateful
@drakis507 жыл бұрын
This is awesome! Thanks to you I can finally continue with a project that me and couple friends are doing, we really needed this field of view. Any tip of how to convert this to a spherical Field of View?
@andresmicalizzi54204 жыл бұрын
Awesome tutorial. Haven't tried it yet, but how does it perform? Considering it's creating meshes each frame. Isnt it a resource hog?
@Hukhaa6 жыл бұрын
How to translate this script to a 2D view? i cant create the mesh on YX axis.
@Milfofin4 жыл бұрын
This worked for me: In the DirFromAngle function, check the line starting with return new Vector3, and see to it that (Mathf.Sin[...], 0, Mathf.Cos[...]) are changed to (Mathf.Sin[...], Mathf.Cos[...], 0), i.e. that the X and Y is populated.
@indoxperia8 жыл бұрын
Hope the best for you to make a lot of tutorial.
@MattTaylorMotion Жыл бұрын
Hey Sebastian, This is incredible. Thank you so much for getting this out. There is a case that your mesh refinement step doesn't solve for, which is when two subsequent rays hit two different obsticles at different depths. I attemped to use the distance between the end points of the rays, instead of rays 'hit' boolean, and that works, but this solution tends to cause problems on very steep collisions. I've been struggling for a day to come up with a solution but no luck. I know this is a super old video, but I wonder if you have any insight for this particular case. Thanks again.
@ornithorink Жыл бұрын
Hello I'm in the exact same situation for my project, have you found a solution?
@nickstavrou26938 жыл бұрын
Excellent tut man genius! Is there a way to UV planar map that mesh filter so i can apply a round texture to it and give a falloff effect using additive material?
@paranormalgamesstudios8 жыл бұрын
Awesome work! How could i make the shader have a falloff? How could i make the furthest vert alpha transparent?? thanks
@gamedevmonkey67634 жыл бұрын
Can I use this without the mesh aspect and can height be added to this? i.e. a thickness in height or perhaps up and down angles? For detecting things at knee level and things at head level? Without the mesh aspect can I strip out the mesh construction stuff?
@ulgmail7 жыл бұрын
Hi, I really love your tutorials - great job! If you have a free minute, maybe you could at least have a quick look on a question I have regarding a movement area/circe. I want to draw a circle on a terrain like the circle you are drawing in the video above, but as a terrain might not be flat I'm struggling a bit with how to achieve this. I already implemented 2 approaches, but I'm not happy with both of them and wanted to ask you if you have an opinion or maybe a hint what I could/should do. My first attempt was to create custom meshes in a circle around my character and with raycasting I placed the vertices right above the terrain, even on non flat places - it works, but in my opinion it doesn't look good. My second attempt was to use a projector to project a circle around my character which has the size equivalent to the character's actionpoints - this works too, but then I have the problem that I cannot modify the circle if there is some obstacle in the way.... did you ever implement such a thing? As mentioned, if you have some free minute, any hint or help would be greatly appreciated!!
@mateuszbiaas15596 жыл бұрын
How I can add texture for cone field ? Like Shadow tactic,commandos etc.
@Shringyshrong4 жыл бұрын
Hey! Can someone help? For some reason using the "Fade" option in the shader for the View Visualisation Material just does not work and makes it disapear. On both the "Opaque" and "Cutout" options of this shader it works, although I can not make it transparent at all. Would anyone happen to know why this is happening?
@AletseDev2 жыл бұрын
How change where is the field of view? i need the cone on the head of my character but it is on ground, how im put a offset to put on reight place?
@RyanJhider3 жыл бұрын
Some body know how to Make it compatible with multiplayer using Mirror ?
@leopripos8 жыл бұрын
Hello +Sebastian Lague I have a problem to add mesh collider to the field of view. could you please explain about it? thanks before
@PaycoTsunami5 жыл бұрын
add a meshfilter as well as the meshrenderer to the "View Visualization" I know its 2 years later but helps anyone who needs it
@--------------------------..9 жыл бұрын
The last bug when two consecutive viewcasts hit is still not fixed. As I understand it, viewcast.dst is just the distance to the hitpoints. Two different obstacles can of course be set up to be the same distance to you, and you would not refine your viewcasts.
@JulienCroain9 жыл бұрын
+/ / I think you have right. We could test the collider return by the RayCastHit to know if they are different. What do you think +Sebastian Lague
@slurpleslixie4 жыл бұрын
Did Unity at the time not allow Vertices/Triangles of a mesh to be created with a List? Or was there some other reason to manually construct Arrays for them?
@Somiaz3 жыл бұрын
For some reason FindEdge is coming up with an error that 'not all code paths return a value'. Also, the i++ in the FindEdge for loop has an error of 'unreachable code detected'. Anyone know what could be wrong? Also, because this is happening, I can't enter playmode in Unity.
@kermitfroggers48792 жыл бұрын
I have 2 problems with guards being able to see my player: 1) I found out by accident if the player is close enough to the enemy, he won't be seen by the enemy when standing in their field of view. I have to walk almost near the edge of the FOV's radius for the enemy to see me. 2) The second problem is enemies can only see my player if the FOV's angle high enough (at least 80 degrees). Any lower and my player won't be seen by the enemy even when I stand inside the enemy's FOV viewcone. How do I fix these 2 problems?
@MrBalinSuperTV4 жыл бұрын
Mesh won't show if smaller than 3 degrees. Is there a way we can fix?
@abnejne47377 жыл бұрын
Great video, but if one would like to make this kind of field of view in "3d" meaning in a way so that the visualisation could also handle hight differences. How could that be done? I have been thinking about this for a while, but the solutions i come up with would use so many raycasts, that I think that there has to be a better and smarter way.
@mchristensen56837 жыл бұрын
I know that this is an old video, but i'm having trouble using the ViewCastInfo strut. My method declared inside the struct is not working and writing: "Method must have a return type" even though i've written it exactly as in the video?
@paul_lifemademe6 жыл бұрын
hello, If I want to bool to return true on the fov script, whenever a target is spotted, please how would I do this. thanks...
@shurikend8 жыл бұрын
If we add a 2nd player in local mode with the same script, is there some interferences issue between the 2 field of view ?
@oreonengine94448 жыл бұрын
great job man!
@NFMynster9 жыл бұрын
Hello again man, how (and where) would I detect what's in the view cone? Such as enemies as you have done.
@mukining01502 жыл бұрын
My modernized and complete version of both scripts for 2D games if anybody is interested or having some trouble. Note: In my script, I didn't use view Radius as I wanted mine to exceed everywhere. So if you want to copy this script you will have to Add the edge radius float back in, change the Mathf.Infinity back to the edge radius variable and change the max range back to [0, 360]. This also won't work for 3D games as the changes I have made work only in 2D. The changes aren't too drastic so if you want to use 3D and are really struggling I suppose you could just look in the Field of View Script for all the components I have changed, mainly just some formatting and the added 'Physics2D' here and there. Enjoy! :) Field of View Script - Script 1 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; [ExecuteInEditMode] public class FieldOfView : MonoBehaviour { [Range(0, 361)] public float viewAngle; public LayerMask targetMask; public LayerMask obstacleMask; public List visibleTargets = new List(); public float meshResolution; public int edgeResolveIterations; public float edgeDstThreshold; public MeshFilter viewMeshFilter; Mesh viewMesh; private void Start() { viewMesh = new Mesh(); viewMesh.name = "View Mesh"; viewMeshFilter.mesh = viewMesh; StartCoroutine("FindTargetsWithDelay", .2f); } IEnumerator FindTargetsWithDelay(float delay) { while (true) { yield return new WaitForSeconds(delay); FindVisibleTargets(); } } private void LateUpdate() { DrawFieldOfView(); } void FindVisibleTargets() { visibleTargets.Clear(); Collider2D[] targetsInViewradius = Physics2D.OverlapCircleAll(transform.position, Mathf.Infinity, targetMask); for (int i = 0; i < targetsInViewradius.Length; i++) { Transform target = targetsInViewradius[i].transform; Vector3 dirToTarget = (target.position - transform.position).normalized; if (Vector3.Angle(transform.forward, dirToTarget) < viewAngle / 2) { float disToTarget = Vector3.Distance(transform.position, target.position); if (!Physics2D.Raycast(transform.position, dirToTarget, disToTarget, obstacleMask)) { visibleTargets.Add(target); } } } } void DrawFieldOfView() { int stepCount = Mathf.RoundToInt(viewAngle * meshResolution); float stepAngleSize = viewAngle / stepCount; List viewPoints = new List(); ViewCastInfo oldViewCast = new ViewCastInfo(); for (int i = 0; i < stepCount; i++) { float angle = transform.eulerAngles.y - viewAngle / 2 + stepAngleSize * i; //Debug.DrawLine(transform.position, transform.position + DirFromAngle(angle, true) * 7, Color.red); ViewCastInfo newViewCast = ViewCast(angle); if (i > 0) { bool edgeDstThresholdExceeded = Mathf.Abs(oldViewCast.dst - newViewCast.dst) > edgeDstThreshold; if (oldViewCast.hit != newViewCast.hit || (oldViewCast.hit && newViewCast.hit && edgeDstThresholdExceeded)) { EdgeInfo edge = FindEdge(oldViewCast, newViewCast); if (edge.pointA != Vector3.zero) { viewPoints.Add(edge.pointA); } if (edge.pointB != Vector3.zero) { viewPoints.Add(edge.pointB); } } } viewPoints.Add(newViewCast.point); oldViewCast = newViewCast; } int vertexCount = viewPoints.Count + 1; Vector3[] vertices = new Vector3[vertexCount]; int[] triangles = new int[(vertexCount - 2) * 3]; vertices[0] = Vector3.zero; for (int i = 0; i < vertexCount - 1; i++) { vertices[i + 1] = transform.InverseTransformPoint(viewPoints[i]); if (i < vertexCount - 2) { triangles[i * 3] = 0; triangles[i * 3 + 1] = i + 1; triangles[i * 3 + 2] = i + 2; } } viewMesh.Clear(); viewMesh.vertices = vertices; viewMesh.triangles = triangles; viewMesh.RecalculateNormals(); } EdgeInfo FindEdge(ViewCastInfo minViewCast, ViewCastInfo maxViewCast) { float minAngle = minViewCast.angle; float maxAngle = maxViewCast.angle; Vector3 minPoint = Vector3.zero; Vector3 maxPoint = Vector3.zero; for (int i = 0; i < edgeResolveIterations; i++) { float angle = (minAngle + maxAngle) / 2; ViewCastInfo newViewCast = ViewCast(angle); bool edgeDstThresholdExceeded = Mathf.Abs(minViewCast.dst - newViewCast.dst) > edgeDstThreshold; if (newViewCast.hit == minViewCast.hit && !edgeDstThresholdExceeded) { minAngle = angle; minPoint = newViewCast.point; } else { maxAngle = angle; maxPoint = newViewCast.point; } } return new EdgeInfo(minPoint, maxPoint); } ViewCastInfo ViewCast(float globalAngle) { Vector3 dir = DirFromAngle(globalAngle, true); RaycastHit2D hit = Physics2D.Raycast(transform.position, new Vector2(dir.x, dir.y), Mathf.Infinity, obstacleMask); if (/*hit != null &&*/ hit.collider != null) { return new ViewCastInfo(true, hit.point, hit.distance, globalAngle); } else { return new ViewCastInfo(false, transform.position + dir * Mathf.Infinity, Mathf.Infinity, globalAngle); } } public Vector3 DirFromAngle(float angleInDegrees, bool angleIsGlobal) { if (!angleIsGlobal) { angleInDegrees += transform.eulerAngles.y; } return new Vector3(Mathf.Sin(angleInDegrees * Mathf.Deg2Rad), Mathf.Cos(angleInDegrees * Mathf.Deg2Rad), 0); } public struct ViewCastInfo { public bool hit; public Vector3 point; public float dst; public float angle; public ViewCastInfo(bool _hit, Vector3 _point, float _dst, float _angle) { hit = _hit; point = _point; dst = _dst; angle = _angle; } } public struct EdgeInfo { public Vector3 pointA; public Vector3 pointB; public EdgeInfo(Vector3 _pointA, Vector3 _pointB) { pointA = _pointA; pointB = _pointB; } } } FieldOfViewEditor Script - Script 2 using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; [CustomEditor(typeof(FieldOfView))] public class FieldOfViewEditor : Editor { void OnSceneGUI() { FieldOfView fow = (FieldOfView)target; Handles.color = Color.white; Handles.DrawWireArc(fow.transform.position, Vector3.forward, Vector3.right, 360, Mathf.Infinity); Vector3 viewAngleA = fow.DirFromAngle(-fow.viewAngle / 2, false); Vector3 viewAngleB = fow.DirFromAngle(fow.viewAngle / 2, false); Handles.DrawLine(fow.transform.position, fow.transform.position + viewAngleA * Mathf.Infinity); Handles.DrawLine(fow.transform.position, fow.transform.position + viewAngleB * Mathf.Infinity); Handles.color = Color.red; foreach(Transform visibleTarget in fow.visibleTargets) { Handles.DrawLine(fow.transform.position, visibleTarget.position); } } }
@colonthree4 жыл бұрын
What about using the hit.normal and/or object ID (int) to also help with checking along with the Exceedingly Edge Distance Thresholde? ;w;
@perendi55838 жыл бұрын
Most of time i just work with the 2D tools of unity, because im not confident with 3d modelling. It is not possible to use this method for 2D sprites / 2DCollider, because they have no mesh renderer right?