ok here is the code I did. It runs at 60FPS but it’s not smooth. How can I make the movement smooth??
public class ParallaxStandAlone extends JFrame {
/** Parallax Engine. */
private ParallaxEngine parallaxEngine;
public ParallaxStandAlone() throws Exception {
setSize(640, 400);
setResizable(false);
show();
// Load image with a sprite sheet.
Image mount = ImageLoader.loadImage(this, "mount1.png");
Image mount2 = ImageLoader.loadImage(this, "mount2.png");
Image road = ImageLoader.loadImage(this, "road2.png");
Image tree = ImageLoader.loadImage(this, "tree.png");
// Set horizontal speed for each layer.
double[] vx = { -0.15, -0.25, -0.4, -0.5 };
// Set y position for each layer.
int[] y = { 0, 50, 280, 0 };
// Gap for each layer.
int[] gap = { 0, 0, 0, 1000 };
// Break main image in several pieces.
Image layers[] = new Image[4];
// layers[0] = tree;
layers[0] = mount2;
layers[1] = mount;
layers[2] = road;
layers[3] = tree;
// Create a parallax engine.
parallaxEngine = new ParallaxEngine(640, (int) (32 * 0.25), layers, vx,
y, gap);
createBufferStrategy(2);
BufferStrategy strategy = getBufferStrategy();
int fps = 0;
long lastLoopTime = System.currentTimeMillis();
long nextFrameStart = System.nanoTime();
long FRAME_PERIOD = 1000000000L / 60;
while (true) {
if (System.currentTimeMillis() - lastLoopTime > 1000) {
lastLoopTime += 1000;
super.setTitle("FPS=" + fps);
fps = 0;
}
do {
// Tell the engine to move layers to the right.
parallaxEngine.setMoveRight();
// Actually performs the movement.
parallaxEngine.move();
nextFrameStart += FRAME_PERIOD;
} while (nextFrameStart < System.nanoTime());
Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
g.setColor(Color.blue);
g.fillRect(0, 0, 640, 400);
parallaxEngine.render(g);
strategy.show();
fps++;
long remaining = nextFrameStart - System.nanoTime();
if (remaining > 0) {
try {
Thread.sleep(remaining / 1000000);
} catch (Throwable t) {
}
}
}
}
public static void main(String[] args) throws Exception {
new ParallaxStandAlone();
}
}
public class ParallaxEngine {
/** Layers used to execute parallax scrolling. */
private Layer[] layers;
/** Number of layers. */
private int numLayers;
/**
* Creates a new parallax engine.
*
* @param pScreenWidth
* Screen width in pixels.
* @param pDx
* Movement factor in pixels.
* @param pImages
* Images used to compose parallax layers.
* @param pVx
* Velocity for layers movement.
*/
public ParallaxEngine(int pScreenWidth, int pDx, Image[] pImages,
double[] pVx, int[] gap) {
this(pScreenWidth, pDx, pImages, pVx, new int[pImages.length], gap);
}
/**
* Creates a new parallax scrolling engine.
*
* @param pScreenWidth
* Screen width in pixels.
* @param pDx
* Movement factor in pixels.
* @param pImages
* Images used to compose parallax layers.
* @param pVx
* Velocity for layers movement.
* @param pY
* Y position to render the image layers.
*/
public ParallaxEngine(int pScreenWidth, int pDx, Image[] pImages,
double[] pVx, int[] pY, int[] gap) {
this.numLayers = pImages.length;
this.layers = new Layer[this.numLayers];
for (int i = 0; i < this.numLayers; i++) {
this.layers[i] = new Layer(pScreenWidth, 0, pY[i], pImages[i],
(int) (pVx[i] * pDx), gap[i]);
}
}
/**
* Move layers to the right.
*/
public void setMoveRight() {
for (int i = 0; i < this.numLayers; i++) {
this.layers[i].setRightDirection();
}
}
/**
* Move layers to the left.
*/
public void setMoveLeft() {
for (int i = 0; i < this.numLayers; i++) {
this.layers[i].setLeftDirection();
}
}
/**
* Stop layers movement.
*/
public void stop() {
for (int i = 0; i < this.numLayers; i++) {
this.layers[i].stop();
}
}
/**
* Move layers.
*/
public void move() {
for (int i = 0; i < this.numLayers; i++) {
this.layers[i].move();
}
}
/**
* The display order is important. Display layers from the back to the front
* of the scene.
*
* @param g
* Graphics context.
*/
public void render(Graphics2D g) {
for (int i = 0; i < this.numLayers; i++) {
this.layers[i].render(g);
}
}
/**
* Represents an horizontal parallax layer.
*
*/
private class Layer {
/** Image for the layer. */
private Image image;
/** Width of the image in pixels. */
private int width;
/** Height of the image in pixels. */
private int height;
/** Width of the screen in pixels. */
private int screenWidth;
/**
* X position in screen where the left side of the image should be
* drawn.
*/
private int x;
/**
* Y position in screen where the left side of the image should be
* drawn.
*/
private int y;
/** Number of pixels the layer will move. */
private int dx;
/** Gap between layers. */
private int gap;
/** Flag indicating if the layer is moving to the right. */
private boolean isMovingRight;
/** Flag indicating if the layer is moving to the left. */
private boolean isMovingLeft;
/**
* Creates a new layer at origin (0,0).
*
* @param pScreenWidth
* Screen width in pixels.
* @param pImage
* Image for the layer.
* @param pDx
* Movement factor in pixels.
*/
private Layer(int pScreenWidth, Image pImage, int pDx) {
this(pScreenWidth, 0, 0, pImage, pDx, 0);
}
/**
* Creates a new layer in a specific (x,y) position.
*
* @param pScreenWidth
* Screen width in pixels.
* @param pX
* The x position in the screen where the start of the image
* should be drawn. It can range between -width to width-1
* ,so can have a value beyond the confines of the screen
* (0-pScreenWidth).
* As x varies, the on-screen layer will usually be a
* combination of its tail followed by its head.
* @param pY
* The y position in the screen where the start of the image
* should be drawn.
* @param pImage
* Image for the layer.
* @param pDx
* Movement factor in pixels.
*/
private Layer(int pScreenWidth, int pX, int pY, Image pImage, int pDx,
int gap) {
this.screenWidth = pScreenWidth;
this.image = pImage;
this.width = pImage.getWidth(null);
this.height = pImage.getHeight(null);
this.dx = pDx;
this.isMovingRight = false;
this.isMovingLeft = false;
this.x = pX;
this.y = pY;
this.gap = gap;
}
/**
* Make the layer move to the right.
*/
private void setRightDirection() {
this.isMovingRight = true;
this.isMovingLeft = false;
}
/**
* Make the layer move to the left.
*/
private void setLeftDirection() {
this.isMovingRight = false;
this.isMovingLeft = true;
}
/**
* Stop layer movement.
*/
private void stop() {
this.isMovingRight = false;
this.isMovingLeft = false;
}
/**
* Increment the x value depending on the movement flags. It can range
* between -width to width-1, which is the width of the image.
*/
private void move() {
if (this.isMovingRight) {
this.x = (this.x + this.dx) % (this.width + gap);
} else if (isMovingLeft) {
this.x = (this.x - this.dx) % this.width;
}
}
/**
* Performs the layer rendering.
*
* @param g
* Graphics context.
*/
private void render(Graphics2D g) {
if (x == 0) {
// Draws image head at (0,0).
draw(g, 0, screenWidth, 0, screenWidth);
} else if ((x > 0) && (x < screenWidth)) {
// Draws image tail at (0,0) and image head at (x,0).
// Tail.
draw(g, 0, x, width - x, width);
// Head.
draw(g, x, screenWidth, 0, screenWidth - x);
} else if (x >= screenWidth) {
// Draws only image tail at (0,0).
draw(g, 0, screenWidth, width - x, width - x + screenWidth);
} else if ((x < 0) && (x >= screenWidth - width)) {
// Draws only image body.
draw(g, 0, screenWidth, -x, screenWidth - x);
} else if (x < screenWidth - width) {
// Draws image tail at (0,0) and image head at (width+x,0)
// Tail.
draw(g, 0, width + x, -x, width);
// Head.
draw(g, gap + width + x, gap + screenWidth, 0, screenWidth
- width - x);
}
}
/**
* Actually draws the layer.
*
* @param g
* Graphics context.
* @param destX1
* Destination X1 position in the graphics context.
* @param destX2
* Destination X2 position in the graphics context.
* @param imageX1
* Source X1 position of image's layer.
* @param imageX2
* Source X2 position of image's layer.
*/
private void draw(Graphics2D g, int destX1, int destX2, int imageX1,
int imageX2) {
g.drawImage(image, destX1, y, destX2, y + height, imageX1, 0,
imageX2, height, null);
}
}
}