marc.mitchell_ Posted July 25, 2018 Share Posted July 25, 2018 Hi, I’ve setup a project to use the Xbox controller for player controls. I’ve done this using the ControlsXPad360 class to get the controller input and the set the control states for the player based on the game pad input like so: int leftThumbstickX = (int)gamepad.getLeftX(); if (gamepad.getLeftX() > 0.25) leftThumbstickX = 1; else if (gamepad.getLeftX() < -0.25) leftThumbstickX = -1; else leftThumbstickX = 0; if (App.get().getKeyState(ControlsApp.get().getStateKey(Controls.STATE_MOVE_RIGHT)) == 0 && leftThumbstickX >= 0.1f) { controlsRef.setState(Controls.STATE_MOVE_RIGHT, leftThumbstickX); } The problem with this is setState only takes an int so you lose the analogue values and fine movement controls for the player. I’ve started to look at the following information in the documentation: https://developer.unigine.com/en/docs/2.7.1/code/uniginescript/scripts/input Is this the correct way to use the gamepad with a player? I’ve created a short xml to test this but in the Unigine script file that was created when I created the test project when I do Step 4 and add the code to load the xml controls: Control control = new Control(); control.loadFromFile("Input.xml"); and then run the project, the world no longer loads and I get the attached error, without this code it runs fine. Can you advise on the correct way to implement xbox controller controls for a player while maintaining the analogue input? Thanks, Marc. Link to comment
fox Posted July 26, 2018 Share Posted July 26, 2018 Hi Marc, Looks like a bug in a code snippet, we'll fix it ASAP! Sorry for the inconvenience caused! Try replacing Control control = new Control(); with Unigine::Input::Control control = new Unigine::Input::Control(); And don't forget to include header files #include <scripts/input/input_device.h> #include <scripts/input/control.h> Thanks! Link to comment
marc.mitchell_ Posted July 26, 2018 Author Share Posted July 26, 2018 Hi, I’ve had a further look at this today, using Unigine::Input::Control works thank you. I have some further input and questions as I looked through it. Documentation Section: How to use Setting up controls and controls definition xml Documentation: <controls definition="controls_def.xml"> Give error: xml::do_parse(): can’t find close tag “</controls>” Fix: <controls definition="controls_def.xml"/> Close definition node / Section: Editing the controls using GUI interface After adding the code to show the GUI interface I see the control setup UI and accelerating with two buttons labelled N/A. Clicking either brings up learn control pop-up. This states ‘Choose button for action accelerating. Pressing a keyboard key doesn’t do anything. Esc hides window with no error. Pressing delete give the error message attached in image ‘InputSystem_DeleteInput.png’. Attached sample project in zip file ‘InputSystem_DeleteInput.zip’ Questions: · How do you setup an xml for use with the PlayerSpectator/Controls class states. States are defined as constants i.e. STATE_FORWARD · Do you have any sample xml files or sample projects you can share? Additional Notes: · I would be good to have a sample project showing the input system in use or some sample xml files defining various control setups. Thanks Marc. InputSystem_DeleteInput.zip Link to comment
marc.mitchell_ Posted July 31, 2018 Author Share Posted July 31, 2018 Hi, I'm still unsure how this works can you answer the question below please, if you need further information let me know. Also is this system actually still used as none of the samples, i don't think, seem to use it? Questions: · How do you setup an xml for use with the PlayerSpectator/Controls class states. States are defined as constants i.e. STATE_FORWARD · Do you have any sample xml files or sample projects you can share? Link to comment
fox Posted August 1, 2018 Share Posted August 1, 2018 Hi Marc, Sorry for the late reply! Yes, this system is actually used, and will evolve, so don't worry. Errors in Your code are caused by the controls file, should look like this: <?xml version="1.0" encoding="utf-8"?> <controls definition="controls_def.xml"> <action name="accelerate"> <input device="Keyboard" state="119"/> </action> <action name="break"> <input device="Keyboard" state="115"/> </action> </controls> There was an extra opening <controls> tag in the example (should've been removed), but when you closed the first tag like this: <controls definition="controls_def.xml"/> all actions below were simply not parsed resulting in N/A labels on the buttons. As you tried to remove missing control bindings via DELETE you obviously got an error (as there was nothing parsed). Moreover, there was no Unigine::Input initialization, update and shutdown in your code, the corresponding methods were only called for Unigine::Input::ControlSetupWindow. Sorry for any inconvenience caused, we will fix all related bugs in documentation and add a code sample to be available in the upcoming release. Here's a simple example in UnigineScript illustrating how to setup an xml file with controls and use them to control the player in a default world. Just copy and paste code below to the corresponding files. Hope this helps! Thanks! controls.xml file: <?xml version="1.0" encoding="utf-8"?> <controls definition="controls_def.xml"> <action name="forward"> <input device="Keyboard" state="119"/> </action> <action name="backward"> <input device="Keyboard" state="115"/> </action> </controls> controls_def.xml file: <?xml version="1.0" encoding="utf-8"?> <controls_def> <action_def name="forward" min="0" max="1" neutral="0" type="state"/> <action_def name="backward" min="0" max="1" neutral="0" type="state"/> </controls_def> world.cpp file: #include <core/unigine.h> // including all necessary files #include <scripts/input/input_device.h> #include <scripts/input/control.h> #include <scripts/input/control_setup_window.h> // This file is in UnigineScript language. // World script, it takes effect only when the world is loaded. Unigine::Input::Control control; /// Pawn class definition class Pawn { // movement states int forward = 0; int backward = 0; // node to be controlled Node pawn_node; // Pawn constructor Pawn(Node n) { pawn_node = n; } // updated controlled node's position depending on the current control states int update(float ifps) { Vec3 delta_movement = Vec3(0.0f, 0.0f, 0.0f); if(forward) { delta_movement = Vec3(0.0f, 1.0f, 0.0f); } else if (backward) { delta_movement = Vec3(0.0f, -1.0f, 0.0f); } pawn_node.setWorldPosition(pawn_node.getWorldPosition() + delta_movement*ifps); return 1; } // setting forward state void setForward(int f) { forward = f; } // setting backward state void setBackward(int b) { backward = b; } }; Pawn pawn; int init() { // Write here code to be called on world initialization: initialize resources for your world scene during the world start. Player player = new PlayerSpectator(); player.setPosition(Vec3(0.0f,-3.401f,1.5f)); player.setDirection(Vec3(0.0f,1.0f,-0.4f)); //disabling standard keybord control for player player.setControlled(0); engine.game.setPlayer(player); // initializing the input system Unigine::Input::init(); // creating and loading controls from the controls.xml file control = new Unigine::Input::Control(); control.loadFromFile("controls.xml"); // initializing the control setup window and showing it Unigine::Input::ControlSetupWindow::init(engine.getGui()); Unigine::Input::ControlSetupWindow::show(control); pawn = new Pawn(node_cast(player)); return 1; } // start of the main loop int update() { // Write here code to be called before updating each render frame: specify all graphics-related functions you want to be called every frame while your application executes. // updating the input system Unigine::Input::update(); float ifps = engine.game.getIFps(); // updating controls control.update(ifps); // getting current actions' states and passing them to our pawn object Unigine::Input::Action action = control.getAction("forward"); pawn.setForward(action.getState()); action = control.getAction("backward"); pawn.setBackward(action.getState()); // calling pawn's update pawn.update(ifps); // updating the control setup window Unigine::Input::ControlSetupWindow::update(); return 1; } int render() { // The engine calls this function before rendering each render frame: correct behavior after the state of the node has been updated. return 1; } int flush() { // Write here code to be called before updating each physics frame: control physics in your application and put non-rendering calculations. // The engine calls flush() with the fixed rate (60 times per second by default) regardless of the FPS value. // WARNING: do not create, delete or change transformations of nodes here, because rendering is already in progress. return 1; } // end of the main loop int shutdown() { // Write here code to be called on world shutdown: delete resources that were created during world script execution to avoid memory leaks. // shutting down the input system and control setup window Unigine::Input::shutdown(); Unigine::Input::ControlSetupWindow::shutdown(); return 1; } Link to comment
marc.mitchell_ Posted August 1, 2018 Author Share Posted August 1, 2018 @fox Thanks for the detailed response. Link to comment
Recommended Posts