[MODULE] Alternative KeyboardMovement v0.3 (Running, Mapping)

Started by Khris, Thu 10/02/2011 20:51:43

Previous topic - Next topic

Khris

Spent a few hours today whipping this up; I tried to test it thoroughly but as you know, some bugs always seep through the cracks. I'd welcome some extensive testing :D

This module is a replacement for the one included in the default game. Be sure to remove the old one if you try this!
I wrote it from scratch but it's set up so the game_start line will still work. You might still want to change that though, the module was primarily written to be used in RPGs together with JoyToKey so ideally it should be set to pressing mode.

Note that the module completely relies on moving and animating the character manually; this allows changing the player's view and speed during movement. The module detects walkable areas pixel-perfectly, so no need to draw them 3 pixels wide any longer.

I've tried to integrate it as far as possible, the module uses several character settings (AdjustSpeedWithScaling, AnimationDelay, DiagonalLoops, MovementSpeedX, MovementSpeedY)

Update: v0.3 - added support for frame sounds (like footsteps)


General control commands:

   KeyboardMovement.SetMode(eKMMode Mode);
Mode is either eKMModePressing or eKeyboardMovement_Tapping (to maintain compatibility with Default Game Global.asc)

   int KeyboardMovement.GetMode()
Returns the current control mode.

   KeyboardMovement.Enable();
   KeyboardMovement.Disable();
Enables/disables the module functionality altogether.

   bool KeyboardMovement.IsEnabled();
Returns whether the module is enabled.
   KeyboardMovement.StopMoving();
In tapping mode, stops the character moving and changes to standing frame. If not in tapping mode, does nothing.


Key binding commands

   KeyboardMovement.SetKey(eKMKey key, eKeyCode k);
Assigns ASCII code k to movement key key.
Example:  KeyboardMovement.SetKey(eKMKeyLeft, eKeyLeftArrow);

   KeyboardMovement.SetRunKey(eKeyCode k);
Assigns ASCII code k to run key.
Example:  KeyboardMovement.SetRunKey(eKMModKeyLeftShift);

   int KeyboardMovement.GetKey(eKMKey key);
Returns ASCII code assigned to movement key key.

   KeyboardMovement.SetMovementKeys(eKMMovementKeys mk);
Assigns scheme mk to movement keys.
The default value is eKMMovementWASD.
Example:  KeyboardMovement.SetMovementKeys(eKMMovementArrowKeys);


Settings commands

   KeyboardMovement.SetRunSpeed(int RunSpeed);
Sets running animation delay to RunSpeed. The default value is 2. Like Character.AnimationSpeed, lower values mean faster movement.

   int KeyboardMovement.GetRunSpeed();
Returns the currently set animation delay of the player's running animation.

   KeyboardMovement.SetLoopDomination(eKMLoopDomination LoopDomination);
Changes which loop the player uses when moving diagonally when there are no diagonal loops.
LoopDomination is either eKMLoopDHorizontal, eKMLoopDVertical or eKMLoopDLast, the default value.

   KeyboardMovement.SetRunView(int RunView, int RunSpeedX, int RunSpeedY);
Allows using a second view for the run-cycle. RunSpeedX and RunSpeedY specify the movement of the character per frame i.e. are determined by the pixels of the run-cycle sprites. In theory it is possible to use the player's NormalView here, however, running by playing the walk animation faster is already implemented by default and increasing the movement values is not recommended because it leads to gliding.

   int KeyboardMovement.GetRunView();
Read back the currently set RunView. If none was set, this returns 0, an invalid view number!

   KeyboardMovement.SetDiagonalFactor(float DiagonalFactor);
Use this to slow down diagonal movement. The default value is 0.707. A value of 1.0 will add horizontal and vertical movement without correction.

   KeyboardMovement.SetEdgeAnimation(bool AnimateAtEdge);
Call this with true as parameter, and the character will continue to animate after having stopped at the edge of the walkable area. It is off by default.

   KeyboardMovement.SetBlockedTurn(bool TurnIfBlocked);
