I am new to android and trying to develop a game. I am trying to replace images in my ImageView on recursive function call after some delay. The problem I am facing is that if once an image is set to the ImageView it is not changing though the function is being called every time.
I have used both setImageResource() and setImageDrawable() but still could not achieve desired result.
Can someone help me?
The function I am using to do this is:
type and laneNumber are passed from the calling function play()
int images[] = {R.drawable.blue, R.drawable.bluesq, R.drawable.red, R.drawable.redsq};
void play()
{
type = random.nextInt(2);
laneNumber = random.nextInt(4);
createBlock(type,laneNumber);
if(--count>0)
{
play();
}
}
void createBlock(int type, int laneNumber) {
switch (laneNumber)
{
case 0:
selector = 0;
objectLane1.setImageResource(images[type+selector]);
animateDown(objectLane1);
break;
case 1:
selector = 0;
objectLane1.setImageResource(images[type+selector]);
animateDown(objectLane1);
break;
case 2:
selector =2;
objectLane1.setImageResource(images[type+selector]);
animateDown(objectLane1);
break;
case 3:
selector = 2;
objectLane1.setImageResource(images[type+selector]);
animateDown(objectLane1);
break;
}
}
Since there is no waiting period between recursive calls, there is no way to see ImageView change, even if it does occur.
Solution:
Wait for the animation to finish by using AnimationListener. This way next recursive will not execute before animation finishes.
Related
I am a basic beginner at android studio and I am developing a weather app. I want to put conditionals for icon images to weather condition.
For example:
sun = sun image
rain = rain image
snow = snow image
I understand a switch case might be useful:
switch (id) {
case "Raining":
icon = "rainIcon";
break;
case "Snowing":
icon = "snowIcon";
break;
case "Drizzling":
icon = "drizzlingIcon";
break;
case "Foggy":
icon = "fogIcon";
break;
case "Thunderstorm":
icon = "thunderIcon;";
break;
case "Sunny":
icon = "sunIcon";
break;
}
However, I am confused how to implement it into my code as I am retrieving my data from my AsyncTask and need to implement the image change in that class but there is no proper method to change my ImageView variable there.
I understand there are ways to implement this on the onCreateView method but this is the way my code is implemented right now
I suggest to create an enum of type Weathers.
public enum Weathers {
RAINING(R.drawable.ic_raining),
SNOWING(R.drawable.ic_snowing);
private int iconResId;
private Weathers(int iconResId) {
this.iconResId = iconResId;
}
public int getIconResId() {
return iconResId;
}
}
This might lessen the conditionals (The switch case above). To display into imageview, get an instance of the Weather instance by using Weathers.valuesOf(String) where String is upper-cased.
Weathers snowing = Weathers.valueOf("Snowing".toUpperCase(Locale.ENGLISH));
imageViewIcon.setImageResource(snowing.getIconResId());
I wrote some code to control the movement of a small rectangle on the screen with JavaFX. Basically, I move the player smoothly in the game loop with these codes:
(P.S: player is my object)
player.setTranslateX(player.getTranslateX() + player.velocityX);
player.setTranslateY(player.getTranslateY() + player.velocityY);
And these are the key bindings:
myScene.setOnKeyPressed(e -> {
Thread t1;
t1 = new Thread(new Runnable() {
#Override
public void run() {
switch(e.getCode()) {
case A:
player.velocityX = -1;
break;
case D:
player.velocityX = 1;
break;
case W:
player.velocityY = -1;
break;
case S:
player.velocityY = 1;
break;
}
}
});
t1.start();
})
Key releases:
myScene.setOnKeyReleased(e -> {
Thread t2;
t2 = new Thread(new Runnable() {
#Override
public void run() {
switch(e.getCode()) {
case A:
player.velocityX = 0;
break;
case D:
player.velocityX = 0;
break;
case W:
player.velocityY = 0;
break;
case S:
player.velocityY = 0;
break;
}
}
});
t2.start();
})
It is working fine but there is a bug that when I press multiple keys at the same time and release one of them, the objects stops moving until I release my finger off the key and press the key again. Now I know it has something to do with the ambiguity concept but I've hit a brick wall and I'm open for ideas.
I've run into this problem before when writing a game just like you're writing.
After a bunch of debugging, it looked like the issue is actually related to the code you're writing, but rather to the library itself. It seems that if you hold down multiple keys, the buffer of received key presses gets "jammed" and it doesn't respond until you let go and press again.
One workaround for this on Mac is to run the following command in terminal:
defaults write NSGlobalDomain ApplePressAndHoldEnabled -bool false
This seemed to fix the behavior. For Windows, we weren't able to find anything to fix the issue.
I've been writing a method to switch two images. This method is called in a mouse drag-and-drop event and is followed by another method that lets images drop down a few positions (I'm talking about a sort of candy crush mechanism).
In my case, the transition in the second method starts before the switch is done, which is why you can barely see the switch.
What I'm looking for is a way to make the program wait until the first transition is finished before it steps into the next method. Thread.sleep() isn't working for me since it stops the switch animation as well, and I don't know how to use the transition.setOnFinished() properly within my switch method without causing an infinite loop.
This is part of my switch method:
public void animateSwitch(int xFirst, int yFirst, int xLast, int yLast) {
/.../
ParallelTransition allMovements = new ParallelTransition();
TranslateTransition tt = new TranslateTransition(Duration.millis(FALL_TIME_PER_ROW), getNodeFromGridPane(grdPane, xFirst, yFirst));
TranslateTransition tt2 = new TranslateTransition(Duration.millis(FALL_TIME_PER_ROW), getNodeFromGridPane(grdPane, xLast, yLast));
Image old = iv1.getImage();
iv1.setImage(iv2.getImage());
iv1.setTranslateX(iv2.getX());
iv1.setTranslateY(iv2.getY());
iv2.setImage(old);
iv2.setTranslateX(iv1.getX());
iv2.setTranslateY(iv1.getY());
if (xFirst == xLast) {
tt.toYProperty().set(0);
tt.toXProperty().set(tt.getFromX());
if (yFirst < yLast) {
tt.fromYProperty().set(rowHeight);
tt2.fromYProperty().set(-rowHeight);
}
else {
tt.fromYProperty().set(-rowHeight);
tt2.fromYProperty().set(rowHeight);
}
tt2.toYProperty().set(0);
tt2.toXProperty().set(tt2.getFromX());
}
else if (yFirst == yLast) {
tt.toXProperty().set(0);
tt.toYProperty().set(tt.getFromY());
if (xFirst < xLast) {
tt.fromXProperty().set(rowWidth);
tt2.fromXProperty().set(-rowWidth);
}
else {
tt.fromXProperty().set(-rowWidth);
tt2.fromXProperty().set(rowWidth);
}
tt2.toXProperty().set(0);
tt2.toYProperty().set(tt2.getFromY());
}
allMovements.getChildren().add(tt);
allMovements.getChildren().add(tt2);
allMovements.play();
}
Thanks in advance!
You will have to set the onFinished event handler using allMovements.setOnFinished(eventHandler); Here eventHandler is an object that implements the EventHandler interface.
EDIT:
I skipped past the part where you don't know how to prevent an infinite loop using this solution. You can use two different eventHandlers to do the different parts. The first calls the second when it finishes. The second doesn't need to call the first, so you will not get into a loop.
This function should check if the explosion hit a box and should be canceled on the first box it hits.
For example bsp.getBomb().getStrength() is currently 2, when a box is hit i=3, but the loop is executed one more time even if the condition isn't met, why is that?
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY()+i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
// i = bsp.getBomb().getStrength()+1;
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
Try adding break to the loop:
public void detectBomb(BombSpritePair bsp) {
for(int i = 0; i <= bsp.getBomb().getStrength(); i++) {
if(bd.detect(bsp.getBomb().getX(), bsp.getBomb().getY() + i)) {
Sprite sprite = new Sprite(new Texture("gras.png"));
sprite.setPosition(bsp.getBomb().getX()*16, (bsp.getBomb().getY()+i)*16);
sprites.add(sprite);
System.out.println("RIP"+i);
System.out.println(bsp.getBomb().getStrength());
break;
}
}
}
You may be seeing duplicate print statements if you are calling the detectBomb method multiple times. Putting a breakpoint or print statement at the beginning of this method will help determine what the problem is.
Another thing to keep in mind is that you are creating a new Texture for the Sprite every time the method get executed - it would be wise to only instantiate the Texture once and share it with all subsequent Sprite instances that require it.
I try to improve the movement of my figures but i dont find the real reason why they stutter a bit. I am moving them with an SequenceAction containing an MoveToAction and an RunnableAction that does reset the moveDone flag so there can be started a new move.
The game itself is gridbased so if a move is done the squence starts a move to the next grid depending on the direction. So here is how it looks like:
note that this is inside of the Act of the figure
....//some more here
if (checkNextMove(Status.LEFT)) //check if the position is valid
{
status = Status.LEFT; //change enum status
move(Status.LEFT); // calls the move
screen.map.mapArray[(int) mapPos.x][(int) mapPos.y] = Config.EMPTYPOSITION;
screen.map.mapArray[(int) (mapPos.x - 1)][(int) mapPos.y] = Config.CHARSTATE;
mapPos.x--;
moveDone = false;
}
//... same for the up down right and so on.
//at the end of this checking the updating of the actor:
// methode from the absctract to change sprites
updateSprite(delta);
super.act(delta); // so the actions work
//end of act
And here is the move Method that does add the Actions
protected void move(Status direction)
{
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
//restart all actions to they can used again
sequence.restart();
switch (direction)
{
case LEFT:
moveAction.setPosition(getX() - Config.TILE_SIZE, getY());
addAction(sequence);
break;
case RIGHT:
moveAction.setPosition(getX() + Config.TILE_SIZE, getY());
addAction(sequence);
break;
case UP:
moveAction.setPosition(getX(), getY() + Config.TILE_SIZE);
addAction(sequence);
break;
case DOWN:
moveAction.setPosition(getX(), getY() - Config.TILE_SIZE);
addAction(sequence);
break;
default:
break;
}
}
The figures dont really move smothy.
Anyone does see a misstake or isnt it possible to let them move smothy like this?
It always stutter a bit if a new move is started. So i think this might not work good. Is there a differnt approach to move them exactly from one Grid to an nother? (Tried it myself with movementspeed * delta time but this does not work exactly and i struggeled around and used the Actionmodel)
it seems to make troubles with the one Frame where it does not move for example.
Here is an mp4 Video of the stuttering:
stuttering.mp4
just to mention, the camera movement is just fine. it's smothy but the figure stutters as you can see i hope
If you use your moveAction each move, you should call moveAction.restart() to reset the counter inside it:
// delete all old actions if there are some left.
clearActions();
sequence.reset(); // clear sequence
// add movementspeed. Note it can change!
moveAction.restart();
moveAction.setDuration(speed);
UPDATE:
Now issue occurs, because you call restart of SequenceAction after clearActions(). If your clearActions() removes all actions from SequenceAction then restart will be called for empty SequenceAction. So, do this instead:
//restart all actions to they can used again
sequence.restart();
// delete all old actions if there are some left.
clearActions();
moveAction.setDuration(speed);
Okay so i solved it myself. It has nothing todo with changing sequences around. It has something todo with the updatefrequency of the act() of the figures. The MoveToAction interpolates between the 2 points given by time. So if the last update, updates the MoveToAction by "to much time" it would need to go over the 100% of the action. So it would move to far but the action does not do this it set the final position and thats what it should do. Thats why it does not look fluent.
So how to solve this issue?
By decreasing the updatetime the "to far movement" decreases too because the steplength is getting smaller. So i need to increase the updatespeed above the 60fps. Luckily i got an thread for my updating of the figures and positions and so on. GameLogicThread. This ran on 60fps too. So i solved the stuttering by increasing it's frequence. up to around 210fps at the moment so the "overstep" is minimal. You can't even notice it.
To Show how my thread works:
public class GameLogicThread extends Thread
{
private GameScreen m_screen;
private boolean m_runing;
private long m_timeBegin;
private long m_timeDiff;
private long m_sleepTime;
private final static float FRAMERATE = 210f;
public GameLogicThread(GameScreen screen)
{
m_screen = screen;
setName("GameLogic");
}
#Override
public void run()
{
m_runing = true;
Logger.log("Started");
while (m_runing)
{
m_timeBegin = TimeUtils.millis();
// hanlde events
m_screen.m_main.handler.processEvents();
synchronized (m_screen.figureStage)
{
// now figures
if (m_screen.m_status == GameStatus.GAME)
{
m_screen.character.myAct(1f / GameLogicThread.FRAMERATE);// and here it is ;)
m_screen.figureStage.act(1f / GameLogicThread.FRAMERATE);
}
}
m_timeDiff = TimeUtils.millis() - m_timeBegin;
m_sleepTime = (long) (1f / GameLogicThread.FRAMERATE * 1000f - m_timeDiff);
if (m_sleepTime > 0)
{
try
{
Thread.sleep(m_sleepTime);
}
catch (InterruptedException e)
{
Logger.error("Couldn't sleep " + e.getStackTrace());
}
}
else
{
Logger.error("we are to slow! " + m_sleepTime);
}
}
}
public void stopThread()
{
m_runing = false;
boolean retry = true;
while (retry)
{
try
{
this.join();
retry = false;
}
catch (Exception e)
{
Logger.error(e.getMessage());
}
}
}
}