Why Image() moved on screen, jump to default position , every click on screen , and start moving from default position? - animation

I have simple demo project. Image moved along screen follow mouse point.
LibGDX Image instance jump to default x coordinate along x axis, determined inside MainMenuScreen.kt show method, every time i click on screen, and start from default position moving. But i expect Image will continue/start new moving from last position before click on screen. How fix it, and what problem?
Code is simple and short, and i can't understand what can be wrong.
pastebin link to full project code:
https://pastebin.com/4UQDjSWa
github link to project:
https://github.com/3dformortals/demo-libgdx/tree/master/DemoMovingImageOnScreen
full project code:
//-------
//KDA.kt
//-------
package com.kda
import com.badlogic.gdx.Game
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.GL20
import gui.AnimationSkin as AniSkin
class KDA : Game() {
internal var screenWidth:Float = 0.0f
internal var screenHeight:Float = 0.0f
internal val aniskin:AniSkin = AniSkin() //incuded human.atlas TextureAtlas for animation
override fun create() {
screenWidth = Gdx.graphics.width.toFloat()
screenHeight = Gdx.graphics.height.toFloat()
aniskin.prepare() //call preparing method for connect human.atlas for later using for animation
}
override fun render() {
Gdx.gl.glClearColor(1f, 0f, 0f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
if (Gdx.input.justTouched()){
setScreen(MainMenuScreen(this))
}
super.render()
}
}
//-------------------
//AnimationSkin.kt
//-------------------
package gui
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.graphics.g2d.TextureAtlas
import com.badlogic.gdx.scenes.scene2d.ui.Skin
class AnimationSkin : Skin() {
fun prepare(){
addRegions(TextureAtlas(Gdx.files.internal("animation/human.atlas")))
}
}
//----------------------
//MainMenuScreen.kt
//----------------------
package com.kda
import animated.ImageMoving
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.ScreenAdapter
import com.badlogic.gdx.graphics.GL20
import com.badlogic.gdx.scenes.scene2d.Stage
import com.badlogic.gdx.utils.viewport.FitViewport
class MainMenuScreen(private val game: KDA) : ScreenAdapter() {
private val stage: Stage = Stage(FitViewport(game.screenWidth, game.screenHeight))
private val player = ImageMoving(game)
private val sprite = player.viewBox()
override fun show() {
Gdx.input.inputProcessor = stage
stage.isDebugAll = true //turn on frames around objects
sprite.x = 500f
//------------------------------------------------------------------------------------
//later, every mouse click on screen sprite jump to x500 position, and i can't fix it
//if i don't execute `sprite.x = 500f` , then sprite jump to x0 position, every click on screen
//--------------------------------------------------------------------------------------------
stage.addActor(sprite)
}
override fun resize(width: Int, height: Int) {
stage.viewport.update(width, height, true)
}
override fun render(delta: Float) {
super.render(delta)
Gdx.gl.glClearColor(0f, 0.5f, 0.5f, 1f)
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT)
if(Gdx.input.justTouched()) println("before calculateAction box.x= "+sprite.x.toString()) //500 always
player.calculateAction(delta) //call player method for calculation moving on screen
println(sprite.x) //print normal as expected
stage.act(delta)
stage.draw()
}
}
//-----------------
//ImageMoving.kt
//-----------------
package animated
import com.badlogic.gdx.Gdx
import com.badlogic.gdx.scenes.scene2d.ui.Image
import com.kda.KDA
class ImageMoving(game: KDA) {
fun viewBox() = img
private val img = Image(game.aniskin.getDrawable("move-skin-male-back-R-0"))
fun calculateAction(delta:Float){
if (img.x > Gdx.input.x) img.x-=(100*delta).toInt().toFloat()
else if (img.x < Gdx.input.x) img.x+=(100*delta).toInt().toFloat()
}
}
//----------------------
//DesktopLauncher.kt
//---------------------
package com.kda.desktop
import com.badlogic.gdx.backends.lwjgl.LwjglApplication
import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration
import com.kda.KDA
object DesktopLauncher {
#JvmStatic
fun main(arg: Array<String>) {
val config = LwjglApplicationConfiguration()
config.height = 720
config.width = 1280
LwjglApplication(KDA(), config)
}
}
gif animation demo of jumping image to default position x=500 after clicking on screen

Related

JavaFX Media Player - Binding Progress bar with Media Player (Mac m1 Silicon)

