Snippet EasyKeys

Prozix

New Member
Reaction score
7
This library makes checking for arrow key presses a lot easier. You should definitely check the demo map out to see what you can accomplish with this.

JASS:

library EasyKeys initializer Init
//EasyKeys v1.1 by Prozix

//pros: -  Everything has been done for you
//      -  Easy to use
//      -  You can check for: Newpress, Doublepress, Release, Held and Doubleheld in this version!

//cons: -  Slow (due to warcraft keypress event limitations)
//      -  EasyKeys requires you to call an update function in order to make this system work which would become annoying to do properly if you have multiple triggers using this system at once

//how to use:
//      Lets say I want to know if player 1 (red) is holding the up key:
//      if Pad[0].U.Held() then
//          BJDebugMsg("Up key being pressed by player 1")
//      endif

//      general syntax: Pad[#playerid#].#key#.#state()# with
//          playerid = the players id (0-11)
//          key = U, D, L or R (up down left right)
//          state() = Held(), Doubleheld(), Newpress(), Doublepress() or Released()

//      Maximum amount of ticks to register a double press can be adjusted in the globals section below

globals
    private constant integer KEY_LOOSE = 0
    private constant integer KEY_NEWPRESS = 1
    private constant integer KEY_HELD = 2
    private constant integer KEY_RELEASED = 3
    private constant integer KEY_DOUBLEPRESS = 4
    private constant integer KEY_DOUBLEHELD = 5
    
    private constant integer DOUBLEPRESS_TICKLIMIT = 8
endglobals

private struct KEY 
    integer action
    integer ticks
    static method create takes nothing returns thistype
        local thistype k = thistype.allocate()
        set k.action = KEY_LOOSE
        set k.ticks = 0
        return k
    endmethod
    
    method Newpress takes nothing returns boolean
        if .action == KEY_NEWPRESS then
            return true
        endif
        return false
    endmethod
    method Doublepress takes nothing returns boolean
        if .action == KEY_DOUBLEPRESS then
            return true
        endif
        return false
    endmethod
    method Held takes nothing returns boolean
        if .action == KEY_NEWPRESS or .action == KEY_DOUBLEPRESS or .action == KEY_HELD or .action == KEY_DOUBLEHELD then
            return true
        endif
        return false
    endmethod
    method Doubleheld takes nothing returns boolean
        if .action == KEY_DOUBLEHELD then
            return true
        endif
        return false
    endmethod
    method Released takes nothing returns boolean
        if .action == KEY_RELEASED then
            return true
        endif
        return false
    endmethod
    
    method Update takes nothing returns nothing
        if .action == KEY_NEWPRESS then
            if .ticks == 0 then
                set .ticks = 1
                set .action = KEY_HELD
            elseif .ticks < DOUBLEPRESS_TICKLIMIT then
                set .action = KEY_DOUBLEPRESS
            endif
            
        elseif .action == KEY_DOUBLEPRESS then
            set .ticks = 0
            set .action = KEY_DOUBLEHELD
            
        elseif .action == KEY_RELEASED then
            set .action = KEY_LOOSE
        endif
        
        if .ticks>0 then
            set .ticks = .ticks+1
        endif
        if .ticks>DOUBLEPRESS_TICKLIMIT then
            set .ticks = 0
        endif
    endmethod
endstruct

struct ARROWS
    KEY U
    KEY D
    KEY L
    KEY R
    static method create takes nothing returns thistype
        local thistype a = thistype.allocate()
        set a.U = KEY.create()
        set a.D = KEY.create()
        set a.L = KEY.create()
        set a.R = KEY.create()
        return a
    endmethod
    method Update takes nothing returns nothing
        call .U.Update()
        call .D.Update()
        call .L.Update()
        call .R.Update()
    endmethod
endstruct

globals
    ARROWS array Pad[12]
endglobals

//! textmacro ArrowFunc takes KEY
private function PressArrow$KEY$ takes nothing returns nothing
    set Pad[GetPlayerId(GetEventDetectingPlayer())].$KEY$.action = KEY_NEWPRESS
endfunction
private function ReleaseArrow$KEY$ takes nothing returns nothing
    set Pad[GetPlayerId(GetEventDetectingPlayer())].$KEY$.action = KEY_RELEASED
endfunction
//! endtextmacro
//! runtextmacro ArrowFunc("U")
//! runtextmacro ArrowFunc("D")
//! runtextmacro ArrowFunc("L")
//! runtextmacro ArrowFunc("R")

