So I am currently busy with a kind of pong game for android. All i have currently is the paddle and the ball. The controls for the player (the paddle) is as followed:
If player touches on left side of screen, paddle goes left
If player touches on right side of screen, paddle goes right
Actually the above 2 points work fine, but what bothers me, is that when im holding right with my right finger, and after that release it and really fast holding left with my left finger, the paddle only executes one time "going left", and then stops, while I am still holding left. (and vice versa)
I discovered this only happens if I use two fingers. If im holding down right with my finger, and try to go really fast to press the other side, it doesnt stop and actually keeps going left.
But it is important to use two fingers, since that is the way how the game should be played.
This all may be explained unclear, so you can ask in the comments more specific questions.
Player.java: http://pastebin.com/pdFZJTRB
MyInputProcessor.java: http://pastebin.com/XPzi8JPB
I think your problem resides in the fact that you have the touchDown boolean being shared between the left and right sides. If you press the left side fast enough, the touchDown for the left finger gets set to true before the touchDown for the right finger is set to false, thus making them all false. Try something like this instead:
package com.nahrot.teleportball;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.math.Vector2;
public class MyInputProcessor implements InputProcessor
{
public Vector2 leftTouchPos = new Vector2();
public Vector2 rightTouchPos = new Vector2();
public boolean touchLeft = false;
public boolean touchRight = false;
#Override
public boolean keyDown(int keycode)
{
return false;
}
#Override
public boolean keyUp(int keycode)
{
return false;
}
#Override
public boolean keyTyped(char character)
{
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button)
{
if(sideTouched(screenX, true))
{
touchLeft = true;
leftTouchPos.set(screenX, screenY);
}
if(sideTouched(screenX, false))
{
touchRight = true;
rightTouchPos.set(screenX, screenY);
}
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button)
{
if(sideTouched(screenX, true))
{
touchLeft = false;
}
if(sideTouched(screenX, false))
{
touchRight = false;
}
return false;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer)
{
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY)
{
return false;
}
#Override
public boolean scrolled(int amount)
{
return false;
}
private boolean sideTouched(int x, boolean checkLeft)
{
if(checkLeft)
{
if(x <= Gdx.graphics.getWidth() / 2)
return true;
}
else
{
if(x > Gdx.graphics.getWidth() /2)
return true;
}
return false;
}
}
Here, I separated the booleans and vectors into left side and right side, and made a convenience function for checking whether a touchDown or touchUp is on the right or left side of the screen, and adjusted the corresponding booleans and vectors accordingly. I assume the vector was needed to check which side was pressed anyway, so I suspect you could work it so that all you need is the two booleans for the sides touched. This code is untested, by the way, but you should get the idea if it doesn't work.
Related
I am trying to set up proper multitouch support in my android game for some time. For input handling I use my InputHandler(implementing InputProcessor). I use something like this
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
screen.renderer.cam.unproject(touchPos);
if (left.isTouchDown((int) touchPos.x, (int) touchPos.y)) {
player.setMovingLeft(true);
player.leftPressed();
}
and this
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
screen.renderer.cam.unproject(touchPos);
if (left.isTouchUp((int) touchPos.x, (int) touchPos.y)) {
player.setMovingLeft(false);
player.leftReleased();
}
I have set up 3 buttons like that, but I have no idea why it doesn't work. All the answers I've found aren't very helpful when using InputProcessor.
I know that it has something to do with touch pointers and iterating input, but that's where my knowledge ends, unfortunately.
The code "when touched" and "when released" is working for sure, I'm using it the same way with keyboard input. The only problem is multitouch.
I encoutered similar problem once,trying to set up 3 buttons on screen. Those buttons can be pressed separately (then there is no problem, you always use just one finger and one pointer - therefore pointer ID can be ignored), but they should also react properly, if any two of them are pressed, or player presses all at once.
You have to make use of pointer ID, given by InputProcessor. Pointer ID is an int from 0 to 9 range (for 10 fingers).
I did it that way:
first declared three variables for three pointers:
int forwardPointer, leftPointer, rightPointer;
then in TouchDown method i checked, which finger pressed which button (was it first, second or third press?), and stored this information in my variables for future use.
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if (game.forwardButton.contains(screenX, screenY)) {
game.forwardButton.isPressed=true;
forwardPointer=pointer;
}
if (game.leftButton.contains(screenX, screenY)) {
game.leftButton.isPressed=true;
leftPointer=pointer;
}
if (game.rightButton.contains(screenX, screenY)) {
game.rightButton.isPressed=true;
rightPointer=pointer;
}}
and then, in TouchUp method i checked, which finger was lifted up (by comparing pointer ID from TouchUp method with stored pointer variable value), and according to this, i "relased" proper button.
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
if (pointer==forwardPointer) {
game.forwardButton.isPressed=false;
}
if (pointer==leftPointer) {
game.leftButton.isPressed=false;
}
if (pointer==rightPointer) {
game.rightButton.isPressed=false;
}}
This worked for me. No need to use Gdx.input.getX(), Gdx.input.getY(), as
those values are already given by touchDown and touchUp method (screenX and screenY).
You're mixing the libGDX input polling interfaces with the libGDX input event API. Specifically, these calls:
Gdx.input.getX(), Gdx.input.getY()
are equivalent to:
Gdx.input.getX(0), Gdx.input.getY(0)
see the getX documentation. So you're always reading the x/y coordinates of the 0th touch index, independent of which touch is active.
The event API is passing in the x, y and pointerID to the callback, so you just need to do something like:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
Vector3 touchPos = new Vector3(screenX, screenY, 0);
screen.renderer.cam.unproject(touchPos);
if (left.isTouchDown((int) touchPos.x, (int) touchPos.y)) {
player.setMovingLeft(true);
player.leftPressed();
}
You should use the "pointer" parameter to distinguish fingers during multi-touch.
Since pointer value passed in event methods is a unique id of the touching finger, you can use a hashmap to store and manipulate all of the touches with that unique key.
Create a hashmap.
public static HashMap<Integer, Vector2> touchlist;
public Constructor(){
touchlist=new HashMap<>();
}
Add as new if touch is not present.
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
if(!touchlist.containsKey(pointer))touchlist.put(pointer, new Vector2(screenX, screenY));
return false;
}
Remove if finger is up.
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
touchlist.remove(pointer);
return false;
}
Update the corresponding touch event if finger is dragged
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
Vector2 touch=touchlist.get(pointer);
if(touch!=null)touch.set(screenX, screenY);
return false;
}
Key is the pointer and value is a vector that will store the touch coordinates.
And to use them anywhere you want just iterate over the map
for(Integer key:touchlist.keySet()){
Vector2 touchpos=touchlist.get(key);
//do your manipulation here
if(isvalid(touchpos)) //use if valid skip if not etc..
}
My game only has 2 classes right now, "MyGdxGame" and "Player". I've added a method jump() to my Player class and overridden the touchDown() method to call jump every time the screen is tapped:
public void jump() {
startTime = TimeUtils.nanoTime();
elapsedTime = TimeUtils.timeSinceNanos(startTime);
boolean jumpTime = elapsedTime < 2000000001;
while (jumpTime) {
moveBy(xSpeed, ySpeed);
}
moveBy(xSpeed, -ySpeed);
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
//moveBy(xSpeed, ySpeed);
jump();
return true;
}
Right now when the screen is tapped the sprite goes up but doesn't come back down. before the screen is tapped the sprite is moving from left to right at constant speed xSpeed. Any ideas?
edit: I built my project then ran it again. It freezes when I tap the screen then crashes lol
The boolean jumpTime is never getting updated inside the while loop in the jump() method.
Try:
startTime = TimeUtils.nanoTime();
long jumpTime= 2000000001;
while (TimeUtils.timeSinceNanos(startTime) < jumpTime) {
moveBy(xSpeed, ySpeed);
}
moveBy(xSpeed, -ySpeed);
What's up everyone,
Thanks for your time.
I am making a Pong clone, and I want to restrict Box2D to two MouseJoints maximum; one MouseJoint maximum per paddle. The MouseJoints should be created only if one of the user's two touches lands within either of the two paddle's boundaries.
I am getting a weird result with my code. If my first touch lands within the left paddle and my second touch lands outside of either paddle, a second MouseJoint is created on the left paddle (see attached image).
Note: In addition to the two MouseJoints on the left paddle, there are two PrismaticJoints in the image; one attached to each paddle.
To no avail, I've tried all of the algorithms that I could think of or adapt from other people's code.
If a code solution example or link could be posted, I would be much obliged.
Here is my code:
public class MyScreen implements Screen, InputProcessor{
/*========some variables and methods omitted for clarity========*/
/*multiple mouse joint experiment*/
public MouseJoint mouseJoint[] = new MouseJoint[2];
Body hitBody[] = new Body[2];
Body tempBody;
public MyScreen(Pong game) {
this.game = game;
}
/*---------------------Screen interface methods--------------------------*/
//methods omitted for clarity
/*---------------------end Screen interface methods----------------------*/
/*---------------------InputProcessor interface methods------------------*/
#Override
public boolean keyDown(int keycode) {
return false;
}
#Override
public boolean keyUp(int keycode) {
return false;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
testPoint.set(screenX, screenY, 0);
camera.unproject(testPoint);
// ask the world which bodies are within the given
// bounding box around the mouse pointer
hitBody[pointer] = null;
world.QueryAABB(callback, testPoint.x - 1.0f, testPoint.y - 1.0f, testPoint.x + 1.0f, testPoint.y + 1.0f);
hitBody[pointer] = tempBody;
// if we hit something we create a new mouse joint
// and attach it to the hit body.
if (hitBody[pointer] != null) {
MouseJointDef def = new MouseJointDef();
def.bodyA = groundBody;
def.bodyB = hitBody[pointer];
def.collideConnected = true;
def.target.set(hitBody[pointer].getPosition().x, hitBody[pointer].getPosition().y);
def.maxForce = 3000.0f * hitBody[pointer].getMass();
mouseJoint[pointer] = (MouseJoint)world.createJoint(def);
hitBody[pointer].setAwake(true);
} else {
}
return false;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
if (mouseJoint[pointer] != null) {
world.destroyJoint(mouseJoint[pointer]);
mouseJoint[pointer] = null;
}
return false;
}
/**a temporary vector for delta target destination during touchDragged() method**/
Vector2 target = new Vector2();
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
if (mouseJoint[pointer] != null) {
camera.unproject(testPoint.set(screenX, screenY, 0));
mouseJoint[pointer].setTarget(target.set(testPoint.x, testPoint.y));
}
return false;
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
/*----------------end InputProcessor interface methods------------------*/
/*------------------------helper methods------------------------------------*/
/*android screen touch vector for a mouse joint*/
Vector3 testPoint = new Vector3(); //we instantiate this vector and the callback here so we don't irritate the GC
QueryCallback callback = new QueryCallback() {
#Override public boolean reportFixture (Fixture fixture) {
// if the hit fixture's body is the ground body
// we ignore it
if (fixture.getBody() == groundBody) return true;
if (fixture.testPoint(testPoint.x, testPoint.y)) {
tempBody = fixture.getBody();
return false;
} else
return true;
}
};
/*------------------------end helper methods-------------------------------*/
}
From what I can see the tempBody is never reset to null. What that means is that the first time you touch the pad it sets the tempBody to the touched paddle and then when you press outside the body the callback will not find a new body but not reset the testBody to null, so when you assign testBody to hitBody[pointer] it is setting it to the first paddle.
The way your touch down function should look like is:
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
testPoint.set(screenX, screenY, 0);
camera.unproject(testPoint);
// ask the world which bodies are within the given
// bounding box around the mouse pointer
hitBody[pointer] = null;
world.QueryAABB(callback, testPoint.x - 1.0f, testPoint.y - 1.0f, testPoint.x + 1.0f, testPoint.y + 1.0f);
hitBody[pointer] = tempBody;
// if we hit something we create a new mouse joint
// and attach it to the hit body.
if (hitBody[pointer] != null) {
MouseJointDef def = new MouseJointDef();
def.bodyA = groundBody;
def.bodyB = hitBody[pointer];
def.collideConnected = true;
def.target.set(hitBody[pointer].getPosition().x, hitBody[pointer].getPosition().y);
def.maxForce = 3000.0f * hitBody[pointer].getMass();
mouseJoint[pointer] = (MouseJoint)world.createJoint(def);
hitBody[pointer].setAwake(true);
} else {
}
tempBody = null;
return false;
}
This way the tempBody is always reset to null after use.
how to perform single touch on isActionMove() because when i move finger on sprites it takes multipal touch events and update scores twice thrice
mHardware[active] = new Sprite(pX, pY, java, this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float X, float Y) {
if (pSceneTouchEvent.isActionMove()) {
score++;
}
}
};
i cant use isActionDown because its a game like fruit ninja in which i need to move finger across screen
now problem is score is sometimes increasse by 2 sometimes by 3 because when i move finger on sprite application notices several short movements in place of one
you should use
private static boolean isFirstMove;
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float X, float Y) {
if (pSceneTouchEvent.isActionDown()) {
isFirstMove = true;
}
if (pSceneTouchEvent.isActionMove()) {
if(isFirstMove) {
score++;
isFirstMove = false;
}
}
if (pSceneTouchEvent.isActionUp()) {
isFirstMove = false;
}
});
If you found some what above answer correct for you then I have some suggestion in this.
You have to implement both scene and area touch event for your game scene.
SceneTouch event method contains two events isActionDown() and isActionUp() like in the following code.
public void onSceneTouchEvent(...){
if(pSceneTouchEvent.isActionDown()){
isFirstTouch=true;
return true;
} else if(pSceneTouchEvent.isActionUp()){
isFirstTouch=false;
return true;
}
return false;
}
Area Touch method contains only single event isActionMove() like in the following code.
public void onAreaTouch(...){
if(pSceneTouchEvent.isActionMove()){
if(isFirstMove) {
score++;
isFirstMove = false;
}
return true;
}
return false;
}
You have to follow above strategy because some time desire event not occur for your sprite so you don't get your desire result.
solution given by julien dumortier is working perfectly
static boolean isFirstMove=true;
public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float X, float Y) {
if (pSceneTouchEvent.isActionMove()) {
if(isFirstMove) {
score++;
isFirstMove = false;
}
}
});
when i touch finger on sprite, score increses randomly not by fix rate i mean that i set score
to increase 50 each time but when i scroll on sprite sometimes it increases by 100 sometimes by 150 and 200;
mHardware1[active] = new Sprite(pX, pY, samsung,
this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float X, float Y) {
if (pSceneTouchEvent.isActionMove()) {
scene.detachChild(mHardware1[active]);
score+50;
}
it works when i use isActionDown in place of isActionMove but m working a game like fruit ninja in which i need to scroll finger on screen that why i cant use isActionDown
You can use a SurfaceScrollDetector, which detects when the user is sliding his finger across the screen. It has the following events associated with it:
onScrollStarted
onScroll
onScrollFinished
I guess you could increase by 50 when you reach the onScrollFinished.
I am currently using the SurfaceScrollDetector for a project, but I haven't used it in a way you are asking about, so I can't say forsure if it will work as expected.
Here is one of the examples that uses it (in addition to the PinchZoomDetector):
https://github.com/nicolasgramlich/AndEngineExamples/blob/GLES2/src/org/andengine/examples/PinchZoomExample.java
Scene updates happen on a different thread to UI events, so possibly multiple queued touchscreen events are getting through before the event handler realises that the sprite has been detached.
Set a local boolean variable to prevent this, e.g.:
boolean touchProcessed = false;
mHardware1[active] = new Sprite(pX, pY, samsung,
this.getVertexBufferObjectManager());
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float X, float Y) {
if (!touchProcessed & pSceneTouchEvent.isActionMove()) {
touchProcessed = true;
scene.detachChild(mHardware1[active]);
score += 50;
}
}
Note that you can use: mHardware1[active].detachSelf() instead of scene.detachChild(...).
Also note that you should be detaching in the sprite in the update thread, thus:
boolean touchProcessed = false;
mHardware1[active] = new Sprite(pX, pY, samsung,
this.getVertexBufferObjectManager());
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float X, float Y) {
if (!touchProcessed & pSceneTouchEvent.isActionMove()) {
touchProcessed = true;
score += 50;
engine.runOnUpdateThread(new Runnable() {
#Override
public void run() {
mHardware1[active].detachSelf();
}
});
}
}