Call this with false as parameter, and the character will no longer face a direction they cannot walk in. It is on by default.

Edit:
Lewis has brought to my attention that the module doesn't work with IdleViews. I fixed the code and added this command:
   KeyboardMovement.SetIdleView(int view, int delay);
Call this instead of player.SetIdleView().


Status functions

   bool KeyboardMovement.Animating();
   bool KeyboardMovement.Moving();
Returns whether the player is currently animating/moving. Use this instead of player.Animating/player.Moving since they won't work with module movement. If edge animations are on, the character might animate but not move!



Phew. After you have imported the module, make sure it is above Global.asc/h. By default, the character will move with WASD and run when you hold down the left shift key.

   DOWNLOAD

hedgefield

This sounds really cool! I like the fact that you can now change speed and view whíle you're walking, that's good. I just tried it with my game though and the character walks way slower with the keys than he does by point-and-click.

I've set AnimationDelay to 1, MovementLinkedToAnimation to false, MovementSpeedX to 5 and MovementSpeedY to 3. Is there anywhere in your script I can maybe apply a speed modifier or something?

Khris

If you set MovementLinkedToAnimation to false, mouse walking will be much faster, yes.

Currently, my module only simulates walking with MovementLinkedToAnimation set to true i.e. the character moves MovementSpeed pixels every AnimationSpeed frames, not every frame.

I guess I could implement that setting, let me check that.
(checked it)
Actually, I'm not handling movement and animation separately, it's going to take some time to fix that.

hedgefield

Yes I assumed that would be where the issue stemmed from. The thing is that with the old keyboardmovement module there was no speed difference, but ofcourse that one uses the built-in walk handling. I turned off the MovementLinkedToAnimation because the walkcycle has a lot of frames and it looks choppy otherwise.

But couldn't I add a +5 to the walkspeed variable in your script somewhere? I looked around a bit but I couldn't discern exactly where you set/adjust those values. It's not that big of a deal though, I don't really need running for this game, so I could get by fine with the old module.

Khris

The module uses the player character's MovementSpeed setting, just change the value in the editor and you should be set.

Daniel Eakins

This module is pretty good but the main issue (with Bernie's 8 Direction Movement module too) is that it does not do collision detection for characters, unlike the default KeyboardMovement script.
We all have our time machines, don't we?

Khris

You're right, and this is pretty much a bug in AGS.
Solid characters cut a rectangle out of walkable areas but this seems to not have any effect on GetWalkableAreaAt, it'll still return the drawn area, ignoring the hole.

It's possible to check for this manually though; as soon as I find the time I'll update the module.

Vincent

I Love This Module so much !  It Is Pretty Much Perfect ! Thank You Khris For Exist :)

May I should move this topic to beginning area...
I'm Having Hard Times to set the  KeyboardMovement.SetIdleView(int view, int delay);
When I do that, my Player set the idleview for an instant, then, he start to Loop the Idle view...

I'm trying to figure out the latest sentence

Code: ags

void repeatedly_execute() {

  if (Enabled) HandleMovement();

  if (IdleView == 0) IdleView = player.IdleView;
  if (KeyboardMovement.Animating() && !was_animating) player.SetIdleView(-1, 0);
  if (!KeyboardMovement.Animating() && was_animating) player.SetIdleView(IdleView, IdleDelay);
  was_animating = KeyboardMovement.Animating();

} 


Khris

Could you post the line you're actually using to set the idle view?
Note that delay is supposed to be game frames, not seconds. A value of 40 means that the idle view will start after one second.

Vincent

Firstly, Thanks So Much Khris For Your Respond, Very Appreciated !!! :-D

I'm Not So Sure Where I Should Put The KeyboardMovement.SetIdleView(int view, int delay) line...
I Put It In The game_start section firstly...

Code: ags


