May 22, 2012, 05:25:44 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: Please report any bugs or issues that you might be encountering with the Beta in the Support System so that we can better keep track of any oustanding issues that may come up.

GameCore Support System
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: Pressing a key  (Read 1927 times)
Tiles
Full Member
***
Posts: 135



View Profile WWW
« on: September 29, 2008, 07:28:10 AM »

I try to figure out a simple key pressing.

I have grabbed the Hello World example from Jim?s Examplepage at http://ridereport.net/bv/scripting-tutorial-hello-world

What i did was to insert an if statement. But all i get is errors. Seems i miss an important bit. Could you please tell me which one/s? ^^

Code:
void main()
{
print ("how to press a key");
if (key == "Key1")
{
print ("key is pressed");
}
}

And the error messages i get:



Confuses me a bit. I never needed to declare keymappings in 3DGS. Do i need to do so in Gamecore?
Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
LutinMalefique
Full Member
***
Posts: 146



View Profile WWW
« Reply #1 on: September 29, 2008, 09:21:17 AM »

I will try to help you, but i'm a noob in scripting:

- first you need to declare keymapping in "input.cfg".

- in your script, the input test  should be in "bool HandleEvent". Take a look in the default character script
Quote
bool HandleEvent( Object@ object, const String& in event, GameEventParams@ params)
{
   if (params.player == null || !params.player.InInventory(object))
   {
      return false;
   }

   if (event == "Input")
   {
      // Capture keyboards events   
      if (params.stringValue == "Forward")
      {
         
         forwardPressed = params.floatValue;
         return true;
      }   
         }   
}
- and then you declare what the pressed key do in "void DynamicsAdvance(Object@ object, float seconds)"
Quote
void DynamicsAdvance(Object@ object, float seconds)
{
   Vector piratePos = object.GetPosition();
   if (forwardPressed > 0 && params.floatValue > 0.5)
   {
      
      piratePos.z = piratePos.z + 1;
      object.SetPosition (piratePos);
         }
}

I hope that it is going to help you.
Logged

http://lutinmalefique.wordpress.com/
"Just remember: a damn game can be played, and if you have not created something that can be played, it's not a damn game!" Derek Yu
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #2 on: September 29, 2008, 12:37:14 PM »

Ouch. Looks complicated as hell for a simple thing like pressing a key. And i thought Angelscript is easy  Cheesy

Many thanks LutinMalefique, I will try to figure that one out Smiley

Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #3 on: September 29, 2008, 12:56:21 PM »

Okay. Key1 is already declared in the input.cfg. Is premapped for the Weapon1

Hmm and here the trouble starts. I don't have any object. And so no object to point to. Just a script. And a simple task: print ("key is pressed"); . I also dont want to deal with miliseconds. Just to print the message when the key is pressed once. Something very simple, normally.
Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #4 on: September 29, 2008, 01:33:37 PM »

I have it working. My first working piece of script  Grin

I have grabbed and modified the pausing snippet from the menu scripting section.

Quote
bool HandleKeyPress( const String& in key)
{
if (key == "KeyA")
{
print ("key is pressed");
return true;
}
return false;
}

void main()
{
   print ("how to press a key, please press key A");
}

On with some further experiments. For example finding out now what the return true and false is good for Smiley
« Last Edit: September 29, 2008, 01:38:12 PM by Tiles » Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
Squat
Hero Member
*****
Posts: 592


View Profile
« Reply #5 on: September 29, 2008, 02:25:39 PM »

I'm not entirely certain about this, but I think that as soon as "return" is read, it pops out of the entire function and returns that value which basically states if the function was valid or not. Try this and read the error, (it's why I think this)

Quote
bool HandleEvent( Object@ object, const String& in event, GameEventParams@ params)
{
   if (event == "Input")
   {
        return true;
        print("Reachable?");
   }
}

The error is "unreachable code" and the reason is because it reads "return" first and kicks out of the function, so the print line will never get read under any circumstances. You'll also get "not all paths return a value" because what happens if "Input" isn't fullfilled? It'll pass over that code and again not return a value. The HandleEvent function must terminate in returning a value along any branch of your code.

The following code fixes the errors and prints "Reachable?" while you're standing in an input area:

Quote
bool HandleEvent( Object@ object, const String& in event, GameEventParams@ params)
{
   if (event == "Input")
   {   
    print("Reachable?");
    return true;
   }
return false;
}

Somebody may be able to better explain this, but I think it's the gamemanager that is requiring the value to be returned. I think it has something to do with the "Object@ object, const String& in event, GameEventParams@ params" part, which I don't quite get yet.

I don't honestly know why we have to return values on the HandleEvent function or what part of the engine requires them. My guess is that once you hit an input, the game opens itself up for interpretation and perhaps is in a floating state of wonder during that tick or something? Maybe it gets emotional when there's no closure. I dunno.

