How do I slow down an a sprite animation with processing java - 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.

Related

How to magnify display working with pixels[] in Processing (Java)?

I love experimenting with operating on images pixel by pixel using pixels[]. However, I’d like to work on a matrix of 100x100 pixels but have the display be several times larger than 100x100 on my screen.
Is there an efficient and straightforward way to zoom, magnify, scale, resize, or etc… to allow me to work with pixels[] just… bigger?
I was disappointed to see that scale() doesn’t work with pixel arrays.
My first idea to scale by a factor of S is by iterating through my pixel array and drawing a board of SxS rects with the fill of each pixel’s color val. However, this is computationally intensive, and I can’t get my frameRate above 5 or so.
Ah great idea #sorifiend. Since I was calling loadPixels() immediately after setting the window size() and leaving it blank (rather than loading pixels from a image and putting it in the window,) I hadn't thought of that. I found you can use createImage() to make an empty image, which resizes crisply with noSmooth(); on! Thanks for the start.
Here's my code for posterity:
void setup() {
i = createImage(100, 100, RGB);
background(0);
size(800, 800);
i.loadPixels();
noSmooth();
}
void draw() {
i.loadPixels();
for (int x = 0; x < i.width; x++) {
for (int y = 0; y < i.height; y++) {
if (random(0,max(i.width,i.height)) < y) {
i.pixels[x + y*i.height] = color(255);
} else {
i.pixels[x + y*i.height] = color(0);
}
}
}
i.updatePixels();
image(i,0,0,width,height);
}

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]);
}

Smoothly moving JLabel in a JFrame

I am trying to make a Slot Machine with a JFrame.
How do I move my JLabel with a smooth animation?
What I have tried is that I am increasing the delay in the loop with every round, but that is to slow.
It should move at the beginning very fast and getting at the end very slow.
Maybe anyone can help me to calculate the smooth better?
Here is my code of my Animation class extending Thread:
JLabel label; // thre Jlabel
int labelPosY, maxHeight; // label Y position and all Y positions in summary
Animate(JLabel label, int labelPosY, int maxHeight)
{
this.label = label;
this.labelPosY = labelPosY;
this.maxHeight = maxHeight; // for example: -6500
}
public void run()
{
int smooth; // smooth
for (int i = this.maxHeight; i <= 0; i++)
{
try
{
smooth = 100 - (Math.abs(i) / (Math.abs(this.maxHeight) / 100)); // getting percentage of whole moving process
Layout.setLabelPosY(this.label, this.labelPosY++); // changes Y position of JLabel
Thread.sleep(smooth); // waits the always changing process (1ms - 100ms)
}
catch (InterruptedException e) {e.printStackTrace();}
}
}
Image
Here's one way to create a slot machine GUI in Java Swing.
Download slot machine images, like this one. You can find many other images with Google.
Read the image file from a properties folder in your Java project into a BufferedImage.
Divide the BufferedImage into individual BufferedImages. With this image, that would be 9 individual BufferedImages.
Create a BufferedImage strip that's one image wide by nine images high.
Create the rotating image of a slot machine by animating the rotation of three or four copies of the BufferedImage strip. You draw this image on a JPanel in the JFrame.
Keep track of the money spent and winnings on a control JPanel in the JFrame. The spin JButton would also be placed on the control JPanel.

How to make it so an image disappears upon collision and then re-appears in a random spot on the screen