private function Init takes nothing returns nothing
    local integer i = 0
    local trigger PressU = CreateTrigger()
    local trigger PressD = CreateTrigger()
    local trigger PressL = CreateTrigger()
    local trigger PressR = CreateTrigger()
    
    local trigger ReleaseU = CreateTrigger()
    local trigger ReleaseD = CreateTrigger()
    local trigger ReleaseL = CreateTrigger()
    local trigger ReleaseR = CreateTrigger()
    set i = 0
    loop
        call TriggerRegisterPlayerEvent(PressU, Player(i), EVENT_PLAYER_ARROW_UP_DOWN)
        call TriggerRegisterPlayerEvent(PressD, Player(i), EVENT_PLAYER_ARROW_DOWN_DOWN)
        call TriggerRegisterPlayerEvent(PressL, Player(i), EVENT_PLAYER_ARROW_LEFT_DOWN)
        call TriggerRegisterPlayerEvent(PressR, Player(i), EVENT_PLAYER_ARROW_RIGHT_DOWN)
        
        call TriggerRegisterPlayerEvent(ReleaseU, Player(i), EVENT_PLAYER_ARROW_UP_UP)
        call TriggerRegisterPlayerEvent(ReleaseD, Player(i), EVENT_PLAYER_ARROW_DOWN_UP)
        call TriggerRegisterPlayerEvent(ReleaseL, Player(i), EVENT_PLAYER_ARROW_LEFT_UP)
        call TriggerRegisterPlayerEvent(ReleaseR, Player(i), EVENT_PLAYER_ARROW_RIGHT_UP)
        
        set Pad<i> = ARROWS.create()
        
        set i = i+1
        exitwhen i == bj_MAX_PLAYERS or i == Pad.size
    endloop
    call TriggerAddAction(PressU, function PressArrowU)
    call TriggerAddAction(PressD, function PressArrowD)
    call TriggerAddAction(PressL, function PressArrowL)
    call TriggerAddAction(PressR, function PressArrowR)
    
    call TriggerAddAction(ReleaseU, function ReleaseArrowU)
    call TriggerAddAction(ReleaseD, function ReleaseArrowD)
    call TriggerAddAction(ReleaseL, function ReleaseArrowL)
    call TriggerAddAction(ReleaseR, function ReleaseArrowR)
endfunction
endlibrary
</i>


This system is a time saver with an easy way to accomplish things involving keypresses

An extensive example of how you could use it:
JASS:

scope MoveHeroes initializer Init
globals
    private unit array heroes[3]
    private constant string SPECIAL_EFFECT = &quot;Abilities\\Spells\\Human\\Polymorph\\PolyMorphTarget.mdl&quot;
    private constant real MOVESPEED = 8
    private constant real TURNSPEED = 8
endglobals

private function MoveHero takes nothing returns boolean
    local integer i = 0
    local real a
    loop
        if heroes<i>!=null then
            set a = GetUnitFacing(heroes<i>)*bj_DEGTORAD
            //Up key
            if Pad<i>.U.Doublepress() then
                call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(heroes<i>), GetUnitY(heroes<i>)))
                call DisplayTextToPlayer(Player(i), 0, 0, &quot;SPRINTING!&quot;)
            endif
            if Pad<i>.U.Doubleheld() then
                call SetUnitPosition(heroes<i>, GetUnitX(heroes<i>)+Cos(a)*MOVESPEED*3, GetUnitY(heroes<i>)+Sin(a)*MOVESPEED*3)
            elseif Pad<i>.U.Held() then
                call SetUnitPosition(heroes<i>, GetUnitX(heroes<i>)+Cos(a)*MOVESPEED, GetUnitY(heroes<i>)+Sin(a)*MOVESPEED)
            endif
            //Down key
            if Pad<i>.D.Newpress() then
                call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(heroes<i>), GetUnitY(heroes<i>)))
            elseif Pad<i>.D.Held() then
                call SetUnitPosition(heroes<i>, GetUnitX(heroes<i>)-Cos(a)*MOVESPEED, GetUnitY(heroes<i>)-Sin(a)*MOVESPEED)
            elseif Pad<i>.D.Released() then
                call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(heroes<i>), GetUnitY(heroes<i>)))
            endif
            //Left key
            if Pad<i>.L.Doubleheld() then
                call SetUnitFacing(heroes<i>, GetUnitFacing(heroes<i>)+TURNSPEED*3)
            elseif Pad<i>.L.Held() then
                call SetUnitFacing(heroes<i>, GetUnitFacing(heroes<i>)+TURNSPEED)
            endif
            //Right key
            if Pad<i>.R.Doubleheld() then
                call SetUnitFacing(heroes<i>, GetUnitFacing(heroes<i>)-TURNSPEED*3)
            elseif Pad<i>.R.Held() then
                call SetUnitFacing(heroes<i>, GetUnitFacing(heroes<i>)-TURNSPEED)
            endif
            //instant spin
            if Pad<i>.L.Doublepress() or Pad<i>.R.Doublepress() then
                call DisplayTextToPlayer(Player(i), 0, 0, &quot;Superturnspeed!&quot;)
            endif
            //Camera
            if Player(i) == GetLocalPlayer() then
                call SetCameraTargetController(heroes<i>, 0, 0, true)
                call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, 1100, 0)
                call SetCameraField(CAMERA_FIELD_ZOFFSET, 100, 0)
                call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, 325, 0)
                call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(heroes<i>), 0.0625)
                call SetCameraField(CAMERA_FIELD_FIELD_OF_VIEW, 65, 0)
            endif
        endif
        call Pad<i>.Update()
        set i = i+1
        exitwhen i==heroes.size
    endloop
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 0.03125, true)
    call TriggerAddCondition(t, Condition(function MoveHero))
    
    set heroes[0] = gg_unit_Hpal_0001
    set heroes[1] = gg_unit_Hpal_0002
    set heroes[2] = gg_unit_Hpal_0003
    
    call PauseUnit(heroes[0], true)
    call PauseUnit(heroes[1], true)
    call PauseUnit(heroes[2], true)
