create a polyline in gluon mapLayer - javafx

Google maps API makes it possible to create a layer on the map containing a polyline linking points together.
I have searched where I could to find an example or an implementation for this for gluon's mapLayer.
Please advice

While there's no explicit API for drawing lines, polylines or polygons on top of a MapView, the MapLayer is a layer where you can draw any JavaFX Shape, providing you take care of scaling it to the map coordinates.
For that, if you have a look at the PoiLayer class, you can see that for any MapPoint (defined by latitude and longitude) you can get a 2D point (defined by x and y), and you can draw a node at that position:
MapPoint point = new MapPoint(37.396256,-121.953847);
Node icon = new Circle(5, Color.BLUE);
Point2D mapPoint = baseMap.getMapPoint(point.getLatitude(), point.getLongitude());
icon.setTranslateX(mapPoint.getX());
icon.setTranslateY(mapPoint.getY());
So if you want to create, for instance, a Polygon based on a set of points, you have to add a Polygon object to the layer:
public class PoiLayer extends MapLayer {
private final Polygon polygon;
public PoiLayer() {
polygon = new Polygon();
polygon.setStroke(Color.RED);
polygon.setFill(Color.rgb(255, 0, 0, 0.5));
this.getChildren().add(polygon);
}
#Override
protected void layoutLayer() {
polygon.getPoints().clear();
for (Pair<MapPoint, Node> candidate : points) {
MapPoint point = candidate.getKey();
Node icon = candidate.getValue();
Point2D mapPoint = baseMap.getMapPoint(point.getLatitude(), point.getLongitude());
icon.setTranslateX(mapPoint.getX());
icon.setTranslateY(mapPoint.getY());
polygon.getPoints().addAll(mapPoint.getX(), mapPoint.getY());
}
}
}
Now, on the demo class, create a set of mapPoints, and add them to the map:
private final List<MapPoint> polPoints = Arrays.asList(
new MapPoint(37.887242, -122.178799), new MapPoint(37.738729, -121.921567),
new MapPoint(37.441704, -121.921567), new MapPoint(37.293191, -122.178799),
new MapPoint(37.441704, -122.436031), new MapPoint(37.738729, -122.436031));
private MapLayer myDemoLayer () {
PoiLayer poi = new PoiLayer();
for (MapPoint mapPoint : polPoints) {
poi.addPoint(mapPoint, new Circle(5, Color.BLUE));
}
return poi;
}
And you will have a map with your geo-located polygon on top of it.

Related

Preventing overlapping shapes while dragging on a Pane

I've looked at similar questions but they all are concerned with collision detection rather than preventing overlap. I've gotten most of it to work with the below code:
private final EventHandler<MouseEvent> onPress = mouseEvent -> {
xDrag = this.getCenterX() - mouseEvent.getX();
yDrag = this.getCenterY() - mouseEvent.getY();
};
private final EventHandler<MouseEvent> onDrag = mouseEvent -> {
for (Shape shape : getAllShapes()) {
if (!this.equals(shape)) {
Shape intersect = Shape.intersect(shape, this);
if (intersect.getLayoutBounds().getWidth() > 0) {
return;
}
}
}
this.setCenterX(mouseEvent.getX() + xDrag);
this.setCenterY(mouseEvent.getY() + yDrag);
};
However, the problem is, once there is a tiniest bit of overlap, the Shape is no longer draggable at all. Meaning, if I drag a shape to another, once they become essentially tangent, neither of them are draggable anymore. What I want to happen is just that, for example, if you try to drag a circle onto another, the circle won't follow the mouse position as long as the future position of the drag will cause an overlap.
I can't figure out exactly how to accomplish this.
EDIT: Minimum Reproducible Example:
Main.java
public class Main extends Application {
static Circle circle1 = new DraggableCircle(100, 200);
static Circle circle2 = new DraggableCircle(200, 300);
static Circle[] circleList = new Circle[]{circle1, circle2};
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Hello World");
Pane pane = new Pane();
primaryStage.setScene(new Scene(pane, 300, 275));
primaryStage.show();
pane.getChildren().addAll(circle1, circle2);
}
public static void main(String[] args) {
launch(args);
}
}
DraggableCircle.java
public class DraggableCircle extends Circle {
private double xDrag, yDrag;
public DraggableCircle(double x, double y) {
super(x, y, 30);
this.setFill(Color.WHITE);
this.setStroke(Color.BLACK);
this.setStrokeWidth(1.5);
this.addEventHandler(MouseEvent.MOUSE_PRESSED, onPress);
this.addEventHandler(MouseEvent.MOUSE_DRAGGED, onDrag);
}
private final EventHandler<MouseEvent> onPress = (mouseEvent) -> {
xDrag = this.getCenterX() - mouseEvent.getX();
yDrag = this.getCenterY() - mouseEvent.getY();
};
private final EventHandler<MouseEvent> onDrag = mouseEvent -> {
for (Shape shape : Main.circleList) {
if (!this.equals(shape)) {
Shape intersect = Shape.intersect(shape, this);
if (intersect.getLayoutBounds().getWidth() > 0) {
return;
}
}
}
this.setCenterX(mouseEvent.getX() + xDrag);
this.setCenterY(mouseEvent.getY() + yDrag);
};
}
This also has an issue where dragging too quickly causes a noticeable overlap between the circles, before the drag detection ends.
A simple (imperfect) solution
The following algorithm will allow a node to continue to be dragged after an intersection has occurred:
Record the current draggable shape position.
Set the new position.
Check the intersection.
If an intersection is detected, reset the position to the original position.
An implementation replaces the drag handler in the supplied minimal example code from the question.
private final EventHandler<MouseEvent> onDrag = (mouseEvent) -> {
double priorCenterX = getCenterX();
double priorCenterY = getCenterY();
this.setCenterX(mouseEvent.getX() + xDrag);
this.setCenterY(mouseEvent.getY() + yDrag);
for (Shape shape : Main.circleList) {
if (!this.equals(shape)) {
Shape intersect = Shape.intersect(shape, this);
if (intersect.getLayoutBounds().getWidth() > 0) {
this.setCenterX(priorCenterX);
this.setCenterY(priorCenterY);
return;
}
}
}
};
This handler does work better than what you had, it does at least allow you to continue dragging after the intersection.
But, yes, if you drag quickly it will leave a visible space between nodes when it has detected that the drag operation would cause an intersection, which isn't ideal.
Also, the additional requirement you added in your comment about having the dragged shape glide along a border would require a more sophisticated solution.
Other potential solutions
I don't offer code for these more sophisticated solutions here.
One potential brute force solution is to interpolate the prior center with the new center and then, in a loop, slowly move the dragged object along the interpolated line until an intersection is detected, then just back it out to the last interpolated value to prevent the intersection. You can do this by calculating and applying a normalized (1 unit distance) movement vector. That might fix space between intersected nodes.
Similarly to get the gliding, on the intersection, you could just update either the interpolated x or y value rather than both.
There may be more sophisticated methods with geometry math applied, especially if you know shape geometry along with movement vectors and surface normals.
+1 for #jewelsea answer.
On top of #jewelsea answer, I would like to provide a fix for the "space between nodes" issue.
So you might have already observed that when you drag fast, it will not cover each and every pixel in the drag path. It varies with the speed of the drag. So when you decide to move it to the previous recorded point, we will do a quick math, to see if there is any gap between the two nodes, if yes:
We will do a math "to determine a point along a line which is at distance d" and move the drag circle to that point. Here..
start point of line is : previous recorded point
end point of line is : the intersected shape center
d is : the gap between the two shapes.
So the updated code to the #jewelsea answer is as below:
private final EventHandler<MouseEvent> onDrag = (mouseEvent) -> {
double priorCenterX = getCenterX();
double priorCenterY = getCenterY();
this.setCenterX(mouseEvent.getX() + xDrag);
this.setCenterY(mouseEvent.getY() + yDrag);
for (Circle shape : Main.circleList) {
if (!this.equals(shape)) {
Shape intersect = Shape.intersect(shape, this);
if (intersect.getLayoutBounds().getWidth() > 0) {
Point2D cx = new Point2D(priorCenterX, priorCenterY);
Point2D px = new Point2D(shape.getCenterX(), shape.getCenterY());
double d = cx.distance(px);
if (d > getRadius() + shape.getRadius()) {
cx = pointAtDistance(cx, px, d - getRadius() - shape.getRadius());
}
this.setCenterX(cx.getX());
this.setCenterY(cx.getY());
return;
}
}
}
};
private Point2D pointAtDistance(Point2D p1, Point2D p2, double distance) {
double lineLength = p1.distance(p2);
double t = distance / lineLength;
double dx = ((1 - t) * p1.getX()) + (t * p2.getX());
double dy = ((1 - t) * p1.getY()) + (t * p2.getY());
return new Point2D(dx, dy);
}

How to get 2D coordinates on window for 3D object in javafx

In javafx if we have 2D HUD (made of Pane and then out of it we create SubScene object for 2D Hud) and 3D SubScene and inside 3D scene we have some object with coordinates (x,y,z) - how can we get 2D coordinates in our HUD of the object if it is in visual field of our perspective camera?
I tried to get first Scene coordinates of the object and then convert it (sceneToScreen) coordinates and the same for point (0,0) of Pane and then to subtract first point from second point but i don't get right result. Sorry because of my bad English.Can Someone help with this?
There is a way to convert the 3D coordinates of an object in a subScene to a 2D scene coordinates, but unfortunately it uses private API, so it is advised not to rely on it.
The idea is based on how the camera projection works, and it is based on the com.sun.javafx.scene.input.InputEventUtils.recomputeCoordinates() method that is used typically for input events from a PickResult.
Let's say you have a node in a sub scene. For a given point of that node, you can obtain its coordinates like:
Point3D coordinates = node.localToScene(Point3D.ZERO);
and you can find out about the sub scene of the node:
SubScene subScene = NodeHelper.getSubScene(node);
Now you can use the SceneUtils::subSceneToScene method that
Translates point from inner subScene coordinates to scene coordinates.
to get a new set of coordinates, referenced to the scene:
coordinates = SceneUtils.subSceneToScene(subScene, coordinates);
But these are still 3D coordinates.
The final step to convert those to 2D is with the use of CameraHelper::project:
final Camera effectiveCamera = SceneHelper.getEffectiveCamera(node.getScene());
Point2D p2 = CameraHelper.project(effectiveCamera, coordinates);
The following sample places 2D labels in the scene, at the exact same position of the 8 vertices of a 3D box in a subScene.
private final Rotate rotateX = new Rotate(0, Rotate.X_AXIS);
private final Rotate rotateY = new Rotate(0, Rotate.Y_AXIS);
private double mousePosX;
private double mousePosY;
private double mouseOldX;
private double mouseOldY;
private Group root;
#Override
public void start(Stage primaryStage) {
Box box = new Box(150, 100, 50);
box.setDrawMode(DrawMode.LINE);
box.setCullFace(CullFace.NONE);
Group group = new Group(box);
PerspectiveCamera camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000.0);
camera.setFieldOfView(20);
camera.getTransforms().addAll (rotateX, rotateY, new Translate(0, 0, -500));
SubScene subScene = new SubScene(group, 500, 400, true, SceneAntialiasing.BALANCED);
subScene.setCamera(camera);
root = new Group(subScene);
Scene scene = new Scene(root, 500, 400);
primaryStage.setTitle("HUD: 2D Labels over 3D SubScene");
primaryStage.setScene(scene);
primaryStage.show();
updateLabels(box);
scene.setOnMousePressed(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
});
scene.setOnMouseDragged(event -> {
mousePosX = event.getSceneX();
mousePosY = event.getSceneY();
rotateX.setAngle(rotateX.getAngle() - (mousePosY - mouseOldY));
rotateY.setAngle(rotateY.getAngle() + (mousePosX - mouseOldX));
mouseOldX = mousePosX;
mouseOldY = mousePosY;
updateLabels(box);
});
}
private List<Point3D> generateDots(Node box) {
List<Point3D> vertices = new ArrayList<>();
Bounds bounds = box.getBoundsInLocal();
vertices.add(box.localToScene(new Point3D(bounds.getMinX(), bounds.getMinY(), bounds.getMinZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMinX(), bounds.getMinY(), bounds.getMaxZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMinX(), bounds.getMaxY(), bounds.getMinZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMinX(), bounds.getMaxY(), bounds.getMaxZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMaxX(), bounds.getMinY(), bounds.getMinZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMaxX(), bounds.getMinY(), bounds.getMaxZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMaxX(), bounds.getMaxY(), bounds.getMinZ())));
vertices.add(box.localToScene(new Point3D(bounds.getMaxX(), bounds.getMaxY(), bounds.getMaxZ())));
return vertices;
}
private void updateLabels(Node box) {
root.getChildren().removeIf(Label.class::isInstance);
SubScene oldSubScene = NodeHelper.getSubScene(box);
AtomicInteger counter = new AtomicInteger(1);
generateDots(box).stream()
.forEach(dot -> {
Point3D coordinates = SceneUtils.subSceneToScene(oldSubScene, dot);
Point2D p2 = CameraHelper.project(SceneHelper.getEffectiveCamera(box.getScene()), coordinates);
Label label = new Label("" + counter.getAndIncrement() + String.format(" (%.1f,%.1f)", p2.getX(), p2.getY()));
label.setStyle("-fx-font-size:1.3em; -fx-text-fill: blue;");
label.getTransforms().setAll(new Translate(p2.getX(), p2.getY()));
root.getChildren().add(label);
});
}
The FXyz3D library has another similar sample.
EDIT
A late edit of this answer, but it is worthwhile mentioning that there is no need for private API. There is public API in the Node::localToScene methods that allows traversing the subScene.
So this just works (note the true argument):
Point3D p2 = box.localToScene(dot, true);
According to the JavaDoc for Node::localToScene:
Transforms a point from the local coordinate space of this Node into the coordinate space of its scene. If the Node does not have any SubScene or rootScene is set to true, the result point is in Scene coordinates of the Node returned by getScene(). Otherwise, the subscene coordinates are used, which is equivalent to calling localToScene(Point3D).
Without true the conversion is within the subScene, but with it, the conversion goes from the current subScene to the scene. In this case, this methods calls SceneUtils::subSceneToScene, so we don't need to do it anymore.
With this, updateLabels gets simplified to:
private void updateLabels(Node box) {
root.getChildren().removeIf(Label.class::isInstance);
AtomicInteger counter = new AtomicInteger(1);
generateDots(box).stream()
.forEach(dot -> {
Point3D p2 = box.localToScene(dot, true);
Label label = new Label("" + counter.getAndIncrement() + String.format(" (%.1f,%.1f)", p2.getX(), p2.getY()));
label.setStyle("-fx-font-size:1.3em; -fx-text-fill: blue;");
label.getTransforms().setAll(new Translate(p2.getX(), p2.getY()));
root.getChildren().add(label);
});
}

Can I place 3D geometry objects in a JavaFXCollection?

I have a few 3D geometrical objects like sphere, Tube, Cube etc. I am generating using usual way of using classes like Sphere, Cylinder,Box etc inside FXML based-menu in a FXMLcontroller. This means object box1 is local to #FXMLmakeCube sort of method.
Now I wish to perform few operations like boolean operation, copy, mirroring etc. in another method inside this controller. I want to keep all created geometries in JavaFXCollection sort of List so that I may call the handle to those geometries from inside any other method.
My question is how can I do this? How can I refer this handles in other method inside the same FXMLController?
I did not find exact question in the net.
You can place all those 3D objects in one collection, since all of them extend from Shape3D.
You can create an ObservableList<Shape3D> collection, and add each object to it when you create them. Then you can listen to changes in the collection, and add to the scene/subscene all the new objects.
This would be a sample of a controller with four buttons, where you can create random Box or Sphere 3D objects, add them to the collection, and place them in a subscene.
Also you can perform operations with the full collection (translate or rotate them in this case).
public class FXMLDocumentController {
#FXML
private Pane pane;
private Group pane3D;
private PerspectiveCamera camera;
private ObservableList<Shape3D> items;
#FXML
void createBox(ActionEvent event) {
Box box = new Box(new Random().nextInt(200), new Random().nextInt(200), new Random().nextInt(200));
box.setMaterial(new PhongMaterial(new Color(new Random().nextDouble(),
new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble())));
box.setTranslateX(-100 + new Random().nextInt(200));
box.setTranslateY(-100 + new Random().nextInt(200));
box.setTranslateZ(new Random().nextInt(200));
items.add(box);
}
#FXML
void createSphere(ActionEvent event) {
Sphere sphere = new Sphere(new Random().nextInt(100));
sphere.setMaterial(new PhongMaterial(new Color(new Random().nextDouble(),
new Random().nextDouble(), new Random().nextDouble(), new Random().nextDouble())));
sphere.setTranslateX(-100 + new Random().nextInt(200));
sphere.setTranslateY(-100 + new Random().nextInt(200));
sphere.setTranslateZ(new Random().nextInt(200));
items.add(sphere);
}
public void initialize() {
camera = new PerspectiveCamera(true);
camera.setNearClip(0.1);
camera.setFarClip(10000);
camera.setTranslateZ(-1000);
pane3D = new Group(camera);
SubScene subScene = new SubScene(pane3D, 400, 400, true, SceneAntialiasing.BALANCED);
subScene.setFill(Color.ROSYBROWN);
subScene.setCamera(camera);
pane.getChildren().add(subScene);
items = FXCollections.observableArrayList();
items.addListener((ListChangeListener.Change<? extends Shape3D> c) -> {
while (c.next()) {
if (c.wasAdded()) {
c.getAddedSubList().forEach(i -> pane3D.getChildren().add(i));
}
}
});
}
#FXML
void rotateAll(ActionEvent event) {
items.forEach(s -> {
s.setRotate(new Random().nextInt(360));
s.setRotationAxis(new Point3D(-100 + new Random().nextInt(200),
-100 + new Random().nextInt(200), new Random().nextInt(200)));
});
}
#FXML
void translateAll(ActionEvent event) {
items.forEach(s -> {
s.setTranslateX(-100 + new Random().nextInt(200));
s.setTranslateY(-100 + new Random().nextInt(200));
s.setTranslateZ(new Random().nextInt(200));
});
}
}

JavaFX material's bump and spec maps

When JavaFX8 code loads the color, bump and spec maps, the color and spec work as expected, but bump map is causing strange effects. All three are Mercator maps of Earth. Generally, there is no 3d effect added by the bump map. Bump map only causes Himalaya and Andes appear on the lit side of the globe as black areas with shiny border and on the shaded side as they appear on the color map. What am I doing wrong?
Image diffMap = null;
Image bumpMap = null;
Image specMap = null;
diffMap = new Image(MoleculeSampleApp.class.getResource("Color Map1.jpg").toExternalForm());
bumpMap = new Image(MoleculeSampleApp.class.getResource("Bump1.jpg").toExternalForm());
specMap = new Image(MoleculeSampleApp.class.getResource("Spec Mask1.png").toExternalForm());
final PhongMaterial earthMaterial = new PhongMaterial(Color.WHITE, diffMap, specMap, bumpMap, null);
earthMaterial.setDiffuseColor(Color.WHITE);
earthMaterial.setSpecularColor(Color.WHITE);
Being new to 3d my first thought is that there should be some kind of scaling pixel color values of the bump map into elevation, which I am missing.
Bump map for JavaFX is a normal map, not a height map, for more info see: normal map and height map info.
Here is a sample you can try.
The images for the maps are pretty large, so it might take a little while to download them before your scene shows.
Source I used for images was => Bored? Then Create a Planet (now a dead link).
import javafx.animation.*;
import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.image.Image;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.*;
import javafx.scene.shape.Sphere;
import javafx.scene.transform.Rotate;
import javafx.stage.Stage;
import javafx.util.Duration;
public class EarthViewer extends Application {
private static final double EARTH_RADIUS = 400;
private static final double VIEWPORT_SIZE = 800;
private static final double ROTATE_SECS = 30;
private static final double MAP_WIDTH = 4096;
private static final double MAP_HEIGHT = 2048;
private static final String DIFFUSE_MAP =
"https://imgur.com/vrNnXIs.jpeg";
private static final String NORMAL_MAP =
"https://imgur.com/5T2oAuk.jpeg";
private static final String SPECULAR_MAP =
"https://imgur.com/GV11WNV.jpeg";
private Group buildScene() {
Sphere earth = new Sphere(EARTH_RADIUS);
earth.setTranslateX(VIEWPORT_SIZE / 2d);
earth.setTranslateY(VIEWPORT_SIZE / 2d);
PhongMaterial earthMaterial = new PhongMaterial();
earthMaterial.setDiffuseMap(
new Image(
DIFFUSE_MAP,
MAP_WIDTH,
MAP_HEIGHT,
true,
true
)
);
earthMaterial.setBumpMap(
new Image(
NORMAL_MAP,
MAP_WIDTH,
MAP_HEIGHT,
true,
true
)
);
earthMaterial.setSpecularMap(
new Image(
SPECULAR_MAP,
MAP_WIDTH,
MAP_HEIGHT,
true,
true
)
);
earth.setMaterial(
earthMaterial
);
return new Group(earth);
}
#Override
public void start(Stage stage) {
Group group = buildScene();
Scene scene = new Scene(
new StackPane(group),
VIEWPORT_SIZE, VIEWPORT_SIZE,
true,
SceneAntialiasing.BALANCED
);
scene.setFill(Color.rgb(10, 10, 40));
scene.setCamera(new PerspectiveCamera());
stage.setScene(scene);
stage.show();
stage.setFullScreen(true);
rotateAroundYAxis(group).play();
}
private RotateTransition rotateAroundYAxis(Node node) {
RotateTransition rotate = new RotateTransition(
Duration.seconds(ROTATE_SECS),
node
);
rotate.setAxis(Rotate.Y_AXIS);
rotate.setFromAngle(360);
rotate.setToAngle(0);
rotate.setInterpolator(Interpolator.LINEAR);
rotate.setCycleCount(RotateTransition.INDEFINITE);
return rotate;
}
public static void main(String[] args) {
launch(args);
}
}
Normal? Why????
The JavaDoc states for the PhongMaterial bumpMapProperty states:
The bump map of this PhongMaterial, which is a normal map stored as a RGB Image.
A normal map is used rather than a height map because:
[normal maps] are much more accurate, as rather than only simulating the pixel
being away from the face along a line, they can simulate that pixel
being moved at any direction, in an arbitrary way.
A brief description of both normal mapping and height mapping is provided in the wikipedia bump mapping article.
Sample Images
Update, July 2021
Unfortunately the image source from "Bored? Then Create a Planet" is no longer available, so I updated the answer to link to different images (hopefully those will remain online). Because it is linked to different images, the resultant rendering of earth looks a bit different than the example image above, though it is similar. The code to render is basically no different, though the images changed.
Diffuse map
Normal map
Specular map

How can I animate a circle with PlayN?

This is a follow up to my last question:
How can I draw a circle to the screen with PlayN?
For my simple case, I want to programmatically create a single colored circle and move it across a 2-D plain (doesn't need to use box2d lib).
A real-world example would likely involve animating several circles. Two real-world examples for this case (sorry, I had to remove the links -- not enough karma!):
Browsmos for Chrome
Ants AI Challenge
It was suggested in response to my last question that I would want to use the ImmediateLayer class, so I am looking to understand how to properly incorporate this into my game loop.
Here's is my code sample:
public class SimpleCircleAnimation implements Game {
// Surface
private GroupLayer rootLayer;
private ImmediateLayer surface;
private Canvas canvas;
private Circle circle;
private CanvasImage circleImage;
#Override
public void init() {
// create root layer
rootLayer = graphics().rootLayer();
// a simple circle object
int circleX = 0; int circleY = 0;
int circleRadius = 20;
circle = new Circle(circleX, circleY, circleRadius);
// create an immediate layer and add to root layer
ImmediateLayer circleLayer = graphics().createImmediateLayer(new ImmediateLayer.Renderer() {
public void render (Surface surf) {
circleImage = graphics().createImage(circle.radius*2, circle.radius*2);
canvas = circleImage.canvas();
canvas.setFillColor(0xff0000eb);
canvas.fillCircle(circle.radius, circle.radius, circle.radius);
surf.drawImage(circleImage, circle.x, circle.y);
}
});
rootLayer.add(circleLayer);
}
#Override
public void paint(float alpha) {
}
#Override
public void update(float delta) {
// move circle
int newX = circle.x + 4; int newY = circle.y + 4;
circle.setPoint(newX, newY);
}
#Override
public int updateRate() {
return 25;
}
}
This successfully moves the circle diagonally down the screen from left to right. A couple questions:
Is this implemented properly?
In the case of multiple animated circles, is the idea with ImmediateLayer that you would create a circle image for each circle within the Renderer callback? Or would you perhaps create an Immediate Layer for each circle and add those to the root layer?
I would not use ImmediateLayer wiht render (Surface surf) adapter. Here u have, inside the render method creation of an image
circleImage = graphics().createImage(circle.radius*2, circle.radius*2);
just put this in the paint method
surf.drawImage(circleImage, circle.x, circle.y);
using the normal layer and u should be fine
Painting is done in paint method, and do not put calculations there
Update is for calculations, and physics oriented stuff
I discovered a detailed practical example of ImmediateLayer usage in the Cute Game source within the PlayN Samples:
CuteGame.java (code.google.com)

Resources