[TUT] Semiclip
Before we begin, I'd just like to state that this tutorial is intended for intermediate to expert level scripters. You should be able to read all the code I've put here and almost immediately understand what should happen. Also, this tutorial is a bit of a detour from my previous ones; it's more of a discussion than a point by point process. I wouldn't be surprised if some of the code doesn't work (feel free to let me know, I'm always willing to fix it up).
I'm putting this up because there's been many requests for semiclip plugins lately. A lot of people seem to be stuck in my step 1 or 2 (as you'll see as you read further). Hopefully this will help get them on the right track. For those of you that don't know, semiclip is exactly that: half-way between noclip and clipping. You can pass through other entities, but not through walls, nor can you fly. I've had to try many different methods of semiclip and I've found that none at all are pretty. I have yet to find one be-all-end-all, but hopefully this will bring someone closer to making one. To start off, I'm going to show you the failed ones: The Scripter's Initial Instinct - Failed Attempts I first attacked this using simple stuff. The first (or one of the first) things that should come to your mind on how to solve this is using something like register_touch. Using this forward, we can pick up when 2 entities collide and either let the engine do its work or supersede it. Here's an example of how I tried this: Code:
This looks pretty nice and easy (of course you'd have to add more like cvar checks and such), but there's one catch: it really doesn't do what you want it to. Because of client prediction, the player gets stopped first and then passes through. If you're using this on the ground it's really not a big deal (although kind of annoying), but when you're using it for something like surfing (like I am), it becomes a big problem. You can also use fakemeta in a similar way. I'm too lazy to type it out, but you can register FM_Touch, then check whether the touched and toucher are alive (is_user_alive). The next method I went onto was constantly setting a player to unsolid. Again, this sounds very nice as it eliminates the problem of clipping right before the touch is blocked, but again there is a catch. The script first, of course: Code:
Very nice and compact. In fact, you can probably not even use client_PreThink and instead do it in a forward like ResetHUD or something similar that isn't called all that often. But again for the hitch: the server crashes when you pass through any trigger_* entities. Okay, not really a problem. We can run a check to scan around the player and see if they are within any distance of a trigger_* ent and then deactivate semiclip if they are. Sure, but what if 2 players are close to the trigger? They will collide, which is a problem. Then what about maps where the entire ground is trigger_teleports, such as some surf maps? This just gets too complicated. I suppose it has some potential, but I think there are really some better methods. Potential Solutions The final method I tried that failed was a direct scan around the player for other players. Essentially, you just scan around the player a certain distance, and if the search turns up another player, semiclip is activated. This method has the most potential, as we'll see in the final script. For now, this is what this would look like: Code:
But we run into yet another problem here: the checking simply isn't fast enough. If we make the radius insanely large, we run into the risk of crashing the server if the user is close to a trigger_* entity. There's no way to solve this the way it is now, client_PreThink is simply too slow. The Only Known Solution If you can challenge the above statement, feel free to. I'd like to see a better solution personally, I could use it. But for now, this is the closest to perfect semiclip that I know of. A demonstration of it in use can be found in uSurf. Essentially, it's the last attempt except sped up using an entity thinking every 0.01 seconds. Very very resource intensive, but it gives the most accuracy and responsiveness. Here's the implementation from uSurf with uSurf specific stuff stripped out: Code:
Is this level necessary for most uses? No, most people just want to be able to pass through others. For that, the first method may even work. Feel free to use whatever you want, there's really no standard as they all suck. As always, if you have any questions, comments or whatever feel free to post. As aforementioned, I invite anyone to challenge anything said here. Hope this helps. |
Re: [TUT] Semiclip
you forget to register a think\ register FM_think forward.
other than that, this is really usefull in so many ways thx man gj |
Re: [TUT] Semiclip
Quote:
|
Re: [TUT] Semiclip
Long time no see.
|
Re: [TUT] Semiclip
Quote:
|
Re: [TUT] Semiclip
I like busy. anyways welcome back
|
Re: [TUT] Semiclip
I tried to optimize it, tell me what you think:
Code:
|
Re: [TUT] Semiclip
Thanks, Hawk. If I ever need some help with coding plugins, I'll know where to go. :up:
|
Re: [TUT] Semiclip
this is a good sign, it means he will be around for a while. :)
|
Re: [TUT] Semiclip
Optimisation (IsColliding(id)):
new Ent,Float:Origin[3] Should be: static Ent,Float:Origin[3] Reason being well it can be potentially called as often as ForwardThink(Ent). Optimisation (public ForwardThink(Ent)): new Float:Time Should be: static Float:Time Same reason as the other. :mrgreen: IMO and I think it is covered on the WIKI, all fast ticking function variables should be declared static. Cheers, Orang |
All times are GMT -4. The time now is 23:34. |
Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.