I'm creating a game similar to Snake in which my Batman character image collides with the Joker character image and "catches" it. Once the first one disappears, another Joker pops up on the screen in a random spot for the Batman to chase after and then so and so forth.
I've made it so the first Joker disappears when my Batman character collides with it but I'm struggling to get a second Joker to pop on the screen. I'm not sure if a for loop would be best - but then how do I make it so only one Joker appears until Batman "catches" it and then the next can appear - or perhaps an if statement. Any help would be greatly appreciated because I'm feeling really stuck right now.
//loads music for background
import processing.sound.*;
SoundFile file;
String audioName = "dark_knight_rises.wav";
String path;
//loads gif library for background
import gifAnimation.*;
Gif myAnimation;
PImage batman; //pixel images
PImage joker; //pixel images
int batmanX = 100; //batman X position on screen
int batmanY = 100; //batman Y position on screen
int jokerX = 500; //joker X position on screen
int jokerY = 500; //joker Y position on screen
int batman1Size = 50; //for batman distance
int joker2Size = 50; //for joker distance
int width = 100; //width for characters
int height = 100; // height for characters
boolean showImage = true; // boolean to help joker disappear and reappear
int score = 0; // declaration for high score
void setup() {
size(1067, 800);
//plays background music
path = sketchPath(audioName);
file = new SoundFile(this, path);
file.play();
//loads background and pixel-style batman/joker
myAnimation = new Gif(this, "background.gif");
myAnimation.play();
batman = loadImage("pixelbatman.png");
joker = loadImage("pixeljoker.png");
}
void draw() {
image(myAnimation, 0, 0); //lays down gif background
//display the score
textSize(20);
text("Jokers caught:", 900, 40);
text(score, 1045, 40);
image(batman, batmanX, batmanY, width, height); //places Batman character on screen
//pixel batman movement
if (keyPressed) {
if (key == CODED) {
if (keyCode == UP) batmanY--;
if (keyCode == RIGHT) batmanX++;
if (keyCode == DOWN) batmanY++;
if (keyCode == LEFT) batmanX--;
}
} //end of pixel batman movement
if (showImage) image(joker, jokerX, jokerY, width, height); //if Boolean is true, place Joker character on screen
if (dist(batmanX, batmanY, jokerX, jokerY) < (batman1Size + joker2Size)/10 ) { //if batman and joker collide - joker disappears
showImage = false;
score += 1; //increase the score by 1 when batman eats a joker
// idea is that the first joker disappears and another pops up in a random position
if (showImage == false) {
image(joker, random(jokerX, 0), random(0, jokerY), width, height);
}
} // end of what happens if batman and joker collide
} // end of void draw
The answer is easier than you think. In fact, you already did most of the job, you just need a rubber duck.
I'll take that job.
In the draw() function, you do a lot of things. When you have free time, I suggest you break these down a little bit. draw() is the main loop in processing, and as such it'll always tend to be clogged with code. When you do this, aim to have an easily understandable loop, something like this:
void draw() {
drawBackground();
manageInput();
collisions();
drawCharacters();
}
Now, to the matter which interests you:
What you're doing good:
you use clear nomenclature (your naming convention makes things easy to read, a mistake beginners do is to shorten variables names because they know what they are speaking about, then it confuses everybody else including themselves later on)
great job overall with being able to add stuff like gif and sounds!
What we're going to do to achieve the joker thing:
Get rid of the showImage variable. I get what you're doing here, and it was a good idea, but we won't need it.
In the If where you check for a collision, right where you wrote showImage = false, instead we'll update the joker's coordinates:
Like this (I randomized it, but now that you get the idea you can custom this):
jokerX = (int)random(width);
jokerY = (int)random(height);
Delete the if (showImage == false).
Aaand... there you go! If you read well, you'll notice that your mistake wat that, in the if (showImage == false) part, you "teleported" the joker without actually changing his coordinated.
I'll stick around in case you have questions. Have fun!

Drawing list of animated bitmaps

So I've got this nice Android game (a snake-clone with animations), doing the final testing, when BAM! My second testing device (Nexus 1, HTC Magic was my 1.) flickers when drawing.
Does anyone know why this code won't work correctly with the Nexus 1?
public void draw(Canvas canv) {
int count = 0;
isHead = false;
for (int i = 0; i < SPACES; i++) {
if (mDrawSpaces[i]) {
count++;
if (count == SPACES - 1) {
setDrawSpacesToFalse();
if (bmp != null)
super.drawPlaceable(canv);
}
} else {
mDrawSpaces[i] = true;
return;
}
}
}
I have a list of Birds (Birds / UFOs / others) with SPACES (4) times as many elements which are being drawn on the screen. So I thought to myself, instead of calculating the rotation and scale of the pictures for every Bird, I merely have 3 placeholders between the Birds which each have a picture to be drawn once they're set to visible. These pictures are generated by the first Bird:
public void drawHead(Canvas canv) {
//calculate the rotation & mirroring of the picture
super.drawPlaceable(canv);
//generate the pics for smaller birds following it
mat.preScale((float) 0.6, (float) 0.6);
this.bmp = Bitmap.createBitmap(SPRITESHEET, Bird.mCurFrame
* BIG_W[mUseBird], 0, BIG_W[mUseBird], BIG_H[mUseBird],
mat, true);
}
Any ideas? Is my draw(Canvas) method wrong in some part?
EDIT: I don't know why, I don't know how, but this afternoon when I tested it again, it magically worked...
I can see you are using matrix to scale - another option would be to use
canvas.DrawBitmap(spriteSheet, fromRect, toRect, paint);
Where toRect should be a Rect class of any size, in this way you would create no bitmap objects when drawing game frames. The piant should have filter bitmap enabled.
To rotate you would have to use:
canvas.save();
canvas.rotate(spriteAngle,spriteCenterX, spriteCenterY);
canvas.DrawBitmap(spriteSheet, fromRect, toRect, paint);
canvas.restore();
This is a fast enough code for many 2D games, though not as fast and powerful as OpenGL.

Categories