I have a mobile game which has a level select menu. The menu consists of 15 level buttons per page and of 4 pages. Page can be changed by swiping the screen. Swiping can be done over the buttons (it can start and end on a button) without triggering any of them. Buttons can be tapped which should activate their touchUp() method.
Currently the dragging works properly but the level select buttons are not handling the touchUp events.
I have done this by creating an actor that is the size of the whole screen. It is behaving as the dragHandler actor which detects touchDown, touchDragged and touchUp. It is working properly.
Under the dragHandler actor (on the stage) lies all the level button actors that move on the screen as the user drags it. Because the dragHandler is above the buttons, the buttons touchDown or touchUp methods are not called, the events are being handled in the dragHandler.
In my dragHandlers InputListeners touchUp method I have a piece of code that checks if the drag was long enough to be interpreted as a drag. If it wasn't, the event should be marked as unhandled. However, the InputListeners touchUp method prototype is returning a void so it cannot tell the lower levels that the event wasn't really handled (the touch seems to be marked as handled in the touchDown method already).
Here is my version of the InputListener in the dragHandler:
dragHandler.addListener(new MyInputListener() {
#Override
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
// Mark dragging on, save drag start position
dragStartX = x;
isDragging = true;
return true;
}
#Override
public boolean touchUp(InputEvent event, float x, float y, int pointer, int button) {
// If the drag was long enough, mark the event as handled
if (Math.abs(dragXOffset) >= minDrag) {
// Do stuff
return true;
}
else
// Return false to tell that this event was not yet handled,
// and should be handled by another actor (in this case, a level select button)
return false;
}
public void touchDragged(InputEvent event, float x, float y, int pointer) {
dragXOffset = x - dragStartX;
updateLevelButtonPositionsToDraggedX();
}
}
I have made a new class called MyInputListener which is exactly the same class as the original InputListener.java but I have changed the touchUp method to return a boolean instead of void, and changed the switch-case to return its result (instead of a constant true). This however didn't affect in any way. I guess it is because the touchDown event is being already handled in the dragHandler, so the touchUp cannot be handled by a different EventListener anymore.
All the actors are on the same stage, and the applications input processor is set to be the stage. If I put the dragHandler below the button actors, the touchUp method of a button is called always when the touchUp event is fired on top of a button. I don't want the touchUp after a drag to trigger the touchUp event of any of the buttons.
Is there any way to achieve what I want with any approach similar to what I have done already?
Thank you for your time!
Related
I am developing a mobile game for Android with libGDX. I have noticed that when I click the home button and then go back to the game, the player has disappeared. All other actors attached to the stage exist, and when I remove the code that moves the player it is also drawn. It only disappears when it is moving. I have done so much debugging, and sometimes the position seems to update corretly but the player is invisible, but sometimes it is just NaN. I have for example tried to save position and velocity in pause function and provide the player with them in the resume function, but nothing helps.
This is what I am doing in the player update function:
// When these lines are removed, the app works perfectly
velocity.add(0.0f, GRAVITY);
velocity.scl(deltaTime);
position.add(velocity);
velocity.scl(1/deltaTime);
It doesn't even help if I re-create the player in resume function
player2 = new Player(resourceManager.getRegion("player"), new Vector2(320.0f, 350.0f), 300.0f);
Finally I tried to create completely distinct player object that is drawn after the home button is clicked. It is visible, but is does not move:
player2 = new Player(resourceManager.getRegion("player"), new Vector2(320.0f, 350.0f), 300.0f);
Intrestingly enough I was dealing with the same issue today , every texture (actors) remains in screen after resume but not the main actor which was the one who was moving (main actor in my case). After hours debuging I found that when the game state changes between pause and resume the render method (mine looks like this) will get 0 for deltaTime:
#Override public void render(float deltaTime) {
update(delta);
spriteBatch.setProjectionMatrix(cam.combined);
spriteBatch.begin();
spriteBatch.draw(background, cam.position.x - (WIDTH / 2), 0, WIDTH, HEIGHT);
....
spriteBatch.end();}
deltaTime is time elapsed from last render.
apparently there is no time elapsed from pause to resume hence 0.
down the chain of actor updates I was updating my main actor like this
velocity.scl(deltaTime);
position.add(MOVEMENT * deltaTime, velocity.y);
which was passed 0 at very next render after resume hence the NaN (Not a Number).
anyway not sure if there is a better way to go about this or not but this is how I did, a simple check for zero deltaTime in my main actor update method and replace with a very small amount .001f : (please note in subsequent update deltaTime wont be zero and this if statment only get called once and exactly after resume)
public void update(float deltaTime) {
if (deltaTime <= 0) {
deltaTime=.001f;
}
velocity.scl(deltaTime);
position.add(MOVEMENT * deltaTime, velocity.y);
...
}
Oh yeah, I had the same issue before.
What I did was in onPause(), which is called when you press home button, I destroyed all assets references.
Then in onResume(), which is called when you're back, I reassigned the assets again.
render() method continue called when you press home button on Android so it's seems that you player position continue updating with gravity so when you resume your game you not able to see you player on screen so use a flag on position update code and change flag in pause() and resume() method of ApplicationListener interface.
enum GameState{
PAUSED, RESUMED
}
GameState gameState;
#Override
public void create() {
gameState=GameState.RESUMED;
...
}
#Override
public void render() {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if(gameState==GameState.RESUMED) {
velocity.add(0.0f, GRAVITY);
velocity.scl(deltaTime);
position.add(velocity);
velocity.scl(1/deltaTime);
}
}
#Override
public void pause() {
gameState=GameState.PAUSED;
}
#Override
public void resume() {
gameState=GameState.RESUMED;
}
So in my game I want to have it so the longer someone holds down on the screen the higher my character jumps. However I don't know how to check if someone is holding down on the screen.
My current attempt is to do this:
And run it every frame in the update method
public void handleInput(float dt) {
if (Gdx.input.isTouched()) {
if (sheep.getPosition().y != sheep.maxHeight && sheep.getPosition().y == sheep.minHeight) {
sheep.jump(1);
}
if (sheep.getPosition().y == sheep.maxHeight && sheep.getPosition().y != sheep.minHeight) {
sheep.jump(-1);
}
}
}
I am suggesting two way to detect long touch, choose one according to your requirement.
You can use longPress method of GestureListener interface to detect there is a long press or not. By default longPress duration is 1.1 seconds that mean user have to touch the screen equal to this duration, to fire a longPress event.
#Override
public boolean longPress(float x, float y) {
Gdx.app.log("MyGestureListener","LONG PRESSED");
return false;
}
Set your implementation as InputProcessor.
Gdx.input.setInputProcessor(new GestureDetector(new MyGestureListener()));
longPress only gets called one time after holding the screen for X time. so it's better to create own logic and check how long user touched the screen.
if (Gdx.input.isTouched()) {
//Finger touching the screen
counter++;
}
And on touchUp of InputListener interface make jump according to value of counter and reset value of counter to zero.
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
//make jump according to value of counter
counter=0; //reset counter value
return false;
}
Set your implementation as InputProcessor.
Gdx.input.setInputProcessor(new MyInputListener());
I understand that code inside Processing's mouseDragged() function will run if the mouse is moved and pressed at the same time. I was wondering how I could detect such movement through a variable since Processing doesn't provide a corresponding variable for mouseDragged() unlike mousePressed(). Thanks!
You need the MouseMotionListener instead. It has two methods:
Mousedragged
MouseMoved
A solution specific to Processing would be to create the variable that stores whether the user dragged the mouse or not. Under mouseDragged(), the variable is set to true. Inside the draw() function, if the mouse is not pressed, the variable is set to false.
Example:
boolean mouseDragged = false;
void draw()
{
if (mousePressed == false)
{
mouseDragged = false;
}
println(mouseDragged);
}
void mouseDragged()
{
mouseDragged = true;
}
There is https://processing.org/reference/mouseMoved_.html which sounds like the right thing.
I am making a button using MouseOverArea. After some trial and error, I realized I can override the methods in InputListener to do particular actions when an input event is notified.
For example, do things when mouse left button is pressed while cursor is over the component.
#Override
public void mousePressed(int button, int mx, int my) {
if (isMouseOver() && button == Input.MOUSE_LEFT_BUTTON) {
// Some magic happens
}
}
However, I will not able to do things like changing current game state because no Game object around. I know there are many ways to solve this problem, but I would like to know what is the Slick way to do this.
Are these methods suitable for such behavior ?
One way to modify game states is to use boolean states; Which are boolean variables that hold the state of the game or player. For example:
boolean isMovingUp, isMovingLeft, isMovingRight, isMovingDown;
You can then set these to true/false depending on what mouse or keyboard event takes place and your game class then read these variables, like so:
if (isMovingUp) {
// do something
isMovingUp = !isMovingUp;
}
Hope that helps!
i am using AndEngine.
I have a scene that i would like to reuse for all of my levels.
The only thing that will change is the objects loaded on the scene through a method i created to load the level.
The problem i am facing is that at the end of the level the user gets the option to continue to the next level. I allow the user to load the next level with this method.
this.nextlevel = new Sprite(0,0,150,80,this.nextLevelRegion,this.getVertexBufferObjectManager()){
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX,
final float pTouchAreaLoca) {
GameScene.detachChildren();
loadLevel(level);
return true;
}
};
The loadLevel(int level_number) takes a int as a parameter. I increase this variable by level++; after the current level is loaded.
The problem is when the sprite is clicked it keeps adding +1 to the level integer and trying to load the wrong level..
Anyone know a better way of doing this?
this is what i did in my game:
i created a class that creates the game play scene, this class has a method that creates the scene and loads an XML level based on the number that it recieves when i call it.
when i want to go to next level i get the current level number (lets say its x) and call the method with x+1 as an attribute for it.
you should note that i depend in this method on recreating the scene all over again so you should reset every thing when you do that.
this is the call for the method:
Sprite Next=new Sprite(x-48/factor, y+30/factor, 96/factor, 60/factor,LoadAssets.WinMenuNextTextureRegion){
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
if(pSceneTouchEvent.isActionUp()){
pEngine.setScene(GamePlayScene.CreateTheGamePlayScene(context,pEngine,camera_width, camera_height,GamePlayScene.LevelNumber+1));
}
return true;
}};
and here is the link for my game if you want to see how that works:
https://market.android.com/details?id=com.ayham.blowangryshapes
i only have one game play scene in the game and the levels are loaded as needed.