endfunction
endscope
</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>


This example is included in the demo map :)

Have fun!
 

Attachments

  • EasyKeysv1.1.w3x
    34 KB · Views: 303
This system doesn't make any sense as far as I can see, except to see whether or not a player is holding down a key, which would tend to be done in periodic effects and hence this is total overkill. As for checking if a key was pressed or released, the natives do that and this doesn't really seem to simplify anything.
I think it is highly probable that you, yes you, will find this quite useless.
And on that note, I will graveyard this until it is apparently useful.
 
As long as people using the search function are able to find this I'm okay with whatever you do.

The extra thing this library does is that you can check for a newpress. Also I think it's easier to use than with the events:

this:
JASS:

scope MoveHeroesBad initializer Init
globals
    unit array heroes[12]
    integer array Up[12]
    integer array Down[12]
    integer array Left[12]
    integer array Right[12]
endglobals

private function MoveHeroNewpressUp takes nothing returns nothing
    local unit u = heroes[GetPlayerId(GetEventDetectingPlayer())]
    set Up[GetPlayerId(GetEventDetectingPlayer())] = 1
    if not(u == null) then
        call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(u), GetUnitY(u)))
    endif
endfunction
private function MoveHeroNewpressDown takes nothing returns nothing
    local unit u = heroes[GetPlayerId(GetEventDetectingPlayer())]
    set Down[GetPlayerId(GetEventDetectingPlayer())] = 1
    if not(u == null) then
        call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(u), GetUnitY(u)))
    endif
endfunction
private function MoveHeroNewpressLeft takes nothing returns nothing
    local unit u = heroes[GetPlayerId(GetEventDetectingPlayer())]
    set Left[GetPlayerId(GetEventDetectingPlayer())] = 1
    if not(u == null) then
        call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(u), GetUnitY(u)))
    endif
endfunction
private function MoveHeroNewpressRight takes nothing returns nothing
    local unit u = heroes[GetPlayerId(GetEventDetectingPlayer())]
    set Right[GetPlayerId(GetEventDetectingPlayer())] = 1
    if not(u == null) then
        call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(u), GetUnitY(u)))
    endif
endfunction


private function MoveHeroHeld takes nothing returns nothing
    //every...
    local integer i = 0
    loop
        if Up<i> == 1 and not(heroes<i> == null) then
            call SetUnitPosition(GetUnitX(heroes<i>), GetUnitY(heroes<i>)+12)
        endif
        //Down, Left and Right
        i = i+1
        exitwhen i==heroes.size
    endloop
endfunction

private function MoveHeroReleased takes nothing returns nothing
    set UP[GetPlayerId(GetEventDetectingPlayer())] = 0
    //do stuff
endfunction

private function Init takes nothing returns nothing
    local trigger upNewpress = CreateTrigger()
    local trigger upReleased = CreateTrigger()
    local trigger upHeld = CreateTrigger()
    // oh jesus...
    
    //blabla
endfunction
endscope
</i></i></i></i>


would become this:

JASS:

scope MoveHeroes initializer Init
globals
    unit array heroes[12]
endglobals

private function MoveHero takes nothing returns boolean
    local integer i = 0
    loop
        if not(heroes<i>==null) then
            if Pad<i>.U.Newpress() then
                call DestroyEffect(AddSpecialEffect(SPECIAL_EFFECT, GetUnitX(heroes<i>), GetUnitY(heroes<i>)))
            elseif Pad<i>.U.Held() then
                call SetUnitPosition(GetUnitX(heroes<i>), GetUnitY(heroes<i>)+12)
            elseif Pad<i>.U.Released() then
                //do stuff
            endif
        endif
        set i = i+1
        exitwhen i==heroes.size
    endloop
    Pad<i>.Update()
    return false
