[CSON original] HTML5 game framework cnGameJS development record (external input module)

Source: Internet
Author: User
Tags allkeys

Returned directory

1. Why do we need an external input module?

In games, we often use operations like this: click a location, move the player object to this location, or press the mouse arrow key to move the player in different directions. None of these operations have to deal with external input devices. As a game designer, we need to know the current location of the mouse and the clicking status of the keyboard at any time, so that we can easily control the game elements. Therefore, as a game framework, external input modules are also essential.

2. What functions are provided and how to use them?

The main function of the external input module is to dynamically record the location of the mouse relative to the canvas, and record which keys on the keyboard are pressed, which keys are just released, and trigger the corresponding callback function.

We can use the two fields saved by the Framework to obtain the cursor position on the canvas:

 

var x=cnGame.input.mouseX;
var y=cnGame.input.mouseY;


The game programming mode under canvas is Frame Animation implemented through a game loop (for details about the game loop, see: HTML5 game framework cnGameJS development record (game loop )),Therefore, the binding of keyboard keyup and keydown often fails to achieve the expected effect.For example, if you want to keep the element moving to the left when you press the left button on the keyboard:

 

cnGame.input.onKeyDown("left",function(){
player.move(-10);
})

We will find that this method cannot be well applied to frame animation programming models. When we press the left arrow key on the keyboard, the callback function is continuously triggered.The trigger frequency cannot be the same as the animation frequency of your frame.(Either too fast or too slow, depending on your frame frequency), it is better to determine whether the left button is pressed every time the frame is updated, if you press the game element to move a certain position to the left, the game element becomes a part of the frame animation, updated with each frame update:

 

/* Function called for each frame update */
Var update = function (){
CnGame. input. isPressed ("left", function () {player. move (-10 );})
}


3. Code Implementation

First, let's take a look at how to keep the mouse in the canvas position. The position of the mouse relative to the canvas is actually the difference between the position of the mouse relative to the page and the position of the canvas. I have already introduced the HTML5 game framework cnGameJS development real-time recording (core function module). In the Framework initialization function, we have obtained the canvas location on the page through getCanvasPos, therefore, the cursor position relative to the canvas can be calculated as follows:

 

/**
* Record the cursor position in the canvas
**/
Var recordMouseMove = function (eve ){
Var pageX, pageY, x, y;
Eve = cg. core. getEventObj (eve );
PageX = eve. pageX | eve. clientX + document.doc umentElement. scrollLeft-document.doc umentElement. clientLeft;
PageY = eve. pageY | eve. clientY + document.doc umentElement. scrollTop-document.doc umentElement. clientTop;
Cg. input. mouseX = pageX-cg.x;
Cg. input. mouseY = pageY-cg.y;

}

Then let's take a look at how the keyboard input records are implemented. We need an array to save the name and value pairs (key and key encoding) of each key and some objects, save the pressing and released callback functions corresponding to each key, and the last object to save the key names that need to disable the default behavior. (It is necessary to prohibit the default keyboard behavior in game development. This can prevent players from triggering unnecessary browser default behaviors, such as scroll bars, when controlling game objects ).

First, create a dictionary for the key name and key encoding:

/**
* Keyboard key encoding and key name
**/
Var k = [];
K [8] = "backspace"
K [9] = "tab"
K [13] = "enter"
K [16] = "shift"
K [17] = "ctrl"
K [18] = "alt"
K [19] = "pause"
K [20] = "capslock"
K [27] = "esc"
K [32] = "space"
K [33] = "pageup"
K [34] = "pagedown"
K [35] = "end"
K [36] = "home"
K [37] = "left"
K [38] = "up"
K [39] = "right"
K [40] = "down"
K [45] = "insert"
K [46] = "delete"

K [91] = "leftwindowkey"
K [92] = "rightwindowkey"
K [93] = "selectkey"
K [106] = "multiply"
K [107] = "add"
K [1, 109] = "subtract"
K [1, 110] = "decimalpoint"
K [1, 111] = "divide"

K [2, 144] = "numlock"
K [145] = "scrollock"
K [186] = "semicolon"
K [187] = "signature sign"
K [1, 188] = "comma"
K [1, 189] = "dash"
K [190] = "period"
K [191] = "forwardslash"
K [192] = "graveaccent"
K [1, 219] = "openbracket"
K [220] = "backslash"
K [2, 221] = "closebracket"
K [1, 222] = "singlequote"