#sectionstart game_start  // DO NOT EDIT OR REMOVE THIS LINE
function game_start() {
KeyboardMovement.SetMovementKeys(eKMMovementArrowKeys);
Game.SpeechFont=eFontFont3;
player.SetWalkSpeed(5, 5);
cCkid.SetWalkSpeed(7, 7);
SetBackgroundFrame(0);
srSetSnowAmount(700);
srSetWindSpeed(9);
cCkid.FaceLocation(1, 192);
cCkid.ManualScaling=true;
cCkid.Scaling=107;
cCkid.Transparency=100;
BtnarmorEquip.Visible=false;
eShadow.Disable(player);
SmoothScroll_ScrollingOn();
SmoothScroll_PxOn();
KeyboardMovement.SetIdleView(7, 0);
}
#sectionend game_start  // DO NOT EDIT OR REMOVE THIS LINE


Then, I Move It In The Section repeatedly_execute()
or in the repeatedly_execute_always()
But
He Still Loop The Idle View... 
(Maybe Cause My idleview delay was to 0 ) ?!
When I Put The IdleView Delay To 40... well... nothing will happen ! =(

The Trouble is not when it start the idle view...
But it's that he loop the idle view very very much...
Maybe there is a contrast with The void HandleMovement() ?
I Tried To Hide //HandleMovement() and it work good...
But then the character don't use anymore the walkview...
Just like he Move (as example player.move)

Vincent

Well, I'm also using a gravity jump module that it work nice
Maybe cause contrast with it

Code: ags


// Original module 'Platform Movement v0.01a' Author: Bernie 

// Overhauled By VinVin




//===================================================================
//This extension is actually more like an experiment 
//and only allows customized controls through direct module code editing. 
//It demonstrates a simple way of coding a platform gravity jump.
//A quick explanation of the module's values:
//if gravity is lower than 0, it makes the character go up. The lower, the faster. 
//If it's greater, the character moves down, the greater, the faster.
//xmove behaves the same way, only on the x axis. 
//below zero is left, above zero is right.
//===================================================================







void repeatedly_execute() {
  
  
int a;
while ((gravity>0)&&(a < gravity)){ if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==0) {player.y=player.y +1;} 
//1 down if no walkable area found
a=a+1;
}

int b;
while ((gravity<0)&&(b > gravity)){ if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==0) {player.y=player.y -1;} 
//1 up if no walkable area found above
b=b-1;
}




//===================================================================
//managing movement values and gravity--
//===================================================================
if (gravity < 6) {gravity=gravity+1;}
if ((IsKeyPressed(377)==1)&&(xmove<1)) {xmove=xmove+1;}//right
if ((IsKeyPressed(375)==1)&&(xmove>-1)) {xmove=xmove-1;}//left
if ((IsKeyPressed(375)==0)&&(IsKeyPressed(377)==0)&&(xmove<1)) {xmove=xmove+1;}//right
if ((IsKeyPressed(375)==0)&&(IsKeyPressed(377)==0)&&(xmove>-1)) {xmove=xmove-1;}//left
if (((IsKeyPressed(375)==0 && IsKeyPressed(380)==0 && IsKeyPressed(377)==0 && xmove>0 ))) {xmove=xmove-1;}
if (((IsKeyPressed(375)==0 && IsKeyPressed(380)==0 && IsKeyPressed(377)==0 && xmove<0 ))) {xmove=xmove+1;}

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






//===================================================================
//diagonal stuff--
//===================================================================
if ((IsKeyPressed(372)==1) || IsKeyPressed(32)==1){ 
if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())>0) {player.y=player.y-1;}
player.y=player.y+2;
//===================================================================






//===================================================================
//jump----------------------------------
//===================================================================
if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==1) {gravity=-20;}  // jump
player.y=player.y-2;
}
//===================================================================


if ((player.View==13 && (IsKeyPressed(372)==1))){
player.ManualScaling=true;
player.Scaling=150;
player.LockView(5);
}
if (IsKeyPressed(372) && IsKeyPressed(eKeyDownArrow)){
  player.PlaceOnWalkableArea();
}