I want to update Progress Bar with Media Player Playing. But, after start playing my progressBar fill 100% within one second while the media is 15 seconds - 5 minutes long. I can't figure out the cause.
My codes are as follows:
public static ProgressBar progress = new ProgressBar();
ObjectBinding<TimeElapsed> elapsedBinding =createElapsedBindingByBindingsAPI(player);
DoubleBinding elapsedDoubleBinding =createDoubleBindingByBindingsAPI(elapsedBinding);
progress.progressProperty().bind(elapsedDoubleBinding);
And The methods are :
public static #NotNull ObjectBinding<TimeElapsed> createElapsedBindingByBindingsAPI(
final #NotNull MediaPlayer player
) {
return Bindings.createObjectBinding(
new Callable<TimeElapsed>() {
#Override
public TimeElapsed call() throws Exception {
return new TimeElapsed(player.getCurrentTime());
}
},
player.currentTimeProperty()
);
}
public static #NotNull DoubleBinding createDoubleBindingByBindingsAPI(
final ObjectBinding<TimeElapsed> elapsedBinding
) {
return Bindings.createDoubleBinding(
new Callable<Double>() {
#Override
public Double call() throws Exception {
return elapsedBinding.getValue().getElapsed();
}
},
elapsedBinding
);
}
And the TimeElapsed class :
static class TimeElapsed {
private final double elapsed;
TimeElapsed(#NotNull Duration duration) {
elapsed = duration.toSeconds();
}
public double getElapsed() {
return elapsed;
}
}
So, what's the code changes that 1) update the progressBar with Playing, and 2) seek the song with progress bar clicked or dragged?
The progress of a ProgressBar should be, when determinate, between the values of 0.0 and 1.0 (inclusive). This means you should be dividing the current time by the total duration to get the progress and bind the progress property of the bar to that value. Note that the duration of a Media is observable and is pretty much guaranteed to be set some time after it was instantiated.
As for being able to seek when the progress bar is clicked or dragged, the simplest way—which is what I show in the example below—is to add a MOUSE_CLICKED and a MOUSE_DRAGGED handler to the progress bar, determine the ratio between the mouse's x position and the bar's width, and then seek the calculated time. Unfortunately, this setup may not exactly match up with the visuals of the progress bar because the actual "bar" is smaller than the entire space taken up by the node (at least with default styling). You would probably have to create your own control if you want "pixel perfect" behavior.
Here is a minimal example demonstrating what's discussed above:
import java.util.Optional;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.StackPane;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.MediaView;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Main extends Application {
#Override
public void start(Stage primaryStage) {
var mediaView = new MediaView();
var progressBar = new ProgressBar();
progressBar.setMaxWidth(Double.MAX_VALUE);
StackPane.setAlignment(progressBar, Pos.BOTTOM_CENTER);
StackPane.setMargin(progressBar, new Insets(10));
var root = new StackPane(mediaView, progressBar);
primaryStage.setScene(new Scene(root, 1000, 650));
primaryStage.setTitle("Video Progress Demo");
primaryStage.show();
chooseMediaFile(primaryStage)
.ifPresentOrElse(
uri -> {
var media = new Media(uri);
var mediaPlayer = new MediaPlayer(media);
mediaPlayer.setAutoPlay(true);
mediaView.setMediaPlayer(mediaPlayer);
bindProgress(mediaPlayer, progressBar);
addSeekBehavior(mediaPlayer, progressBar);
},
Platform::exit);
}
private void bindProgress(MediaPlayer player, ProgressBar bar) {
var binding =
Bindings.createDoubleBinding(
() -> {
var currentTime = player.getCurrentTime();
var duration = player.getMedia().getDuration();
if (isValidDuration(currentTime) && isValidDuration(duration)) {
return currentTime.toMillis() / duration.toMillis();
}
return ProgressBar.INDETERMINATE_PROGRESS;
},
player.currentTimeProperty(),
player.getMedia().durationProperty());
bar.progressProperty().bind(binding);
}
private void addSeekBehavior(MediaPlayer player, ProgressBar bar) {
EventHandler<MouseEvent> onClickAndOnDragHandler =
e -> {
var duration = player.getMedia().getDuration();
if (isValidDuration(duration)) {
var seekTime = duration.multiply(e.getX() / bar.getWidth());
player.seek(seekTime);
e.consume();
}
};
bar.addEventHandler(MouseEvent.MOUSE_CLICKED, onClickAndOnDragHandler);
bar.addEventHandler(MouseEvent.MOUSE_DRAGGED, onClickAndOnDragHandler);
}
private boolean isValidDuration(Duration d) {
return d != null && !d.isIndefinite() && !d.isUnknown();
}
private Optional<String> chooseMediaFile(Stage owner) {
var chooser = new FileChooser();
chooser
.getExtensionFilters()
.add(new FileChooser.ExtensionFilter("Media Files", "*.mp4", "*.mp3", "*.wav"));
var file = chooser.showOpenDialog(owner);
return Optional.ofNullable(file).map(f -> f.toPath().toUri().toString());
}
}

