Android animation blink - java

The code is for making a text color change evenly every 200 ms. Why is the first version change uneven/flickering, and the second one evenly changes?
//first version
long lt = System.currentTimeMillis();
TextView tv = ...
for (int i = 1; i < 120; i++) {
final int cl = i % 2 == 0 ? 0xFFFF0000 : 0x00000000;
Message w = Message.obtain(handler, new Runnable() {
public void run() {
tv.setTextColor(cl);
tv.requestLayout();
}
});
handler.sendMessageDelayed(w,i * 200L - (System.currentTimeMillis()-lt));
}
//second version
Animation anim = new AlphaAnimation(0.0f, 1.0f);
anim.setDuration(200); //You can manage the time of the blink with this parameter
anim.setStartOffset(20);
anim.setRepeatMode(Animation.RESTART);
anim.setRepeatCount(Animation.INFINITE);
tv.startAnimation(anim);

I have had this problem before when creating/using animations. After you are done with your animation, simply call clearAnimation().
This will insure that it has fully stopped and should be nice and smooth, giving the user the experience you desire.
How to stop an animation (cancel() does not work)
Read more:
http://developer.android.com/reference/android/view/View.html
Regards,

Related

How do I slow down an a sprite animation with processing java

I'm attempting to slow down a sprite animation that I found from this website here: https://processing.org/examples/animatedsprite.html
Here is the class for the animation:
class Animation {
PImage[] images;
int imageCount;
int frame;
Animation(String imagePrefix, int count) {
imageCount = count;
images = new PImage[imageCount];
for (int i = 0; i < imageCount; i++) {
// Use nf() to number format 'i' into four digits
String filename = "images/" + imagePrefix + nf(i, 2) + ".png";
images[i] = loadImage(filename);
}
}
void display(float xpos, float ypos) {
frame = (frame+1) % imageCount;
image(images[frame], xpos, ypos);
}
int getWidth() {
return images[0].width;
}
}
From the website showing the animation, it says:
It would be easy to write a program to display animated GIFs, but would not allow as much control over the display sequence and rate of display.
So far, the animation plays at the current frame rate (around 60 FPS), but what if I want to play it at 5 FPS? Obviously, I can't just slow down the entire framerate, because I want just the animation to slow down, not my entire project/canvas.
I've tried slowing the animation down by doing something like this:
if (frameCount % 10 == 1) {
//Show image
}
But the above approach flashes the image, only showing it every ten frames. How would I successfully slow down the rate of display of the animation, so that the frames don't appear so quickly?
Here's what the animation looks like right now:
And here's what I want it to look like:
Thanks for any help.
You're sooo close ! :)
You've got the solution pretty much using frameCount, just need to separate the frame update from the drawing. You want to update based on the frameCount (every once in a while), but display continuously:
void display(float xpos, float ypos) {
if(frameCount % 12 == 0){
frame = (frame+1) % imageCount;
}
image(images[frame], xpos, ypos);
}
(feel to ajust 12 (60/5) to what suits your project best)
Shameless plug, you can also use the image-sequence-player library I wrote which allows you to call setDelay(1000/5) to have the image sequence play at 5fps.

Play next sound without waiting for previous playback to end

