Hit Key - Run Script

Started by MMMorshew, Sun 03/04/2011 17:31:27

Previous topic - Next topic

MMMorshew

This question may be very easy to answer for some here, but I never bothered with scripts like these until now.  :(
Basically, I only want to achieve that a script gets triggered as soon as the player hits a certain key on his keyboard. The script should also stop if the same key is being hit again. Would be very awesome if someone here could show what the script should look like to work.

Joe

#1
Let's imagine that the trigger key is 'P'

So in global script you'll find a function called ok_key_press(eKeyCode keycode)
there you must type something like this:
Code: ags

function on_key_press(eKeyCode keycode) {
  if (keycode == eKeyP){
    //Your script
  }
}


EDIT: if you want to stop your script you'll need to create a variable which determinates if you code is running or not, for example:
Code: ags

//At top of global script
bool running=false;
//At on_key_press
function on_key_press(eKeyCode keycode) {
  if (keycode == eKeyP){
    if(!running){
      //Code to start your script
      running =true;
    }
    else if(running){
      //Code to stop your script
      running=false;
    }
  }
}
Copinstar © Oficial Site

Sephiroth

#2
Hello,

It really depends on what kind of code is executed when the key is pressed, you cant really stop a function once it is launched unless you have Thread/Fork support in the scripting language, or if the triggered code consists of a while loop.

You may use the repeatedly_execute_always, since it is actually threaded, if I remember well.


monkey0506

Sephiroth, I'm not sure what you mean by saying that a function can't be stopped once it's called. When you call a function in AGS, its code is executed exactly once. It will stop itself once the end of the function is reached (until the next time the function is called).

Within the function itself you can stop the execution at any time by simply returning from the function.

Sephiroth

#4
Sorry if I wasn't clear, what I mean is for example you call a function within on_key_press, the function code is executed, but can't be stopped with another trigger of the key, because the function is already executing.

Yes you can use "return" anytime within the function but can you make it return from outside? You'd probably need to add a bunch of "if(is_cancelled) return;".

One common way to work arround this problem is to launch the function in a separate thread, which isn't possible in AGS I think, or I missed the new feature.

Also, it would really be useful if you could post the code you want to be executed on keypress, or an explaination.

Monsieur OUXX

Quote from: Sephiroth on Mon 04/04/2011 09:41:06
Sorry if I wasn't clear, what I mean is for example you call a function within on_key_press, the function code is executed

+1 with Sephiroth's comment. Joe's edit is virtually unnecessary since :
- the script will be executed when P is pressed
- it will be executed only once, and until the end
- it doesn't give the opportunity to the user to press P again in the meantime (or at least it's not tested by the custom script). Therefor the script cannot be run again until the next game loop
- In conclusion: You don't need to test if the game is running
 

Sephiroth

#6
This is where I think repeatedly_execute_always may be used to check for keypress while other (blocking) code is still executing, but it would be ugly.

Edit: Deleted the code, it's useless until we see MMMorshew answer with some more details.

Joe

Quote from: Ouxxey_games on Mon 04/04/2011 11:02:24
Quote from: Sephiroth on Mon 04/04/2011 09:41:06
Sorry if I wasn't clear, what I mean is for example you call a function within on_key_press, the function code is executed

+1 with Sephiroth's comment. Joe's edit is virtually unnecessary since :
- the script will be executed when P is pressed
- it will be executed only once, and until the end
- it doesn't give the opportunity to the user to press P again in the meantime (or at least it's not tested by the custom script). Therefor the script cannot be run again until the next game loop
- In conclusion: You don't need to test if the game is running


Yes but if the code he is running is a non-blocking function? like player.Walk(....,eNoBlock,...); or something similar?
Copinstar © Oficial Site

Sephiroth

#8
I suppose basic cutscene could be achieved with player.saybackground(), player.walk(noblock), aMusic.play(), and then stopped without a problem since it's non-blocking code, yes.

As I said in the first post, (I'm sorry for my English), it really depends on what kind of code is executed but you're totally right about that Joe.

Edit: Also Happy Birthday Monkey!

Monsieur OUXX

Ah OK, I overlooked the case of non-blocking functions.
Those script languages are very confusing, you never know if you should think "multithreaded" or not :-) (I have the same issues with AutoIt)
 

Sephiroth

#10
But then again, if you're using these non blocking functions, you will need a few "Wait()" to synchronize things. This will result in blocking code.

So basically, it will only work if you just need to play a music for example...

tzachs

The fact that you want to be able to stop the script, is what makes this complicated, so be sure first that you really need this functionality.
Now, let's assume that you have to do this.
In order for you to be able to stop the script you want to run, you have to re-organize that script so it will run in small portions at a time, instead of doing it all at once.