How, or if, you'll need to use them when creating your own custom functions is still a bit beyond me too.
« Last Edit: September 29, 2008, 02:41:09 PM by Squat » Logged
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #6 on: September 30, 2008, 03:15:20 AM »

Thanks for the explanation Squat Smiley

Quote
I don't honestly know why we have to return values on the HandleEvent function or what part of the engine requires them.

Yeah, that's what i wondered too. On the other hand, we don't need to put a function call in the void main. So that may be the substitute Smiley
Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
gekido
Guest
« Reply #7 on: September 30, 2008, 03:37:35 AM »

The reason you need to return values from HandleEvent() is to tell the engine that you have processed the key event.

You should NOT be implementing anything using the default HandleKeyPress() style system that the 'pause menu' uses in the menu.gsl script.  A number of people have suggested implementing game-input doing this on the forums, but it is a bad idea and not recommended at all.  The HandleKeyPress() system is for system-wide override's (for like the pause menu etc) but not for gameplay code input handling.

The way that event handling / keypresses works works is basically like this:

1) you define Actions in the input.cfg file.  Actions are essentially what the keypress is supposed to do - things like 'MoveForward', 'Crouch', 'Jump' - basically the 'end result' of what the keypress should be interpreted as.

2) you assign KeyMappings to the actions (again, in the input.cfg file).  Actions can have multiple KeyMap assignments, so you can define MoveForward as both the 'Up Arrow' and the 'W' key for example.

3) you create a player for your game.  Any object in a player's inventory that has a controller script associated with it receives input events, which can either be processed by the object's controller or ignored.

In the HandleEvent() function, there are multiple types of events that get sent.  

Input is one of them (triggers are the other big one - ie EnterProximity / ExitProximity events)

So a simple version of the HandleEvent function, is like so:

Code:
bool HandleEvent( Object@ object, const String& in event, GameEventParams@ params)
{
   if (event == "Input")
   {
      Print(params.stringValue);
      // we handled the event, so return true to let the engine know
      return true;
   }
   // didn't handle the event, return false so other scripts can see if they want to
   return false;
}

If you add that statement:

Print( params.stringValue);

to the top of your HandleEvent function (inside the event == "Input' section), you will see output of all the events that are received by the controller.

Note that the above script snippet basically tells you all of the actions that you have defined in the input.cfg file, but not what they are set to.  That's what the params.floatValue variable is for:


Code:
bool HandleEvent( Object@ object, const String& in event, GameEventParams@ params)
{
   if (event == "Input")
   {
      Print( "Input Action: " + params.stringValue + " value set to: " + params.floatValue);
      // we handled the event, so return true to let the engine know
      return true;
   }
   // didn't handle the event, return false so other scripts can see if they want to
   return false;
}

In this chunk of script, you will see that your script is receiving all of the actions, and that they are all set to 0.0 by default.  If you start pressing keys (that are mapped to the actions), you will see that the states change as keys are pressed.

Basically every action you have defined is sent to the controller script, in whatever state that it is - so if you have an action defined called 'Crouch', the controller script receives that action every time the HandleEvent() function is called - if it's not being pressed, it will be set to 0, if it IS being pressed, it will be greater than 0.  

Input events are floats, which allows for analog input devices (gamepads / joysticks), where a button can be 'sort of' pressed ;}

Now that we can see all of the actions that a controller is receiving, then it becomes obvious that we need to start narrowing them down and actually 'catching' some of the events ourselves.

For example, if we have an Action called 'Forward' defined, we add a small section of script to 'catch' that event and process it, like so:

Code:
bool HandleEvent( Object@ object, const String& in event, GameEventParams@ params)
{
   if (event == "Input")
   {
       if (params.stringValue == "Forward")
       {
          // set a variable that remembers what forward was set to
          forwardPressed = params.floatValue;
          // return true to tell the engine that we handled this event
          return true;
       }
  }
  // ignore all of the other events, so let other scripts handle them if they want
  return false;
}

Basically using this kind of system, each controller can 'trap' events that they want to handle, and if they ignore them, then the events get sent to the other objects in the player's inventory (or other players) to let them handle the events if desired.

So using the default FPS Template as an example, there are 3 levels of controller that are active usually:

1) the player itself
2) the player object
3) inventory items in the player's inventory (ie weapons etc)

If you look at the weapon script, you'll see that the weapon actually handles the firing of the gun, not the player.  This way you can have any number of objects in a player's inventory, and they can each handle their own input events and in essence be very 'self-contained' in how they behave in the game.
Logged
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #8 on: September 30, 2008, 04:15:30 AM »

I see. Many thanks for the explanation Smiley