I am making a roulette game type application, I have 10 rectangles that change color simulating a random choice, In addition to the color change, I want a sound to be played every time the roulette goes through a rectangle.
First a list of possible prizes is created awardList, then the winner is randomly selected positionAwardSelected
I tried to do the following:
final Handler handler = new Handler();
int count = 0;
private void playRoulette(){
List<Award> awardList = new ArrayList<>();
int positionAwardSelected;
// ... List filling and winner selection code (not necessary to include for the question) ...
int numberMovements = ThreadLocalRandom.current().nextInt(20, 60 + 1);
MediaPlayer mp = MediaPlayer.create(getApplicationContext(), R.raw.pin);
final Runnable runnable = new Runnable() {
public void run() {
if (count > numberMovements){
resetColors();
getConstrainLayoutRectangle(positionAwardSelected).setBackground(ContextCompat.getDrawable(Roulette.this, R.drawable.selected_rectangle));
} else {
resetColors();
int randomPosition = ThreadLocalRandom.current().nextInt(0, awardList.size());
getConstrainLayoutRectangle(randomPosition).setBackground(ContextCompat.getDrawable(Roulette.this, R.drawable.selected_rectangle));
}
mp.start();
if (count++ < numberMovements) {//Time it takes to change the rectangle, before the winner 70% of the time it takes 175ms and 30% of the time it takes 250ms, to change to the winner it takes 100ms
handler.postDelayed(this, timeDelay());
} else {
handler.postDelayed(this, 100);
}
}
};
handler.post(runnable);
}
private int timeDelay(){
int a = new Random().nextInt(100);
if (a >= 30){
return 175;
} else {
return 250;
}
}
Color changes, speed and award selection work fine, I have 2 sound issues unfortunately. The first problem is that the sound does not match the color change of the roulette wheel, it seems that the sound is slower, the second problem is that the sound seems to go into an infinite loop since it never finishes playing
I realize that the first problem happens because the duration of the sound is greater than the duration of timeDelay (), when timeDelay > duration of sound, it matches the change of the selected rectangle with sound, but I need timeDelay () to be shorter for a fluid motion.
Alternative 2
When I substitute mp.start(); for MediaPlayer.create(this, R.raw.pin).start(); everything matches perfectly regardless of the duration of timeDelay (), but only the first 5 positions of the wheel, then the following loop occurs: silence of about 4 seconds, the sound is played 5 times and it never ends.
Hope someone can help me, thanks

LibGdx - How can I not load my textures every single frame?

