• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Need help with a kb system

Status
Not open for further replies.
Level 11
Joined
May 31, 2008
Messages
698
Okay, im making a knockback system where units will push each other back when they run into each other, so unit a runs into unit b, b will be push forward. Unit b should only be pushed back if unit a is facing him. But if unit a and b run into each other head on, both should be pushed back.

I got most of the hard stuff down, the units bounce off walls and whatnot.

But sometimes it will push units when they arent facing each other and idk how to fix it. I tried a bunch of times, but each time something else got messed up, usually what gets messed up is they dont push each other sometimes

And yes, i used custom value for indexing xD (i might change it tho)


Its kind of a lot, so i will break it up a little bit
JASS:
//===============
globals
    unit pusher = null
    real tempX = 0
    real tempY = 0
    real pushvelX = 0
    real pushvelY = 0
    integer doodadsx = 0
    integer doodadsy = 0
endglobals

//===============

JASS:
function Cond2 takes nothing returns boolean
    return (GetUnitTypeId(GetFilterUnit()) != 'h000') and (GetEnumUnit() != GetFilterUnit())
endfunction

function Cond5 takes nothing returns boolean
    if ( not ( udg_Temp_Real[0] >= ( udg_Temp_Real[1] - 15.00 ) ) ) then
        return false
    endif
    if ( not ( udg_Temp_Real[0] <= ( udg_Temp_Real[1] + 15.00 ) ) ) then
        return false
    endif
    return true
endfunction

I tried getting rid of this, because it seems like i dont really need it but for some reason when i take this away it will only push sometimes and when 2 units run into each other only one gets pushed
JASS:
function Act3 takes nothing returns nothing
    local unit u = GetEnumUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real r = bj_RADTODEG * Atan2(y - tempY, x - tempX)
    set udg_Temp_Real[1] = GetUnitFacing(udg_Temp_Unit)
    if (Cond5()) then
        call GroupAddUnit(udg_Push_Group, u)
        if udg_CV >= 100 then
            set udg_CV = 0
        else
        endif
        set udg_CV = ( udg_CV + 1 )
        call SetUnitUserData( GetEnumUnit(), udg_CV )
        set udg_Push_Angle[udg_CV] = r
        set udg_Push_Speed[udg_CV] = 20.00
        set udg_Push_X[udg_CV] = 20.00
        set udg_Push_Y[udg_CV] = 20.00
    else
    endif
endfunction

JASS:
function Enum1 takes nothing returns nothing
    local unit u = GetEnumUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local group g = CreateGroup()
    local real r = 128
    set tempX = x
    set tempY = y
    set pusher = GetEnumUnit()
    call GroupEnumUnitsInRange(g, x, y, r, Condition(function Cond2))
    call ForGroup( g, function Act3 )
endfunction

JASS:
function Act2 takes nothing returns nothing
    set udg_Temp_Real[0] = udg_Push_Angle[GetUnitUserData(GetEnumUnit())]
    set udg_Temp_Real[1] = GetUnitFacing(udg_Temp_Unit)
    if (Cond5()) then
        call GroupAddUnit(udg_Push_Group, GetEnumUnit())
        if udg_CV >= 100 then
            set udg_CV = 0
        else
        endif
        set udg_CV = (udg_CV + 1)
        call SetUnitUserData(GetEnumUnit(), udg_CV)
        set udg_Push_Angle[udg_CV] = udg_Temp_Real[0]
        set udg_Push_Speed[udg_CV] = 20.00
        set udg_Push_X[udg_CV] = 20.00
        set udg_Push_Y[udg_CV] = 20.00
    endif
endfunction

JASS:
function DoodadCountX takes nothing returns nothing
    set doodadsx = doodadsx + 1
endfunction

function DoodadCountY takes nothing returns nothing
    set doodadsy = doodadsy + 1
endfunction

function DestEnumX takes real x, real y returns nothing
        local real r = 100
        local rect c
        set c = Rect(x - r, y - r, x + r, y + r)
        set doodadsx = 0
        call EnumDestructablesInRect(c, null, function DoodadCountX)
        call RemoveRect(c)
    endfunction

