- Joined
- Apr 29, 2007
- Messages
- 826
hai thar, I present you a new system (wow)
It allows you to make simple projectils with a linear or a parabolic throw(parabola is the standard wc3 thingie from Shadow1500)
You can configurate everything the projectile is going to do.
Demo map with 2 example spells below. Enjoy
It allows you to make simple projectils with a linear or a parabolic throw(parabola is the standard wc3 thingie from Shadow1500)
You can configurate everything the projectile is going to do.
JASS:
/*
LINEAR- & PARABOLIC THROW
by YourName
DESCRIPTION
>> This is an easy to modificate system that allows you to throw projectiles by the
linear of parabolic way. Through an interface you're able to setup anything the
projectile should do.
Some functions are made by default, but you can simply rewrite those methods in
your child struct.
FUNCTIONS LIST
>> Interface
>> method OnInit takes nothing returns nothing
method OnLoop takes nothing returns nothing
method OnDestroy takes nothing returns nothing
method OnHeightCollision takes nothing returns nothing
method OnUnitCollision takes nothing returns nothing
method OnUnitCollisionCheck takes nothing returns boolean
method OnDoodadCollision takes destructable d returns nothing
method OnPathableCollision takes nothing returns nothing
>> Struct
>> method create takes unit target, real angle, real speed, real reduce returns Throw
method stop takes nothing returns nothing
NOTE: Please use this instead of destroying the struct, this won't screw things up.
SIMPLE USAGE
>> All you have to do is extend the LinearThrow or ParabolicThrow struct depending on
which one you want. After that setup all the stuff and you're done.
For an example look in the spell section at the demo map.
*/
JASS:
library_once LinearThrow initializer Init
globals // Configuration
// The interval how often the stuff is executed
constant real THROWSYSTEM_INTERVAL = 0.02
// The Radius in which units/doodads get picked
constant real THROWSYSTEM_RADIUS = 100
// The minimum height the projectile has to have before it can hit any of those 2
constant real THROWSYSTEM_MIN_UNIT_HEIGHT = 125
constant real THROWSYSTEM_MIN_DESTR_HEIGHT = 225
// If the height should decrease or be constant
constant boolean THROWSYSTEM_DECREASE_HEIGHT = true
// Whether the projectile should drift a bit or not
constant boolean THROWSYSTEM_ALLOW_DRIFT = true
// Maximum drift amount
constant real THROWSYSTEM_DRIFT_MAX = 1000
// It might look ugly when the projectiles flies of too much. So set this value higher
constant real THROWSYSTEM_DRIFT_Z_CORRECTION = 2
// If the projectile should be stopped whenever the Z of it reaches 0
constant boolean THROWSYSTEM_DESTROY_WHEN_Z_0 = true
endglobals
interface LinearThrowFace // I love Vex
static timer t
static integer total
static LinearThrow array save
static group g
static boolexpr bool
static unit victim
static rect r
static LinearThrow tempsave
static location zloc
static item i1 = null
static item i2 = null
real Interval = THROWSYSTEM_INTERVAL
real Radius = THROWSYSTEM_RADIUS
real MinUnitHeight = THROWSYSTEM_MIN_UNIT_HEIGHT
real MinDestrHeight = THROWSYSTEM_MIN_DESTR_HEIGHT
boolean DecreaseHeight = THROWSYSTEM_DECREASE_HEIGHT
boolean Drift = THROWSYSTEM_ALLOW_DRIFT
real DriftValue = THROWSYSTEM_DRIFT_MAX*.Interval
real DriftCorrection = THROWSYSTEM_DRIFT_Z_CORRECTION
boolean DestroyWhenZ = THROWSYSTEM_DESTROY_WHEN_Z_0
method OnInit takes nothing returns nothing defaults nothing
method OnLoop takes nothing returns nothing defaults nothing
method OnDestroy takes nothing returns nothing defaults nothing
method OnHeightCollision takes nothing returns nothing defaults nothing
method OnUnitCollision takes nothing returns nothing defaults nothing
method OnUnitCollisionCheck takes nothing returns boolean defaults true
method OnDoodadCollision takes destructable d returns nothing defaults nothing
method OnPathableCollision takes nothing returns nothing defaults nothing
endinterface
struct LinearThrow extends LinearThrowFace
unit target
real sin
real cos
real speed
real reduce
real distance
real maxdist
real iniz
real zr
integer i
method operator x takes nothing returns real
return GetUnitX(.target)
endmethod
method operator y takes nothing returns real
return GetUnitY(.target)
endmethod
method operator z takes nothing returns real
call MoveLocation(.zloc, .x, .y)
if .DecreaseHeight then
return .iniz - GetLocationZ(.zloc) - (.zr*.i)
else
return .iniz - GetLocationZ(.zloc)
endif
endmethod
private method operator x= takes real x returns nothing
call SetUnitX(.target, x)
endmethod
private method operator y= takes real y returns nothing
call SetUnitY(.target, y)
endmethod
private method operator z= takes real z returns nothing
call SetUnitFlyHeight(.target, z, 0)
endmethod
method operator pathable takes nothing returns boolean
if .i1 == null or .i2 == null then
if .i1 == null then
set .i1 = CreateItem('sehr', .x, .y)
endif
if .i2 == null then
set .i2 = CreateItem('sehr', .x, .y)
endif
endif
call SetItemPosition(.i1, .x, .y)
call SetItemPosition(.i2, .x, .y)
if (GetItemX(.i1) == .x and GetItemY(.i1) == .y) and not (GetItemX(.i2) == .x and GetItemY(.i2) == .y) then
call SetItemVisible(.i1, false)
call SetItemVisible(.i2, false)
return true
endif
call SetItemVisible(.i1, false)
call SetItemVisible(.i2, false)
return false
endmethod
method OnHeightCollision takes nothing returns nothing
call .stop()
endmethod
method OnDoodadCollision takes destructable d returns nothing
if GetWidgetLife(d) > 0.405 then
call KillDestructable(d)
call .stop()
endif
endmethod
method stop takes nothing returns nothing
set .speed = 0
endmethod
static method create takes unit target, real angle, real speed, real reduce returns LinearThrow
local LinearThrow this = LinearThrow.allocate()
local real time
set .target = target
set .sin = Sin(angle)
set .cos = Cos(angle)
set .speed = speed
set .reduce = reduce
call MoveLocation(.zloc, .x, .y)
set .iniz = GetUnitFlyHeight(.target) + GetLocationZ(.zloc)
set .zr = .iniz / ( speed / reduce )
set .i = 0
set time = speed / ((reduce/.Interval)+1)
set .maxdist = (speed*((time/.Interval)+1)) / 2
set .distance = 0.01
call .OnInit()
if .total == 0 then
call TimerStart(.t, .Interval, true, function LinearThrow.work)
endif
set .save[.total] = this
set .total = .total + 1
return this
endmethod
private static method work takes nothing returns nothing
local LinearThrow this
local integer i = 0
local real angle
loop
exitwhen i >= .total
set this = .save[i]
set .i = .i + 1
set .distance = .distance + .speed
set .x = .x + .speed * .cos
set .y = .y + .speed * .sin
set .z = .z
if .Drift then
set angle = (GetUnitFacing(.target) - 90)
set .x = .x + GetRandomReal(-.DriftValue, .DriftValue) * Cos(angle * bj_DEGTORAD)
set .y = .y + GetRandomReal(-.DriftValue, .DriftValue) * Sin(angle * bj_DEGTORAD)
set .z = .z + GetRandomReal(-.DriftValue, .DriftValue)/.DriftCorrection
call SetUnitFacing(.target, angle)
endif
call .OnLoop()
set .speed = .speed - .reduce
if .z < .MinUnitHeight then
call GroupEnumUnitsInRange(.g, .x, .y, .Radius, .bool)
loop
set .victim = FirstOfGroup(.g)
exitwhen .victim == null
if .OnUnitCollisionCheck() then
call .OnUnitCollision()
endif
call GroupRemoveUnit(.g, .victim)
endloop
set .victim = null
endif
if .z < .MinDestrHeight then
if .Radius != THROWSYSTEM_RADIUS then
set .r = Rect(0-.Radius, 0-.Radius, 0+.Radius, 0+.Radius)
endif
call MoveRectTo(.r, .x, .y)
set .tempsave = this
call EnumDestructablesInRect(.r, .bool, function LinearThrow.DoodadCollision)
endif
if GetLocationZ(.zloc) > .iniz then
call .OnHeightCollision()
endif
if not .pathable then
call .OnPathableCollision()
endif
if .speed <= 0 or (.z < 1 and .DestroyWhenZ) or .distance > .maxdist then
set .total = .total - 1
set .save[i] = .save[.total]
call .OnDestroy()
call .destroy()
endif
set i = i + 1
endloop
if .total == 0 then
call PauseTimer(.t)
endif
endmethod
private static method DoodadCollision takes nothing returns nothing
local LinearThrow this = .tempsave
call .OnDoodadCollision(GetEnumDestructable())
endmethod
endstruct
private function Init takes nothing returns nothing
set LinearThrow.t = CreateTimer()
set LinearThrow.zloc = Location(0,0)
set LinearThrow.g = CreateGroup()
set LinearThrow.bool = null
set LinearThrow.victim = null
set LinearThrow.r = Rect(0-THROWSYSTEM_RADIUS, 0-THROWSYSTEM_RADIUS, 0+THROWSYSTEM_RADIUS, 0+THROWSYSTEM_RADIUS)
set LinearThrow.total = 0
endfunction
endlibrary
JASS:
library_once ParabolicThrow initializer Init
globals // Configuration
// The interval how often the stuff is executed
constant real THROWPARABOLICSYSTEM_INTERVAL = 0.02
// The Radius in which units/doodads get picked
constant real THROWPARABOLICSYSTEM_RADIUS = 100
// The minimum height the projectile has to have before it can hit any of those 2
constant real THROWPARABOLICSYSTEM_MIN_UNIT_HEIGHT = 125
constant real THROWPARABOLICSYSTEM_MIN_DESTR_HEIGHT = 225
// If the height should decrease or be constant
constant boolean THROWPARABOLICSYSTEM_DECREASE_HEIGHT = true
// Whether the projectile should drift a bit or not
constant boolean THROWPARABOLICSYSTEM_ALLOW_DRIFT = true
// Maximum drift amount
constant real THROWPARABOLICSYSTEM_DRIFT_MAX = 1000
// It might look ugly when the projectiles flies of too much. So set this value higher
constant real THROWPARABOLICSYSTEM_DRIFT_Z_CORRECTION = 2
// If the projectile should be stopped whenever the Z of it reaches 0
constant boolean THROWPARABOLICSYSTEM_DESTROY_WHEN_Z_0 = true
// The curve the projectile will have
constant real THROWPARABOLICSYSTEM_CURVE = 2
endglobals
interface ParabolicThrowFace // I love Vex
static timer t
static integer total
static ParabolicThrow array save
static group g
static boolexpr bool
static unit victim
static rect r
static ParabolicThrow tempsave
static location zloc
static item i1 = null
static item i2 = null
real Interval = THROWPARABOLICSYSTEM_INTERVAL
real Radius = THROWPARABOLICSYSTEM_RADIUS
real MinUnitHeight = THROWPARABOLICSYSTEM_MIN_UNIT_HEIGHT
real MinDestrHeight = THROWPARABOLICSYSTEM_MIN_DESTR_HEIGHT
boolean DecreaseHeight = THROWPARABOLICSYSTEM_DECREASE_HEIGHT
boolean Drift = THROWPARABOLICSYSTEM_ALLOW_DRIFT
real DriftValue = THROWPARABOLICSYSTEM_DRIFT_MAX*.Interval
real DriftCorrection = THROWPARABOLICSYSTEM_DRIFT_Z_CORRECTION
boolean DestroyWhenZ = THROWPARABOLICSYSTEM_DESTROY_WHEN_Z_0
real Curve = THROWPARABOLICSYSTEM_CURVE
method OnInit takes nothing returns nothing defaults nothing
method OnLoop takes nothing returns nothing defaults nothing
method OnDestroy takes nothing returns nothing defaults nothing
method OnHeightCollision takes nothing returns nothing defaults nothing
method OnUnitCollision takes nothing returns nothing defaults nothing
method OnUnitCollisionCheck takes nothing returns boolean defaults true
method OnDoodadCollision takes destructable d returns nothing defaults nothing
method OnPathableCollision takes nothing returns nothing defaults nothing
endinterface
struct ParabolicThrow extends ParabolicThrowFace
unit target
real sin
real cos
real speed
real reduce
real distance
real maxdist
real iniz
real zr
integer i
// Function by Shadow1500
private method operator parabola takes nothing returns real
local real t = (.distance*2) / .maxdist-1
return (-t*t+1) * (.maxdist/.Curve)
endmethod
method operator x takes nothing returns real
return GetUnitX(.target)
endmethod
method operator y takes nothing returns real
return GetUnitY(.target)
endmethod
method operator z takes nothing returns real
call MoveLocation(.zloc, .x, .y)
if .DecreaseHeight then
return .iniz + .parabola - GetLocationZ(.zloc) - (.zr*.i)
else
return .iniz + .parabola - GetLocationZ(.zloc)
endif
endmethod
private method operator x= takes real x returns nothing
call SetUnitX(.target, x)
endmethod
private method operator y= takes real y returns nothing
call SetUnitY(.target, y)
endmethod
private method operator z= takes real z returns nothing
call SetUnitFlyHeight(.target, z, 0)
endmethod
private method operator pathable takes nothing returns boolean
if .i1 == null or .i2 == null then
if .i1 == null then
set .i1 = CreateItem('sehr', .x, .y)
endif
if .i2 == null then
set .i2 = CreateItem('sehr', .x, .y)
endif
endif
call SetItemPosition(.i1, .x, .y)
call SetItemPosition(.i2, .x, .y)
if (GetItemX(.i1) == .x and GetItemY(.i1) == .y) and not (GetItemX(.i2) == .x and GetItemY(.i2) == .y) then
call SetItemVisible(.i1, false)
call SetItemVisible(.i2, false)
return true
endif
call SetItemVisible(.i1, false)
call SetItemVisible(.i2, false)
return false
endmethod
method OnHeightCollision takes nothing returns nothing
call .stop()
endmethod
method OnDoodadCollision takes destructable d returns nothing
if GetWidgetLife(d) > 0.405 then
call KillDestructable(d)
call .stop()
endif
endmethod
method stop takes nothing returns nothing
set .speed = 0
endmethod
static method create takes unit target, real angle, real speed, real reduce returns ParabolicThrow
local ParabolicThrow this = ParabolicThrow.allocate()
local real time
set .target = target
set .sin = Sin(angle)
set .cos = Cos(angle)
set .speed = speed
set .reduce = reduce
set time = speed / ((reduce/.Interval)+1)
set .maxdist = (speed*((time/.Interval)+1)) / 2
set .distance = 0.01
call MoveLocation(.zloc, .x, .y)
set .iniz = GetUnitFlyHeight(.target) + GetLocationZ(.zloc)
set .zr = .iniz / ( speed / reduce )
set .i = 0
call .OnInit()
if .total == 0 then
call TimerStart(.t, .Interval, true, function ParabolicThrow.work)
endif
set .save[.total] = this
set .total = .total + 1
return this
endmethod
private static method work takes nothing returns nothing
local ParabolicThrow this
local integer i = 0
local real angle
loop
exitwhen i >= .total
set this = .save[i]
set .i = .i + 1
set .distance = .distance + .speed
set .x = .x + .speed * .cos
set .y = .y + .speed * .sin
set .z = .z
if .Drift then
set angle = (GetUnitFacing(.target) - 90)
set .x = .x + GetRandomReal(-.DriftValue, .DriftValue) * Cos(angle * bj_DEGTORAD)
set .y = .y + GetRandomReal(-.DriftValue, .DriftValue) * Sin(angle * bj_DEGTORAD)
set .z = .z + GetRandomReal(-.DriftValue, .DriftValue)/.DriftCorrection
call SetUnitFacing(.target, angle)
endif
call .OnLoop()
set .speed = .speed - .reduce
if .z < .MinUnitHeight then
call GroupEnumUnitsInRange(.g, .x, .y, .Radius, .bool)
loop
set .victim = FirstOfGroup(.g)
exitwhen .victim == null
if .OnUnitCollisionCheck() then
call .OnUnitCollision()
endif
call GroupRemoveUnit(.g, .victim)
endloop
set .victim = null
endif
if .z < .MinDestrHeight then
if .Radius != THROWPARABOLICSYSTEM_RADIUS then
set .r = Rect(0-.Radius, 0-.Radius, 0+.Radius, 0+.Radius)
endif
call MoveRectTo(.r, .x, .y)
set .tempsave = this
call EnumDestructablesInRect(.r, .bool, function ParabolicThrow.DoodadCollision)
endif
if GetLocationZ(.zloc) > .iniz then
call .OnHeightCollision()
endif
if not .pathable then
call .OnPathableCollision()
endif
if .speed <= 0 or (.z < 1 and .DestroyWhenZ) or .distance >= .maxdist then
set .total = .total - 1
set .save[i] = .save[.total]
call .OnDestroy()
call .destroy()
endif
set i = i + 1
endloop
if .total == 0 then
call PauseTimer(.t)
endif
endmethod
private static method DoodadCollision takes nothing returns nothing
local ParabolicThrow this = .tempsave
call .OnDoodadCollision(GetEnumDestructable())
endmethod
endstruct
private function Init takes nothing returns nothing
set ParabolicThrow.t = CreateTimer()
set ParabolicThrow.zloc = Location(0,0)
set ParabolicThrow.g = CreateGroup()
set ParabolicThrow.bool = null
set ParabolicThrow.victim = null
set ParabolicThrow.r = Rect(0-THROWPARABOLICSYSTEM_RADIUS, 0-THROWPARABOLICSYSTEM_RADIUS, 0+THROWPARABOLICSYSTEM_RADIUS, 0+THROWPARABOLICSYSTEM_RADIUS)
set ParabolicThrow.total = 0
endfunction
endlibrary
JASS:
library_once Convert
/*
This is just a simple library to convert those values, so you don't have to type the damn formulas
yourself.
*/
function Distance2Speed takes real distance, real time returns real
return (2*distance) / ((time/THROWSYSTEM_INTERVAL)+1)
endfunction
function Time2SpeedReduce takes real time, real speed returns real
return speed / (time/THROWSYSTEM_INTERVAL)
endfunction
endlibrary
Demo map with 2 example spells below. Enjoy
Attachments
Last edited: