How to create an update function for multiple ImageViews? - java

I'm trying to create an update function for multiple ImageView's but kept running into issues. I'm currently passing an individual ImageView to the updateBlobPosition function inside a timer, which works fine for one ImageView. But as soon I pass a second ImageView (blob2), now both ImageViews mimic each other as they have the same trajectory and velocity.
In addition, when one ImageView hits a wall and bounces back, the other one does the same. What I want is for each ImageView to be independent of each other. Any help would be appreciated.
...
blob1.setX(generateRandomNumber(0, 930));
blob1.setY(generateRandomNumber(0, 1750));
blob2.setX(generateRandomNumber(0, 930));
blob2.setY(generateRandomNumber(0, 1750));
...
//start the timer
timer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(new Runnable() {
#Override
public void run() {
playerMovement();
updateBlobPosition(blob1);
updateBlobPosition(blob2);
collision(blob1);
collision(blob2);
}
});
}
}, 0, 20);
...
protected ImageView updateBlobPosition(ImageView blob) {
blobX = blob.getX();
blobY = blob.getY();
blobX += blobVelocityX;
blobY += blobVelocityY;
//left
if ((blob.getX() + blobVelocityX < 0)) {
blobVelocityX = -blobVelocityX;
}
//right
else if (blob.getX() - blobVelocityX > 930) {
blobVelocityX = -Math.abs(blobVelocityX);
}
//top
if ((blob.getY() + blobVelocityY < -20)) {
blobVelocityY = -blobVelocityY;
}
//bottom
else if (blob.getY() - blobVelocityY > 1750) {
blobVelocityY = -Math.abs(blobVelocityY);
}
blob.setX(blobX);
blob.setY(blobY);
return blob;
}

You're using the same velocity variables for both. So of course they be updated in the same way. If you want them to move independently, give them independent speeds.

Related

How can I get specific fields from an AnimationTimer object?

I've written a simple game using JavaFX for the GUI and AnimationTimer for the game itself, but I've found that any fields that update within the AnimationTimer object can't be found outside of the object. I've managed to continuously record how long a game runs, and the score of that game, but can't find a way to get these values out of the AnimationTimer object so I can add them to my GUI.
I've already tried java.lang.Reflect, but I can't seem to get it to work.
AnimationTimer animations = new AnimationTimer() //creates animations
{
#Override
public void handle(long now)
{
//update frames
if(jump == 0) //moves the player model to the starting position
{
playerY = 160;
}
else if(jump == 1) //moves the player model up (jumping)
{
playerY = 100;
}
if(shout == 1) //makes player immune while "shouting"
{
player.setFill(Color.GREEN);
}
if(shout == 0) //makes player not immune anymore
player.setFill(Color.BLUE);
if(obstacleX == PLAYER_X) //updates the score
{
points += 10;
score.setText("Score: " + String.valueOf(points));
}
if(player.getBoundsInParent().intersects(obstacle.getBoundsInParent())) //detects if the player model touches an obstacles
{
if(obstacle.getEndY() == 0)
{
if(player.getFill() == Color.BLUE)
player.setFill(Color.RED);
}
else if(obstacle.getEndY() == 130)
player.setFill(Color.RED);
}
if(obstacleX > 0) //moves the obstacles' reference point from the right to the left
obstacleX -= 5;
if(obstacleX == 0)
{
obstacleX = 400;
int[] array = new int[]{0, 0, 130};
Random randomNum = new Random();
int i = randomNum.nextInt(array.length);
random = array[i];
obstacle.setEndY(random);
}
//render frames
player.setCenterY(playerY);
obstacle.setStartX(obstacleX); //this and line 110 move the obstacle across the scene
obstacle.setEndX(obstacleX);
try{ //exception handler for outputs
if(player.getFill() == Color.GREEN)
{
digitalOutput6.setDutyCycle(1); //turns on green LED
digitalOutput0.setDutyCycle(0);
}
if(player.getFill() == Color.BLUE)
{
digitalOutput6.setDutyCycle(0); //turns off LEDs
digitalOutput0.setDutyCycle(0);
}
if(player.getFill() == Color.RED) //stops the animation when the player model reacts to touching an obstacle
{
endTime = System.currentTimeMillis() - startTime;
finalScore = score.getText();
this.stop(); //ends game
gameOver = 1;
digitalOutput0.setDutyCycle(1); //turns on red LED
digitalOutput6.setDutyCycle(0);
gameStage.setScene(gameEnd); //establishing scene
gameStage.setTitle("Game Over");
gameStage.show();
}
} //end of try block
catch(PhidgetException e)
{
System.out.println("Phidget Output Error");
}
} //end of animation handle itself
}; //end of animation method
I tried using
long finalTime = animations.getLong(endTime);
and
String endScore = animations.getField(finalScore);
But no luck. Any help appreciated.
AnimationTimer itself doesn't expose any attributes, make a custom class which wraps an AnimationTimer object in it, and save any attributes you want to access.
When you initialize the custom class, initialize the AnimationTimer object and override the function (as what you've done), also updates whatever attributes you want to expose.
I am not familiar with javafx, there might be other better ways, this is the one quick solution I can think of.
Did a quick search, these examples might be helpful:
https://netopyr.com/2012/06/14/using-the-javafx-animationtimer/
https://tbeernot.wordpress.com/2011/11/12/javafx-2-0-bubblemark/
First of all do not use Reflections on Anonymous classes It will work but will cause a lot of ineffeciency and dirty code.
Second of all, you try to acces fields which are in the Methodscope of
handle(long now) not in the Class scope.
AnimationTimer t = new AnimationTimer() {
int fieldInt = 0; // would be accessible
#Override
public void handle(long now) {
//do something
}
};
AnimationTimer t = new AnimationTimer() {
#Override
public void handle(long now) {
int fieldInt = 0; // is not accessible as regular field
//do something
}
};
What you can do is the following:
Use a class that extends a Animationtimer
public class Scheduler extends AnimationTimer{
private int gameEnd = 42;
private String someValue = "hello";
#Override
public void handle(long now) {
gameEnd += 1;
if(gameEnd >= 1000000) {
someValue ="Bye bye";
}
}
public String getSomeValue() {
return someValue;
}
here you can use:
Scheduler s = new Scheduler();
s.start();
//whatever you want to do
System.out.Println(s.getSomeValue());
or when you want to use the Anonymous class approach, you should create a Property that is outside of AnimationTimer and use it. (Wich is a thing that I would prefer, because you can have a changeListener on the Property and recieve a callback when the value is changed)
public void whateverMethod() {
SimpleIntegerProperty gameEndProp = new SimpleIntegerProperty(42);
AnimationTimer t = new AnimationTimer() {
#Override
public void handle(long now) {
gameEndProp.set(gameEndProp.get()+1);
}
};
t.start();
//Do something
System.out.println(gameEndProp.get());
}

Concurrent Modification Exception in Processing Sketch

I'm working on modifying the Attraction2D example from the Toxiclibs library to be controlled by gestures from a Leap Motion sensor, as opposed to the mouse in the example.
I'm doing all my gesture recognition in an Open Frameworks app, and sending that over OSC.
When a Gesture 0 event occurs, I call the method below to remove the gestureAttractor from the physics object:
void resetAttraction() {
  if (gestureAttractor != null){
      physics.removeBehavior(gestureAttractor);
      println("ATTRACTOR NULL");
     } else {
        println("not null");
     }
}
If a Gesture 1 event occurs, I call this method to create a new gestureAttractor, and add it back to the physics object:
void addAttraction(){
if (gestureAttractor == null) {
println("ATTRACTOR NULL");
position1.set(340, 191);
gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
physics.addBehavior(gestureAttractor);
} else {
println("not null");
}
}
What seems to happen consistently is whenever the gesture state changes, I'll get a ConcurrentModificationException crash at physics.update(); in the draw method.
I'm sure it has something to do with the way the lifecycle of these objects are handled, but I haven't been able to determine anything yet - anyone have any ideas?
Below is the entirety of the sketch:
import toxi.geom.*;
import toxi.physics2d.*;
import toxi.physics2d.behaviors.*;
import oscP5.*;
import netP5.*;
OscP5 oscP5;
int NUM_PARTICLES = 750;
VerletPhysics2D physics;
//AttractionBehavior2D mouseAttractor;
AttractionBehavior2D gestureAttractor;
//Vec2D mousePos;
Vec2D position1;
boolean isGestureAttractorAdded;
void setup() {
size(680, 382,P3D);
// setup physics with 10% drag
physics = new VerletPhysics2D();
physics.setDrag(0.05f);
physics.setWorldBounds(new Rect(0, 0, width, height));
// the NEW way to add gravity to the simulation, using behaviors
physics.addBehavior(new GravityBehavior2D(new Vec2D(0, 0.15f)));
// start oscP5, listening for incoming messages at port 12000
oscP5 = new OscP5(this, 6000);
position1 = new Vec2D(340, 191);
addAttraction();
//gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
//physics.addBehavior(gestureAttractor);
}
void addParticle() {
VerletParticle2D p = new VerletParticle2D(Vec2D.randomVector().scale(5).addSelf(width / 2, 0));
physics.addParticle(p);
// add a negative attraction force field around the new particle
physics.addBehavior(new AttractionBehavior2D(p, 20, -1.2f, 0.01f));
}
void draw() {
background(255,0,0);
noStroke();
fill(255);
if (physics.particles.size() < NUM_PARTICLES) {
addParticle();
}
physics.update();
for (VerletParticle2D p : physics.particles) {
ellipse(p.x, p.y, 5, 5);
}
}
void mousePressed() {
//position1 = new Vec2D(mouseX, mouseY);
//create a new positive attraction force field around the mouse position (radius=250px)
//gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
//physics.addBehavior(gestureAttractor);
//println(physics.behaviors);
}
void mouseDragged() {
// update mouse attraction focal point
//position1.set(mouseX, mouseY);
}
void mouseReleased() {
// remove the mouse attraction when button has been released
//physics.removeBehavior(gestureAttractor);
}
///// OSC RECEIVING
void oscEvent(OscMessage theOscMessage) {
/* check if theOscMessage has the address pattern we are looking for. */
if (theOscMessage.checkAddrPattern("/gesture_classification") == true) {
/* check if the typetag is the right one. */
if(theOscMessage.checkTypetag("i")) {
/* parse theOscMessage and extract the values from the osc message arguments. */
int gestureClassLabel = theOscMessage.get(0).intValue();
println(" Gesture is: ", gestureClassLabel);
if (gestureClassLabel == 0){
resetAttraction();
} else if (gestureClassLabel == 1) {
addAttraction();
} else if (gestureClassLabel == 2) {
//physics.removeBehavior(gestureAttractor);
}
}
}
}
//////METHODS FOR SETTING POSITION / REMOVAL OF ATTRACTORS...
void resetAttraction() {
if (gestureAttractor != null){
physics.removeBehavior(gestureAttractor);
println("ATTRACTOR NULL");
} else {
println("not null");
}
}
void addAttraction(){
if (gestureAttractor == null) {
println("ATTRACTOR NULL");
position1.set(340, 191);
gestureAttractor = new AttractionBehavior2D(position1, 250, 0.9f);
physics.addBehavior(gestureAttractor);
} else {
println("not null");
}
}
tl;dr: You shouldn't modify a data structure with one thread while you're iterating over it from another thread.
The draw() function is happening on one thread, and it's accessing and modifying data structures inside the physics library.
The oscEvent() function is happening on another thread, and it's also accessing and modifying those same data structures. That's what's causing your error. And please note that wrapping it in a try block is not fixing anything. It's just printing out more information when the error does happen.
To really fix the problem, you need to read up on synchornizing data access between threads. For example, you could use synchronized blocks to prevent different threads from accessing the same data structure. You'll find a ton of results if you google your error.

javaFX - creating smooth animation without creating a new Thread

I have a car in my javaFX project where the position of the car(Node) should change(the car should jump smoothly) when SPACE is pressed . so I have used an event handler which invokes a method named :moveUp()
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode())
{
case SPACE:
moveUp();
break;
}
}
});
This creates a new Thread where the speed of the car is changed 10 times with an interval of 75 milliseconds.
private void moveUp() {
new Thread(new Runnable() {
#Override
public void run() {
carSpeed = 10;
for(;carSpeed>=0;carSpeed--)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y-=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
for(carSpeed=0;carSpeed<=10;carSpeed++)
{
try {
Thread.currentThread().sleep(75);
} catch (InterruptedException e) {
e.printStackTrace();
}
carPosition_X+=carSpeed;
carPosition_Y+=carSpeed;
car.relocate(carPosition_X,carPosition_Y);
}
}
}).start();
}
This code is doing like this (pressing SPACE once and jumping the car):
If I don't use a different thread the GUI thread will be freeze and if I don't use Thread.sleep() the car will jump abruptly(not smoothly). This code is doing well . But I have learnt that thread.start() doesn't guarantee immediate execution of the thread. How can I guarantee immediate execution ?
I would suggest to stay in the FX Application Thread and to use the class AnimationTimer. Here is a short demo for a smooth jump:
private void moveUp() {
new AnimationTimer() {
long startTime = -1;
double initCarPosition_Y;
#Override
public void handle(long now) {
if(startTime == -1){
startTime = now;
initCarPosition_Y = carPosition_Y;
carSpeedX = 3d;
carSpeedY = -15d;
}
double time = (now - startTime) / 1E9d;
carPosition_X += carSpeedX * time;
carPosition_Y += carSpeedY * time;
if(carSpeed > 0 && initCarPosition_Y <= carPosition_Y){
carPosition_Y = initCarPosition_Y;
stop();
}
carSpeedY += 0.8d * time; //gravity
car.relocate(carPosition_X, carPosition_Y);
}
}.start();
}
This approach gives you full and direct control over what happens in every single frame. However, javaFX also provides high level animation classes including predefined interpolators and transitions. Suitable for alternative approaches could be the following classes:
PathTransition: Allows you to define points and curves which a given node is animated along.
TimeLine: Allows you to define arbitrary animation key frames based on properties like the position of a node.
Note that generally working with these high level classes could become challenging when you want to animate an user controlled actor like your car. These classes all take an exact duration for the animation to last. For example when you want to translate a node as long as a specific key is pressed, you don't know the duration of the animation in beforehand.

JavaFX - Calling GUI methods from a different thread

I am writing an application that maps eyetracking data to an image that is displayed to the user. To make sure the GUI doesn't freeze i do the eyetracking data polling, mapping and other calculations in a separate Task.
The problem i am facing is, that for mapping screen coordinates to my displayed image, i have to call Node.screenToLocal(x,y). How can i make these calls without violating thread-safety?
Use a AnimationTimer to do this call:
Task<Point2D> task = new Task<Point2D>() {
#Override
protected Point2D call() throws Exception {
while (!isCancelled()) {
Point2D eyePos = getEyePos();
updateValue(eyePos);
}
}
};
AnimationTimer animation = new AnimationTimer() {
#Override
public void handle(long now) {
Point2D point = task.getValue();
if (value != null) {
Point2D pointOnScreen = node.screenToLocal(point);
// TODO: use result
}
}
};
animation.play();

Andengine TimerHandler and detecting collisions

I'm developing a game where LittleMan can move from block to block, and certain blocks are moving. I'm trying to detect when he moves to a new moving block, if that block is beneath him or if it has moved. I'm using Andengine's TimerHandler to check every 0.1 seconds but it is not working. Here's the code:
private void OnMovingBlock(final int CurrentPosRow, final int CurrentPosColumn) {
this.getEngine().registerUpdateHandler(new TimerHandler(0.1f, true, new ITimerCallback() {
#Override
public void onTimePassed(final TimerHandler pTimerHandler) {
if (LittleManPos[0] == CurrentPosRow && LittleManPos[1] == CurrentPosColumn) {
if (!LittleMan.collidesWith(MapRectangles[CurrentPosRow][CurrentPosColumn])) {
RestartScene();
}
}
}
}));
}
It seems he can move to the block and sit there with it moving in and out beneath him but it doesn't call RestartScene() UNTIL I move him again. Any idea where I am going wrong? Or is there another way to do this?
Why don't create a Timer?
TimerTask task = new TimerTask(){
#Override
public void run(){
// your code goes here
}
};
Timer timer = new Timer();
timer.sechedule(task, 0, 100); // 100 --> 0.1 second
To cancel the Timer, call timer.cancel();.

Categories

Resources