//===================================================================
//left and right 
//uses the same logic as moving up and down 
//but has additional checks so uneven terrain won't cause problems
//right---------------------------------
//===================================================================
int d;

while ((xmove>0)&&(d < xmove)){

player.x=player.x+1;
if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==0) {player.x=player.x+1;}
player.x=player.x-1;

player.x=player.x+1;
//int check=0;


if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())>0) {check_gravity=1;}
player.y=player.y+1;
if ((GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==0)&&(check_gravity==1)) {player.y=player.y+1;}
player.y=player.y-1;
   

 d=d+1;
}




//===================================================================
//left---------------------------------
//===================================================================
int c;
while ((xmove<0)&&(c > xmove)){



player.x=player.x+1;
if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==0) {player.x=player.x-1;}
player.x=player.x-1;

player.x=player.x-1;
//int check=0;


if (GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())>0) {check_gravity=1;}
player.y=player.y+1;
if ((GetWalkableAreaAt(player.x-GetViewportX(),player.y-GetViewportY())==0)&&(check_gravity==1)) {player.y=player.y-1;}
player.y=player.y-1;

 
 c=c-1;
  }

}


Khris

I'm surprised that the two modules work together at all... :-\

As for the idle view, afaik AGS continually plays it as soon as the delay ends. If you want the character to play an idle animation once, then stop for several seconds, then play it again, you have to use another way.
My module uses the built-in idle view functionality.

As for HandleMovement(); that's pretty much the entire module. If you comment that out, you might as well not use it.

Vincent

well yeah... if i hide the HandleMovement();
it's just like the module is beign cutted off
and not any purpose then
with some trick //
i can join both together very nice..
as example
in room 1 i can trigger a gravity jump
and walking/running the player in diagonal
also while walking in a new high platform.
(with Alt Keyboard Movement is simply Amazing)
(not that's the same from the standard module KeyboardMovement using with the gravity jump)
#region then, are usefull for setting limits to the player
player.IsStandingOnRegion(1) { player.PlaceOnWalkableArea();}
and will not fall to underground
It's actually good stuff together


the description you did it's exactly what i wish for
probably i should give a global timer that animate the idle view taking out from modules
something like
in GlobalScript.ash
#define TIMER_IDLE_VIEW  1
in GlobalScript.asc
function IDLE_VIEW() {
if (!KeyboardMovement.Animating() && was_animating) { SetTimer(TIMER_IDLE_VIEW, 160); }

if (IsTimerExpired(TIMER_IDLE_VIEW))
{
// animate the idle view avoid Alt KeyboardMovement Loops ,
// if keyboard is animating then, normal view/walking
// How Khris could you do something alike to do the trick ?
// i wish you could help me with this
}


slavec

I have the same Idleview problem.
When I use "KeyboardMovement.SetIdleView(4, 0);"  in global's game_start(or repeatedly_execute), the character only plays the first two frames of the idle, then loops that over and over again.
The same if I write (4,40). It waits 40 frames, and then show first 2 idleframes and loops quickly.
I have tried with a new clean AGS project also, but the same will happen.
Otherwise the module is great!

Khris

I found the problem and updated the module. Just redownload it.
What happened was the player's frame got reset to 0 constantly whenever the module detected that the character had stopped moving.

Note that the delay parameter is supposed to be seconds, not loops!

slavec


Vincent

OH, Khris you did it !
I just saw this fixing right now ! Thank you very much !

Vincent

I am sorry to review this *old post again.
But I think I had found another small issue.
I can actually keep walking in any direction in diagonal as well.
But when we are running, we can't actually move to the DOWN-RIGHT side (roll)
Can you confirm this kind of issue in your free time ?

Thank you in advance 

[EDITED]
My mistake only, it's everything work perfectly.

eri0o

Is this the most update version of this module?

I've been thinking a lot about it since with joystick plugin this module essentially enables walking around in non point and click games. It just doesn't solve slopes well.

morganw

When you say "solve slopes", do you mean applying drag when moving up-hill, and moving faster down-hill?

SMF spam blocked by CleanTalk