HomeUser Control Panel (unavailable in archive)ForumsTutorialsArt GalleryResourcesMaps

Trigger: Strafing movement

11-16-2007, 04:33 AM#1
Fuzzyetdeadly
I would like to design a trigger that will cause a unit to strafe when the left or right arrow keys are placed.

I understand it is possible to order a unit to move leftward or rightward, however this will cause the unit to face 0 or 180 degrees, which is not what i desire.

Basically i would like to design a system that
-Allows units to move left and right while maintaining the direction it is facing.
For example, if a unit is facing 90 degrees, i want it to always be facing 90 degrees during strafing movement.

I have thought of a possible way to do this but im not sure how or weather it is possible.

-Basically i am just required to move the unit (instead of order it to move) sideways.
-The alternative would be to have a dummy unit that forces the unit sideways upon contact, but i have no idea how to do this.. If anyone has played dota before im thinking of spiritbreakers greater bash.

Thanks in advance

Regards,
FuzzyetDeadly.
11-16-2007, 04:38 AM#2
Earth-Fury
play the units walk animation and move it instantly left or right. It would be the best solution. (and 5 minutes to code it using JASS...)
11-16-2007, 07:17 AM#3
Fuzzyetdeadly
Quote:
Originally Posted by Earth-Fury
play the units walk animation and move it instantly left or right. It would be the best solution. (and 5 minutes to code it using JASS...)

Im still quite new to JASS, but im interested in learning it. Do you think you could give me an idea of what natives i require to perform the JASS coding for this?
11-16-2007, 01:01 PM#4
Earth-Fury
Collapse JASS:
native SetUnitAnimation takes unit whichUnit,string whichAnimation returns nothing
// Or, even better but more complex:
native SetUnitAnimationByIndex takes unit whichUnit,integer whichAnimation returns nothing

native SetUnitX takes unit whichUnit,real newX returns nothing
native SetUnitY takes unit whichUnit,real newY returns nothing

native CreateTimer takes nothing returns timer
native TimerStart takes timer whichTimer,real timeout,boolean periodic,code handlerFunc returns nothing

i would use a global array of units and loop throgh it each iteration of a timer, moving them based on a value attatched to the units. If you need an easy method of attatchment, i use Grim's data system (requires vJASS):
http://wc3campaigns.net/pastebint.ph...3ffd04408ae7e1

also, a decent timeout for the timer would be around 1/40, so it would loop 40 times a second giving decently smooth movement.

SetUnitX and Y can move units outside of the map, causing a crash. make sure a unit does not exit the playable map area. these two functiosn also ignore pathing, so you will need a method of detecting the patability of terrain. (moving a global item and detecting if the position it was actually moved to was the desired position, down to a specific error range, is one of the fastest ways)
11-16-2007, 02:45 PM#5
Fuzzyetdeadly
Ill keep a note of those natives you mentioned.. tho i think itll be awhile before i actually learn how to use them properly.

Ive done some trial and error with the GUI then tried to make my own version of it with JASS.

I tried running the Movement system with the GUI trigger and it was really smooth.

I tried testing again with the JASS script i programmed and the movement was kinda choppy.. ill paste a copy of the code here and the map too, if its not too troublesome maybe you could take a look and tell me what ive done wrong. Im taking a guess its got something to do with the multitude of function calls the GUI uses.. But im not so sure.

Im pretty sure my script isnt optimized as this is my official first attempt at JASS.

Heres my script
Collapse JASS:
//Function call to move location of unit.
function moveloc takes unit u1,real x,real y returns nothing
    call SetUnitPositionLoc( u1, OffsetLocation(GetUnitLoc(u1), x, y) )
endfunction

//udg_mU00, udg_mD00, udg_mR00 and udg_mL00 are boolean variables used to determine keystrokes.
function Trig_move_Actions takes nothing returns nothing
    call SetUnitAnimation( gg_unit_hgyr_0000, "walk" )
    if ( udg_mU00 == true ) then