Okay. I will try to not use key pressings that way ingame, besides global needs like a pause menu of course. This simple example has teached me lots of the scripting basics though. Something i wasn't able to do with the a bit much much more complicated way you have to use ingame. As told, i don't have an object here  Smiley
« Last Edit: September 30, 2008, 04:49:01 AM by Tiles » Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #9 on: September 30, 2008, 06:59:50 AM »

Hmm, the more i think about it, the more i ask myself, why does it have to be this complicated? I read and read and try and try. But cannot figure it out to even load a level so that i can go on with the told advice. Where's the sense to make it so cumbersome?
« Last Edit: September 30, 2008, 07:01:44 AM by Tiles » Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
Squat
Hero Member
*****
Posts: 592


View Profile
« Reply #10 on: September 30, 2008, 06:03:56 PM »

Tiles you're gonna have to take our word for it, it's not that complicated nor cumbersome. It's just that you're not that familiar with it yet so it's seemingly all over the place. I felt pretty much exactly the same way and there's still many parts to all of this that get me flustered, frustrated and angry. All the time. I'm simply not that experienced. The more I learn, the more I realize there's perfectly reasonable...er, reasons for these things to be the way they are. They allow for much more freedom when being utilized. Before you realize why something may be, it's quite natural to get frustrated at it and question why the hell it has to be the way it is.

If you read some of my earlier posts, you can clearly detect me getting flabberghasted with things like passing variables. You'll see me go into a state of elation as it all comes clear and I get to move forward. Undoubtedly, unless you outright give up, you'll go through exactly the same set of stages. You'll run into brickwalls, figure out tools to knock them down and then charge in with your head down for the next one.
Logged
zknack
Full Member
***
Posts: 207


View Profile
« Reply #11 on: September 30, 2008, 08:57:48 PM »

*chuckles* Tiles don't feel bad man- if you're the same Tiles I'm thinking of, you have scripting in your bones  Wink
which is why I was frustrated a lil with you before.

Once you get the hang of it it'll be fast and you'll wonder why other engines don't do the same (but it is sometimes
mind numbingly annoying), but the upside is this:

*You're only coding a condition or behaviour once. Just once to get it working- then it's cloning the bejebus out of it.
    *That means wayyyy easier for so many things.

Good example scenario is this-
                *I wanted to make it so that when box, or plant, or crate, etc. was broken, it spawned an item from a list.
                  I only had to make it work once. Then I just copied the coding across all of the items, and simply changed
                  out the FX for the breaking and spawning.

Keep up the faith Tiles :-)

I'm sure you'll blow us away soon.
Logged
Tiles
Full Member
***
Posts: 135



View Profile WWW
« Reply #12 on: October 01, 2008, 03:36:38 AM »

Don't worry guys, i am very mulish. And as you can see, i am on my way. Slow but unstoppable Wink

It's just that at the first look it looks much easier to have one file with four lines of code for one key pressing. The way Gediko describes uses three files, actions and pointers and more code for the same thing. Which is of course more complicated and more cumbersome, compared to four lines of code and just one file.

Quote
*You're only coding a condition or behaviour once. Just once to get it working- then it's cloning the bejebus out of it.
    *That means wayyyy easier for so many things.

Good example scenario is this-
                *I wanted to make it so that when box, or plant, or crate, etc. was broken, it spawned an item from a list.
                  I only had to make it work once. Then I just copied the coding across all of the items, and simply changed
                  out the FX for the breaking and spawning.

And here comes the answer. Now it starts to make sense why. Thanks Smiley

Oh, and please have a bit patience with me. I am a bit slow with picking up new knowledge nowadays. I'm getting old it seems ^^
« Last Edit: October 01, 2008, 03:58:56 AM by Tiles » Logged

free gamegraphics, freewaregames
http://www.reinerstileset.de
gekido
Guest
« Reply #13 on: October 28, 2008, 02:23:30 AM »

This may get lengthy and off-topic, I apologize in advance, but it seems like a more in-depth explanation may be necessary.

----------------------

I think the simplest explanation as to the 'why' is because unlike most engines that I've seen, you aren't implementing your entire game and logic in the scripting language - you are implementing the 'stub' code of what each object's specific behavior is instead, using the framework that we have created.

So instead of you having to implement a main loop like so:

Main()
{
    while(gamerunning)
    {
        CheckForKeyPress()
        DoObjectBehaviors()
        RenderScene()
    }
}

You are instead implementing the specifics of what each object would be doing in those steps.  We have created an optimized structure for handling object behaviors, input and camera management that seperates you from the low-level details (for example, needing to know what the individual low-level keycodes are), and can instead simply define game-specific behaviors (input handlers) and then set your game to react to them.

The low-level Main() loop that would normally be required is taken care of for you in a very optimal way, and all you need to do is implement the behaviors that affect your game, instead of worrying about low-level details.

So where normally you might be responding to the low-level ascii keycodes for individual keypresses, in GameCore, you can simply define an event called "Forward" and then any script that wants to handle that event can do so.