How to animate several nodes with pause between each one?

I am trying to animate a series of nodes one after the other in a loop. The goal is to have the first node begin its animation, followed by a short pause before the next node begins to animate.
However, when running this within a loop, it executes too fast and all nodes appear to be animating at the same time.
For simplicity, I am using the AnimateFX library to handle the animations, but I assume the functionality needed here would apply in other situations?
How would I add a pause between each of the HBox animations?
import animatefx.animation.Bounce;
import javafx.application.Application;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class AnimationTest extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
final VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
final HBox tiles = new HBox(5);
tiles.setAlignment(Pos.CENTER);
// Create 5 tiles
for (int i = 0; i < 5; i++) {
HBox tile = new HBox();
tile.setPrefSize(50, 50);
tile.setStyle("-fx-border-color: black; -fx-background-color: lightblue");
tiles.getChildren().add(tile);
}
Button button = new Button("Animate");
button.setOnAction(event -> {
// Animate each tile, one at a time
for (Node child : tiles.getChildren()) {
Bounce animation = new Bounce(child);
animation.play();
}
});
root.getChildren().add(tiles);
root.getChildren().add(button);
primaryStage.setWidth(500);
primaryStage.setHeight(200);
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
}
I don't know AnimateFX, but using the standard libraries you can add animations to a SequentialTransition.
For example, to animate each node but starting at a later time, add PauseTransitions of increasing duration and the desired animation to SequentialTransitions, and play the SequentialTransitions.
As I said, I'm not familiar with the library you're using, but I think it would look like this:
Button button = new Button("Animate");
button.setOnAction(event -> {
Duration offset = Duration.millis(500);
Duration start = new Duration();
// Animate each tile, one at a time
for (Node child : tiles.getChildren()) {
Bounce bounce = new Bounce(child);
PauseTransition delay = new PauseTransition(start);
SequentialTransition animation = new SequentialTransition(delay, bounce.getTimeline());
animation.play();
start = start.add(offset);
}
});

Haxe Type Not Found