function DestEnumY takes real x, real y returns nothing
        local real r = 100
        local rect c
        set c = Rect(x - r, y - r, x + r, y + r)
        set doodadsy = 0
        call EnumDestructablesInRect(c, null, function DoodadCountY)
        call RemoveRect(c)
    endfunction


JASS:
function Act1 takes nothing returns nothing
    local unit u = GetEnumUnit()
    local real x = GetUnitX(u)
    local real y = GetUnitY(u)
    local real r = 128
    local real x2
    local real y2
    local integer i
    set udg_Temp_Unit = u
    call GroupEnumUnitsInRange(udg_Temp_Group, x, y, r, Condition(function Cond2))
    call ForGroup(udg_Temp_Group, function Act2)
    // Move
    set i = GetUnitUserData(u)
    set udg_Temp_Int = i
    if udg_Push_X[i] < 0 then
        set udg_Push_X[i] = (udg_Push_X[i] + .5)
    else
        set udg_Push_X[i] = (udg_Push_X[i] - .5)
    endif
    if udg_Push_Y[i] < 0 then
        set udg_Push_Y[i] = (udg_Push_Y[i] + .5)
    else
        set udg_Push_Y[i] = (udg_Push_Y[i] - .5)
    endif
    set udg_Push_Speed[i] = (udg_Push_Speed[i] - .5)
    set x2 = x + udg_Push_X[i] * Cos(udg_Push_Angle[i] * bj_DEGTORAD)
    set y2 = y + udg_Push_Y[i] * Sin(udg_Push_Angle[i] * bj_DEGTORAD)
    call DestEnumX(x2, y)
    call DestEnumY(x, y2)
    if IsTerrainPathable(x2, y, PATHING_TYPE_WALKABILITY) == false and doodadsx == 0 then
        call SetUnitX(u, x2)
    else
        set udg_Push_X[i] = -udg_Push_X[i]*.64
        set udg_Push_Speed[i] = udg_Push_Speed[i]*.8
        set x2 = x + udg_Push_X[i] * Cos(udg_Push_Angle[i] * bj_DEGTORAD)
        call SetUnitX(u, x2)
    endif
    if IsTerrainPathable(x, y2, PATHING_TYPE_WALKABILITY) == false and doodadsy == 0 then
        call SetUnitY(u, y2)
    else
        set udg_Push_Y[i] = -udg_Push_Y[i]*.64
        set udg_Push_Speed[i] = udg_Push_Speed[i]*.8
        set y2 = y + udg_Push_Y[i] * Sin(udg_Push_Angle[i] * bj_DEGTORAD)
        call SetUnitY(u, y2)
    endif
    if udg_Push_Speed[i] < 1.00 then
        call GroupRemoveUnit(udg_Push_Group, u )
    else
    endif
endfunction

JASS:
function PushInit takes nothing returns nothing
    call ForGroup(udg_Units, function Enum1)
    call RemoveLocation(udg_Temp_Loc)
    call DestroyGroup(udg_Temp_Group)
    set udg_Temp_Unit = null
    call ForGroup(udg_Push_Group, function Act1 )
endfunction

JASS:
//===========================================================================
function InitTrig_PushWorking_Copy takes nothing returns nothing
    set gg_trg_PushWorking_Copy = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_PushWorking_Copy, 0.03 )
    call TriggerAddAction( gg_trg_PushWorking_Copy, function PushInit )
endfunction

How i made this was:
1) made the trigger in GUI
2) converted to JASS
3) tried to make a new JASS trig based on converted one (didnt work)
4) cleaned up the converted trigger (threw away the one i tried to make in step 3)


Thank you in advance for any help. I really wanna make this work right!
+rep to whoever helps of course :)
 

Attachments

  • Map1.w3x
    33.2 KB · Views: 36
Last edited:

Dr Super Good

Spell Reviewer
Level 64
Joined
Jan 18, 2005
Messages
27,198
function Cond5 takes nothing returns boolean
if ( not ( udg_Temp_Real[0] >= ( udg_Temp_Real[1] - 15.00 ) ) ) then
return false
endif
if ( not ( udg_Temp_Real[0] <= ( udg_Temp_Real[1] + 15.00 ) ) ) then
return false
endif
return true
endfunction