Var numpadkeys = ["numpad1", "numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7", "numpad8", "numpad9"]
Var fkeys = ["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9"]
Var numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8 ", "9"]
Var letters = ["a", "B", "c", "d", "e", "f", "g", "h", "I ", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s ", "t", "u", "v", "w", "x", "y", "z"]
For (var I = 0; numbers [I]; I ++) {k [48 + I] = numbers [I]}
For (var I = 0; letters [I]; I ++) {k [65 + I] = letters [I]}
For (var I = 0; numpadkeys [I]; I ++) {k [96 + I] = numpadkeys [I]}
For (var I = 0; fkeys [I]; I ++) {k [112 + I] = fkeys [I]}

It's a little long, but there is no technical content, that is, it makes it easy for us to know what the key name of a code is. For example, if we press the left button, the process is: get the left-click keyboard encoding-> get the key name in the dictionary-> get the handler that was previously saved by the key name in the object through the key name and execute it.

The code for binding a handler to the keyboard is as follows:

/**
* Record the keys pressed by the keyboard
**/
Var recordPress = function (eve ){
Eve = cg. core. getEventObj (eve );
Var keyName = k [eve. keyCode];
Pressed_keys [keyName] = true;
If (keydown_callbacks [keyName]) {
For (var I = 0, len = keydown_callbacks [keyName]. length; I <len; I ++ ){
Keydown_callbacks [keyName] [I] ();

}

}
If (keydown_callbacks ["allKeys"]) {
For (var I = 0, len = keydown_callbacks ["allKeys"]. length; I <len; I ++ ){
Keydown_callbacks ["allKeys"] [I] ();

}
}
If (preventDefault_keys [keyName]) {
Cg. core. preventDefault (eve );
}
}

Each key can have multiple handlers. Therefore, the objects stored in the handler store an array. In addition, note that the pressed key (pressed_keys [keyName] = true;) is saved through the pressed_keys array ;), this is to facilitate consistent parameter updates in frame updates (isPressed (keyName) can be used to determine whether a key is pressed during each update ).

The following is the source code of the input module:

/**
*
* Input record module
*
**/
CnGame. register ("cnGame. input", function (cg ){

This. mouseX = 0;
This. mouseY = 0;
/**
* Record the cursor position in the canvas
**/
Var recordMouseMove = function (eve ){
Var pageX, pageY, x, y;
Eve = cg. core. getEventObj (eve );
PageX = eve. pageX | eve. clientX + document.doc umentElement. scrollLeft-document.doc umentElement. clientLeft;
PageY = eve. pageY | eve. clientY + document.doc umentElement. scrollTop-document.doc umentElement. clientTop;
Cg. input. mouseX = pageX-cg.x;
Cg. input. mouseY = pageY-cg.y;

}

Cg. core. bindHandler (window, "mousemove", recordMouseMove );

/**
* Set of keys to be pressed
**/
Var pressed_keys = {};
/**
* A set of keys that require disabling default Behaviors
**/
Var preventDefault_keys = {};
/**
* Processing function triggered by pressing the keyboard
**/
Var keydown_callbacks = {};
/**
* Handling functions triggered by keyboard bounce
**/
Var keyup_callbacks = {};


/**
* Keyboard key encoding and key name
**/
Var k = [];
K [8] = "backspace"
K [9] = "tab"
K [13] = "enter"
K [16] = "shift"
K [17] = "ctrl"
K [18] = "alt"
K [19] = "pause"
K [20] = "capslock"
K [27] = "esc"
K [32] = "space"
K [33] = "pageup"
K [34] = "pagedown"
K [35] = "end"
K [36] = "home"
K [37] = "left"
K [38] = "up"
K [39] = "right"
K [40] = "down"
K [45] = "insert"
K [46] = "delete"

K [91] = "leftwindowkey"
K [92] = "rightwindowkey"
K [93] = "selectkey"
K [106] = "multiply"
K [107] = "add"
K [1, 109] = "subtract"
K [1, 110] = "decimalpoint"
K [1, 111] = "divide"

K [2, 144] = "numlock"
K [145] = "scrollock"
K [186] = "semicolon"
K [187] = "signature sign"
K [1, 188] = "comma"
K [1, 189] = "dash"
K [190] = "period"
K [191] = "forwardslash"
K [192] = "graveaccent"
K [1, 219] = "openbracket"
K [220] = "backslash"
K [2, 221] = "closebracket"
K [1, 222] = "singlequote"

Var numpadkeys = ["numpad1", "numpad2", "numpad3", "numpad4", "numpad5", "numpad6", "numpad7", "numpad8", "numpad9"]
Var fkeys = ["f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9"]
Var numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8 ", "9"]
Var letters = ["a", "B", "c", "d", "e", "f", "g", "h", "I ", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s ", "t", "u", "v", "w", "x", "y", "z"]
For (var I = 0; numbers [I]; I ++) {k [48 + I] = numbers [I]}
For (var I = 0; letters [I]; I ++) {k [65 + I] = letters [I]}
For (var I = 0; numpadkeys [I]; I ++) {k [96 + I] = numpadkeys [I]}
For (var I = 0; fkeys [I]; I ++) {k [112 + I] = fkeys [I]}

/**
* Record the keys pressed by the keyboard
**/
Var recordPress = function (eve ){
Eve = cg. core. getEventObj (eve );
Var keyName = k [eve. keyCode];
Pressed_keys [keyName] = true;
If (keydown_callbacks [keyName]) {
For (var I = 0, len = keydown_callbacks [keyName]. length; I <len; I ++ ){
Keydown_callbacks [keyName] [I] ();

}

}
If (keydown_callbacks ["allKeys"]) {
For (var I = 0, len = keydown_callbacks ["allKeys"]. length; I <len; I ++ ){
Keydown_callbacks ["allKeys"] [I] ();

}
}
If (preventDefault_keys [keyName]) {
Cg. core. preventDefault (eve );
}
}
/**
* Record the keys released by the keyboard
**/
Var recordUp = function (eve ){
Eve = cg. core. getEventObj (eve );
Var keyName = k [eve. keyCode];
Pressed_keys [keyName] = false;
If (keyup_callbacks [keyName]) {
For (var I = 0, len = keyup_callbacks [keyName]. length; I <len; I ++ ){
Keyup_callbacks [keyName] [I] ();

}
}
If (keyup_callbacks ["allKeys"]) {
For (var I = 0, len = keyup_callbacks ["allKeys"]. length; I <len; I ++ ){
Keyup_callbacks ["allKeys"] [I] ();

}
}
If (preventDefault_keys [keyName]) {
Cg. core. preventDefault (eve );
}
}
Cg. core. bindHandler (window, "keydown", recordPress );
Cg. core. bindHandler (window, "keyup", recordUp );

/**
* Determines whether a key is pressed.
**/
This. isPressed = function (keyName ){
Return !! Pressed_keys [keyName];
};
/**
* Disable the default behavior of a key press
**/
This. preventDefault = function (keyName ){
If (cg. core. isArray (keyName )){
For (var I = 0, len = keyName. length; I <len; I ++ ){
Arguments. callee. call (this, keyName [I]);
}
}
Else {
PreventDefault_keys [keyName] = true;
}
}
/**
* Bind a keyboard press event
**/
This. onKeyDown = function (keyName, handler ){
KeyName = keyName | "allKeys ";
If (cg. core. isUndefined (keydown_callbacks [keyName]) {
Keydown_callbacks [keyName] = [];
}
Keydown_callbacks [keyName]. push (handler );

}
/**
* Bind a keyboard to record events
**/
This. onKeyUp = function (keyName, handler ){
KeyName = keyName | "allKeys ";
If (cg. core. isUndefined (keyup_callbacks [keyName]) {
Keyup_callbacks [keyName] = [];
}
Keyup_callbacks [keyName]. push (handler );

}
/**
* Clear the keyboard and press the event handler.
**/
This. clearDownCallbacks = function (keyName ){
If (keyName ){
Keydown_callbacks [keyName] = [];
}
Else {
Keydown_callbacks = {};
}

}
/**
* Clear the keyboard and pop up the event handler.
**/
This. clearUpCallbacks = function (keyName ){
If (keyName ){
Keyup_callbacks [keyName] = [];
}
Else {
Keyup_callbacks = {};
}

}
});

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.