| 11-22-2007, 07:30 PM | #1 |
I'm in trouble. I have made knockback triggers before for one player in gui and have also tried toying with scripts others have made for moving units around circles.. but i dont know if i can handle this one.. because i need to make a trig that knockbacks a unit with a buff anywhere's from one to several (maybe hundreds) of these little units around until they bump into something.. and then are to be ordered to die. heh So i was wondering if any of you know of either a way to do this or know of a simple script i can copy, paste and edit easily that is totally multi-instance and is leak-free. it's a 10 player map. as each player walks up to one of these little units, they can target it with a spell (or maybe some other way) and the unit will instantly move away from them. so since there are many players and many of these little units.. i need this to be able to handle the possibility of a bunch of units being kicked around at a time independantly. example: i kick the one critter.. and whle that is flying at my opponent, i may kick another one before the other finishes and player 2 might also kick a few during that time. Thank you for your time. |
| 11-22-2007, 07:44 PM | #2 | |
Here's my Knockback script. You just call the knockback function and enter whatever values you want and you're good to go. Sorry it isn't more documented / commented, wasn't planning on anyone else figuring it out :P if you need help with it let me know.
|
| 11-22-2007, 09:53 PM | #3 |
or u could always use my system, but nvm it now :P |
| 11-23-2007, 12:12 AM | #4 |
Actually, Silvenon made a tutorial for this very thing. I think you will find it to be rather useful: Coding an Efficient Knockback (vJASS) |
| 11-23-2007, 12:28 AM | #5 | |
Quote:
thanks a lot. i will give it a try. How do you mean call it? you mean have another trig set up to tell it when to launch? or something in the map script to set it up? i'm rather a noob at jassing, though i've had some successful moments with small amounts of script. also been a few months away from comp. so, if i had a hero with a certain ability that casts on another unit to be knocked back, what things do i change in this? |
| 11-23-2007, 03:27 AM | #6 |
Yup, make a new trigger and copy/paste that library, then when you want to use the knock back have whatever conditions on a new trigger then run the function. Here's the function. JASS:function Knockback takes unit u, real d, real a, real w, real r, integer t, string s, string p returns nothing So you'd supply the info like... JASS:call Knockback(GetEnumUnit(), 400, AngleBetweenPoints(GetUnitLoc(GetTriggerUnit()), GetUnitLoc(GetEnumUnit()))*0.01745, 4, 90, 0, "", "") Pretty much I'm giving Unit,Distance,Angle they travel,Time you want them to travel,collision size,type of special effect to add to the 0 = none 1 = entered string 2 = chest, special effect name, where to attach it if entered 1. |
| 11-23-2007, 07:08 AM | #7 |
Stop using Vexorian's pathability check script people, that thing is years old and will lag like hell if you're moving "hundreds of units" |
| 11-23-2007, 08:43 AM | #8 | ||
Quote:
Not if it's modified to move a single global item instead of creating one each time (thanks to you and Pyrogasm I managed to fix it). Quote:
I'm glad that my tut has actually helped someone. |
| 11-23-2007, 09:16 AM | #9 |
It's still using a null boolexpr and doesn't detect collisions with other units (only unpathable terrain), and could be easily inlined if all of the wasted operations were removed |
| 11-23-2007, 09:30 AM | #10 | |
Quote:
(to move unit in such way takes more time than calc all the math for (particle or something) movement) it's a pure perf killer GetLocationZ() is also a weak point in algorithms (it's doesnt have "constant" calc rate) |
| 11-23-2007, 07:10 PM | #11 | |
Quote:
Why don't you write the code then? (Yes, this is an excuse so you can make me a better function ) |
| 11-23-2007, 07:21 PM | #12 |
He wrote a very good collision detection algorithm used in this code that creates a shockwave that bounces from unit-to-unit and dies if it hits too steep terrain or a destructable... if you want to decipher it: JASS:globals real udg_SW_X real udg_SW_Y unit udg_SW_Wave real udg_SW_Cos real udg_SW_Sin timer udg_SW_Timer integer udg_SW_Iteration unit udg_SW_Caster real udg_SW_XDir real udg_SW_YDir group udg_SW_Group rect udg_SW_Rect destructable udg_SW_Destructable location udg_SW_Location1 location udg_SW_Location2 sound gg_snd_ShockwaveBurn sound gg_snd_ShockwaveImpact unit udg_PathabilityUnit item udg_PathabilityItem real udg_MaxX real udg_MinX real udg_MaxY real udg_MinY endglobals function Shockwave_UnitConditions takes nothing returns boolean return GetWidgetLife(GetFilterUnit()) > 0.405 endfunction function Shockwave_DestructableConditions takes nothing returns boolean return GetDestructableLife(GetFilterDestructable()) > 0.405 endfunction function Shockwave_GetDestructable takes nothing returns nothing local destructable d = GetEnumDestructable() local real xd = udg_SW_X - GetDestructableX(d) local real yd = udg_SW_Y - GetDestructableY(d) if xd*xd + yd*yd <= 110*110 then //? set udg_SW_Destructable = GetEnumDestructable() endif set d = null endfunction function Shockwave_Callback takes nothing returns nothing local real Period = 0.022 local real Damage = 500. local real Speed = 1050. local real KnockbackScale = 1. local real Radius = 77. //? local boolean KillDestructables = true local real x local real y local real x2 local real y2 local real l local real p local unit target = null local boolean none = true local boolean terrain = false set udg_SW_Iteration = udg_SW_Iteration+1 if udg_SW_Iteration < 300 then call StartSound(gg_snd_ShockwaveBurn) set udg_SW_X = udg_SW_X + Speed*Period*udg_SW_XDir set udg_SW_Y = udg_SW_Y + Speed*Period*udg_SW_YDir if udg_SW_X > udg_MaxX or udg_SW_X < udg_MinX then set udg_SW_XDir = -udg_SW_XDir set none = false endif if udg_SW_Y > udg_MaxY or udg_SW_Y < udg_MinY then set udg_SW_YDir = -udg_SW_YDir set none = false endif if not none then call StartSound(gg_snd_ShockwaveImpact) call SetWidgetLife(udg_SW_Wave, 0.) set udg_SW_Wave = CreateUnit(GetOwningPlayer(udg_SW_Caster), 'h000', udg_SW_X, udg_SW_Y, Atan2(udg_SW_YDir, udg_SW_XDir)*57.2957795) call AttachSoundToUnit(gg_snd_ShockwaveBurn, udg_SW_Wave) call AttachSoundToUnit(gg_snd_ShockwaveImpact, udg_SW_Wave) endif call GroupEnumUnitsInRange(udg_SW_Group, udg_SW_X, udg_SW_Y, Radius, Condition( function Shockwave_UnitConditions )) call GroupRemoveUnit(udg_SW_Group, udg_SW_Wave) if FirstOfGroup(udg_SW_Group) != null then set target = FirstOfGroup(udg_SW_Group) set x2 = GetUnitX(target) - udg_SW_X set y2 = GetUnitY(target) - udg_SW_Y set none = false endif if none then set udg_SW_Destructable = null call SetRect(udg_SW_Rect, udg_SW_X-Radius, udg_SW_Y-Radius, udg_SW_X+Radius, udg_SW_Y+Radius) call EnumDestructablesInRect(udg_SW_Rect, Condition( function Shockwave_DestructableConditions ), function Shockwave_GetDestructable) if udg_SW_Destructable != null then set x2 = GetDestructableX(udg_SW_Destructable) - udg_SW_X set y2 = GetDestructableY(udg_SW_Destructable) - udg_SW_Y if KillDestructables then call KillDestructable(udg_SW_Destructable) endif set none = false endif endif if none then call SetUnitX(udg_SW_Wave, -1150.) call SetUnitY(udg_SW_Wave, 3000.) call SetUnitPosition(udg_PathabilityUnit, udg_SW_X, udg_SW_Y) //? set x = GetUnitX(udg_PathabilityUnit) - udg_SW_X set y = GetUnitY(udg_PathabilityUnit) - udg_SW_Y call SetUnitX(udg_PathabilityUnit, -1150.) call SetUnitY(udg_PathabilityUnit, 3000.) call SetUnitX(udg_SW_Wave, udg_SW_X) call SetUnitY(udg_SW_Wave, udg_SW_Y) if x*x + y*y > 100. then call MoveLocation(udg_SW_Location1, udg_SW_X, udg_SW_Y) call MoveLocation(udg_SW_Location2, udg_SW_X+udg_SW_XDir*Radius, udg_SW_Y+udg_SW_YDir*Radius) if GetLocationZ(udg_SW_Location1) < GetLocationZ(udg_SW_Location2) then call MoveLocation(udg_SW_Location1, udg_SW_X-Radius, udg_SW_Y) call MoveLocation(udg_SW_Location2, udg_SW_X+Radius, udg_SW_Y) set x2 = GetLocationZ(udg_SW_Location1)-GetLocationZ(udg_SW_Location2) call MoveLocation(udg_SW_Location1, udg_SW_X, udg_SW_Y-Radius) call MoveLocation(udg_SW_Location2, udg_SW_X, udg_SW_Y+Radius) set y2 = GetLocationZ(udg_SW_Location1)-GetLocationZ(udg_SW_Location2) set none = false set terrain = true endif endif endif if not none then set l = SquareRoot(x2*x2 + y2*y2) set x2 = x2/l set y2 = y2/l set x = udg_SW_XDir*Speed set y = udg_SW_YDir*Speed set p = x*x2 + y*y2 if p > 0. or terrain then if target != null then call UnitDamageTarget(udg_SW_Wave, target, Damage, false, true, null, null, null) if not IsUnitType(target, UNIT_TYPE_STRUCTURE) then //Use a better knockback function! call KnockbackFunctions_KBUnit(target, Atan2(y2, x2)*57.2957795, p*Period*KnockbackScale, 0., 0.022, true, false) endif set target = null endif set x = x - x2*p*2. set y = y - y2*p*2. set l = SquareRoot(x*x + y*y) set udg_SW_XDir = x / l set udg_SW_YDir = y / l call StartSound(gg_snd_ShockwaveImpact) call SetWidgetLife(udg_SW_Wave, 0.) set udg_SW_Wave = CreateUnit(GetOwningPlayer(udg_SW_Caster), 'h000', udg_SW_X, udg_SW_Y, Atan2(udg_SW_YDir, udg_SW_XDir)*57.2957795) call AttachSoundToUnit(gg_snd_ShockwaveBurn, udg_SW_Wave) call AttachSoundToUnit(gg_snd_ShockwaveImpact, udg_SW_Wave) endif endif else call PauseTimer(udg_SW_Timer) call SetWidgetLife(udg_SW_Wave, 0.) endif endfunction function Shockwave_Cast takes nothing returns nothing local real SpawnOffset = 100. local unit U = GetTriggerUnit() local real X = GetUnitX(U) local real Y = GetUnitY(U) local location L = GetSpellTargetLoc() local real X2 = GetLocationX(L) local real Y2 = GetLocationY(L) local unit U2 local real Angle if L == null then set U2 = GetSpellTargetUnit() set X2 = GetUnitX(U2) set Y2 = GetUnitY(U2) set U2 = null else call RemoveLocation(L) set L = null endif set Angle = Atan2((Y2-Y),(X2-X)) set udg_SW_XDir = Cos(Angle) set udg_SW_YDir = Sin(Angle) set udg_SW_X = X+udg_SW_XDir*SpawnOffset set udg_SW_Y = Y+udg_SW_YDir*SpawnOffset set udg_SW_Wave = CreateUnit(GetOwningPlayer(U), 'h000', udg_SW_X, udg_SW_Y, Angle*57.2957795) set udg_SW_Caster = U call AttachSoundToUnit(gg_snd_ShockwaveBurn, U) call AttachSoundToUnit(gg_snd_ShockwaveImpact, U) call StartSound(gg_snd_ShockwaveBurn) set udg_SW_Iteration = 0 call TimerStart(udg_SW_Timer, 0.022, true, function Shockwave_Callback) set U = null endfunction //=========================================================================== function InitTrig_Bouncing_Shockwave takes nothing returns nothing set gg_trg_Bouncing_Shockwave = CreateTrigger( ) call TriggerRegisterAnyUnitEventBJ(gg_trg_Bouncing_Shockwave, EVENT_PLAYER_UNIT_SPELL_EFFECT) call TriggerAddAction( gg_trg_Bouncing_Shockwave, function Shockwave_Cast ) set udg_SW_Group = CreateGroup() set udg_SW_Rect = Rect(0., 0., 0., 0.) set udg_SW_Location1 = Location(0., 0.) set udg_SW_Location2 = Location(0., 0.) endfunction |
| 11-23-2007, 09:26 PM | #13 |
grim001 is master of collision detection algoritm ^^ at least he have made it to life |
| 11-23-2007, 10:58 PM | #14 | |
Oh god, looking at that code reminds me of how ugly standard JASS is. that was just a test to see if I could make a shockwave which bounces off terrain, destructables and units while reflecting at the correct angle and knocking back the target as well. turned out to be possible but extremely ugly. that code isn't multi-instancable, though, would need to change it to arrays and add an allocator/deallocator... Anyway, a long time ago I thought that using a dummy unit and SetUnitPositionLoc was the best way to notice a unit blocking knockback path, but now I would only do it with GroupEnumUnitsInRange. With that method you could set it up so that some of the knockback force transfers to units that you're knocked into, or you take damage based on the force of collision when you run into a destructable/building/terrain. Trying to do all of those things using standard knockback scripts is lame though. Might as well go all the way to a physics engine. Quote:
|
| 11-24-2007, 01:51 AM | #15 | |
Quote:
|