I am kinda new to Java and LibGdx but for my school project I need to Animate a Player-Sprite.
For only one Animation per Player everything went fine with the Methode I made for this but now I also need a Walking, Idling and Fighting Animation. I managed to get the Animations to switch but the Problem is now, that only one Frame of each Animation gets Displayed. After some research I know that I need to stop updating my Textures every frame but I cant get to know how to do so.
So far Ive tried a simple timer before updating but this just looks weird.
Here is my Code:
public Player(){
img3 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_idle_anim_strip_4.png");
img1 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_run_anim_strip_6.png");
img2 = new Texture("platform_metroidvania asset pack v1.01/herochar sprites(new)/herochar_sword_attack_anim_strip_4.png");
animation();
changeCharacter();
}
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
img3 = img2;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
img3 = img1;
tileWidth = 16;
amount = 3;
}else{
img3 = img;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(img3, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
Timer.schedule(new Timer.Task() {
#Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
}
Both Methodes "animation" and "changeCharacter" are called in render().
I know there are simpler solutions for this in LibGdx but the rest of my code is based on this and I basically would have to rewrite the entire Project...
If you need any other classes just ask. I'm probably asking a very easy thing but I dont know what to do with this.
You need to rename first.
img3 looks like it serves the purpose of being the pointer to the currentTextureSet. so when you initialise in Player() you might want to rename img3 to currentTextureSet and then, instead of the duplicate load of herochar_idle_anim_strip_4.png, set
currentTextureSet = img;
after
(you may also want to rename img, img1, img2 to idleTextureSet, runTextureSet and swordAttackTextureSet).
That aside,
definitely get rid of Timer.schedule which you are calling from render will run in a background thread you don't want that.
Looking at the asset pack here https://o-lobster.itch.io/platformmetroidvania-pixel-art-asset-pack?download if this is the same one, the images should be selected left to right i.e. x should be incremented not y. However, it looks like you increment y...
sprite.setRegion(regions[0][frame]); and the incorrect array access is swallowed because in a background timer task and the only textureRegion you can access is [0][0] i.e. you just see a single frame.
So dump this
Timer.schedule(new Timer.Task() {
#Override
public void run() {
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
}, 0, 1 / 12f);
and replace with
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[frame][0]);
*EDIT
So this means that your frame updates with every render, which is too fast. So the -easy fragile way- (not the best which would be deltaTime please read this excellent article https://gafferongames.com/post/fix_your_timestep/ ). The easy way, not the best in the case there is no time left, would be to declare
long renderCallCount =0;
put the above where frame is declared, then in your render method
renderCallCount++; //One more render call
if (renderCallCount % 60 == 0) { //Should I update frame?
frame++;
if (frame > amount) {
frame = 0;
}
sprite.setRegion(regions[0][frame]);
}
So whenever renderCallCount is divisible by 60 using the mod operator https://www.edureka.co/blog/mod-method-in-java/ , which would be once a second if your refresh rate is 60hz, then your frame is incremented. To switch frames twice a second change 60 to 30.
This assumes your monitor is ONLY going to run at 60hz. I think your application probably depends on the timing on the refresh rate for position updates so you may want to update that in the future based on some thinking from the article. On a monitor with a faster frame rate everything will speed up (consistently).
I just put some stuff in the right order and it now works! I dont really get why the number after the mod operator needs to be so small but otherwise it just doesnt look right. Also I know that you shouldnt create the Spritebatch in render() but when I do it in the constructor the Program just crashesbecause of the missing Spritebatch??? But thanks for the help :) Here is the working code for anyone whos interested in this:
public static void animation(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT) && InfoGame.cl.isGrounded() && current > Enemy.lastDmg + Enemy.dmgCool){
currentTextureSet = attackTexture;
amount = 3;
tileWidth = 32;
}else if(Gdx.input.isKeyPressed(Input.Keys.D) || Gdx.input.isKeyPressed(Input.Keys.A)){
currentTextureSet = runTexture;
tileWidth = 16;
amount = 3;
}else{
currentTextureSet = idleTexture;
amount = 3;
tileWidth = 16;
}
}
public static void changeCharacter(){
batch = new SpriteBatch();
regions = TextureRegion.split(currentTextureSet, tileWidth, 16);
sprite = new Sprite(regions[0][0]);
sprite.setPosition(x,y);
sprite.setOrigin(8,8);
if (renderCallCount % 6 == 0) {
frame++;
if (frame > amount) {
frame = 0;
}
}
sprite.setRegion(regions[0][frame]);
}

How do I make timelines called through a loop occur at different times?

I am currently writing an assignment for my Java class in which I need to create the class "Simon Says" game (guess colors in sequence). My issue comes where when I attempt to show the second color, it appears at the exact same time as the first color.
My loop to call a method to make the color flash looks like the following:
private void GameCycle(ArrayList<Color> colorSequence)
{
colorSequence.add(generateColor());
for(int i = 0; i<colorSequence.size(); i++)
{
Color colorRef = colorSequence.get(i);
if (colorRef != null)
{
showColor(findRect(colorRef), colorRef);
}
}
getGuesses(colorSequence);
}
and then my code to show the color is the following:
private void showColor(Rectangle shapeToChange, Color colorToChangeTo)
{
toggleVisibility(); //make buttons invisible when displaying a color
KeyFrame swapColor = new KeyFrame(Duration.millis(0), f->{ //Occurs immediately
shapeToChange.setFill(colorToChangeTo); //change to the inputed color
});
KeyFrame swapColorBack = new KeyFrame(Duration.millis(1000), f->{ //Occurs after 1 second into the cycle
shapeToChange.setFill(Color.BLACK); //change back to black
});
Timeline anim = new Timeline(swapColor, swapColorBack);
anim.setCycleCount(1); //Animation will play once
anim.play();
anim.setOnFinished(e ->{
toggleVisibility(); //make buttons visible
});
}
I can add all of my code, but it is fairly long and somewhat sloppy at the moment.
To give an example of my issue: First color show up on start (red), user clicks red button, now red and green show up at the same time.
What I want to change is so that green will not show up until after red has finished. Is there a simple way I can implement this without screwing up the rest of my code?
Thanks
I think your problem is that you are creating multiple Animations that run parallel. You should just create one Animation and add all your KeyFrames to it:
private void GameCycle(ArrayList<Color> colorSequence)
{
colorSequence.add(generateColor());
Timeline anim = new Timeline();
anim.setCycleCount(1); //Animation will play once
for(int i = 0; i<colorSequence.size(); i++)
{
Color colorRef = colorSequence.get(i);
if (colorRef != null)
{
showColor(anim, i, findRect(colorRef), colorRef);
}
}
anim.play();
anim.setOnFinished(e ->{
toggleVisibility(); //make buttons visible
});
getGuesses(colorSequence);
}
private void showColor(Timeline anim, int step, Rectangle shapeToChange, Color colorToChangeTo)
{
toggleVisibility(); //make buttons invisible when displaying a color
KeyFrame swapColor = new KeyFrame(Duration.millis(1000*step), f->{ //Occurs immediately
shapeToChange.setFill(colorToChangeTo); //change to the inputed color
});
KeyFrame swapColorBack = new KeyFrame(Duration.millis(1000*(step+1)), f->{ //Occurs after 1 second into the cycle
shapeToChange.setFill(Color.BLACK); //change back to black
});
anim.getKeyFrames().add(swapColor);
anim.getKeyFrames().add(swapColorBack);
}

Looking for an algorithm to switch lights in traffic light

Given a greenLightDuration and a yellowLightDuration, I need to switch lights (including red Light) based on duration. This all happens inside a run method for the traffic light. The reason for the run method is because it is used when running the entire simulation (trafficLight is an Agent).
//Run method for agents in Model
public void run(double duration) {
if (disposed)
throw new IllegalStateException();
for (int i=0; i<duration; i++) {
time++;
for (Agent a : agents.toArray(new Agent[0])) {
a.run(time);
}
super.setChanged();
super.notifyObservers();
}
}
In Light I have the run method...
public void run(double runTime){
double check_time = runtime - time;
if(check_time >= yellowLightDuration&& color == Color.RED){
color = Color.GREEN;
time = runtime;
}else if(check_time >= greenLightDuration&& color == Color.GREEN){
color = Color.RED;
time = runtime;
}
...but it was just something silly I did to get the lights switching from red/green and obviously does not work for yellow or is not proportionate to green/yellow light duration(I don't think).
For color I use
Color.RED, Color.YELLOW, Color.GREEN from java.awt.Color.
public void run(double runtime){
if(this.color == Color.GREEN){
if(time%greenLightDuration==0){
color = Color.YELLOW;
}
}
if(this.color == Color.YELLOW){
if(time%yellowLightDuration == 0){
color = Color.RED;
}
}
else
color = Color.GREEN;
}
Tried this but the three colors are blinking furiously. I set green to 200 and yellow to 40.
Since this is a cycle, you want to get the current phase of the cycle using the modulus operator. Something like: double phase = (runTime - startTime) % (greenDuration + yellowDuration + redDuration). You can take the modulus of a floating-point number in Java.
the three colors are blinking furiously.
The first/main cause of this is the simulator/model, and not necessarily the traffic light (though your traffic light my still be a problem). The issue is that your current model for time is just some sketchy for-loop, which will run however fast it runs... and it clearly runs a lot faster than your eyes would like.
What you can do is attempt to control the time in your simulation, using Thread.sleep() to delay the program momentarily. The following version will run an iteration roughly once per millisecond...
//Run method for agents in Model
public void run(double duration) {
if (disposed)
throw new IllegalStateException();
for (int i=0; i<duration; i++) {
time++;
try{ Thread.sleep(1); } //wait 1ms
catch(Exception e){} //just resume after interruption
for (Agent a : agents.toArray(new Agent[0])) {
a.run(time);
}
super.setChanged();
super.notifyObservers();
}
}
Now a duration of 300 for green lights takes roughly 0.3 seconds, which is brisk but not unobservable.

Categories