• 3D Game Kit Teardown
    13 replies, posted
I'm taking a look into the 3D Game Kit that Unity Just Posted, while posting anything interesting I find in this post. Christ this is taking a long time to import. 25 minutes. Assets folder is 4.5gb. Not a good start, fresh install. https://files.facepunch.com/garry/a0a08839-48f0-4397-ad50-8c8b44b5e4b0.png Restarting fixed it. Hey they have an options screen, might be some good stuff to rip here https://files.facepunch.com/garry/b4bfbbc8-e87e-4511-b508-3738196e6ae0.png No key rebinding, it just tells you what the controls are.. fail. https://files.facepunch.com/garry/db1cac6f-3406-4efe-9803-586d37b5f55a.png They seem to have a nice background HUD blur in game.. lets see how that works. https://files.facepunch.com/garry/637323b4-3f4b-4a10-a1b2-0fd87e69abe4.png Hey the UI a bunch of different Canvases. I always try to use just one because in Rust we found there was a significant stutter when turning canvases on and off. Background blur is done with a frostedglass shader. It's much nicer than the one I wrote for Tub. Stealing. Two unnammed grabpasses though. IIRC this means that if you're using it on 10 panels, there'll be 20 grabpasses. Camera movement kind of sucks. Don't know whether that's too much smoothing or too sensitive. Using regular Unity character controller. Lots of UnityEvents on their objects. Don't know whether that's optimal or just because they're going for the "no coding" angle. TIL Vector.Set exists. https://files.facepunch.com/garry/3f947bbd-a711-4915-b865-ec10d0521ada.png Oh boy. They want it so when you press fire m_Attack stays true for 0.03 seconds. Here's how it's done. https://files.facepunch.com/garry/d471e366-ae78-4225-b91c-cb937193ab1e.png The AttackWait coroutine is https://files.facepunch.com/garry/773ec77f-e923-4bac-b4e2-666735afc818.png What the fuck is m_AttackInputWait? https://files.facepunch.com/garry/5cd49332-5326-4eab-8761-a5d8d3b83e4a.png Jeysus. Here's a tip if you're doing shit like this: TimeSince – Garry's Blag Can we talk about variable names too please. m_, s_ - stop it. Private variables start with lowercase. Public variables start with uppercase. This is c#. I don't want to nitpick on the code too much - because we'd all be eating shit if someone was criticising our code, but at the same time I was hoping this would be Unity showing us best practices. I'm not sure that managing a coroutine to keep a bool true for 0.03 seconds is that. And please don't think I went digging, it was the first file I opened. WIth levels, they seem to make common stuff prefabs and then count on them being in every level. https://files.facepunch.com/garry/115d6360-f0e6-4e18-9ed6-8811c505a400.png This works, but it's probably not ideal if you have 40 levels and need to add or remove a common prefab in each one. I usually have common stuff in another scene and additive load it in on load. It's maybe understandable that it works like this though, if you're trying to keep things simple and easily understandable. It's funny how they organise stuff with the ---- BLAH -----. People have been asking for years for ways to organise stuff like this. Grouping stuff, setting colours, background colours, icons. Anything. It doesn't seem ideal to be creating GameObjects to create sections like this. There's some stuff like this: https://files.facepunch.com/garry/cd31111a-c823-4104-a1c0-c38c54c7e575.png Where they've made an animation that does stuff like turning a renderer on and off, changes its UV's and position and stuff. In this instance it's for when the character melee attacks with the staff, it makes a swish effect. https://files.facepunch.com/garry/d6f6b846-104b-4aaf-abf3-90f98cea8f56.png This isn't something I'd considered doing before, always opting to make components that fade shit out, flicker lights etc. I'm not sure this is optimal, but I can definitely see benefits of it from an artist/no coding point of view. The Staff doesn't seem to be animated in any way, but it's still a skinned mesh. https://files.facepunch.com/garry/ce62377f-e4ac-483c-a0a7-91b0038b5bc5.png I'm not sure there's a reason for that. Melee works by defining a number of points along the staff, then in FixedUpdate tracing between their last and current position., using a SphereCast. It then checks for a Damageable component on the hit colliders. It plays audio based on a renderer material. https://files.facepunch.com/garry/ace2f8b2-9580-4d92-b6d6-6cb1972a78c3.png (I think GetComponentinChildren returns component on the object you call it on anyway, so that first GetComponent might be redundant). This doesn't seem like a particularly smart thing to do unless you have like 6 materials in your game. It seems like the smart thing to do would be to do it base don the collider's physics material. That way you could still have different sounds based on stuff being metal or whatever, but wouldn't have to add every meal material in there. https://files.facepunch.com/garry/af03740a-f3a2-4457-90c9-2c5c70862ff0.png Hey if you add any new ground materials, please go around all the audio sources in the game and update them They have an object pooler class https://files.facepunch.com/garry/afb17674-41a5-4dd6-ab97-afcd62298cab.png Seems like a nice idea. Instead of creating new projectiles over and over again, it creates 20 and lets you use them. It's nice and simple, doesn't handle over-popping (you'll get errors if there's more than 20 projectiles live), or handle destroying the pool once the owning object is destroyed. But I guess it works in some situations, and explains the main concept. They have an audiosource on the objects for each sound they can make. https://files.facepunch.com/garry/4ddc4843-cb91-45e1-8156-da00775d5105.png And they change the audioclip on those sources to a random one to give some variety (along with changing pitch etc). This seems like the right way to do it. In Rust we had all the effects on different prefabs, and spawned then when needed. This has the benefit that we could have particle effects and shit on there too. The problem with that is you're spawning objects all the time. I think we still do that in Rust, but now we pool it all. Looking at some of the editor gizmos. They're showing connections between shit. https://files.facepunch.com/garry/d3817b9b-c5fa-4827-ac09-8260096d6f31.png That's done by this in an editor. https://files.facepunch.com/garry/fdd4b615-8df1-4d49-8421-373b73345d62.png I never even knew about this attribute, I've been doing some really hacky shit to get shit to draw when it's not selected. Something I've just noticed is that the Scene view is playing even when I'm not interacting. I wonder what's doing that - because I had to do some terrible hacks to get that to happen. I can't find anything. They have a skybox camera https://files.facepunch.com/garry/cd1ad676-4c1f-4cd9-8dec-3c16e02a406f.png So they're rendering two cameras every frame. My experience with Rust tells me this is a bad idea, not because of the rendering cost - but because of the culling cost. But I'm sure things have improved since then. This is pretty nice. The PainterTools are MonoBehaviours. So you select them in the Hierarchy view. https://files.facepunch.com/garry/3dcd6b5d-0695-4494-9c59-04d50dfa4c6d.png Runs like dogshit though. Allocates half a mb of memory every frame redraw when using it. Some good rippable stuff there though. AssetPreview buttons in the inspector, drawing a model in the scene view, all good stuff. Camera stuff is using Cinemachine, so it's not using raw mouse input for the freelook, which is why it feels so floaty and runaway. Probably feels okay with a controller. Looks like they didn't use UnityEvent for everything. https://files.facepunch.com/garry/62ee80e1-4fe5-4a33-838a-137c060b3311.png Their alternative seems to be an abstract component called GameCommandHandler. Then you implement a class for what you need. https://files.facepunch.com/garry/bfa58911-c006-46b6-9305-33e5a58ef4d4.png Apparently UnityEvent is okay for triggering sound plays and shit on hovering something in the UI, but not when pressing a button in a game There's a hair and eye shader in there that seem like they'd be useful to someone for something. https://files.facepunch.com/garry/fbdf48ff-4773-49ff-8296-6b2cccca77bd.mp4 https://files.facepunch.com/garry/276824c5-9670-4666-b9f7-ba5d29b1ce04.mp4
If they're going to use game objects to sort things, at least parent them under the BLAH section, fucking hell
Nice. Not surprised the pack itself is a mess - I've been waiting for Unity to start putting more effort into spreading good practices but, I don't know when that is gonna happen.
Thanks for the post. I too was hoping to see some best practices and this is kinda disappointing. You said that in Rust you would spawn sound effects and particles, isnt it better to just have a prefab for each of the effects in the scene and just position it in the desired place and play it when needed? Especially when it comes to particles since you can just play them in global space and the effect stays there even when you move the particle GO far away.
Interesting stuff. Had a laugh at the fact they didn't bother to implement re-bindable keys under their controls menu. I'll have to dig through this myself and see what I can scrape up, the blur shader for UI seems useful, one I've used in the past sucked pretty bad.
Interesting stuff and great insights, thanks Garry.
I wouldn't describe it as a mess, but I wouldn't look at it for best practices either
People are going to bypass code, then bypass blueprints (bolt?), then spend all their time learning how to use these kits and imported assets.
The coroutine part shows how to start/cache/stop coroutines without using the string version of StartCoroutine (which they did in the docs for the longest time), and that you can cache yield instructions instead of creating new ones. If their intention is to show "how to cororutine" I guess it kinda works, though it might not be the best scenario. But isn't WaitForSeconds limited by your frame rate? Like, WaitForSecond of 0.01 sec will actually wait for 0.167 sec if your target FPS is 60.
This is something I'd expect to see in your blog rather than the forums, but still solid write up. Shame they didn't make it as optimal as possible, seems like they really tried selling it with the "everyone can make a game" attitude Liked the bits where you gave actual coding advice, hope to see more educational stuff in the future
Would be nice if they had a way to refresh while in Unity instead of having to restart or to delete and redo assemblies it drives me mad. Also I have pools in my game and It's absolutely amazing the performance increase you get, main one being I have machine gun towers (Tower Defense) and the bullets are pooled it simply lags to fuck on mobile without it but as you said once that's used it's throwing object reference not set errors.
Hey, one of the programmer from the project here. First, thanks for all the feedback! The project have been a bit rocky for the 9~10 peoples involved in between other projects, so it's pretty easy to loose sight of stuff and stop seeing any problems after a while, so proper feedback is always useful for us! Also, as said in this topic, you're right, do not look at that for best practice (especially code wise). The goal of the project was to allow very beginner to grab a "full" project and play around the scene view & inspector. showing what can be done, so some decision we took during the ~5 month dev time was more about making it simple to use in editor, sometime at the cost of proper code structure (also, well, deadline have a bad habit of leading to some rush code :p ) Some more info on the thing : The errors are pretty bad. They are because the package manager manifest can't be packaged with asset store project for now, so when a project is imported, it compile with missing package, so error in compilation. The PackageManagerAssembly.dll is supposed to add all the packages to the manifest list and then import them. I though I had fix the need to reload the editor but I guess it don't work properly everywhere. Back to the drawing board... key rebinding : we skipped on that for the project as not the target, but been so often I've seen people asked around for it, adding that to todo list of tutorial/sample pack! UI Blur : you're right if 20 canvas use it, there will be 20 grab pass. You can make a grabpass happen only once, even if 20 objects use it, by adding a name to the grab pass (see after for example) but the problem is that then you'll only blur the background. Overlapping UI element won't blur each other. Need to choose the tradeoff depending on the need of your project. GrabPass { Tags{ "LightMode" = "Always" } "_ScreenContent" } //then just use the texture with the name instead of _GrabTexture sampler2D _ScreenContent; Lots of UnityEvents : yeah it is NOT optimal at all, UnityEvent use Reflection and all, avoid them if you're a more experienced programmer, prefer them interface on object or any other "explicit" system. They are just very practical for simple drag'n drop, so for beginner learning how to use the editor, that's what we have gone for (mostly, there is also an alternative somewhere in the project offered as a "you can also do something like that" for people poking at the code) variable names : I totally second you there we were sticking to the internal code convention for C# code (if you look at other open sourced unity c# part, you'll see a lot of that, it's a legacy thing from decade ago, it sucks, and hopefully will be changed soon...) Common thing prefab in all level : yeah we wanted to avoid the additive loading for beginner, to simplify adding them in all thing, there is a Create New Scene tool (in the kit tool menu) that will copy a "template" scene that already have everything setup. It is explored more in detail in the quick start guide and manual of the kit. organise stuff with the ---- BLAH ----- : Again seconding you on that, using gameobject isn't optimal. The cost is zero to none, as those are top object that never move, but a hierarchy with 'meta data' to "order" it would be sweet (my preference would even be different "view" for the hierarchy window, you can view it as hierarchy, as category etc...) Animation for fading/effect : it will of course be less optimal than a pure script that handle that. But it got the added benefit that an artist can handle/tweak all that without opening the code and/por exposing 30 variables. Legacy animation system (the one used here) is not really expensive (well apart from the setup cost that can be high...) so as long as it's not used on a thousand object, it shouldn't be your bottleneck. skinned mesh Staff : There is a reason for it being a Skinned Mesh...and it's not a good one it's basically a bad legacy thing that stayed in (quietly adding it to the list of issue) the stuff use to bend/stretch with the attack for artistic reason, but we decided later to remove it "for now" and it stayed like that...we never replaced the mesh...um um... GetComponentinChildren do indeed check on the gameobject itself before the children, so no need for the second line. It's just bad code Using physic material for sound override : the problem with physic material is that you have one per object, so you can't i.e. use submesh data for different sound. And not every object that need sound is a physical one, so some don't have collider for physical material. What is bad here though is that the override are on the audio source. Should have added a scriptable object that act as a proxy and assign that to source, so you have a centralized "database" of your overrides SceneView updated : if you search through the code for RepaintAll you'll see some call to SceneView.RepaintAll() and RepainAllViews() in some custom editor (like the instance painter, the layerculldistance editor etc...) this code update the scene view. That's why the scene view is actually updated only when one of those editor is open/inspector selected! 2 Cameras : There is actually more than that rendering :p (reflectiosn also use a camera). For the Skybox though the camera only render a single layer, which contains very few object, so culling cost is ultra minimal. Rule of thumbs when rendering more than one camera is to use the layers to reduce to a max what each camera need to render.
The problem with that is if the project is huge re-importing it all takes a long ass time, also that never seems to fix it for me it's the first thing I try and it doesn't always work and having Unity decide to re-import everything like how when you switch build target is irritating. So I found my method seems to provide a quick fix sometimes.
Neat stuff, definitely going to use some of it in my projects.
Sorry, you need to Log In to post a reply to this thread.