Recently I've been trying to use a wired Xbox 360 controller to interface with my Arduino Uno (via Processing) that I'm using in a test circuit to control two brushed motors. I came across this video that uses the library to control a single servo motor along with videos made by the library's author. I made a few modifications to the code (from the first link) just to support the two motors, and it works (sort of). The only problem is that it accepts input from my Bluetooth mouse instead of the Xbox controller which are both connected to my laptop's USB ports. I set the text configuration file so that "Button 0" and "Button 2" -which correspond to the A and X buttons respectively- make two pins on the Arduino go high which feed into the bases of two transistors that control the motors. Instead, the left mouse button and scroll wheel button on my Bluetooth mouse controls these outputs.
I'm a bit confused about why this is happening and I've tried a few different things to resolve the issue. I thought that when creating the configuration file (with a program that comes with the library) I accidentally choose my mouse as the input device, so I made another configuration file just to make sure that this wasn't the case, though I'm not exactly sure what in the configuration file indicates the correct device to use. Maybe I'm missing something extremely obvious, I just know that I need a second set of eyes to look things over for me. If you have experience with this library your help would be much appreciated, thank you.
/////////////////////////////////////////////////////////////////////////////////////////////////////////
Configuration File:
Tests the xbox controller with motors.
lMotor Left Motor 1 BUTTON Button 0 0 0.0 0.0
rMotor Right Motor 1 BUTTON Button 2 0 0.0 0.0
/////////////////////////////////////////////////////////////////////////////////////////////////////////
Java from Processing:
import processing.serial.*;
import net.java.games.input.*;
import org.gamecontrolplus.*;
import org.gamecontrolplus.gui.*;
import cc.arduino.*;
import org.firmata.*;
ControlDevice cont;
ControlIO control;
Arduino arduino;
//variables for the "A Button" and "X Button" on the xbox controller
ControlButton aButton;
ControlButton xButton;
//needed variables of type int for background function to work (change window color when buttons are pressed)
int aInt;
int xInt;
void setup() {
size(360, 200);
control = ControlIO.getInstance(this);
cont = control.getMatchedDevice("xboxtest");
if(cont == null) {
println("Error, something went wrong");
System.exit(-1);
}
//println(Arduino.list());
arduino = new Arduino(this, Arduino.list()[0], 57600);
arduino.pinMode(8, Arduino.OUTPUT);
arduino.pinMode(11, Arduino.OUTPUT);
}
//gets the input and is called in the looping function (void draw)
public void getUserInput() {
//rMotor and lMotor are references to the configuration file
aButton = cont.getButton("lMotor");
xButton = cont.getButton("rMotor");
aInt = 0;
xInt = 0;
if (aButton.pressed() == true) {
aInt = 1;
}
if (xButton.pressed() == true) {
xInt = 1;
}
}
void draw() {
getUserInput();
//changes the color of the interactive window when the input changes
background(100 * aInt, 100, 100 * xInt);
arduino.digitalWrite(8, aInt * 255);
arduino.digitalWrite(11, xInt * 255);
}
UPDATE: I was able to fix the problem after looking at some example code provided by the library that I was previously unaware of. In my defense, there is little support for this library and the video that I watched didn't use the line of code that I found in the example. I hope that this benefits someone in the future.
I ended up changing this:
cont = control.getMatchedDevice("xboxtest");
To this:
cont = control.filter(GCP.GAMEPAD).getMatchedDevice("xboxtest");
Related
Using Forge 1.8.9 in Eclipse (Mars.1 Release (4.5.1)) in local development environment.
The goal is to set a player's location to a predetermined xyz every time they join (or re-join) a world. So if they quit the game, but then come back to the world, they will start in the same location as determined by the code below instead of wherever they left off. Basically, it will work like a lobby, where players start in the same place each time.
The code works using the chat component (e.g. the chat message appears upon joining the game) but I've commented it out, for now. The player simply appears wherever they left off after having left the game from last time around.
Questions are:
1. is the PlayerLoggedInEvent the best event to use, or is there a better event?
2. is setLocationAndAngles the best to use, or should a different set location type event (or move) better?
Thanks in advance. Lots of experience with LAMP stack, but Java and mods are a new interest (obvs). Code is below.
import net.minecraftforge.client.event.RenderPlayerEvent;
//import net.minecraft.util.ChatComponentText;
//import net.minecraft.util.EnumChatFormatting;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
//import cpw.mods.fml.common.eventhandler.SubscribeEvent;
public class JoinGameLocation {
#SubscribeEvent
public void SpawningLocation(PlayerLoggedInEvent event){
event.player.setLocationAndAngles(145, 72, 145, 0, 0);
//-----This works when uncommented
//event.player
//.addChatMessage(
// new ChatComponentText(
// EnumChatFormatting.RED + "You joined the game"));
//event.world.setWorldTime(0);
int ticks = 0;
double good_x = 145;
double good_y = 72;
double good_z = 145;
event.player.setLocationAndAngles(good_x, good_y, good_z, 0, 0);
}
}
Use the entity join world and the clone event
#SubscribeEvent
public void onClonePlayer(PlayerEvent.Clone event) {
}
#SubscribeEvent
public void onEntityJoinWorld(EntityJoinWorldEvent event) {
if (event.entity != null && event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
}
}
The clone event is triggered upon tp, dimension change, etc...
The join world obviously when the world is joined. I suggest you play around with these.
On the Dell Inspiron 15 3000, the touchpad doesn't have any physical left/right buttons. Instead, it is one giant touchpad that is pressure sensitive. I'm assuming it detects right/left clicks based off of hand position on the trackpad.
In my LWJGL application, I detect mouse button clicks with Mouse.isButtonDown(0). This works fine on computers with a mouse with physical buttons, but doesn't work on touchpads that lack physical buttons. Mouse.getButtonCount() returns 0.
Has anybody had any success in detecting if a mouse button is pressed, should the user be using a trackpad that doesn't have physical buttons?
I think, instead of using
org.lwjgl.input.Mouse
This class could be what you are searching for:
org.lwjgl.input.Controllers
http://legacy.lwjgl.org/javadoc/org/lwjgl/input/Controllers.html
Im not entirely sure though since I only have a mouse and no way to test this with a touchpad.
For those who find this in the future, I did find a fix:
You cannot, should there be no physical buttons, use the Mouse.isButtonDown() method. Instead, you are going to have to read the event buffer. To do so, I wrote my own helper class:
public class Mouse{
private static boolean button_left = false, button_right = false;
public static boolean isButtonDown(int button){
if(button == 0) return button_left;
if(button == 1) return button_right;
return false;
}
public static void update(){
while(org.lwjgl.input.Mouse.next()){
if(org.lwjgl.input.Mouse.getEventButton() == 0) button_left = org.lwjgl.input.Mouse.getEventButtonState();
if(org.lwjgl.input.Mouse.getEventButton() == 1) button_right = org.lwjgl.input.Mouse.getEventButtonState();
}
}
}
The update() method is called every tick, and as such I can get button states using Mouse.isButtonDown(button).
I have built a mouse emulator for a severely disabled person, which has a series of buttons arranged in a + pattern, with the center button being a 'click'. The inputs are read into an Arduino Micro, which then connects through USB to the computer. A processing script, using the Arduino library, responds to these changes by moving the mouse, using the Robot class. I exported an application, for both 32-bit and 64-bit windows, but found that the .exe files were problematic, and instead opted for .bat files using the embedded Java.
This all works perfectly on my computer (Microsoft Surface, Windows 8, 64-bit). But on the client's computer (Windows 7, 32-bit), the results are erratic. Each time I load the program, I get a different result. For example, sometimes up, down, and click work. Sometimes only up and click work. And so forth. The click usually seems to work, but the directions are less reliable, with vertical working more often than horizontal.
I have verified that nothing is wrong with the board. I tried putting in a debug statement which ran println() each time a movement's "if" statement was tripped - I only got printing from directions that worked on that particular run.
I see a number of potential sources for this problem: the differences between 32-bit and 64-bit Windows, possible issues with the Robot class, USB performance issues (though I've tried multiple ports on the client's laptop), etc. The client's laptop has generally poor performance (for example, if I click "Control Panel", it may be a full minute before Control Panel opens), so that may also be related.
Does anyone have other insights on this?
EDIT: As requested, here's a minimal version of the Processing code. The Arduino is just running Firmata:
import processing.serial.*;
import cc.arduino.*;
import java.awt.*;
import java.awt.event.*;
Arduino arduino;
Robot r;
final int upPin=8;
final int downPin=12;
final int leftPin=10;
final int rightPin=11;
final int buttonPin=9;
final int SPEED=8;
boolean arduinoConnected;
int prevButton=Arduino.LOW;
void setup() {
arduinoConnected = (Arduino.list().length>0);
if (arduinoConnected) {
arduino = new Arduino(this, Arduino.list()[Arduino.list().length-1], 57600);
arduino.pinMode(buttonPin, Arduino.INPUT);
arduino.pinMode(upPin, Arduino.INPUT);
arduino.pinMode(downPin, Arduino.INPUT);
arduino.pinMode(leftPin, Arduino.INPUT);
arduino.pinMode(rightPin, Arduino.INPUT);
}
try {
r = new Robot();
}
catch (Exception e) {
e.printStackTrace();
}
}
void draw() {
arduinoConnected = (Arduino.list().length>0);
if (arduinoConnected && arduino==null) setup();
if (arduinoConnected) {
if (arduino.digitalRead(upPin)==Arduino.HIGH) moveMouse(0,0-SPEED);
if (arduino.digitalRead(downPin)==Arduino.HIGH) moveMouse(0,SPEED);
if (arduino.digitalRead(leftPin)==Arduino.HIGH) moveMouse(0-SPEED,0);
if (arduino.digitalRead(rightPin)==Arduino.HIGH) moveMouse(SPEED,0);
int button=arduino.digitalRead(buttonPin);
if (button==Arduino.LOW && prevButton==Arduino.HIGH) clickMouse(InputEvent.BUTTON1_DOWN_MASK);
prevButton=button;
}
}
void moveMouse(int x, int y) {
PointerInfo pinfo = MouseInfo.getPointerInfo();
Point p = pinfo.getLocation();
r.mouseMove((int)p.getX()+x, (int)p.getY()+y);
}
void clickMouse(int whichType) {
r.mousePress(whichType);
r.mouseRelease(whichType);
r.waitForIdle();
}
I'm creating java game (I'm a beginner with this for now) and I'd like to start with some kind of platform game.
I'd like to know how I can make the player jump (I know how to move him up and down), but I don't know how how to make him go back down after going up.
Here is my code:
public void keyPress() {
if (listener.arrowUp) {
Jump();
}
}
private void Jump() {
if(player.get(1).getPosY() > maxJump) {
player.get(1).moveY(-10);
} else if(player.get(1).getPosY() == maxJump) {
player.get(1).moveY(85);
}
}
So.. the player moves -10px upwards as long as i press 'w' and when he hits maxJump (which is 375 and players position at the start is 465) he "teleports" back to 465 instead of sliding back down like he does when going up.. It's really hard to explain this without a video, but i hope somebody understands and can help me with this.
This question gives a basic answer to yours. Now in your jump function, you have to set the vertical_speed only once and only call fall() every frame and add some moveY.
Here are two alternatives:
Option 1. Simulating some very simple physics. You add forces to your player, so pressing the up arrow will add a force that makes the player move upwards. Gravity is constantly applied and thus it will gradually cancel out the force you applied when the up arrow was pressed. Perhaps you only want to use forces in the vertical direction you do something like this:
// Each frame
if(notOnTheGround){
verticalVelocity -= GRAVITATIONAL_CONSTANT;
}
// When user jumps
vertivalVelocity += JUMP_FORCE;
Option 2. An alternative is to kind of animate the jumps using projectile motion.
// Each frame
if(isJumping){
verticalVelocity = initialVelocity*sin(angle) - g*animationTime;
animationTime += TIME_STEP;
}
// When user jumps
isJumping = true;
animationTime = 0;
initialVelocity = ... // calculate initial velocity
I am working on a first person game in Java, and I am trying to get the 3D movement working.
My problem is I would like to capture mouse movement, yet keep the mouse inside the window. After I capture the mouse movement, I figure the best way to keep the mouse in my window is to center the mouse in the window after moving, using Robot.moveMouse(x,y). This works fine, however the movement from the Robot triggers an event in my window which then gets interpreted as a normal event, and thus moves my character in the world.
I've tried various schemes of keeping state and ignoring movements until I am in the center, but they all seem finicky and don't quite detect which events are user vs Robot controlled.
Is there an easy way to detect that a mouse movement came from the Robot?
Is there perhaps a simpler way to solve my problem that I am overlooking?
I solved this by switching to NEWT with JOGL 2.0 RC4. In particular, I use GLWindow and warpPointer instead of an AWT Frame with the Robot.mouseMove. With the switch, I instantly got smooth movements. Some sample code similar to what I'm doing (mileage may vary):
public class MyClass implements MouseListener {
private GLWindow window;
private int centeredX = -1;
private int centeredY = -1;
// ...
public void mouseMoved(MouseEvent e) {
if (centeredX == -1 || centeredY == -1) {
center();
return;
}
int deltaX = e.getX() - centeredX;
int deltaY = e.getY() - centeredY;
// ... Do something with the deltas
centeredX = window.getWidth() / 2;
centeredY = window.getHeight() / 2;
window.warpPointer(centeredX, centeredY);
}
}
Well, I'm not 100% about this, but have you used the getsource() or getComponent() functions on your mouse event? They may return the robot as the source of it. Barring that, I would have a class variable like boolean robotControlling and anytime it takes control of the mouse, set that to true. Then, in you mouseListener, do a if(!robotControlling){...}. Hope this helps.
EDIT: if you have unused mouse buttons in your application (Java has Button 1, Button 2 and Button 3), you could make the robot press that, and in your mouse listener ignore any events with that code pressed. (use evt.getButton() for this) Of course, thats not exactly the cleanest solution :P