endfunction

private function Init takes nothing returns nothing
    local trigger t = CreateTrigger()
    call TriggerRegisterTimerEvent(t, 0.03, true)
    call TriggerAddCondition(t, Condition(function MoveHero))
    
    //init heroes
endfunction
endscope
</i></i></i></i></i></i></i></i></i>


Which is in my opinion a lot neater, don't you agree?
 
Read this.

We want Quality, not Quantity. Thus, submit only what you think is good! If your post contains something like "check out my crappy spell" it will hit graveyard right away.
:p
 
I think you misunderstood what I was trying to say. At first glance this might seem useless but it isn't. It works and it's easy to use. What more do you want?
 
I think J4L's point was simply that you shouldn't submit something and say it's useless. A better description, example and such would be nice.

Anyway, this does indeed seem quite useful, so I'll move it back to the T&R forum for comments and such. :)
 
JASS:
//pros: -  everything has been done for you
//      -  easy to use

//cons: -  slow (due to warcraft keypress event limitations)
//      -  you have to call an update function in order to make this system work which would become annoying to do properly if you have multiple triggers using this system at once


You should put Pro's before Cons.
 
I think J4L's point was simply that you shouldn't submit something and say it's useless. A better description, example and such would be nice.

Anyway, this does indeed seem quite useful, so I'll move it back to the T&R forum for comments and such. :)
Yeah that's true, but I though no matter how I would put it, this might seem useless to some people anyway. I'll just follow the forums rules next time..

There is a little example in the map itself, I suppose I should copy it to the main post. Thanx anyway


> You should put Pro's before Cons.

:p did that on purpose, changed it
 
JASS:
EasyKeys requires you to call an update function in order to make this system work which would become annoying to do properly if you have multiple triggers using this system at once

My point was really that without this being automated, this is just a wrapper for native functionality.

If you threw this up on T32, and maybe provided some Events for on double press... this might be a lot more helpful (you don't have to use the linked stuff, these are just suggestions).

It is poor encapsulation and design to use an update method which the user must call.
 
If this is updated, I may use it for a racing/boating game.
 
The Event system you've written can be very usefull. I think I'm thinking to much in a "game loop" way without events.

Your suggestions are really good. I'm going to rewrite it now ^^

Owkay......... Darn Event doesn't compile. I redownloaded Jassnewgenpack 5d but it says: "destroy, member redeclared".

I made a lot of changes (almost none->inefficient/ugly code) to make it work(I hope) but now Event doens't work. I think I have done something terribly stupid but I don't know what...
 

Attachments

  • EasyKeysv1.1.w3x
    40.1 KB · Views: 277
General chit-chat
Help Users
  • No one is chatting at the moment.
  • V-SNES V-SNES:
    Happy Friday!
    +1
  • The Helper The Helper:
    News portal has been retired. Main page of site goes to Headline News forum now
  • The Helper The Helper:
    I am working on getting access to the old news portal under a different URL for those that would rather use that for news before we get a different news view.
  • Ghan Ghan:
    Easily done
    +1
  • The Helper The Helper:
    https://www.thehelper.net/pages/news/ is a link to the old news portal - i will integrate it into the interface somewhere when i figure it out
  • Ghan Ghan:
    Need to try something
  • Ghan Ghan:
    Hopefully this won't cause problems.
  • Ghan Ghan:
    Hmm
  • Ghan Ghan:
    I have converted the Headline News forum to an Article type forum. It will now show the top 20 threads with more detail of each thread.
  • Ghan Ghan:
    See how we like that.
  • The Helper The Helper:
    I do not see a way to go past the 1st page of posts on the forum though
  • The Helper The Helper:
    It is OK though for the main page to open up on the forum in the view it was before. As long as the portal has its own URL so it can be viewed that way I do want to try it as a regular forum view for a while
  • Ghan Ghan:
    Yeah I'm not sure what the deal is with the pagination.
  • Ghan Ghan:
    It SHOULD be there so I think it might just be an artifact of having an older style.
  • Ghan Ghan:
    I switched it to a "Standard" article forum. This will show the thread list like normal, but the threads themselves will have the first post set up above the rest of the "comments"
  • The Helper The Helper:
    I don't really get that article forum but I think it is because I have never really seen it used on a multi post thread
  • Ghan Ghan:
    RpNation makes more use of it right now as an example: https://www.rpnation.com/news/
  • The Helper The Helper:
  • The Helper The Helper:
    What do you think Tom?
  • tom_mai78101 tom_mai78101:
    I will have to get used to this.
  • tom_mai78101 tom_mai78101:
    The latest news feed looks good

      The Helper Discord

      Members online

      No members online now.

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top