Jump to content

GamePad / Input System


photo

Recommended Posts

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.

playerinputtest_errormessage.png

Link to comment

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

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.png

InputSystem_DeleteInput.zip

Link to comment

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

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
×
×
  • Create New...