I'm trying to run the most basic Haxe program but keep getting errors.
The Main.hx file looks like this:
package;
import flash.display.Sprite;
import flash.display.StageAlign;
import flash.display.StageScaleMode;
import flash.events.Event;
import flash.Lib;
import flixel.FlxGame;
import flixel.FlxState;
class Main extends Sprite {
var gameWidth:Int = 640; // Width of the game in pixels (might be less / more in actual pixels depending on your zoom).
var gameHeight:Int = 480; // Height of the game in pixels (might be less / more in actual pixels depending on your zoom).
var initialState:Class<FlxState> = MenuState; // The FlxState the game starts with.
var zoom:Float = -1; // If -1, zoom is automatically calculated to fit the window dimensions.
var framerate:Int = 60; // How many frames per second the game should run at.
var skipSplash:Bool = false; // Whether to skip the flixel splash screen that appears in release mode.
var startFullscreen:Bool = false; // Whether to start the game in fullscreen on desktop targets
// You can pretty much ignore everything from here on - your code should go in your states.
public static function main():Void
{
Lib.current.addChild(new Main());
}
public function new()
{
super();
if (stage != null)
{
init();
}
else
{
addEventListener(Event.ADDED_TO_STAGE, init);
}
}
private function init(?E:Event):Void
{
if (hasEventListener(Event.ADDED_TO_STAGE))
{
removeEventListener(Event.ADDED_TO_STAGE, init);
}
setupGame();
}
private function setupGame():Void
{
var stageWidth:Int = Lib.current.stage.stageWidth;
var stageHeight:Int = Lib.current.stage.stageHeight;
if (zoom == -1)
{
var ratioX:Float = stageWidth / gameWidth;
var ratioY:Float = stageHeight / gameHeight;
zoom = Math.min(ratioX, ratioY);
gameWidth = Math.ceil(stageWidth / zoom);
gameHeight = Math.ceil(stageHeight / zoom);
}
addChild(new FlxGame(gameWidth, gameHeight, initialState, zoom, framerate, framerate, skipSplash, startFullscreen));
}
}
Just the generic template file. When I run it in Terminal (running Mac OS X El Capitan), I get this error:
Main.hx:8: characters 7-21 : Type not found : flixel.FlxGame
Haven't had problems with the installations or anything and I am new to Haxe so I don't know where to start. Any ideas?
Thanks :)
Did you add the library when you try to run your game ?
You can do that by using the command line haxe -lib flixel -main Main ....
Or by writting an hxml file containing all your CLI arguments :
-lib flixel
-main Main
Update after #Gama11 comment :
HaxeFlixel used the OpenFL format for the compilation information (see http://www.openfl.org/documentation/projects/project-files/xml-format/).
So you should include include flixel library using : <haxelib name="flixel" />in your Project.xml file.

changing rate of Animation/Transition

I'm trying to do some basic animations, but am failing at the most simple things:
Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
Animation anim = new Timeline(new KeyFrame(Duration.seconds(30.0),
new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
rect.setOnMouseClicked(e -> {
if (anim.getStatus() == Status.RUNNING) {
anim.pause();
} else {
anim.setRate(Math.random() * 5.0);
anim.play();
System.out.println(anim.getRate());
}
});
The problem I am facing is that when I click the rectangle multiple times, the size will randomly jump around, instead of just changing the speed at which it drops. So for example, I let it run to about 50% size at speed ~2.5 and then stop it. When I start it up again, it will jump to a totally different size, smaller for a lower speed, bigger for a higher speed, so for example to ~20% for ~1.0 speed or ~80% for ~4.5 speed.
At first I thought animation was pre-calculated for the new speed and thus jumped to the position at which it would be, had it been played with the new speed from the beginning for the time that it was already playing before the pause, but it's bigger for a smaller speed, which doesn't really make sense then.
How do I change the speed/rate of an animation without having it jump around?
I think your diagnosis is correct: the current value is interpolated given the current time and current rate. If you decrease the rate without changing the current time, you are then earlier in the animation. Since the animation is shrinking this has the effect of making the rectangle bigger.
The easiest way is probably just to start a new animation each time:
import javafx.animation.Animation;
import javafx.animation.Animation.Status;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;
import javafx.util.Duration;
public class VariableRateAnimation extends Application {
private Animation anim ;
#Override
public void start(Stage primaryStage) {
Pane mainPane = new Pane();
Rectangle rect = new Rectangle(100.0, 10.0);
mainPane.getChildren().add(rect); //so the rectangle is on screen
rect.setOnMouseClicked(e -> {
if (anim != null && anim.getStatus() == Status.RUNNING) {
System.out.println("Paused (" + anim.getTotalDuration().subtract(anim.getCurrentTime())+ " remaining)");
anim.pause();
} else {
Duration duration = Duration.seconds(30.0 * rect.getWidth() / (100 * Math.random() * 5.0));
System.out.println("Starting: ("+duration+ " to go)");
double currentWidth = rect.getWidth() ;
if (anim != null) {
anim.stop();
}
anim = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rect.widthProperty(), currentWidth, Interpolator.LINEAR)),
new KeyFrame(duration, new KeyValue(rect.widthProperty(), 0.0, Interpolator.LINEAR)));
anim.play();
}
});
primaryStage.setScene(new Scene(mainPane, 600, 600));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

downsample bitmap image pixels actionscript 3?

I need to decrease the pixels in image from 480 X 480 to 30 X 30. This requires downsampling of pixels, i don't see any method to remove individual pixels in a bitmap image.
I need this downsampling because i'm studying distortion in image processing - on the brief side.
Any help in this would be appreciated.
package
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.net.URLRequest;
public class DownSampling extends Sprite
{
private var _loader : Loader;
public function DownSampling()
{
_loader = new Loader;
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImgLoaded);
// Get the bitmap
_loader.load(new URLRequest("https://appharbor.com/assets/images/stackoverflow-logo.png"));
}
private function onImgLoaded(e : Event) : void
{
var currentBitmapdata : BitmapData = Bitmap(_loader.content).bitmapData;
var i : uint = 9;
var downFactor : Number = 0.2;
// this will reduce size by 20%
var downMat : Matrix = new Matrix;
downMat.scale(1 - downFactor, 1 - downFactor);
while(--i)
{
// Create new bitmapdata but smaller
var smallerImg : BitmapData = new BitmapData(currentBitmapdata.width * (1-downFactor), currentBitmapdata.height * (1-downFactor), true, 0);
// Copy and apply scale
smallerImg.draw(currentBitmapdata, downMat);
// Add to stage and set alpha to 50%
addChild(new Bitmap(smallerImg)).alpha = .5;
// Apply the same transform next loop
currentBitmapdata = smallerImg;
}
}
}
}
Result :

Resources