For example, let's say your script is to wait five seconds.
You can change that script to wait 1 second and then run it five times (or change it to wait for 10 milliseconds and run it 500 times which will give you a more responsive stop action), once on each new game loop.
On each time you run the "Wait 1 second", first check that the script really should be running (the 'running' variable introduced by Joe earlier). If the script should not be running, then don't do the "Wait" and return.

That was a really simple example, it can get a lot more complicated, depending on what is that you want to do exactly. If you'd want to do a Walk command, you'll have to split it into several small walk segments, etc etc.

Sephiroth

#12
Quote
The fact that you want to be able to stop the script, is what makes this complicated

One more thing that makes it a bit complicated is the fact you are using the same key to start/stop the event.

Anyway, it should work if the triggered code is a "while" loop but only like this:

Code: ags


//global var
bool cancelled = false;
bool running = false;

function repeatedly_execute() //on_key_press works as well
{

 if(IsKeyPressed(eKeyG))
 {
   int j=0;
   cancelled = false;
   while(j<20 && cancelled == false)
   {
     
     //fire a bullet for example
     j++; 
     Wait(10);
     running = true;
   }
   running = false;
   cancelled = false;
   Wait(10);
 }

}


function repeatedly_execute_always()
{

 if( IsKeyPressed(eKeyG) && running == true && cancelled == false)
 {
  cancelled = true;
  running = false;
 }

}


(edited the syntax) Hope that helps a little.

Monsieur OUXX

Sephiroth pretty much said it all.

============

Just to conclude gracefully  :D :  The technical term for this is "cooperative multitasking" (as opposed to preemptive multitasking)
http://organizedhost.com/web-hosting/preemptive-multitasking-vs-co-operative-multitasking/

- Preemptive multitasking is what non-blocking functions do : The engine is managing the multithreading and letting you do other stuff in the meantime, without letting you interfere with the non-blocking functions execution.

- Instead, here, you find yourself forced to re-create some sort of cooperative multitasking -- that is, you must focus on managing when your bits of code will give back control to the general script, between each bit of critical processing.

I know it's a bit off-topic but I find these issues fascinating.
 

MMMorshew

#14
Wow, thanks so much for all those comments and ideas!  :o
You guys are helpful as hell!

I now see that the main problem is that the script should be stoppable at every time. But luckily, my script is extremely simple. Let me explain it here with this colorful kitschy background:


(This background is anything but pretty of course, it was just a quick test for the 2D-Style and I still have to tweak many things concerning the colors and the contrast between background and foreground. But it gets the point across)

Most of the background I want to use have a sidescroller-like perspective (mainly because its a lot faster and more fun to draw, also you don`t have to worry too much about perspective), but there is one problem - the walkable areas are pretty thin and placed along to topside of the "ground" silouette at the bottom. Clicking along the ground with the Walk cursor and hoping that you hit the walkable area to make the hero move is not very fun, so I thought about using the arrow keys to move left or right. This problem is not really present on this screen, but it will appear an screens where I have walkable "platforms" above each other and thus longer walkable areas that go across the screen (it also seems very unpolished and uneccesary to have a walk cursor in this optical style). AGS already has a built-in keyboard control, but it doesn`t follow the walkable area.

So I thought about a script that reacts when you hit the left or right arrow key.
Left = Character walks to Point A! Right = Character walks to point B!
The script would only consist of a single line like MoveCharacter which doesn`t stop the gameplay in any way. However, it would be cool if that command could be stopped by pressing the key again to trigger another script that makes the character stop walking.

Sephiroth

#15
Hehe, should be way easier than we all thought :p

Something like this would work?

Code: ags

function on_mouse_click(MouseButton button) 
{

 if (button == eMouseLeft) 
 {
   player.StopMoving();
   player.Walk(mouse.x, mouse.y, eNoBlock, eWalkableAreas);
  }

}


Either click or arrow, this code should follow the walkable area regardless of where you click on screen.

Keyboard alternative (replace point A and B coords, only X is used, Y can be anything):

Code: ags

function on_key_press(eKeyCode keycode) 
{
  if(keycode == eKeyLeftArrow)
  {
   if(player.Moving)
    player.StopMoving();
   else
    player.Walk(PointB.x, PointB.y, eNoBlock, eWalkableAreas); 
   Wait(10);
  }
  if(keycode == eKeyRightArrow)
  {
   if(player.Moving)
    player.StopMoving();
   else
    player.Walk(PointA.x, PointA.y, eNoBlock, eWalkableAreas); 
    Wait(10);
  }
}


This should produce the effect of Tapping_Mode but following the walkable area, it is up to you to make a smooth walkable area to avoid strange movements of the sprite.
Edit: had to tweak the code.

SMF spam blocked by CleanTalk