//        call SetUnitPositionLoc( gg_unit_hgyr_0000, OffsetLocation(GetUnitLoc(gg_unit_hgyr_0000), 0.00, 15.00) )
        if ( udg_mL00 == true and udg_mR00 == false) then
            call moveloc( gg_unit_hgyr_0000, -15.00, 15.00 )
        elseif ( udg_mL00 == false and udg_mR00 == true) then 
            call moveloc( gg_unit_hgyr_0000, 15.00, 15.00 )
        else 
            call moveloc( gg_unit_hgyr_0000, 0.00, 15.00 )
        endif
    elseif ( udg_mD00 == true) then
        if ( udg_mL00 == true and udg_mR00 == false) then
            call moveloc( gg_unit_hgyr_0000, -15.00, -15.00 )
        elseif ( udg_mL00 == false and udg_mR00 == true) then 
            call moveloc( gg_unit_hgyr_0000, 15.00, -15.00 )
        else 
            call moveloc( gg_unit_hgyr_0000, 0.00, -15.00 )
        endif
    else
        if ( udg_mL00 == true) then
            call moveloc( gg_unit_hgyr_0000, -15.00, 0.00 )
        elseif ( udg_mR00 == true) then
            call moveloc( gg_unit_hgyr_0000, 15.00, 0.00 )
        else
        endif
    endif
endfunction

//===========================================================================
function InitTrig_move takes nothing returns nothing
    set gg_trg_move = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_move, 0.05 )
    call TriggerAddAction( gg_trg_move, function Trig_move_Actions )
endfunction

Thanks in advance for you help =)
Attached Files
File type: w3xRS25IR_2.w3x (20.4 KB)
11-16-2007, 03:15 PM#6
Troll-Brain
Quote:
SetUnitX and Y can move units outside of the map causing a crash
Only if you try to give an order to the unit
11-16-2007, 04:40 PM#7
Earth-Fury
#1: Download JASS NewGen (in the tools section of this site)
#2: Stop using the variable editor. Its a pile of shit. NewGen allows you to define globals in the code, ala:
Collapse JASS:
globals
    integer MyGlobalVariableName = 23
endglobals
don't use function calls when assigning globals a default value like that. globals can be defined as constant or arrays. NewGen also allows you to use scopes, and public and private modifyers. (private being only usable within the scope its defined in, public being usable anywhere, but you must prefix it with the scope name followed by an underscore if you use it outside of the scope)
Collapse JASS:
globals
    [scope] [constant] type [array] name [= default value]
endglobals
scope being "public" or "private" (only inside a scope or library)
constant being the optional word constant (makes a variable read-only, thus its default value is its only value)
type being the variables type, like real integer boolean ext.
array would be included to make it an array
name is self-evident
[= default value] is not applicable for arrays.


