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: 298

Jesus4Lyf

Good Idea™
Reaction score
397
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.
 

Prozix

New Member
Reaction score
7
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?
 

Romek

Super Moderator
Reaction score
963
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
 

Prozix

New Member
Reaction score
7
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?
 

Romek

Super Moderator
Reaction score
963
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. :)
 

tooltiperror

Super Moderator
Reaction score
231
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.
 

Prozix

New Member
Reaction score
7
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
 

Jesus4Lyf

Good Idea™
Reaction score
397
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.
 

tooltiperror

Super Moderator
Reaction score
231
If this is updated, I may use it for a racing/boating game.
 

Prozix

New Member
Reaction score
7
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: 272
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Staff online

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top