I have a simple problem. I have a button on the screen. I want isActionDown to push the button down, and isActionUp to push the button back up again and make my character jump. But the problem is if I push the button down and drag away from it, the button stays pushed down. I would like the button to push back up again if the user drags away from it.
How can I create the desired affect? isActionCancel doesn't seem to do the trick.
private void addButton(){
goB = new AnimatedSprite(240, 364, ResourceManager.getInstance().go_region, vbom){
#Override
public boolean onAreaTouched(final TouchEvent event, final float x, final float y){
if (event.isActionDown()){
goB.animate(new long[]{ 250 }, new int[] { 1 }, true);
/*if(event.isActionCancel()){
goB.animate(new long[]{ 250 }, new int[] { 0 }, true);
}*/
}
if (event.isActionUp()){
goB.animate(new long[]{ 250 }, new int[] { 0 }, true);
fresh = true;
playerBody.applyLinearImpulse(new Vector2(0, 45), playerBody.getPosition());
}
if (event.isActionCancel() || event.isActionOutside()){
goB.animate(new long[]{ 250 }, new int[] { 0 }, true);
}
return true;
}
};
goB.setScale(3);
registerTouchArea(goB);
attachChild(goB);
goB.animate(250);
}
I'm having the hardest time with this, and I've tried all sorts of variations of the code above. Please let me know if you have the solution.
Thanks for your help!
Use the
setTouchAreaBindingOnActionDownEnabled(true);
setTouchAreaBindingOnActionMoveEnabled(true);
functions
Related
Visual addition
I read that when creating a window a main cycle is started which runs all the events. From this it follows that it is impossible to make a cycle for changing the position of graphic objects in a window. This is not accurate, but somehow it works. In an abstract way, I understood it all.: DDDDD
scene.setOnMouseMoved(e -> {
System.out.println(e.getX()+" "+e.getY());
if(e.getX()>750)
{
camera.cameraControlX(-0.5);
}else if(e.getX()<50)
{
camera.cameraControlX(0.5);
}
if(e.getY()>550)
{
camera.cameraControlY(-0.5);
}else if(e.getY()<50)
{
camera.cameraControlY(0.5);
}
In addition to the picture, I wrote this code. As the mouse moves, everything works as it should. However, I would like to achieve the movement of the house as long as the mouse is in the corner of the windows. Please tell me how to do this? Sorry for my english.
if i understand your problem correctly, i think you want to have the camera continue moving as long as the curser is at one position. I have added an AnimationTimer which continues moving the camera as long as the curser stays in one position. here is my code
boolean north = false, east = false, south = false, west = false;
scene.setOnMouseMoved(e -> {
if(e.getX()>750)
{
east = true;
}else if(e.getX()<50)
{
west = true;
}else{
east = false;
west = false;
}
if(e.getY()>550)
{
south = true;
}else if(e.getY()<50)
{
north = true;
}else{
north = false;
south = false;
}
});
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
if(east)camera.cameraControlX(-0.5);
if(west)camera.cameraControlX(0.5);
if(south)camera.cameraControlY(-0.5);
if(north)camera.cameraControlY(0.5);
}
};
timer.start();
I'm deploying an app in my company to keep track of production etc. Now I wonder how I should implement a hidden debug menu. In my C# programs I usually make a 2px by 2px hidden button in the bottom left corner of the main window, but this seems impractical for an android touch app. In case something goes wrong i need to have a way to open a menu that nobody, who doesnt know exactly how to open it, will ever find. I tried googling but all I found was how to hide/disable the dev settings in the android settings.
So what would be practical solutions to this problems without having to plug it into a PC or have to go to a separate app?
Here is a suggestion : listen to a multitouch pattern (only the sequence of added / removed touches, not the position).
It is easy to do in Activity.dispatchTouchEvent
without interfering with the UI, and difficult to trigger by chance.
A simple implementation (sorry it's in Kotlin, but it should be fairly easy to translate in Java) :
class DebuggableActivity : Activity() {
// This pattern means :
// 1, 2, 3, 4 : touch with 4 fingers (adding one at a time)
// 3, 2 : removes 2 any touches (again one at a time)
// 3, 2 : add, then remove one touch
val pattern = listOf(1, 2, 3, 4, 3, 2, 3, 2)
// current number of touches
val pointers = mutableSetOf<Int>()
// current position in pattern
var patternIndex = 0
override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
when (ev.actionMasked) {
MotionEvent.ACTION_DOWN -> {
// new gesture, reset
pointers.clear()
patternIndex = 0
pointers.add(ev.getPointerId(ev.actionIndex))
checkPattern()
}
MotionEvent.ACTION_POINTER_DOWN -> {
// new touch
pointers.add(ev.getPointerId(ev.actionIndex))
checkPattern()
}
MotionEvent.ACTION_POINTER_UP -> {
// touch released
pointers.remove(ev.getPointerId(ev.actionIndex))
checkPattern()
}
}
return super.dispatchTouchEvent(ev)
}
fun checkPattern() {
if (pattern[patternIndex] == pointers.size) {
// progressing
patternIndex++
if (patternIndex == pattern.size) {
// triggered debug mode
patternIndex = 0
showDebugDialog()
}
} else {
// failed, reset
patternIndex = 0
}
}
fun showDebugDialog() {
AlertDialog.Builder(this)
.setTitle("Debug mode")
.setItems(arrayOf<String>("option 1", "option2", "option3"), { dialog, which ->
Log.d(TAG, "Clicked on " + which)
})
.show()
}
....
}
Inspired by the answer of #bwt, I have updated the implementation to have a true pattern based on the number of fingers.
// ---- DEBUG ----
// The number in the pattern means the number of fingers touching on the current activity.
private val pattern = listOf(1, 2, 3, 2, 1)
// current position in pattern
private var patternIndex = 0
private var shouldReadPointerCount = true
private var pointerCount = 0
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
val action: Int = event.action and MotionEvent.ACTION_MASK
if (action == MotionEvent.ACTION_DOWN || action == MotionEvent.ACTION_POINTER_DOWN) {
pointerCount = 0
shouldReadPointerCount = true
} else if (action == MotionEvent.ACTION_POINTER_UP || action == MotionEvent.ACTION_UP) {
if (shouldReadPointerCount) {
pointerCount = event.pointerCount
shouldReadPointerCount = false
}
if (event.pointerCount == pointerCount) {
Log.i(TAG, pointerCount.toString())
checkPattern(pointerCount)
}
}
return super.dispatchTouchEvent(event)
}
private fun checkPattern(count: Int) {
if (pattern[patternIndex] == count) {
patternIndex++
if (patternIndex == pattern.size) {
patternIndex = 0
showDebugDialog()
}
} else {
patternIndex = 0
}
}
My suggestion: after some screen element gets clicked N times you then open an input dialog and ask for a secret that leads to the hidden debug screen. You can create an "About" menu that directs to a not-so-usefull screen with the name and version of the App and program the "magical clicks" on some label or image on that screen.
#bwt's example translated into Java:
// Variables required
// Change pattern to indicate the sequence of touches required to activate
// the secret action.
private int[] pattern = {1, 2, 3, 4, 3, 2, 3, 2};
private HashSet pointers = new HashSet();
private int patternIndex = 0;
// We override dispatchTouchEvent and count the number of fingers down
// based on the values in pattern. See:
// https://stackoverflow.com/questions/48441348/whats-the-best-way-to-implement-hidden-debug-options
#Override
public boolean dispatchTouchEvent(MotionEvent ev) {
switch(ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
// new gesture, reset
pointers.clear();
patternIndex = 0;
pointers.add(Integer.valueOf(ev.getPointerId(ev.getActionIndex())));
checkPattern();
break;
case MotionEvent.ACTION_POINTER_DOWN:
// new touch
pointers.add(Integer.valueOf(ev.getPointerId(ev.getActionIndex())));
checkPattern();
break;
case MotionEvent.ACTION_POINTER_UP:
// touch released
pointers.remove(Integer.valueOf(ev.getPointerId(ev.getActionIndex())));
checkPattern();
}
return super.dispatchTouchEvent(ev);
}
private void checkPattern() {
if (pattern[patternIndex] == pointers.size()) {
// progressing
patternIndex++;
if (patternIndex == pattern.length) {
// triggered, show debug screen
patternIndex = 0;
showDebugScreen();
}
} else {
// reset
patternIndex = 0;
}
}
private void showDebugScreen() {
// Open your diagnostic screen here.
}
An interesting enhancement is to check the value of a text widget in showDebugScreen, and if a particular value isn't there, return. That helps to reduce the chance that a user will stumble on it accidentally by drumming on the phone.
I am having a really hard time trying to solve this problem :
I programmed an app that allows user to get rid of some colored squares on the screen. In my class coloredSquare, I have a method like this :
public void appearance(){
setLayoutParams(new RelativeLayout.LayoutParams(side/ 10, side/ 10));
final int[] count = {1};
final Runnable run = new Runnable() {
#Override
public void run() {
setLayoutParams(new RelativeLayout.LayoutParams(count[0] * side/ 50, count[0] * side/ 50));//View grows of 1/50 of its final size
if (count[0] < 50){
handler.postDelayed(this, 20);
} else {
setClickable(true);//When done
}
count[0]++;
}
};
handler = new Handler();
handler.postDelayed(run, 10);
}
When running on my Samsung Galaxy S4 mini, it's working juste fine.
But for instance, it does not work on the Wiko Highway 4G or on an emulator 1080x1920 and I can't understand why.
When I say that's not working : The view appears and grows but when it grows, every little view that was here before the postDelayed stays there.
And when I try to make them disappear by tapping on it, it shrinks well but all the other bigger views (before postDelayed) stay there too.
If you do not understand there, you will on the timer below.
In the meantime, I got a very simple timer like this :
final java.util.Timer t = new java.util.Timer();
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
if(termine){
t.cancel();
}
if(seconds == 0){
vCoul.setText(String.valueOf(minutes) + ":00");
} else if (seconds < 10) {
vCoul.setText(String.valueOf(minutes) + ":0" + String.valueOf(seconds));
} else {
vCoul.setText(String.valueOf(minutes) + ":" + String.valueOf(seconds));
}
seconds -= 1;
if(seconds == -1){
seconds = 59;
minutes=minutes-1;
}
}
});
}
}, 0, 1000);
But every second, the new time is overlapping the former one.
Sorry for the long post, thanks in advance for your answer!
I figured this out some months ago but I hope this answer will help others.
I didn't put any background in the Activity so on most of samsung devices, there were no issues since Samsung handle just fine the no background activities.
Though, on several Wiko and Archos devices, you have to put a background (like background:#000000) so that you can move views smoothly upon it.
So, I am developing a flappy bird clone. I created a button which bounces the bird. What I also want for this button is to draw something (totally irrelevant at this point). But not each time the button is hit. I already tried this with:
if (Gdx.input.isTouched()) {
batcher.draw(birdRed, bird.getX(), bird.getY(),
bird.getWidth() / 2.0f, bird.getHeight() / 2.0f,
bird.getWidth(), bird.getHeight(), 1, 1, 1);
}
But this is now what I want. I want specifically to draw something when button is hit first time. I hope you understand my problem. Thanks for your help.
boolean touched = false;
...
if (Gdx.input.isTouched() && !touched) {
touched = true;
batcher.draw(birdRed, bird.getX(), bird.getY(),
bird.getWidth() / 2.0f, bird.getHeight() / 2.0f,
bird.getWidth(), bird.getHeight(), 1, 1, 1);
}
If you use button actor then you can handle change event and use some boolean flag to keep it's first time pressed state.
private boolean wasPressed = false;
Somewhere in button initialization code:
Button pushBirdButton = new Button();
pushBirdButton.addListener(new ChangeListener() {
#Override
public void changed(ChangeEvent event, Actor actor) {
wasPressed = true;
}
});
And then you can always check was you button pressed or not.
I'm trying to animate the showing/hiding of a menu in my app. When I use the showMenu function, the animation works fine. However, when I use the hideMenu function the animation does not play and the menu remains visible.
Without the animation included, hideMenu works fine. The menu_hide animation works fine if used in the showMenu function; the showMenu animation does not work when put in the hideMenu function.
I assume that the animation is not playing because the weight of the view in question is being set to zero immediately after the animation is set. How do I get around this?
private void showMenu() {
animate(tableLayout, R.anim.menu_show);
setWeights(3, 7, 10);
ShowMenu.setVisibility(View.GONE);
}
private void hideMenu() {
animate(tableLayout, R.anim.menu_hide);
setWeights(3, 17, 0);
ShowMenu.setVisibility(View.VISIBLE);
}
private void setWeights(int i, int j, int k) {
int titlePadding = (int) getResources().getDimension(R.dimen.small_pad);
LayoutParams titleParams = new LayoutParams(matchParent, 0, i);
titleParams.setMargins(titlePadding, 0, titlePadding, 0);
titleLayout.setLayoutParams(titleParams);
listLayout.setLayoutParams(new LayoutParams(matchParent, 0, j));
tableLayout.setLayoutParams(new LayoutParams(matchParent, 0, k));
}
public void animate(View view, int animationId) {
view.setAnimation(AnimationUtils.loadAnimation(this, animationId));
}
I had same problems and seems view which has 0 weight is ignored. Try 0.001f instead of 0f.