Bigace360 38 Report post Posted May 17, 2012 I was wondering if anyone knew of a way to close a scene by clicking any button on the keyboard and not just the usually: if Input.trigger?(Input::B) $game_system.se_play($data_system.cancel_se) $scene = Scene_Map.new return end Share this post Link to post Share on other sites
kellessdee 48 Report post Posted May 17, 2012 You could make a hash or something, that maps keys to Scenes: Keys_To_Scene = { Input::B => Scene_Map } Keys_To_Scene.each_key do |key| if Input.trigger?(key) $scene = Keys_To_Scene[key].new break end end Or something similar. Unfortunately, since there isn't an easy way to figure out which key is being pressed you're probably going to have to loop through each key in some way. A hash should be a simple way to Map the values anyways. Share this post Link to post Share on other sites
Bigace360 38 Report post Posted May 17, 2012 (edited) So something like this: Keys_To_Scene = { Input::DOWN => Scene_Map Input::LEFT => Scene_Map Input::RIGHT => Scene_Map Input::UP => Scene_Map Input::A => Scene_Map Input::B => Scene_Map Input::C => Scene_Map Input::X => Scene_Map Input::Y => Scene_Map Input::Z => Scene_Map Input::L => Scene_Map Input::R => Scene_Map Input::SHIFT => Scene_Map Input::CTRL => Scene_Map Input::ALT => Scene_Map Input::F5 => Scene_Map Input::F6 => Scene_Map Input::F7 => Scene_Map Input::F8 => Scene_Map Input::F9 => Scene_Map } Keys_To_Scene.each_key do |key| if Input.trigger?(key) $scene = Keys_To_Scene[key].new break end end So is there a way to make this shorter, because this is a long list of commands. Something like, Keys_To_Scene = {} Keys_To_Scene[scene_Map] => {Input::DOWN, Input::LEFT, Input::RIGHT, Input::UP, Input::A, Input::B, Input::C, Input::X, Input::Y, Input::Z, Input::L, Input::R, Input::SHIFT, Input::CTRL, Input::ALT, Input::F5, Input::F6, Input::F7, Input::F8, Input::F9} Edited May 17, 2012 by bigace Share this post Link to post Share on other sites
kellessdee 48 Report post Posted May 17, 2012 Not really, either way you go about it, you're gonna have to map out the commands. However, if what you're worried about is the loop (to tes which key) i can send you an edit i did of blizzard's custom key input script, where it returns the key being pressed, rather than true/false based on an input Share this post Link to post Share on other sites
Bigace360 38 Report post Posted May 17, 2012 oh lol I didn't knew you posted already I edited my previous post, but I doubt that way will as effective anyways. Sure I'll take a look at the blizzard script. Share this post Link to post Share on other sites
kellessdee 48 Report post Posted May 17, 2012 Here's blizz's script with modifications. I was using the method so I could allow custom player key bindings. I left in blizzard's instructions and of course, the license is included. # This work is protected by the following license: #---------------------------------------------------------------------------- # # Creative Commons - Attribution-NonCommercial-ShareAlike 3.0 Unported # ( http://creativecommons.org/licenses/by-nc-sa/3.0/ ) # # You are free: # to Share - to copy, distribute and transmit the work # to Remix - to adapt the work # # Under the following conditions: # # Attribution. You must attribute the work in the manner specified by the # author or licensor (but not in any way that suggests that they endorse you # or your use of the work). # # Noncommercial. You may not use this work for commercial purposes. # # Share alike. If you alter, transform, or build upon this work, you may # distribute the resulting work only under the same or similar license to # this one. # # - For any reuse or distribution, you must make clear to others the license # terms of this work. The best way to do this is with a link to this web # page. # # - Any of the above conditions can be waived if you get permission from the # copyright holder. # # - Nothing in this license impairs or restricts the author's moral rights. # #---------------------------------------------------------------------------- #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # Custom Game Controls by Blizzard # Modified by kellessdee # - added Input.keys? # - returns array of last triggered key values # - added Input.key? # - optimized version of Input.keys?; returns first "found" triggered key value # - NOTE: Some keys (such as Shift) will usually return 2 values (Shit and Left Shift or Right Shift) # and it may NOT necessarily be the value you intended. Any values that do not exist in the # key map WILL not be returned, i.e. removing "Shift" from the map will force only "Left Shift" or # "Right Shift" to be returned. # Version: 3.0 # Date: 19.4.2007 # Date v1.2: 20.10.2007 # Date v2.0b: 3.4.2008 # Date v2.1b: 25.10.2008 # Date v2.2b: 11.6.2009 # Date v3.0: 20.7.2009 #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= # # VERY IMPORTANT NOTE: # # DO NOT USE THIS ADD-ON IF YOU ARE USING BLIZZ-ABS!!! # # # Compatiblity: # # 99% compatible with SDK 1.x, 90% compatible with SDK 2.x. # # # Note: # # Why is this input module better than others? I has far less code and it # can handle keyboard language layout. # # # Explanation & Configuration: # # This Add-on will allow you to specify your own game controls. Just below # is a list of possible keys, below that is the configuration. The default # configuration is RMXP's real game control configuration. You can add any # key specification into a key array and separate them with commas. Example: # # RIGHT = [Key['Arrow Right'], Key[','], Key['F'], Key['Ctrl'], Key['3'], # Key['NumberPad 6'], Key['F3'], Key['\''], Key['\\']] # # This example would assign for the RIGHT button the following keys: # - directional right (right arrow key) # - comma # - letter key F # - Control key (CTRL) # - Number Key 3 (on top over the letter keys) # - Numberpad Key 6 (number 6 on the numberpad on the right) # - Functional Key 3 (F3) # - apostrophe (') # - backslash (\) #:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:=:= #============================================================================== # module Input #============================================================================== module Input #---------------------------------------------------------------------------- # Simple ASCII table #---------------------------------------------------------------------------- Key = {'A' => 65, 'B' => 66, 'C' => 67, 'D' => 68, 'E' => 69, 'F' => 70, 'G' => 71, 'H' => 72, 'I' => 73, 'J' => 74, 'K' => 75, 'L' => 76, 'M' => 77, 'N' => 78, 'O' => 79, 'P' => 80, 'Q' => 81, 'R' => 82, 'S' => 83, 'T' => 84, 'U' => 85, 'V' => 86, 'W' => 87, 'X' => 88, 'Y' => 89, 'Z' => 90, '0' => 48, '1' => 49, '2' => 50, '3' => 51, '4' => 52, '5' => 53, '6' => 54, '7' => 55, '8' => 56, '9' => 57, 'NumberPad 0' => 45, 'NumberPad 1' => 35, 'NumberPad 2' => 40, 'NumberPad 3' => 34, 'NumberPad 4' => 37, 'NumberPad 5' => 12, 'NumberPad 6' => 39, 'NumberPad 7' => 36, 'NumberPad 8' => 38, 'NumberPad 9' => 33, 'F1' => 112, 'F2' => 113, 'F3' => 114, 'F4' => 115, 'F5' => 116, 'F6' => 117, 'F7' => 118, 'F8' => 119, 'F9' => 120, 'F10' => 121, 'F11' => 122, 'F12' => 123, ';' => 186, '=' => 187, ',' => 188, '-' => 189, '.' => 190, '/' => 220, '\\' => 191, '\'' => 222, '[' => 219, ']' => 221, '`' => 192, 'Backspace' => 8, 'Tab' => 9, 'Enter' => 13, 'Shift' => 16, 'Left Shift' => 160, 'Right Shift' => 161, 'Left Ctrl' => 162, 'Right Ctrl' => 163, 'Left Alt' => 164, 'Right Alt' => 165, 'Ctrl' => 17, 'Alt' => 18, 'Esc' => 27, 'Space' => 32, 'Page Up' => 33, 'Page Down' => 34, 'End' => 35, 'Home' => 36, 'Insert' => 45, 'Delete' => 46, 'Arrow Left' => 37, 'Arrow Up' => 38, 'Arrow Right' => 39, 'Arrow Down' => 40, 'Mouse Left' => 1, 'Mouse Right' => 2, 'Mouse Middle' => 4, 'Mouse 4' => 5, 'Mouse 5' => 6} #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # START Configuration #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: UP = [Key['Arrow Up']] LEFT = [Key['Arrow Left']] DOWN = [Key['Arrow Down']] RIGHT = [Key['Arrow Right']] A = [Key['Shift']] B = [Key['Esc'], Key['NumberPad 0'], Key['X']] C = [Key['Space'], Key['Enter'], Key['C']] X = [Key['A']] Y = [Key['S']] Z = [Key['D']] L = [Key['Q'], Key['Page Down']] R = [Key['W'], Key['Page Up']] F5 = [Key['F5']] F6 = [Key['F6']] F7 = [Key['F7']] F8 = [Key['F8']] F9 = [Key['F9']] SHIFT = [Key['Shift']] CTRL = [Key['Ctrl']] ALT = [Key['Alt']] #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # END Configuration #:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: # All keys ALL_KEYS = (0...256).to_a # Win32 API calls GetKeyboardState = Win32API.new('user32','GetKeyboardState', 'P', 'I') GetKeyboardLayout = Win32API.new('user32', 'GetKeyboardLayout','L', 'L') MapVirtualKeyEx = Win32API.new('user32', 'MapVirtualKeyEx', 'IIL', 'I') ToUnicodeEx = Win32API.new('user32', 'ToUnicodeEx', 'LLPPILL', 'L') # some other constants DOWN_STATE_MASK = 0x80 DEAD_KEY_MASK = 0x80000000 # data @state = "\0" * 256 @triggered = Array.new(256, false) @pressed = Array.new(256, false) @released = Array.new(256, false) @repeated = Array.new(256, 0) #---------------------------------------------------------------------------- # update # Updates input. #---------------------------------------------------------------------------- def self.update # prevents usage with Blizz-ABS if $BlizzABS # error message raise 'Blizz-ABS was detected! Please turn off Custom Controls in Tons of Add-ons!' end # get current language layout @language_layout = GetKeyboardLayout.call(0) # get new keyboard state GetKeyboardState.call(@state) # for each key ALL_KEYS.each {|key| # if pressed state if @state[key] & DOWN_STATE_MASK == DOWN_STATE_MASK # not released anymore @released[key] = false # if not pressed yet if !@pressed[key] # pressed and triggered @pressed[key] = true @triggered[key] = true else # not triggered anymore @triggered[key] = false end # update of repeat counter @repeated[key] < 17 ? @repeated[key] += 1 : @repeated[key] = 15 # not released yet elsif !@released[key] # if still pressed if @pressed[key] # not triggered, pressed or repeated, but released @triggered[key] = false @pressed[key] = false @repeated[key] = 0 @released[key] = true end else # not released anymore @released[key] = false end} end #---------------------------------------------------------------------------- # dir4 # 4 direction check. #---------------------------------------------------------------------------- def self.dir4 return 2 if self.press?(DOWN) return 4 if self.press?(LEFT) return 6 if self.press?(RIGHT) return 8 if self.press?(UP) return 0 end #---------------------------------------------------------------------------- # dir8 # 8 direction check. #---------------------------------------------------------------------------- def self.dir8 down = self.press?(DOWN) left = self.press?(LEFT) return 1 if down && left right = self.press?(RIGHT) return 3 if down && right up = self.press?(UP) return 7 if up && left return 9 if up && right return 2 if down return 4 if left return 6 if right return 8 if up return 0 end #---------------------------------------------------------------------------- # trigger? # Test if key was triggered once. #---------------------------------------------------------------------------- def self.trigger?(keys) keys = [keys] unless keys.is_a?(Array) return keys.any? {|key| @triggered[key]} end #---------------------------------------------------------------------------- # press? # Test if key is being pressed. #---------------------------------------------------------------------------- def self.press?(keys) keys = [keys] unless keys.is_a?(Array) return keys.any? {|key| @pressed[key]} end #---------------------------------------------------------------------------- # repeat? # Test if key is being pressed for repeating. #---------------------------------------------------------------------------- def self.repeat?(keys) keys = [keys] unless keys.is_a?(Array) return keys.any? {|key| @repeated[key] == 1 || @repeated[key] == 16} end #---------------------------------------------------------------------------- # release? # Test if key was released. #---------------------------------------------------------------------------- def self.release?(keys) keys = [keys] unless keys.is_a?(Array) return keys.any? {|key| @released[key]} end #---------------------------------------------------------------------------- # get_character # vk - virtual key # Gets the character from keyboard input using the input locale identifier # (formerly called keyboard layout handles). #---------------------------------------------------------------------------- def self.get_character(vk) # get corresponding character from virtual key c = MapVirtualKeyEx.call(vk, 2, @language_layout) # stop if character is non-printable and not a dead key return '' if c < 32 && (c & DEAD_KEY_MASK != DEAD_KEY_MASK) # get scan code vsc = MapVirtualKeyEx.call(vk, 0, @language_layout) # result string is never longer than 2 bytes (Unicode) result = "\0" * 2 # get input string from Win32 API length = ToUnicodeEx.call(vk, vsc, @state, result, 2, 0, @language_layout) return (length == 0 ? '' : result) end #---------------------------------------------------------------------------- # get_input_string # Gets the string that was entered using the keyboard over the input locale # identifier (formerly called keyboard layout handles). #---------------------------------------------------------------------------- def self.get_input_string result = '' # check every key ALL_KEYS.each {|key| # if repeated if self.repeat?(key) # get character from keyboard state c = self.get_character(key) # add character if there is a character result += c if c != '' end} # empty if result is empty return '' if result == '' # convert string from Unicode to UTF-8 return self.unicode_to_utf8(result) end #---------------------------------------------------------------------------- # unicode_to_utf8 # string - string in Unicode format # Converts a string from Unicode format to UTF-8 format as RGSS does not # support Unicode. #---------------------------------------------------------------------------- def self.unicode_to_utf8(string) result = '' string.unpack('S*').each {|c| # characters under 0x80 are 1 byte characters if c < 0x0080 result += c.chr # other characters under 0x800 are 2 byte characters elsif c < 0x0800 result += (0xC0 | (c >> 6)).chr result += (0x80 | (c & 0x3F)).chr # the rest are 3 byte characters else result += (0xE0 | (c >> 12)).chr result += (0x80 | ((c >> 12) & 0x3F)).chr result += (0x80 | (c & 0x3F)).chr end} return result end # Which keys were triggered? # @author kellessdee # @return [integer] Key value(s) (ascii) which were triggered def self.keys? input = [] keys = Key.invert @triggered.each_index { |i| if @triggered[i] && keys[i] input << i end } return input end # Which key was triggered? # @author kellessdee # returns Integer key value (ascii) which was triggered def self.key? keys = Key.invert @triggered.each_index { |i| if @triggered[i] && key[i] return i end } end end There are a couple of methods in there (Input.key? and Input.keys?) Input.keys? Returns an array of integers (ascii values) of the last keys TRIGGERED Input.key? Slightly optimized version of Input.keys?, only returns the integer (ascii value) of the last key TRIGGERED (it would be similar to saying: Input.key?[0] or Input.key?.first) NOTE: Some keys (such as Shift) will usually return 2 values (Shit and Left Shift or Right Shift) and it may NOT necessarily be the value you intended. Any values that do not exist in the key map WILL not be returned, i.e. removing "Shift" from the map will force only "Left Shift" or "Right Shift" to be returned. So, to use this to do what you are trying to do: 1st Solution: Blizzard uses Arrays to store multiple key bindings for each key, for this next part to work properly, you'll want to use one key per binding (non-array), so the single key values will map to the hash properly Keys_To_Scene = { # Omitted for brevity Input::A => Scene_Map, # Omitted for brevity } # Call scene from key: key = Input.key? scene = Keys_To_Scene[key] if scene $scene = scene.new end 2nd Solution: If you are like me, you'll like the notion of different keys mapping to a single game key, (like Input::B corresponds to x, and escape, etc.) To do this, we'll have to modify the keys? and key? methods, to return something a little more meaningful than ascii values (although, arguably, this is the most meaningful information ABOUT a key) So, my thought might be to add another wrapping list, to then map the ascii values to an actual key constant. KEY_LIST = [ UP, LEFT, DOWN, RIGHT, A, B, C, X, Y, Z, L, R, F5, F6, F7, F8, F9 SHIFT, CTRL, ALT ] Then, just tweak the keys? and key? methods: def self.keys? input = [] keys = Key.invert @triggered.each_index { |i| if @triggered[i] && keys[i] KEY_LIST.each { |k| if k.include?(i) input << k break end } end } return input end def self.key? input = [] keys = Key.invert @triggered.each_index { |i| if @triggered[i] && keys[i] KEY_LIST.each { |k| if k.include?(i) return k end } end } return nil end Now, you can do the same as the first solution, except it will play nicely with arrays (so, multiple key bindings) Unfortunately it adds another loop to it all, and puts some ugly dependencies, and doesn't necessarily follow the DRY principle. Although, I am definitely without a doubt that this entire script could be redesigned to support these concepts, and still be compatible with the standard RMXP input style. Another improvement, might be to create & cache the Key.invert at the start of the game, that way every call to Input.key? doesn't have to do that for you. It should also be easy to extend this to support "pressed" and "released" keys, just replace @triggered with @pressed, @released or @repeated. EDIT: Sorry, those solutions were bugging me. Here's a cleaner solution, and is plug and play. No configurations/workarounds necessary: module Input class << self def triggered_keys? input = [] constants.each do |const| key = const_get(const.to_sym) if trigger?(key) input << key end end return input end def triggered_key? constants.each do |const| key = const_get(const.to_sym) if trigger?(key) return key end end return nil end def pressed_keys? input = [] constants.each do |const| key = const_get(const.to_sym) if press?(key) input << key end end return input end def pressed_key? constants.each do |const| key = const_get(const.to_sym) if press?(key) return key end end return nil end def repeated_keys? input = [] constants.each do |const| key = const_get(const.to_sym) if repeat?(key) input << key end end return input end def repeated_key? constants.each do |const| key = const_get(const.to_sym) if repeat?(key) return key end end return nil end end end This provides support for: Input.triggered_keys? Input.triggered_key? Input.pressed_keys? Input.pressed_key? Input.repeated_keys? Input.repeated_key? And, it wraps nicely around the default Input module. Also, this will work "out of the box" Keys_To_Scene = { # Omitted for brevity Input::A => Scene_Map, # Omitted for brevity } # Call scene from key: key = Input.triggered_key? if Keys_To_Scene.has_key?(key) $scene = Keys_To_Scene[key].new end Share this post Link to post Share on other sites
Bigace360 38 Report post Posted May 18, 2012 Thanks for the edited version, as I'm about to release a script thats not that big and I don't need blizzards huge script for something thats this small. Small problem when I try to open the scene I created I get a error on line 18 after added the your new methods to the module Input when I try to access it from the menu or the map. Script 'Module Input; line 18: TypeError occured. cannot convert String tinto Interger. module Input include ACE::Help class << self alias ace_init_quick_awards_lat update unless $@ def triggered_keys? input = [] constants.each do |const| key = const_get(const.to_sym) if trigger?(key) input << key end end return input end def triggered_key? constants.each do |const| key = const_get(const.to_sym) if trigger?(key) return key end end return nil end def pressed_keys? input = [] constants.each do |const| key = const_get(const.to_sym) if press?(key) input << key end end return input end def pressed_key? constants.each do |const| key = const_get(const.to_sym) if press?(key) return key end end return nil end def repeated_keys? input = [] constants.each do |const| key = const_get(const.to_sym) if repeat?(key) input << key end end return input end def repeated_key? constants.each do |const| key = const_get(const.to_sym) if repeat?(key) return key end end return nil end end def self.update_old; ace_init_quick_awards_lat; end def self.check_blocked Block_Scenes.each {|s| return true if $scene.is_a?(s)} return false end def self.update if Quick_Access != nil && Input.trigger?(Quick_Access) && @scene == nil && !self.check_blocked $game_system.se_play($data_system.decision_se) @scene = Scene_Help.new @scene = nil end ace_init_quick_awards_lat end end Share this post Link to post Share on other sites
kellessdee 48 Report post Posted May 19, 2012 Well, it's because I took the lazy path, and relied on the fact that the only constants defined for Input would be the key values. By bringing in ACE::Help you are probably pulling in extra constants, which will be evaluated in constants.each do |const| # ... etc ... end That's why you are getting the error "string can't be converted into integer", as line 18 (trigger?(key)) expects an integer, not a string (and I'll bet one of the constants pulled in, is a string.) What you can do is, take the proper route: module Input KEYS = [ DOWN, LEFT, RIGHT, UP, A, B, C, X, Y, Z, L, R, SHIFT, CTRL, ALT, F5, F6, F7, F8, F9 ] class << self def triggered_keys? input = [] KEYS.each do |key| if trigger?(key) input << key end end return input end def triggered_key? KEYS.each do |key| if trigger?(key) return key end end return nil end def pressed_keys? input = [] KEYS.each do |key| if press?(key) input << key end end return input end def pressed_key? KEYS.each do |key| if press?(key) return key end end return nil end def repeated_keys? input = [] KEYS.each do |key| if repeat?(key) input << key end end return input end def repeated_key? KEYS.each do |key| if repeat?(key) return key end end return nil end end end There, now it shouldn't matter what constants you bring in, as long as you aren't redefining the existing constants (keys) Share this post Link to post Share on other sites
Bigace360 38 Report post Posted May 19, 2012 I just posted the script that this module is part of: Scene_Help If you want to take a look. I might of done something wrong but when I tryed doing that the scene wouldn't close? The one I posted doesn't have the new methods in module Input I'm still working on it. Share this post Link to post Share on other sites
kellessdee 48 Report post Posted May 21, 2012 Hmm, I'd have to see your implementation, but, shouldn't the Scene objects handle the closing and what not themselves? Like, user presses button and then this is called: $scene = Scene_Whatever.new then, the loop in the current scene will say "hey! $scene != self! cleanup time" (according to RMXP design) then, the loop in the new scene will start up. Finally, when the user exits that scene (or however it's set up to leave) it will do the same. But, I dunno. Thought experiments always seem work better than in practice...let's see what you are trying to do. Share this post Link to post Share on other sites
Punk 0 Report post Posted May 25, 2012 (edited) Try this: [11,12,13,14,15,16,17,18].each { |i| if Input.trigger?(i) $game_system.se_play($data_system.cancel_se) $scene = Scene_Map.new return end } 11: Input::A 12: Input::B 13: Input::C 14: Input::X 15: Input::Y 16: Input::Z 17: Input::L 18: Input::R If you're looking to add more keys (or remove some), you could also use UP (8), LEFT (4), RIGHT (6), DOWN (2), SHIFT (21), CTRL (22) ALT (23), and the F5-F9 (25-29) input buttons. Edited May 25, 2012 by Punk Share this post Link to post Share on other sites