Any object that is a player, or any object that is a player's inventory can handle events, so your player script manages the player-specific movement events, a weapon that is in the player's inventory can handle the 'Shoot' and 'Reload' events, and so on.

The same goes for camera control - any player can choose to have control over the camera, and any object in a player's inventory can choose to override the camera as necessary.

The player 'class' itself is simply a mechanism that allows 3 things:
1) handling user-input
2) managing inventories
3) manipulating the camera

You can have multiple players active at once and allow different characters to handle different events even (for example, an rts style top-down camera can handle certain events, while the individual 'unit' handles others) - you can even switch between the different player's on the fly at any point - so if you want an FPS / RTS style game, you can allow the player to jump from first person view to top down RTS view simply by defining which player has control of the camera at that particular point.

So, as an example, if you want to have a player walking around the world, picking up weapons, getting into cars etc.

For the player to actually represent a physical in-game object (such as a 3d character), you can simply add a character object to the player's inventory (ie check the 'make player' checkbox on an object).  This allows the character to override any of the 3 behaviors listed above (input, inventory, camera).

An object that wants to be a player must have a 'controller' associated with it - this can be translated roughly as an 'entity' to use lingo from other engines.  A controller is just what it says - a set of behaviors that 'controls' the object in question.  Doors, triggers, vehicles, characters etc all have custom controllers.

Once the character is added to the player's inventory, the script associated with the character (ie the controller) starts to receive input events, and can handle them if it so chooses.  Instead of needing to define which individual keys are being pressed and all of that complicated stuff, the character script simply says that 'ok i want to receive the following input events: forward, backward, strafeleft, straferight, jump' and so on.

When the appropriate keys are pressed, the character script gets the message and says 'hey! I just received a 'move forward' event, i'm going to do stuff!'  However, the HandleEvent() function is just that - a message handler.  The controller basically sets a flag saying "got a message saying that the player wants to move forward, need to do something about that'.

The DynamicsAdvance() function is where the action happens.  While the handleevent is only called every so often (relatively speaking), the DynamicsAdvance function is called quite a bit (many times a frame) - it does the physics processing, handles low-level details behind the scenes of your game.  This is where you can start putting objects into motion, playing animations and so on.  The DynamicsAdvance function is basically a big set of flags waiting for specific events to occur in the game that tell it to do stuff.  For example, if the controller receives an event, it tells the dynamicsAdvance function to apply the appropriate forces to get the player moving in the proper direction etc.  This is also where you would check to see which animations you might need to play etc while the player is moving.

Now the other major aspect of player's (camera control) is also handled in the character controller - basically any player can have a SetupCamera() function which allows it to override the camera if desired.  You don't necessarily NEED a SetupCamera function - you could purely use the cinematic viewport.SetCamera() functions to control the game camera if you wish. For example, a resident evil style fixed-camera trigger system might actually use an external set of triggers and change the camera in a different way.

However, most games want dynamic / player controlled cameras (at least to a certain extent). The structure that we have provided is that any player controller can simply define the SetupCamera() function, which will be called once per frame, which allows it to change / modify the camera however it sees fit.

Now, the fun part is when you start adding inventory items into the mix.  So we have a character walking around the world, controlling the camera, doing their thing.

What happens when they get into a vehicle or pickup a weapon?  In GameCore, they are simply added to the player's inventory, and automatically get the ability to handle events of their own, as well as override the camera as desired.

So a vehicle script can say 'I'm in the player's inventory, so i'm now in charge of handling the forward, backward, left & right' events and I also want to control the camera', and it is all automatically handled without any fuss or bother.  Getting out of the car is a simple matter of removing the car from the player's inventory, which automatically reverts camera & input control back to the original character script.

Same thing for weapons - simply add the weapon to the player's inventory, and it can receive events such as 'Shoot', 'Zoom', 'Reload' etc.  The weapon controller handles these events without the character script even knowing that they exist.  The weapon doesn't want to receive the movement events, so the character is still free to manage them the same as before.

This ability to layer controllers keeps your game logic very well defined and compartmentalized, and greatly simplifies the process of creating complex behaviors and advanced games.

Hopefully this doesn't confuse things even further ;}
Logged
DPF
Newbie
*
Posts: 44


View Profile
« Reply #14 on: December 01, 2008, 09:48:27 PM »

consider making this a sticky? Excellent  reference.

Wondering if joystick hat switch can be mapped? I need it for camera control.

thanks.......
Logged
Pages: [1]
  Print  
 
Jump to:  

 
Powered by MySQL Powered by PHP bluBlur Skin © 2006, hbSkins
Powered by SMF 1.1.14 | SMF © 2006-2011, Simple Machines LLC
Valid XHTML 1.0! Valid CSS!