Also, your variable names all suck. And you use locations, which are evil. use raw X and Y cords. (NewGen includes TESH, which has a function finder) you should only use locations when absolutely nessisary. (the only time i've found myself requiring locations is with GetLocationZ()) two more natives:
Collapse JASS:
constant native GetUnitX takes unit whichUnit returns real
constant native GetUnitY takes unit whichUnit returns real

also, you code brackets in if statements as:
if ( condition ) then
wheras you could do:
if condition then
(note: just a style thing... i like it without the un-needed brackets)

the logic of your movement could be improved to somethins as:

Collapse JASS:
local real newx = GetUnitX(u)
local real newy = GetUnitY(u)

if UpPressed then
    set newy = newy + 15
endif

if DownPressed then
    set newx = newx + 15
endif

Also, using trigenometry to base the direction of movement on a units facing would be nice.

As for making this multi-instanciable, you would need to have an array of units, each at a playerid's index. (the owning player) then, you loop throgh player indexes (say, 0 to 11 for all 12 players) and check what keys are pressed, modifying a units position as such.
Collapse JASS:
constant native GetPlayerId takes player whichPlayer returns integer
11-16-2007, 05:00 PM#8
Fuzzyetdeadly
Wow.. thanks alot for the explanation. Looks like i got alot of code revamping to do then. Heh. Ill get back to you again as soon as ive given it a shot.

The newgen thing, i already had it :P i just arent familiar with how to take advantage of it just yet, hence the lousy coding (which was actually converted from GUI and modified.)

Anyways
To note: Rep added

Edit: JASS feels so hard when you started off with GUI =/
11-16-2007, 06:41 PM#9
Earth-Fury
In response to a PM, posted here to allow others to learn from this conversation:

#1: use a scope.
Collapse JASS:
scope MovementSystem
globals
    private constant real UpdatesPerSecond = 40
endglobals

private function DoMove takes nothing returns nothing
    // The TimerStart() in the InitTrig function starts a looping timer with a timeout of 1/UpdatesPerSecond, which calls this function every time the timer expires.
endfunction

public function InitTrig takes nothing returns nothing
    // In a scope, a public function named InitTrig gets post-fixed with the scope name. 
    // Thus, name the trigger the same thing you name the scope, and it will become InitTrig_MovementSystem. 
    // InitTrig functions are automagically called by warcraft 3 before pretty much any other function. when usng Jass NewGen, you do not have to include an InitTrig function in a trigger. But in vanilla, normal WE, you do have to include one.
    call TimerStart(CreateTimer(), 1/UpdatesPerSecond, true, function DoMove)
endfunction
endscope

#2: the warcraft 3 map script is a single script, which all the GUI "Triggers" from the world editor get compiled in to. in the map script, there is a single block for declaring globals, and it is located at the top of the script. JASS NewGen simply takes all globals blocks it finds in a script, and merges them in to that single globals block. you can have a limitless number of globals blocks anywhere in your script.

I can't see any issue with the code you PMed me, but i'm going to presume those udg_ prefixed variables are not defined. Convert your key-press triggers to JASS, and define the key press variables with decent names, like IsUpPressed. then simply, in the action function do:
Collapse JASS:
set IsUpPressed = not IsUpPressed
not causes the value of a boolean to become the oposit of what it is, thus not true = false, not false = true.
11-17-2007, 04:18 PM#10
Fuzzyetdeadly
Ok.. it took me awhile but ive revamped the movement system into JASS code. (Hopefully it looks alot cleaner and more readable now)
Im having trouble declaring globals though, ill show you what i tried.. it gives me compile errors. Its got something to do with the scoping i think.
*Note: The scope name is the same as the trigger name.

I tried to have my global variables declared..
Collapse JASS:
scope movesystem
globals
    private constant real UpdatesPerSecond = 40
    private unit array u
//Temporary names for the boolean variables, 
//assuming i do not use the vannilla WE variable creator thing. 
//I labelled them public because i need them to be used for 
//the key detection triggers
    public boolean hdg_mR00 = false
    public boolean hdg_mL00 = false
    public boolean hdg_mU00 = false
    public boolean hdg_mD00 = false
endglobals

This is the main section that creates movement:
Collapse JASS:
private function DoMove takes nothing returns nothing
//note, original code was just "function DoMove takes nothing returns nothing"
set u[0] = gg_unit_hgyr_0000 //Originally "local unit u = gg_unit_hgyr_0000"
local real a = 30.00
local real newx = GetUnitX(u[0])
local real newy = GetUnitY(u[0])

    if udg_mL00 then
        set newx = newx - a
    endif
    
    if udg_mR00 then
        set newx = newx + a
    endif

    if udg_mU00 then
        set newy = newy + a
    endif
 
    if udg_mD00 then
        set newy = newy - a
    endif
    
call SetUnitX(u[0],newx)
call SetUnitY(u[0],newy)
endfunction

I added this:
Collapse JASS:
public function InitTrig takes nothing returns nothing
    call TimerStart(CreateTimer(), 1/UpdatesPerSecond, true, function DoMove)
endfunction
endscope

I omitted this section of my code:
Collapse JASS:
//===========================================================================
function InitTrig_movesystem takes nothing returns nothing
    set gg_trg_movesystem = CreateTrigger(  )
    call TriggerRegisterTimerEventPeriodic( gg_trg_movesystem, 0.05 )
    call TriggerAddAction( gg_trg_movesystem, function DoMove )
endfunction

Without the added stuff, the original code works fine, but now i need to use global arrays to make this multi-instancible. Also, i would like to get rid of the ugly boolean variable names generated by WE.

Wonder what silly mistake i made this time..

Edit: The compile error i recieved was "Expected end of line"
I tested it out, it appears when i attempt to use globals and endglobals
could it have something to do with the vJASS thing?.. im using the newgen4b at the moment so im assuming it comes with vJASS. Also.. i cant quite understand the Grim01 data system thing.. might have something to do with that as well.
11-17-2007, 06:32 PM#11
Earth-Fury
Collapse JASS:
private function DoMove takes nothing returns nothing
//note, original code was just "function DoMove takes nothing returns nothing"
set u[0] = gg_unit_hgyr_0000 //Originally "local unit u = gg_unit_hgyr_0000"
local real a = 30.00
local real newx = GetUnitX(u[0])
local real newy = GetUnitY(u[0])
local variables must be defined at the top of a function. Move the set statement below the local declirations.

convert your keypress detecting triggers to JASS, and include them in the movesystem scope. Declare key-press variables as arrays, just like your unit array (which has a horrible name) then, you loop from 0 to 11 in the DoMove function and check each key press boolean for each player, moving the unit at the players index in the array based on user input.

Your global declarations appear to be fine, and they compile fine with the fix i mentioned:
Collapse JASS:
scope movesystem
globals
    private constant real UpdatesPerSecond = 40
    private unit array u
//Temporary names for the boolean variables, 
//assuming i do not use the vannilla WE variable creator thing. 
//I labelled them public because i need them to be used for 
//the key detection triggers
    public boolean hdg_mR00 = false
    public boolean hdg_mL00 = false
    public boolean hdg_mU00 = false
    public boolean hdg_mD00 = false
endglobals

private function DoMove takes nothing returns nothing
//note, original code was just "function DoMove takes nothing returns nothing"
local real a = 30.00
local real newx = GetUnitX(u[0])
local real newy = GetUnitY(u[0])
set u[0] = null//gg_unit_hgyr_0000 //Originally "local unit u = gg_unit_hgyr_0000"

    if hdg_mL00 then
        set newx = newx - a
    endif
    
    if hdg_mR00 then
        set newx = newx + a
    endif

    if hdg_mU00 then
        set newy = newy + a
    endif
 
    if hdg_mD00 then
        set newy = newy - a
    endif
    
call SetUnitX(u[0],newx)
call SetUnitY(u[0],newy)
endfunction

public function InitTrig takes nothing returns nothing
    call TimerStart(CreateTimer(), 1/UpdatesPerSecond, true, function DoMove)
endfunction
endscope

anyway, as for adding the keypress triggers to the scope, you will end up with 4 functions, one handling up, one handling down, ect, ect. Then, you will need to inline all the InitTrig functions in to the one in the scope. Use a local trigger, ala:
Collapse JASS:
public function InitTrig takes nothing returns nothing
    local trigger t
    set t = CreateTrigger()
    call TriggerRegisterWhateverEvent(t, blah blah blah)
    call TriggerAddAction(t, function SetUpKeyState)
    set t = CreateTrigger()
    call TriggerRegisterWhateverEvent(t, blah blah blah)
    call TriggerAddAction(t, function SetDownKeyState)
    // ext ext
endfunction

As for why your code doesn't compile, i have no idea, as other than that one error, it compiles fine for me... Odd.
11-17-2007, 07:23 PM#12
Deaod
are you using the syntax checker of TESH? If you do, try saving the map. The problem is, that TESH only uses PJASS to check and does not preprocess the script. Scopes are things that need to be preprocessed, because this is not a normal feature of JASS.
11-17-2007, 11:28 PM#13
burningice95
Ignore this >>
11-18-2007, 04:00 AM#14
Pyrogasm
...? That has nothing to do with what he wants.
11-18-2007, 04:18 AM#15
Fuzzyetdeadly
I presume im using TESH, as it is stated that it is included in the NewGen 1.4b Package. I think its as you say, my scope is not preprocessing, merely getting checked by PJASS.
Scopes and globals are the main things that cause the errors, when i omit them the trigger works alright. But i would really like to implement scopes and globals to get a better insight on how they work.

My question is, how exactly do i have my script pre-processed?