13lade619
is now a game developer :)
- Reaction score
- 399
A P E X
Advanced Projectile EXperiments
Arced Projectiles + Collision Missiles
+ VERTICAL COLLISION
- the projectile can 'leap' above units, can hit flying while ignoring the units below
and will hit ground units when they are close enough.
+ HORIZONTAL ARC
- you can make projectiles arc horizontally, with different settings.
- just like the famous Wild Axes spell.
v5
System Code:
Apex (Latin for top, peak, summit)
Sample Usage:
Upon casting, 3 phoenix models are launched from the caster, each time with random speed.
Demo Map v5:
Advanced Projectile EXperiments
Arced Projectiles + Collision Missiles
+ VERTICAL COLLISION
- the projectile can 'leap' above units, can hit flying while ignoring the units below
and will hit ground units when they are close enough.
+ HORIZONTAL ARC
- you can make projectiles arc horizontally, with different settings.
- just like the famous Wild Axes spell.
v5
Code:
v2
Uses T32 (kingkingyyk3)
Some other code optimizations
v3
Reduced arguments on the create method.
Created separate methods for the optional Horizontal arc and collision.
v4
Added periodic method
Uses GroupUtils
v5
Removed GroupUtils, better group utilization.
new onStart method
new create, you can now set the dummy used.
System Code:
Apex (Latin for top, peak, summit)
JASS:
library APEX requires T32
//=======================================================================================
// __ ___
// _ ____ ____\ \ / /
// /_\ | - \ __\\ \/ / Advanced
// / _ \| -,/ _|_ > < Projectile by 13lade619
// / / \_\_| |____// /\ \ EXperiments
// /_/ /_ / \__\ v5
//
// DISCLAIMER : The values used in this system are NOT based on the
// Obect Editor measures. You as the user WILL need to
// EXPERIMENT to get what shape of trajectory you really
// want to create.
//
// Credits : Jesus4Lyf, for the T32 System.
// : kingkingyyk3 for helping with the T32 implementation
// : Romek, for UAC's optional methods algorithm, and UAC as a basis for coding.
// : emjlr3, for his Wild Axes spell algorithm (provides horizontal arc)
// : Vexorian, for his Caster System arc algorithm (provides vertical arc)
//
// PROS : Supports VERTICAL COLLISION.
// : Supports HORIZONTAL ARC.
// : Can be used as collision missiles and/or AoE missiles.
//
// CONS : Only POINT TO POINT targeting.
// : ..too much maths for movement., even i cant understand.
//
//
// SYSTEM METHODS / FUNCTIONS <Summary>
//
// method onStart takes nothing returns nothing defaults nothing
// method onPeriod takes nothing returns nothing defaults nothing
// method onCollision takes unit u returns nothing defaults nothing
// method cfilter takes unit u returns boolean defaults false
// method onEnd takes nothing returns nothing defaults nothing
//
// yourvar.horizontal( real H_LAUNCH, real X_ARC )
// yourvar.settick( real t )
// yourvar.size( real COLLISION )
//
//
//
// SYNTAXES <Explained> :
// < Struct >
// struct yourstruct extends APEX
//
// < Create >
// local yourstruct yourvar = yourstruct.create(CASTER, START_X, START_Y, START_Z,
// END_X, END_Y, END_Z, Z_ARC,
// SPEED, MODEL, DUMMY)
//
// DUMMY > code for dummy unit to be used.
// Z_ARC real 0-3 > vertical arc, experiment with values 0-2 and find a decent shape..
// SPEED real (.01-.1) > NO DIRECT CONVERSION TO WC3 UNITS.
// > lower values are slower, close to .1 are pretty fast.
//
// < Methods >
//
// yourvar.settick( real t )
// > sets the timeout/frequency for the onPeriod method
//
// yourvar.size( real COLLISION )
//
// COLLISION > collision size of the missile, be sure you have the collision function
// and the filter.
//
// yourvar.horizontal( real H_LAUNCH, real X_ARC )
//
// H_LAUNCH real -45 - +45 > launch angle relative to unit facing.
// X_ARC real 0-1000... > horizontal arc width, again experiment with wide/narrow.
//
// yourvar.scale( real s )
//
// < Optionals >
//
// method onStart takes nothing returns nothing defaults nothing
// > if you want to manipulate anything else before the projectiles move.
//
// method onPeriod takes nothing returns nothing defaults nothing
// > if you want to do other stuff besides move the projectile per tick, do it in this method.
// > you can set the rate method fires via the .settick(t) method
//
// method onCollision takes unit u returns nothing defaults nothing
// > manipulate the unit u when it enters collision range.
//
// method cfilter takes unit u returns boolean defaults false
// > filter for units that will enter range.
//
// method onEnd takes nothing returns nothing defaults nothing
//
//
//======================================================================================
globals
private real TIMEOUT = 0.03125
endglobals
private interface APEXInterface
method onStart takes nothing returns nothing defaults nothing
method onPeriod takes nothing returns nothing defaults nothing
method onCollision takes unit u returns nothing defaults nothing
method cfilter takes unit u returns boolean defaults false
method onEnd takes nothing returns nothing defaults nothing
endinterface
struct APEX extends APEXInterface
unit caster
unit proj
private real x1
private real y1
private real x2
private real y2
private real z1
private real z2
private real arcspeed
private real arc
private real face
private effect fx
group dg
private real range
private real tick
private real tc
private boolean first
private real A
private real outx
private real outy
private real s2
//===================================================================================
method settick takes real t returns nothing
set .tick = I2R(R2I(t/TIMEOUT))*TIMEOUT
endmethod
method scale takes real s returns nothing
call SetUnitScale(.proj,s,s,s)
endmethod
method size takes real r returns nothing
set .range = r
endmethod
method horizontal takes real angle, real width returns nothing
set .outx = .x1+ width *Cos(Atan2(.y2-.y1,.x2-.x1)+(angle))
set .outy = .y1+ width *Sin(Atan2(.y2-.y1,.x2-.x1)+(angle))
endmethod
//===================================================================================
method move takes nothing returns nothing
local real nx
local real ny
local real fly = GetUnitFlyHeight(.proj)
//Calculations from Vexorian's Projectile System.
// calculates the vertical arc.
local real od = SquareRoot(Pow(GetUnitX(.proj)-.x2,2) + Pow(GetUnitY(.proj)-.y2,2))
local real time = od / .arcspeed
local real zspeed = (.z2-fly+0.5*.arc*time*time)/time
//Calculataions from emjlr's Wild Axes spell.
// calculates the horizontal arc.
local real b = 1.-.A
//VERTICAL ARC, from Vexorian
call SetUnitFlyHeight(.proj,fly+zspeed*.035,0)
call SetUnitAnimationByIndex(.proj,R2I(Atan2(zspeed,.arcspeed)* bj_RADTODEG)+90) //Thanks infrane!
//Corrective Facing >by me, 13lade619<
set nx = .x1*.A*.A+.outx*2*.A*b+.x2*b*b
set ny = .y1*.A*.A+.outy*2*.A*b+.y2*b*b
call SetUnitFacingTimed(.proj, bj_RADTODEG*Atan2(ny - GetUnitY(.proj), nx - GetUnitX(.proj)), 0)
//HORIZONTAL ARC, from emjlr.
call SetUnitX(.proj,nx)
call SetUnitY(.proj,ny)
set .A = .A-.s2
endmethod
method collisionhandler takes nothing returns nothing
local unit u
local group g = CreateGroup()
call GroupEnumUnitsInRange(g,GetUnitX(.proj),GetUnitY(.proj),.range,null)
loop
set u = FirstOfGroup(g)
call GroupRemoveUnit(g,u)
exitwhen u == null
if not IsUnitInGroup(u,.dg) and .cfilter(u) and SquareRoot(Pow((GetUnitFlyHeight(.proj)-GetUnitFlyHeight(u)),2))<=.range then
call GroupAddUnit(.dg,u)
call .onCollision(u)
endif
endloop
call DestroyGroup(g)
set g = null
set u = null
endmethod
method periodic takes nothing returns nothing
set .tc = .tc+TIMEOUT
if .onStart.exists and .first==true then
call .onStart()
set .first = false
endif
if (.A <= 0) then
if .onEnd.exists then
call .onEnd()
endif
call .stopPeriodic()
call .destroy()
else
call .move()
if .onCollision.exists and .cfilter.exists then
call .collisionhandler()
endif
if .onPeriod.exists and .tc>=.tick then
call .onPeriod()
set .tc = 0
endif
endif
endmethod
implement T32x
//===================================================================================
method onDestroy takes nothing returns nothing
call DestroyEffect(.fx)
call SetUnitExploded(.proj, true)
call KillUnit(.proj)
call GroupClear(.dg)
set .proj = null
endmethod
//===================================================================================
static method create takes unit caster, real x1, real y1, real z1, real x2, real y2, real z2, real varc, real speed, string model, integer dummy returns thistype
local thistype this = thistype.allocate()
set .caster = caster
if .dg == null then
set .dg = CreateGroup()
endif
set .range = 0
set .x1 = x1
set .y1 = y1
set .x2 = x2
set .y2 = y2
set .z1 = z1
set .z2 = z2
set .tick = TIMEOUT
set .tc = 0
set .face = Atan2(.y2-.y1,.x2-.x1)*bj_RADTODEG
// VERTICALS / Vexorian
set .arcspeed = 2200
set .arc = (varc) * 6000
// HORIZONTALS / emjlr3
set .A = 1
set .outx = .x1
set .outy = .y1
set .s2 = speed // Affects the REAL SPEED of the projectile, lower is slower. always<1
// PROJECTILE
set .proj = CreateUnit(GetOwningPlayer(.caster),dummy,.x1,.y1,.face)
set .fx = AddSpecialEffectTarget(model,.proj,"origin")
call SetUnitFlyHeight(.proj,.z1,0)
set .first = true
call .startPeriodic()
return this
endmethod
endstruct
endlibrary
Sample Usage:
Upon casting, 3 phoenix models are launched from the caster, each time with random speed.
JASS:
struct proj extends APEX
method onPeriod takes nothing returns nothing
call DestroyEffect(AddSpecialEffectTarget("Abilities\\Spells\\Human\\Feedback\\SpellBreakerAttack.mdl",.proj,"origin"))
endmethod
method cfilter takes unit u returns boolean
return IsUnitAliveBJ(u) and u!=.caster
endmethod
method onCollision takes unit u returns nothing
call DestroyEffect(AddSpecialEffectTarget("Objects\\Spawnmodels\\Human\\HumanLargeDeathExplode\\HumanLargeDeathExplode.mdl",u,"origin"))
call KillUnit(u)
endmethod
method onEnd takes nothing returns nothing
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(.proj),GetUnitY(.proj)))
endmethod
method onStart takes nothing returns nothing
call DestroyEffect(AddSpecialEffect("Abilities\\Spells\\Orc\\WarStomp\\WarStompCaster.mdl",GetUnitX(.caster),GetUnitY(.caster)))
endmethod
endstruct
function Trig_Sample_Conditions takes nothing returns boolean
return GetSpellAbilityId() == 039;A000039;
endfunction
function Trig_Sample_Actions takes nothing returns nothing
local unit caster = GetTriggerUnit()
local proj p = proj.create(caster, GetUnitX(caster),GetUnitY(caster), 0, GetSpellTargetX(), GetSpellTargetY(), 0, GetRandomReal(.6,2), GetRandomReal(.02,.09), "units\\human\\phoenix\\phoenix.mdl",039;e001039;)
local proj k = proj.create(caster, GetUnitX(caster),GetUnitY(caster), 0, GetSpellTargetX(), GetSpellTargetY(), 0, GetRandomReal(.6,2), GetRandomReal(.02,.09), "units\\human\\phoenix\\phoenix.mdl",039;e001039;)
local proj j = proj.create(caster, GetUnitX(caster),GetUnitY(caster), 0, GetSpellTargetX(), GetSpellTargetY(), 0, GetRandomReal(.6,2), GetRandomReal(.02,.09), "units\\human\\phoenix\\phoenix.mdl",039;e001039;)
call p.horizontal(GetRandomReal(-45,45),GetRandomReal(200,900))
call j.horizontal(GetRandomReal(-45,45),GetRandomReal(200,900))
call k.horizontal(GetRandomReal(-45,45),GetRandomReal(200,900))
call p.size(64)
call j.size(64)
call k.size(64)
call p.settick(.03125)
call j.settick(.03125)
call k.settick(.03125)
set caster = null
endfunction
//===========================================================================
function InitTrig_Sample takes nothing returns nothing
set gg_trg_Sample = CreateTrigger( )
call TriggerRegisterAnyUnitEventBJ( gg_trg_Sample, EVENT_PLAYER_UNIT_SPELL_EFFECT )
call TriggerAddCondition( gg_trg_Sample, Condition( function Trig_Sample_Conditions ) )
call TriggerAddAction( gg_trg_Sample, function Trig_Sample_Actions )
endfunction
Demo Map v5: