Joined: Mon Oct 11, 2010 1:15 pm Posts: 594 Location: Finlandia
Lightning and sufficient surfaces
In reality, a bolt of lightning is basically an electrical discharge on a surface. I use a script in my mod that creates a more or less random lightning-like line of glows. Provided that the line ends in an object or terrain, it creates a blast there. (A)
How would I go about making the lightning work as first mentioned, appearing only if there is a surface provided in the radius? (B)
In addition to this, I would also want to be able to have a 100% accurate 'lightning' effect to be created relative to both ends, the start (muzzle) and the end, the end being the first found surface straight forward from the muzzle. (C)
I did a quick illustration that should clarify what I mean.
Red = source Black/gray = lightning effects, as they would appear relative to each other Blue = object/surface Green = impact
Current script for the whole gun main point of the script, as found in my mod:
Code:
... -- makes it work both left and right local negativeNum = 1; -- if gun faces left, invert stuff if self.HFlipped == true then negativeNum = -1; end
-- start from muzzle local initPos = self.MuzzlePos; -- old position is used in the impact, redefined later local oldPos = initPos; -- new position is defined later local newPos = Vector(0,0);
-- x marks amount of times the script is read = amount of pixels used for the lightning for i=1, x do
-- randomization of angle happens between -0.8 and 0.8 (rad, I believe) local angleOffset = math.random(-8,8)/10; -- chances of a branch to appear are one in a hundred pixels local branch = math.random(1,100); -- the pixel that the formation is made of eventually local glow = CreateMOPixel("Glow Here");
-- the heading of the formation; every 2 or so pixels (Vector(2,0)), either left or right (*negativeNum), proceed to go in the direction that the gun is pointed (self.RotAngle), while applying a random distortion to make it bouncy-like (angleOffset)
-- new position is always old-new position + the heading newPos = newPos + posVector; -- glow position glow.Pos = initPos + newPos; -- end position is defined for impact local endPos = Vector(0,0);
if i > 2 then -- ray action to see if we have an impact local randomRay = SceneMan:CastMORay(oldPos, posVector, glow.ID, self.Team, 0, false, 0); endPos = SceneMan:GetLastRayHitPos(); local trueLength = SceneMan:ShortestDistance(oldPos, endPos, true).Magnitude; if trueLength < posVector.Magnitude then -- we have impact local impact = CreateAEmitter("Impact Here"); ... MovableMan:AddMO(impact); break end end
-- add glow(s) to visualize the formation (applied x times) MovableMan:AddMO(glow); -- when branch happens, pretty much same thing, but no impact (not relevant) if branch == 100 then ... -- "old position" is now the last glow position oldPos = glow.Pos; end end ...
Last edited by 4zK on Tue Mar 25, 2014 3:34 pm, edited 1 time in total.
I'm not entirely sure I understand what you have now or what you're trying to accomplish, and reading through your script is kind of painful without seeing what it does. Also the lack of comments makes some of a lot of those random names and numbers pretty unintelligible.
If I'm getting this though, you have A, where it shoots out lightning regardless of whether it'll hit something or not, and you'd like C, where all the bolts shot out at random angles come back in to hit a certain point? If that's the case, wouldn't you just want to do one raycast when the gun is fired, and generate random glows from the start point to that end point? Putting together all the random glows could be kind of hard, but if you do it recursively with the start position for the next glow and the final end position as parameters, it should actually be pretty easy. Though doing it recursively may be way too expensive, since I don't know how well CC would take to a bunch of recursion + glow spawning. Maybe separating the process in two parts, i.e. calculating the positions and rotangles, tabling them and spawning all the glows based on the tabled values afterwards, would be better.
Tue Mar 25, 2014 3:15 am
4zK
Joined: Mon Oct 11, 2010 1:15 pm Posts: 594 Location: Finlandia
Re: Lightning and sufficient surfaces
Yeah, sorry, I didn't bother stripping it down. I'll try to clean it up and add comments to everything I know how to explain.
At least my visualizations worked, at least somewhat right. For C, I'd like all formations to end up at the aiming point, not necessarily a specified point no matter where you are aiming.
The only problem for me is that I'm not very well versed with this kind of code in particular, as in rays and tables. What I know I want is for the initial position to be the muzzle and the final position to be in line with the angle of the source. The only aesthetic is the lightning, which must be formed between these two positions.
EDIT: wow, there's a lot of unnecessary stuff here that isn't even used for anything. EDIT2: there, it should make more sense now.
What if you try some recursion like this. Essentially it performs pretty similar actions to your code, it's just pruned down a bit since it's recursive. But CC may not like recursion (I don't know) so if it works terribly, you can change it back into a for loop and work with that. Or there's the possibility of moving all the actual Pixel addition to a separate function if that might help.
Also keep in mind that this almost certainly won't work quite right - aside from any mistakes I made, there's not much safety to make sure it connects back to the end point, so it'll probably miss most of the time haha. We'd have to add in a bit of checking to make it try to make it aim for the endpoint when it gets close to it. Probably the easiest way to do that would be when count == 0, check if the startpos is less than 10 away from the endpoint, and if it is, set the directionangle to be the angle we need to get straight to the endpoint.
Oh, and if all my talk of recursion makes no sense to you, here's a link
Code:
function Create(self) self.Dir = 0; end --Update function, I'm just using pseudocode here since it's straightforward function Update(self) --Cast an obstacle ray from start to the max range of the gun, if it hits a target do stuff if ObstacleRay from muzzleoffset pos using Vector(Gunrange, 0):RadRotate(self.RotAngle) ~= -1 then --Check for HFlipped, swap Dir's value if this is backwards if self.HFlipped == true then self.Dir = -1; else self.Dir = 1; end --Make the starting lightning glowball effect or whatever (lazy nonworking version) MovableMan:AddMO(CreateMOPixel("starting glowball")); --Call the function to make inbetween lightning effects, where startpos is the muzzleoffset and endpos is the point where it hit an obstacle MakeRecursiveLightning(self, startpos, endpos, self.RotAngle + RangeRand(-0.8, 0.8), 0); --The 2 0s are prevangle and count, prevangle is the previous angle it was fired at and count lets us make somewhat straight lines instead of complete messes --Now make the lightning hit effects at the endpos (lazy nonworking version) MovableMan:AddMO(CreateAEmitter("ending glowball")); end end
--This is the recursive function that will generate our in between lightning for us function MakeRecursiveLightning(self, startpos, endpos, prevangle, count) if SceneMan:ShortestDistance(startpos, endpos).Magnitude < 5 --5 should be some small number, basically if we're pretty much at our endpos return; --We've finished making all the lightning, so we can return and ultimately go back to the update function else --If we've travelled more than 6 - 10 pixels in one direction, change the direction if count > math.random(3, 5) then --Because we want to try to hit the endposition, we reverse the direction and then add a bit of randomness to it prevangle = -prevangle + RangeRand(-0.8, 0.8); --NOTE: I think reversing the direction is probably not what should be done, more likely we have to add 90 degrees to it or something end local offset = Vector(2*self.Dir, 0); --The amount we want to offset by each time (with direction), 2 pixels in this case --Make the glow, change its position based on the angle we picked, then add it to the scene local glow = CreateMOPixel("Glow Here"); glow.Pos = startpos + offset:RadRotate(prevangle); MovableMan:AddMO(glow); --Now that this glow is done, call the recursive function again, setting the startpos as the glow's pos and adding one to count MakeRecursiveLightning(self, glow.Pos, endpos, prevangle, count+1); end end
Also, a couple things to note: 1. When you want random values with decimals, there's a seldom used but very useful function RangeRand(val1, val2). It's basically the same as math.random except it does decimals. I don't know which is more efficient or whatever, math.random is a lua library function whereas I think RangeRand is one of Data's C++ functions.
2. This isn't too important, but when you make variables that you're going to use later, it's probably a better idea to set them to nil instead of an empty vector or whatever. Particularly when it's more than just a number or boolean or string (i.e. if it's a vector or some other object). It makes it easier for someone reading the code to know if a value is going to be used as is or if it's going to be used later, and it probably makes your script infinitesimally cheaper.
Tue Mar 25, 2014 5:50 pm
TheLastBanana
DRL Developer
Joined: Wed Dec 13, 2006 5:27 am Posts: 3138 Location: A little south and a lot west of Moscow
Re: Lightning and sufficient surfaces
My biggest concern there is that as you mentioned, the lightning can "miss," but you rely on it getting close enough to the endpoint to terminate the recursive loop. So it could just keep going forever! And even if it doesn't when you're testing it, since it's based on pseudo-random numbers, it's hard to say it never will for somebody else.
The idea is that you're starting with a line directly from point A to point B and then modifying the bits in between. So that means that you're guaranteed to start and end exactly where you wanted to. It's also guaranteed to finish looping after a set number of recursions, so you don't have to worry about that (as long as you don't have a stupidly long lightning arc with stupidly high detail, but that goes without saying).
My only compaint with that code is that the points can be displaced in both the x and the y axis, which can look a little odd since lightning doesn't tend to arc back toward its source. You can restrict it to one axis, of course, but that involves complicating the logic a bit, so I'd probably just stick with what's provided there unless you're really itching to get your hands dirty with some trigonometry.
Yeah, this wouldn't work quite right off the bat but I didn't have time when I put it together to stick in proper safety (I made mention of how it might be done though). Since it does try to stay close to the right path, it probably wouldn't go off course too much. In that case, when it's fairly close (or better yet when one of it's positions is fairly close), you just have to manually adjust the direction. It's probably still a kind of wonky way to do it, but I'd rather not put together something too complex without knowing for sure the CC's not going to have issues with recursion (why do I worry it might? Because it's CC).
All that said, yours is better by far TLB, so 4zk, I suggest using that. Also, for the displacement issue, couldn't you just cheat a bit? Either have the impact glow be big enough that it masks the displacement, or manually adjust the last arc of each beam so it hits more correctly?
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot post attachments in this forum