could be optimized.

function Cond5 takes nothing returns boolean
return udg_Temp_Real[0] >= ( udg_Temp_Real[1] - 15.) and udg_Temp_Real[0] <= ( udg_Temp_Real[1] + 15.)
endfunction

(GetEnumUnit() != GetFilterUnit())
Make sure that even makes sense. Enum unit is the unit itterated in a "ForGroup" function callback. filter unit is the unit itterated in the group filler enums. They also cross over at some points I think so it may be possible that the condition always evaluates to false.

function Enum1 takes nothing returns nothing
local unit u = GetEnumUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local group g = CreateGroup()
local real r = 128
set tempX = x
set tempY = y
set pusher = GetEnumUnit()
call GroupEnumUnitsInRange(g, x, y, r, Condition(function Cond2))
call ForGroup( g, function Act3 )
endfunction
leaks a group, g is never removed. Also not nulling local handles may cause different leaks.

function Act1 takes nothing returns nothing
local unit u = GetEnumUnit()
local real x = GetUnitX(u)
local real y = GetUnitY(u)
local real r = 128
local real x2
local real y2
local integer i
set udg_Temp_Unit = u
call GroupEnumUnitsInRange(udg_Temp_Group, x, y, r, Condition(function Cond2))
call ForGroup(udg_Temp_Group, function Act2)
// Move
set i = GetUnitUserData(u)
set udg_Temp_Int = i
if udg_Push_X < 0 then
set udg_Push_X = (udg_Push_X + .5)
else
set udg_Push_X = (udg_Push_X - .5)
endif
if udg_Push_Y < 0 then
set udg_Push_Y = (udg_Push_Y + .5)
else
set udg_Push_Y = (udg_Push_Y - .5)
endif
set udg_Push_Speed = (udg_Push_Speed - .5)
set x2 = x + udg_Push_X * Cos(udg_Push_Angle * bj_DEGTORAD)
set y2 = y + udg_Push_Y * Sin(udg_Push_Angle * bj_DEGTORAD)
call DestEnumX(x2, y)
call DestEnumY(x, y2)
if IsTerrainPathable(x2, y, PATHING_TYPE_WALKABILITY) == false and doodadsx == 0 then
call SetUnitX(u, x2)
else
set udg_Push_X = -udg_Push_X*.64
set udg_Push_Speed = udg_Push_Speed*.8
set x2 = x + udg_Push_X * Cos(udg_Push_Angle * bj_DEGTORAD)
call SetUnitX(u, x2)
endif
if IsTerrainPathable(x, y2, PATHING_TYPE_WALKABILITY) == false and doodadsy == 0 then
call SetUnitY(u, y2)
else
set udg_Push_Y = -udg_Push_Y*.64
set udg_Push_Speed = udg_Push_Speed*.8
set y2 = y + udg_Push_Y * Sin(udg_Push_Angle * bj_DEGTORAD)
call SetUnitY(u, y2)
endif
if udg_Push_Speed < 1.00 then
call GroupRemoveUnit(udg_Push_Group, u )
else
endif
endfunction


Collision logic potentially incorrect. Checks both X and Y axis from unit orignal position but not if the actual desternation is blocked before moving. Also needlessly updates x2 and y2 in the branches as they never are referenced beyond that point.
 
Level 11
Joined
May 31, 2008
Messages
698
Thanks for the feedback, but i think the problem i was having was with the angles xD because when it does angle + 15, if the angle is 355, then the angle would be 370

So i just removed all of that and made a point offset 35 in front of the unit and selected units within 65 of that point.

And (GetEnumUnit() != GetFilterUnit()) (Cond2),
if unit a is facing unit b,
call GroupEnumUnitsInRange(udg_Temp_Group, x, y, r, Condition(function Cond2))
would select both units. Cond2 makes sure only unit b is selected, otherwise unit a and b would both be selected

But yeah i figured out how to fix this xD
Thanks for pointing out the leaks and stuff tho :)

And the collision works really good actually lol
I have always wondered how to make units bounce off walls accurately, and what i have works good :) Check out the map i have attached to first post
 
Status
Not open for further replies.
Top