I'am working on Pacman clone with Java and libGDX
How to make Pacman move by pressing one button?
Here is my code for moving, but I think it's not the best option:
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
public class Hero {
private int rightBorder;
private int leftBorder;
private int top;
private int bottom;
private GameController gc;
private float cellX;
private float cellY;
private TextureRegion texture;
private float speed;
private boolean isPressedD;
private boolean isPressedA;
private boolean isPressedW;
private boolean isPressedS;
private float offset;
private StringBuilder stringBuilder;
private int score;
public Hero(TextureAtlas atlas, GameController gc){
this.texture = atlas.findRegion("Pacman");
this.cellX = 1;
this.cellY = 1;
this.speed = 5f;
this.isPressedD = false;
this.isPressedA = false;
this.isPressedS = false;
this.isPressedW = false;
this.offset = 36;
this.stringBuilder = new StringBuilder();
this.score = 0;
this.gc = gc;
this.leftBorder = 0;
this.rightBorder = 15;
this.top = 8;
this.bottom = 0;
}
public void update(float dt){
movement(dt);
checkBounds();
}
private void checkBounds(){
if (cellX > rightBorder){
cellX = rightBorder;
}
if (cellX < leftBorder){
cellX = leftBorder;
}
if (cellY > top){
cellY = top;
}
if (cellY < bottom){
cellY = bottom;
}
// if (position.x > 1280 - offset){
// position.x = 1280 - offset;
// }
// if (position.x < 0 + offset){
// position.x = 0 + offset;
// }
// if (position.y > 720 - offset){
// position.y = 720 - offset;
// }
// if (position.y < 0 + offset){
// position.y = 0 + offset;
// }
}
public void movement(float dt){
if (Gdx.input.isKeyJustPressed(Input.Keys.D)){
isPressedD = true;
isPressedA = false;
isPressedS = false;
isPressedW = false;
}
if (Gdx.input.isKeyJustPressed(Input.Keys.A)){
isPressedD = false;
isPressedA = true;
isPressedS = false;
isPressedW = false;
}
if (Gdx.input.isKeyJustPressed(Input.Keys.S)){
isPressedD = false;
isPressedA = false;
isPressedS = true;
isPressedW = false;
}
if (Gdx.input.isKeyJustPressed(Input.Keys.W)){
isPressedD = false;
isPressedA = false;
isPressedS = false;
isPressedW = true;
}
if (isPressedA){
cellX -= speed * dt;
}
if (isPressedD){
cellX += speed * dt;
}
if (isPressedS){
cellY -= speed * dt;
}
if (isPressedW){
cellY += speed * dt;
}
}
public void renderGUI(SpriteBatch batch, BitmapFont font){
stringBuilder.setLength(0);
stringBuilder.append("Score: " + score);
font.draw(batch, stringBuilder, 10, 700);
}
public void render(SpriteBatch batch){
batch.draw(texture, cellX * GameMap.CELL_SIZE, cellY * GameMap.CELL_SIZE);
}
}
Here is moving method directly:
public void movement(float dt){
if (Gdx.input.isKeyJustPressed(Input.Keys.D)){
isPressedD = true;
isPressedA = false;
isPressedS = false;
isPressedW = false;
}
if (Gdx.input.isKeyJustPressed(Input.Keys.A)){
isPressedD = false;
isPressedA = true;
isPressedS = false;
isPressedW = false;
}
if (Gdx.input.isKeyJustPressed(Input.Keys.S)){
isPressedD = false;
isPressedA = false;
isPressedS = true;
isPressedW = false;
}
if (Gdx.input.isKeyJustPressed(Input.Keys.W)){
isPressedD = false;
isPressedA = false;
isPressedS = false;
isPressedW = true;
}
if (isPressedA){
cellX -= speed * dt;
}
if (isPressedD){
cellX += speed * dt;
}
if (isPressedS){
cellY -= speed * dt;
}
if (isPressedW){
cellY += speed * dt;
}
}
It's working but I can't ckeck collisions with walls.
How to change method for moving?
I need to press button and release immediately.
No need to create booleans and then do checks on them. Just check if the key is pressed and then put your code in that if statement.
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
public class Hero {
private int rightBorder;
private int leftBorder;
private int top;
private int bottom;
private GameController gc;
private float cellX;
private float cellY;
private TextureRegion texture;
private float speed;
private float offset;
private StringBuilder stringBuilder;
private int score;
public Hero(TextureAtlas atlas, GameController gc){
this.texture = atlas.findRegion("Pacman");
this.cellX = 1;
this.cellY = 1;
this.speed = 5f;
this.offset = 36;
this.stringBuilder = new StringBuilder();
this.score = 0;
this.gc = gc;
this.leftBorder = 0;
this.rightBorder = 15;
this.top = 8;
this.bottom = 0;
}
public void update(float dt){
movement(dt);
checkBounds();
}
private void checkBounds(){
if (cellX > rightBorder){
cellX = rightBorder;
}
if (cellX < leftBorder){
cellX = leftBorder;
}
if (cellY > top){
cellY = top;
}
if (cellY < bottom){
cellY = bottom;
}
// if (position.x > 1280 - offset){
// position.x = 1280 - offset;
// }
// if (position.x < 0 + offset){
// position.x = 0 + offset;
// }
// if (position.y > 720 - offset){
// position.y = 720 - offset;
// }
// if (position.y < 0 + offset){
// position.y = 0 + offset;
// }
}
public void movement(float dt){
if (Gdx.input.isButtonPressed(Input.Keys.D)){
cellX += speed * dt;
}
else if (Gdx.input.isButtonPressed(Input.Keys.A)){
cellX -= speed * dt;
}
else if (Gdx.input.isButtonPressed(Input.Keys.S)){
cellY -= speed * dt;
}
else if (Gdx.input.isButtonPressed(Input.Keys.W)){
cellY += speed * dt;
}
}
public void renderGUI(SpriteBatch batch, BitmapFont font){
stringBuilder.setLength(0);
stringBuilder.append("Score: " + score);
font.draw(batch, stringBuilder, 10, 700);
}
public void render(SpriteBatch batch){
batch.draw(texture, cellX * GameMap.CELL_SIZE, cellY * GameMap.CELL_SIZE);
}
}
Related
I am following this tutorial on how to create a Java2D platform game. I followed the code precisely, but when I tried to run it, the player moves way too fast when moving left and when jumping and falling compared to when it's moving right.
My player class looks like this:
package Entity;
import TileMap.*;
import java.awt.*;
import java.util.ArrayList;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
public class Player extends MapObject {
// Player stats
private int health, maxHealth, fire, maxFire, fireCost, fireBallDamage, scratchDamage, scratchRange;
private boolean dead, flinching, firing, scratching, gliding;
private long flinchTimer;
// private ArrayList<FireBall> fireballs;
private ArrayList<BufferedImage[]> sprites;
private final int[] numFrames = { 2, 8, 1, 2, 4, 2, 5 };
// Animation actions
private static final int IDLE = 0;
private static final int WALKING = 1;
private static final int JUMPING = 2;
private static final int FALLING = 3;
private static final int GLIDING = 4;
private static final int FIREBALL = 5;
private static final int SCRATCHING = 6;
private int currentAction;
// Constructor
public Player(TileMap tm) {
super(tm);
width = height = 30;
cWidth = cHeight = 20;
moveSpeed = 0.3;
maxSpeed = 1.6;
stopSpeed = 0.4;
fallSpeed = 0.15;
maxFallSpeed = 4.0;
jumpStart = -4.8;
stopJumpSpeed = 0.3;
facingRight = true;
health = maxHealth = 5;
fire = maxFire = 2500;
fireCost = 200;
fireBallDamage = 5;
//fireBalls = new ArrayList<FireBall>();
scratchDamage = 8;
scratchRange = 40;
// Load sprites
try {
BufferedImage spritesheet =
ImageIO.read( getClass().getResourceAsStream("/Sprites/Player/playersprites.gif"));
sprites = new ArrayList<BufferedImage[]>();
// Loop through animation actions
for (int i = 0; i < 7; i++){
BufferedImage[] bi = new BufferedImage[numFrames[i]];
for (int j = 0; j < numFrames[i]; j++) {
// numFrames[6] = SCRATCH has width = 60
if (i != 6) {
bi[j] = spritesheet.getSubimage(j * width, i * height, width, height);
} else {
bi[j] = spritesheet.getSubimage(j * width * 2, i * height, width, height);
}
}
sprites.add(bi); // Add BufferedImageArray to animations list
}
} catch (Exception e) { e.printStackTrace(); }
animation = new Animation();
currentAction = IDLE;
animation.setFrames(sprites.get(IDLE));
animation.setDelay(400);
}
// Getters
public int getHealth() { return health; }
public int getMaxHealth() { return maxHealth; }
public int getFire() { return fire; }
public int getMaxFire() { return maxFire; }
// Setters
public void setFiring() { firing = true; }
public void setScratching() { scratching = true; }
public void setGliding(boolean b) { gliding = b; }
private void getNextPosition() {
// Movement
if (left) {
dx -= moveSpeed;
if ( dx < -maxSpeed) { dx = 0; }
} else if (right) {
dx += moveSpeed;
if (dx > maxSpeed) { dx = maxSpeed; }
} else {
if (dx > 0) {
dx -= stopSpeed;
if ( dx < 0 ) { dx = 0; }
} else if (dx < 0) {
dx += stopSpeed;
if (dx > 0) { dx = 0; }
}
}
// Cannot attack while moving, unless in the air
if ( currentAction == SCRATCHING || currentAction == FIREBALL && !( jumping || falling)) { dx = 0; }
// Jumping
if (jumping && !falling) {
dy += jumpStart;
falling = true;
}
if (falling) {
if ( dy > 0 && gliding) { dy += fallSpeed * 0.1; }
else { dy += fallSpeed; }
if ( dy > 0 ) { jumping = false; }
if ( dy < 0 && !jumping ) { dy += maxFallSpeed; }
if ( dy > maxFallSpeed ) { dy = maxFallSpeed; }
}
}
public void update() {
// Update position
getNextPosition();
checkTileMapCollision();
setPosition(xtemp, ytemp);
// Set animations
if (scratching) {
if (currentAction != SCRATCHING) {
currentAction = SCRATCHING;
animation.setFrames(sprites.get(SCRATCHING));
animation.setDelay(50);
width = 60;
}
} else if (firing) {
if (currentAction != FIREBALL) {
currentAction = FIREBALL;
animation.setFrames(sprites.get(FIREBALL));
animation.setDelay(100);
width = 30;
}
} else if (dy > 0) {
if (gliding) {
if (currentAction != GLIDING) {
currentAction = GLIDING;
animation.setFrames(sprites.get(GLIDING));
animation.setDelay(100);
width = 30;
}
} else if (currentAction != FALLING) {
currentAction = FALLING;
animation.setFrames(sprites.get(FALLING));
animation.setDelay(100);
width = 30;
}
} else if (dy < 0) {
if ( currentAction != JUMPING) {
currentAction = JUMPING;
animation.setFrames(sprites.get(JUMPING));
animation.setDelay(-1);
width = 30;
}
} else if ( left || right ) {
if ( currentAction != WALKING) {
currentAction = WALKING;
animation.setFrames(sprites.get(WALKING));
animation.setDelay(40);
width = 30;
}
} else {
if ( currentAction != IDLE) {
currentAction = IDLE;
animation.setFrames(sprites.get(IDLE));
animation.setDelay(400);
width = 30;
}
}
animation.update();
// Set direction
if ( currentAction != SCRATCHING && currentAction != FIREBALL) {
if ( right) { facingRight = true; }
if ( left ) { facingRight = false; }
}
}
public void draw(Graphics2D g) {
setMapPosition();
// Draw player
if (flinching) {
long elapsed = (System.nanoTime() - flinchTimer) / 1000000;
if (elapsed / 100 % 2 == 0) { return; } // Gives the appearance of blinking
}
if (facingRight) {
g.drawImage(animation.getImage(), (int) (x + xmap - width/2), (int) (y + ymap - height/2), null);
} else {
g.drawImage(animation.getImage(), (int) (x + xmap - width/2 + width), (int) (y + ymap - height/2),
-width, height, null);
}
}
}
I tried changing
private void getNextPosition() {
// Movement
if (left) {
dx -= moveSpeed;
if ( dx < -maxSpeed) { dx = -maxSpeed; }
to
private void getNextPosition() {
// Movement
if (left) {
dx -= moveSpeed;
if ( dx < -maxSpeed) { dx = 0; }
Which helped for the left-movement, but it created a lag in the graphics, so I tried changing theAnimation-class which looks like this:
package Entity;
import java.awt.image.BufferedImage;
public class Animation {
private BufferedImage[] frames;
private int currentFrame;
private long startTime, delay;
private boolean playedOnce;
public void Animation() {
playedOnce = false;
}
public void setFrames(BufferedImage[] frames) {
this.frames = frames;
currentFrame = 0;
startTime = System.nanoTime();
playedOnce = false;
}
public void setDelay(long d) { delay = d; }
public void setFrame(int i) { currentFrame = i; }
public void update() {
if (delay == -1) { return; }
long elapsed = (System.nanoTime() - startTime) / 1000000;
if (elapsed > delay) {
currentFrame++;
startTime = System.nanoTime();
}
if (currentFrame == frames.length) {
currentFrame = 0;
playedOnce = true;
}
}
public int getFrame() { return currentFrame; }
public BufferedImage getImage() { return frames[currentFrame]; }
public boolean hasPlayedOnce() { return playedOnce; }
}
Which I thought was where I could fix the problem, but I am uncertain as I am new to gamelogic. Is there any way I can slow down the movement of the player? All help is appreciated!
I'm trying to make a doodle jump game and currently I cant find a way to make the still image change to leg image once it lands on the ground and then change back to still. It kind of does that for one side but not not for both. I've tried using nested if, but then it wouldn't detect the button press. Here's the code:
GameObject game;
PImage doodle;
void setup() {
size(640, 800);
smooth(4);
frameRate(10);
doodle = loadImage("https://i.imgur.com/ytwebph.png");
game = new Doodle(new PVector(width/2, height-doodle.height*2), doodle);
game.setWidthAndHeight(new PVector(width, height));
}
void draw() {
background(200);
game.display();
game.move();
}
void keyPressed() {
game.setMove(keyCode, true);
}
void keyReleased() {
game.setMove(keyCode, false);
}
protected class Doodle extends GameObject {
protected float velocityY, gravity, time;
protected float groundPosition;
protected int facing = 0; //0 = right; 1 = left
protected Doodle(PVector position, PImage picture) {
super(position, picture);
gravity = 20;
time = 0.4;
velocityY = 35*gravity*time;
super.setSpeed(10);
groundPosition = position.y - picture.height;
}
public void move() {
if (isRight || position.y < groundPosition) {
this.picture = doodleImg[0];
facing = 0;
} else if (isLeft || position.y < groundPosition) {
this.picture = doodleImg[2];
facing = 1;
}
position.x = position.x + speed*(int(isRight) - int(isLeft));
//border control
if (position.x+picture.width/2 <= 0) {
position.x = this.getWidthAndHeight().x-picture.width/2;
} else if (position.x+picture.width/2 >= this.getWidthAndHeight().x) {
position.x = 0-picture.width/2;
}
//jump
velocityY -= gravity * time;
position.y -= velocityY * time;
if (position.y > groundPosition) {
if (facing == 0) {
this.picture = doodleImg[1];
} else if (facing == 1) {
this.picture = doodleImg[3];
}
position.y = groundPosition;
velocityY = 35;
}
}
}
public class GameObject {
public PVector position, widthAndHeight;
public int size, speed;
public PImage picture;
public boolean isLeft, isRight;
public PImage[] doodleImg = new PImage[6];
public GameObject(PVector position, PImage picture) {
this.position = position;
this.picture = picture;
widthAndHeight = new PVector(0, 0);
speed = 1;
//0,1 right; 2,3 left; 4,5 shoot;
doodleImg[0] = loadImage("https://i.imgur.com/ytwebph.png");
doodleImg[1] = loadImage("https://i.imgur.com/Y0cFSFK.png");
doodleImg[2] = loadImage("https://i.imgur.com/FL3IhU5.png");
doodleImg[3] = loadImage("https://i.imgur.com/YuqWihj.png");
}
public void move() {
position.x = 0;
}
public void display() {
image(picture, position.x, position.y);
}
public boolean setMove(int keycode, boolean isPressed) {
switch(keycode) {
case LEFT:
return isLeft = isPressed;
case RIGHT:
return isRight = isPressed;
default:
return isPressed;
}
}
protected PVector getWidthAndHeight() {
return widthAndHeight;
}
void setSpeed(int speed) {
this.speed = speed;
}
public void setWidthAndHeight(PVector newWidthAndHeight) {
widthAndHeight = newWidthAndHeight;
}
}
First set the facing state, dependent on the isRight and isLeft:
if (isRight) {
facing = 0;
} else if (isLeft) {
facing = 1;
}
The set the image dependent on the state of facing and the vertical position position.y:
if (position.y < groundPosition) {
this.picture = doodleImg[facing==0 ? 0 : 2];
} else {
this.picture = doodleImg[facing==0 ? 1 : 3];
}
public void move() {
if (isRight) {
facing = 0;
} else if (isLeft) {
facing = 1;
}
if (position.y < groundPosition) {
this.picture = doodleImg[facing==0 ? 0 : 2];
} else {
this.picture = doodleImg[facing==0 ? 1 : 3];
}
position.x = position.x + speed*(int(isRight) - int(isLeft));
//border control
if (position.x+picture.width/2 <= 0) {
position.x = this.getWidthAndHeight().x-picture.width/2;
} else if (position.x+picture.width/2 >= this.getWidthAndHeight().x) {
position.x = 0-picture.width/2;
}
//jump
velocityY -= gravity * time;
position.y -= velocityY * time;
if (position.y > groundPosition) {
position.y = groundPosition;
velocityY = 35;
}
}
I am trying to implement path drawing for a herding game.
Currently when I run the game on PC I use the mouse to draw a path for which the herder will move through, but I can not get it to draw a line.
package com.mygdx.herdergame.Sprites;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;
import com.mygdx.herdergame.HerderGame;
import com.mygdx.herdergame.Screens.PlayScreen;
import java.util.ArrayList;
public class Herder extends Sprite implements InputProcessor {
HerderGame game;
public World world;
public Body b2body;
private PlayScreen screen;
//States
private enum State {
RUNNINGRIGHT, RUNNINGLEFT, RUNNINGUP, RUNNINGDOWN, STANDINGRIGHT, STANDINGLEFT, STANDINGUP, STANDINGDOWN
}
private State currentState;
private State previousState;
private float stateTimer;
//Textures
private Animation runningRight;
private Animation runningLeft;
private Animation runningUp;
private Animation runningDown;
private TextureRegion standRight;
private TextureRegion standLeft;
private TextureRegion standUp;
private TextureRegion standDown;
private float destinationX;
private float destinationY;
//Velocity
private static final float MAX_SPEED = 500;
private float speedLimit = 1000;
private Vector2 velocity = new Vector2(0, 0);
private static float ACCURACY = 50;
//Touch Screen
private Vector3 touchpoint = new Vector3();
private Vector2 targetPosition;
private ArrayList<Vector2> herderPath = new ArrayList<Vector2>();
boolean dragging;
boolean followingPath = false;
// death variables
private boolean isInTimedDeathZone;
private float deathTimer;
//this is the constructor.
public Herder(World world, PlayScreen screen) {
super(screen.getAtlas().findRegion("herderRight"));
this.screen = screen;
game = screen.getGame();
this.world = world;
defBody();
setTextures();
currentState = State.STANDINGRIGHT;
previousState = State.STANDINGRIGHT;
stateTimer = 0;
isInTimedDeathZone = false;
deathTimer = 0;
}
public void defBody() {
BodyDef bdef = new BodyDef();
bdef.position.set(500, 500);
bdef.type = BodyDef.BodyType.DynamicBody;
b2body = world.createBody(bdef);
FixtureDef fdef = new FixtureDef();
CircleShape shape = new CircleShape();
shape.setRadius(10);
fdef.shape = shape;
b2body.createFixture(fdef).setUserData(this);
}
public void setTextures() {
int herderUpStartX = game.rm.getChapter(game.getCurrentChapter()).getHerderUp().getStartX();
int herderUpStartY = game.rm.getChapter(game.getCurrentChapter()).getHerderUp().getStartY();
int herderDownStartX = game.rm.getChapter(game.getCurrentChapter()).getHerderDown().getStartX();
int herderDownStartY = game.rm.getChapter(game.getCurrentChapter()).getHerderDown().getStartY();
int herderLeftStartX = game.rm.getChapter(game.getCurrentChapter()).getHerderLeft().getStartX();
int herderLeftStartY = game.rm.getChapter(game.getCurrentChapter()).getHerderLeft().getStartY();
int herderRightStartX = game.rm.getChapter(game.getCurrentChapter()).getHerderRight().getStartX();
int herderRightStartY = game.rm.getChapter(game.getCurrentChapter()).getHerderRight().getStartY();
int numberOfFrame = game.rm.getChapter(game.getCurrentChapter()).getHerderRight().getNumberOfFrame();
int width = game.rm.getChapter(game.getCurrentChapter()).getHerderRight().getWidth();
int height = game.rm.getChapter(game.getCurrentChapter()).getHerderRight().getHeight();
//this enables the sprite to be drawn.
Array<TextureRegion> frames = new Array<TextureRegion>();
for (int i = 0; i < numberOfFrame; i++) {
frames.add(new TextureRegion(getTexture(), herderRightStartX + width * i, herderRightStartY, width, height));
}
runningRight = new Animation(0.1f, frames);
frames.clear();
for (int i = 0; i < numberOfFrame; i++) {
frames.add(new TextureRegion(getTexture(), herderLeftStartX + width * i, herderLeftStartY, width, height));
}
runningLeft = new Animation(0.1f, frames);
frames.clear();
for (int i = 0; i < numberOfFrame; i++) {
frames.add(new TextureRegion(getTexture(), herderDownStartX + width * i, herderDownStartY, width, height));
}
runningDown = new Animation(0.1f, frames);
frames.clear();
for (int i = 0; i < numberOfFrame; i++) {
frames.add(new TextureRegion(getTexture(), herderUpStartX + width * i, herderUpStartY, width, height));
}
runningUp = new Animation(0.1f, frames);
standRight = new TextureRegion(getTexture(), herderRightStartX, herderRightStartY, width, height);
setBounds(0, 0, 32, 32);
setRegion(standRight);
standLeft = new TextureRegion(getTexture(), herderLeftStartX, herderLeftStartY, width, height);
setBounds(0, 0, 32, 32);
setRegion(standLeft);
standUp = new TextureRegion(getTexture(), herderUpStartX, herderUpStartY, width, height);
setBounds(0, 0, 32, 32);
setRegion(standUp);
standDown = new TextureRegion(getTexture(), herderDownStartX, herderDownStartY, width, height);
setBounds(0, 0, 32, 32);
setRegion(standDown);
setSize(32, 32);
}
public TextureRegion getFrame(float dt) {
currentState = getState();
TextureRegion region;
switch (currentState) {
case RUNNINGRIGHT:
region = runningRight.getKeyFrame(stateTimer, true);
break;
case RUNNINGLEFT:
region = runningLeft.getKeyFrame(stateTimer, true);
break;
case RUNNINGUP:
region = runningUp.getKeyFrame(stateTimer, true);
break;
case RUNNINGDOWN:
region = runningDown.getKeyFrame(stateTimer, true);
break;
case STANDINGLEFT:
region = standLeft;
break;
case STANDINGUP:
region = standUp;
break;
case STANDINGDOWN:
region = standDown;
break;
case STANDINGRIGHT:
default:
region = standRight;
break;
}
stateTimer = currentState == previousState ? stateTimer + dt : 0;
previousState = currentState;
return region;
}
public State getState() {
Vector2 direction = b2body.getLinearVelocity();
if (direction.isZero()) {
switch (previousState) {
case RUNNINGUP:
return State.STANDINGUP;
case RUNNINGLEFT:
return State.STANDINGLEFT;
case RUNNINGDOWN:
return State.STANDINGDOWN;
case RUNNINGRIGHT:
return State.STANDINGRIGHT;
default:
return previousState;
}
} else if (direction.x >= 0 && direction.y >= 0) {
if (direction.x > direction.y) {
return State.RUNNINGRIGHT;
} else return State.RUNNINGUP;
} else if (direction.x >= 0 && direction.y <= 0) {
if (direction.x > -direction.y) {
return State.RUNNINGRIGHT;
} else return State.RUNNINGDOWN;
} else if (direction.x <= 0 && direction.y >= 0) {
if (-direction.x > direction.y) {
return State.RUNNINGLEFT;
} else return State.RUNNINGUP;
} else if (direction.x <= 0 && direction.y <= 0) {
if (-direction.x > -direction.y) {
return State.RUNNINGLEFT;
} else return State.RUNNINGDOWN;
} else return currentState = previousState;
}
public void update(float dt) {
if (isXStapable() || isYStapable()) {
stop();
}
if (followingPath) {
if (!herderPath.iterator().hasNext()) {
followingPath = false;
herderPath.clear();
stop();
} else if (targetPosition.dst(b2body.getPosition()) < 1.5) {
targetPosition = herderPath.get(0);
herderPath.remove(0);
velocity = calculateVelocity(b2body.getPosition(), targetPosition);
} else {
velocity = calculateVelocity(b2body.getPosition(), targetPosition);
}
}
b2body.setLinearVelocity(velocity);
setPosition(b2body.getPosition().x - getWidth() / 2, b2body.getPosition().y - getHeight() / 2);
setRegion(getFrame(dt));
if (isInTimedDeathZone) {
deathTimer += dt;
} else {
deathTimer = 0;
}
if (deathTimer > 2f) {
screen.gameOver();
}
}
public void setInTimedDeathZone(boolean b) {
this.isInTimedDeathZone = b;
}
#Override
public boolean keyDown(int keycode) {
switch (keycode) {
case Input.Keys.UP:
velocity.y = speedLimit;
break;
case Input.Keys.DOWN:
velocity.y = -speedLimit;
break;
case Input.Keys.LEFT:
velocity.x = -speedLimit;
break;
case Input.Keys.RIGHT:
velocity.x = speedLimit;
break;
default:
return true;
}
followingPath = false;
return true;
}
#Override
public boolean keyUp(int keycode) {
switch (keycode) {
case Input.Keys.UP:
case Input.Keys.DOWN:
velocity.y = 0;
break;
case Input.Keys.LEFT:
case Input.Keys.RIGHT:
velocity.x = 0;
break;
}
return true;
}
#Override
public boolean keyTyped(char character) {
return false;
}
#Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
float diffX;
float diffY;
// ignore if its not left mouse button or first touch pointer
if (button != Input.Buttons.LEFT || pointer > 0) return false;
screen.getCamera().unproject(touchpoint.set(screenX, screenY, 0));
//ignore if the first point is not close to the herder
diffX = touchpoint.x - b2body.getPosition().x;
diffY = touchpoint.y - b2body.getPosition().y;
if (diffX > 25 || diffX < -25 || diffY > 25 || diffY < -25) return false;
dragging = true;
herderPath.clear();
targetPosition = b2body.getPosition();
herderPath.add(targetPosition);
return true;
}
#Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
Vector2 vec2 = new Vector2();
if (!dragging) return false;
screen.getCamera().unproject(touchpoint.set(screenX, screenY, 0));
vec2.set(touchpoint.x, touchpoint.y);
herderPath.add(vec2);
followingPath = true;
return true;
}
#Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
if (button != Input.Buttons.LEFT || pointer > 0) return false;
screen.getCamera().unproject(touchpoint.set(screenX, screenY, 0));
dragging = false;
return true;
}
private Vector2 calculateVelocity(Vector2 currentPosition, Vector2 targetPosition) {
Vector2 tempTP = new Vector2().set(targetPosition);
return tempTP.sub(currentPosition).nor().scl(speedLimit);
}
public boolean isXValid(int x) {
return b2body.getPosition().x <= x + ACCURACY && b2body.getPosition().x >= x - ACCURACY;
}
public boolean isYValid(int y) {
return b2body.getPosition().y <= y + ACCURACY && b2body.getPosition().y >= y - ACCURACY;
}
public boolean isXStapable() {
return isXValid((int) destinationX);
}
public boolean isYStapable() {
return isYValid((int) destinationY);
}
public void stop() {
velocity.set(0, 0);
}
#Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
#Override
public boolean scrolled(int amount) {
return false;
}
public void setSpeedLimit(float multiplier) {
if (speedLimit > MAX_SPEED) {
this.speedLimit = MAX_SPEED;
} else {
this.speedLimit = multiplier;
}
}
}
I've been looking through this code for over 2 days and still can't find any errors in the code as to why it crashes on Android. It works perfectly fine on desktop.
Android Target: 4.0.3
Android Phone used: HTC Desire C
Logcat:
04-07 16:42:35.785: E/AndroidRuntime(24197): FATAL EXCEPTION: GLThread 2955
04-07 16:42:35.785: E/AndroidRuntime(24197): java.lang.ClassCastException: com.badlogic.gdx.math.Vector2 cannot be cast to java.lang.String
04-07 16:42:35.785: E/AndroidRuntime(24197): at com.survivegameandroidtest.survive.Player.readPlayer(Player.java:191)
04-07 16:42:35.785: E/AndroidRuntime(24197): at com.survivegameandroidtest.survive.MainMenu.loadPlayer(MainMenu.java:278)
04-07 16:42:35.785: E/AndroidRuntime(24197): at com.survivegameandroidtest.survive.MainMenu.show(MainMenu.java:127)
04-07 16:42:35.785: E/AndroidRuntime(24197): at com.badlogic.gdx.Game.setScreen(Game.java:62)
04-07 16:42:35.785: E/AndroidRuntime(24197): at com.survivegameandroidtest.survive.GameHub.create(GameHub.java:12)
04-07 16:42:35.785: E/AndroidRuntime(24197): at com.badlogic.gdx.backends.android.AndroidGraphics.onSurfaceChanged(AndroidGraphics.java:334)
04-07 16:42:35.785: E/AndroidRuntime(24197): at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1463)
04-07 16:42:35.785: E/AndroidRuntime(24197): at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1224)
Like I said, this works fine on desktop, but crashes on Android.
Player class
package com.survivegameandroidtest.survive;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Serializable;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2;
public class Player implements Serializable{
private static final long serialVersionUID = 1L;
SpriteBatch batch;
static Vector2 position = new Vector2(1,1);
Vector2 size;
Vector2 boundSize;
Vector2 boundOffset;
Texture texture;
Rectangle bounds;
String direction = "";
StringCheese cheese;
EnemyCheddarling enemy;
int health = 0, damage;
boolean alive;
private static final int col = 4, row = 4;
Animation animation;
TextureRegion[] frames;
TextureRegion currentFrame;
float stateTime;
int speed = 0;
static String name = "";
public Player(Texture texture, Vector2 position, Vector2 size, Vector2 boundSize, Vector2 boundOffset) {
this.texture = texture;
Player.position = position;
this.size = size;
this.boundOffset = boundOffset;
TextureRegion[][] tmp = TextureRegion.split(texture, texture.getWidth() / col, texture.getHeight() / row);
frames = new TextureRegion[col * row];
int index = 0;
for(int i = 0; i < row; i++) {
for(int j = 0; j < col; j++) {
frames[index++] = tmp[i][j];
}
}
animation = new Animation(1f, frames);
stateTime = 0f;
currentFrame = animation.getKeyFrame(0);
this.boundSize = boundSize;
bounds = new Rectangle(position.x + boundOffset.x, position.y + boundOffset.y, boundSize.x, boundSize.y);
health = 100;
damage = 20;
alive = true;
name = "SET YO NAME FOOL";
}
public void update() {
bounds.set(position.x + boundOffset.x, position.y + boundOffset.y, boundSize.x, boundSize.y);
if(health <= 0) {
alive = false;
}
stateTime += Gdx.graphics.getDeltaTime()*8;
if(stateTime > col) {
stateTime = 0;
}
//WASD MOVE METHOD
if(Gdx.input.isKeyPressed(Keys.W)) {
position.y += 2f;
currentFrame = animation.getKeyFrame(12 + stateTime);
direction = "up";
speed = 2;
}
if(Gdx.input.isKeyPressed(Keys.A)) {
position.x -= 2f;
currentFrame = animation.getKeyFrame(4 + stateTime);
direction = "left";
speed = 2;
}
if(Gdx.input.isKeyPressed(Keys.S)) {
position.y -= 2f;
currentFrame = animation.getKeyFrame(0 + stateTime);
direction = "down";
speed = 2;
}
if(Gdx.input.isKeyPressed(Keys.D)) {
position.x += 2f;
currentFrame = animation.getKeyFrame(8 + stateTime);
direction = "right";
speed = 2;
}
//ACCELEROMETER MOVE METHOD
if(Gdx.input.getAccelerometerX() != 1 || Gdx.input.getAccelerometerX() != 0 || Gdx.input.getAccelerometerX() != -1 || Gdx.input.getAccelerometerY() != 1 || Gdx.input.getAccelerometerY() != 0 || Gdx.input.getAccelerometerY() != -1) {
for(int rotation = 2; rotation < 5; rotation++) {
if(Gdx.input.getAccelerometerX() <= -rotation) { //DOWN
position.y += rotation;
currentFrame = animation.getKeyFrame(12 + stateTime);
direction = "down";
speed = rotation;
}
if(Gdx.input.getAccelerometerX() >= rotation) { //UP
position.y -= rotation;
currentFrame = animation.getKeyFrame(0 + stateTime);
direction = "up";
speed = rotation;
}
if(Gdx.input.getAccelerometerY() <= -rotation) { //LEFT
position.x -= rotation;
currentFrame = animation.getKeyFrame(4 + stateTime);
direction = "left";
speed = rotation;
}
if(Gdx.input.getAccelerometerY() >= rotation) { //RIGHT
position.x += rotation;
currentFrame = animation.getKeyFrame(8 + stateTime);
direction = "right";
speed = rotation;
}
}
}
}
public void draw(SpriteBatch batch) {
batch.draw(currentFrame, position.x, position.y, size.x, size.y);
}
public void collision() {
if(direction == "up") {
position.y += speed;
}
if(direction == "down") {
position.y -= speed;
}
if(direction == "left") {
position.y -= speed;
}
if(direction == "right") {
position.y += speed;
}
}
public static void savePlayer(Player playerName) throws IOException{
FileHandle file = Gdx.files.local("player.dat");
OutputStream out = null;
try{
file.writeBytes(serialize(name), false);
}catch(Exception ex){
System.out.println(ex.toString());
}finally{
if(out != null) try{out.close();} catch(Exception ex){}
}
try {
System.out.println("Saving Player" + " " + deserialize(file.readBytes()));
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static String readPlayer() throws IOException, ClassNotFoundException{
String playerName = "";
FileHandle file = Gdx.files.local("player.dat");
playerName = (String) deserialize(file.readBytes());
System.out.println("Reading Player");
return playerName;
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
return b.toByteArray();
}
public static Object deserialize(byte[] bytes) throws IOException, ClassNotFoundException {
ByteArrayInputStream b = new ByteArrayInputStream(bytes);
ObjectInputStream o = new ObjectInputStream(b);
return o.readObject();
}
//GETTERS AND SETTERS
public SpriteBatch getBatch() {
return batch;
}
public String getName() {
return name;
}
public void setName(String object) {
Player.name = object;
}
public Vector2 getBoundOffset() {
return boundOffset;
}
public void setBoundOffset(Vector2 boundOffset) {
this.boundOffset = boundOffset;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public boolean isAlive() {
return alive;
}
public void setAlive(boolean alive) {
this.alive = alive;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
public StringCheese getCheese() {
return cheese;
}
public void setCheese(StringCheese cheese) {
this.cheese = cheese;
}
public Rectangle getBounds() {
return bounds;
}
public void setBounds(Rectangle bounds) {
this.bounds = bounds;
}
public Vector2 getSize() {
return size;
}
public void setSize(Vector2 size) {
this.size = size;
}
public Vector2 getBoundSize() {
return boundSize;
}
public void setBoundSize(Vector2 boundSize) {
this.boundSize = boundSize;
}
public Texture getTexture() {
return texture;
}
public void setTexture(Texture texture) {
this.texture = texture;
}
public Animation getAnimation() {
return animation;
}
public void setAnimation(Animation animation) {
this.animation = animation;
}
public TextureRegion[] getFrames() {
return frames;
}
public void setFrames(TextureRegion[] frames) {
this.frames = frames;
}
public TextureRegion getCurrentFrame() {
return currentFrame;
}
public void setCurrentFrame(TextureRegion currentFrame) {
this.currentFrame = currentFrame;
}
public float getStateTime() {
return stateTime;
}
public void setStateTime(float stateTime) {
this.stateTime = stateTime;
}
public static int getCol() {
return col;
}
public static int getRow() {
return row;
}
public void setBatch(SpriteBatch batch) {
this.batch = batch;
}
public Vector2 getPosition() {
return position;
}
public void setPosition(Vector2 position) {
Player.position = position;
}
}
In savePlayer(), I try to serialize the String variable 'name'.
System.out.println("Saving Player" + " " + deserialize(file.readBytes()));
^ This line of code prints out "Saving Player Hosif Yimms" in the console, and none of the methods return a Vector2.
ANSWER: Used a FileHandle method to save the players name, as deserialize return an Object, not String.
Why are you using Object serialization for strings anyway? Just get a reader/writer for your FileHandle. – Chase
public static void savePlayerName(Player player) {
FileHandle file = Gdx.files.local("playername.dat");
file.writeString(player.getName(), false);
}
public static String readPlayerName() {
FileHandle file = Gdx.files.local("playername.dat");
String name = file.readString();
return name;
}
I would like to know, how to make scrollview swipe effect when mouse is dragged up and down. I'm developing JavaFX application which has ListView & I need to scroll the list when user drags the mouse up and down (like iOS contact list).
Also how to add the user's dragging velocity and speed to the scrolling value?
UPDATED : I got some code here but It doesn't work properly...
import java.util.ArrayList;
import java.util.Arrays;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.animation.TimelineBuilder;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.Event;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.ScrollEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.FlowPane;
import javafx.util.Duration;
public class Swipe extends ScrollPane {
private static final int INERTIA_DURATION = 2400;
private static final double CLICK_THRESHOLD = 20;
private static final double CLICK_TIME_THRESHOLD = Integer.parseInt(System.getProperty("click", "400"));
private final double width;
private final double height;
private long startDrag;
private long lastDrag;
private long lastDragDelta;
private int startDragX;
private int startDragY;
private int lastDragX;
private int lastDragY;
private int lastDragStepX;
private int lastDragStepY;
private double dragVelocityX;
private double dragVelocityY;
private boolean clickThresholdBroken;
private Timeline inertiaTimeline = null;
private long lastClickTime = -1;
private final boolean isFiredByMe = false;
public Swipe(double width, double height) {
this.width = width;
this.height = height;
init();
}
private void init() {
setPrefSize(width, height);
setPannable(true);
setHbarPolicy(ScrollBarPolicy.NEVER);
setVbarPolicy(ScrollBarPolicy.NEVER);
setEventHandlers();
ContentPane cp = new ContentPane();
setContent(cp);
}
private void setEventHandlers() {
setOnMousePressed((MouseEvent event) -> {
lastDragX = startDragX = (int) event.getX();
lastDragY = startDragY = (int) event.getY();
lastDrag = startDrag = System.currentTimeMillis();
lastDragDelta = 0;
if (inertiaTimeline != null) {
inertiaTimeline.stop();
}
clickThresholdBroken = false;
});
setOnDragDetected((MouseEvent event) -> {
// Delta of this drag vs. last drag location (or start)
lastDragStepX = (int) event.getX() - lastDragX;
lastDragStepY = (int) event.getY() - lastDragY;
// Duration of this drag step.
lastDragDelta = System.currentTimeMillis() - lastDrag;
// Velocity of last drag increment.
dragVelocityX = (double) lastDragStepX / (double) lastDragDelta;
dragVelocityY = (double) lastDragStepY / (double) lastDragDelta;
// Snapshot of this drag event.
lastDragX = (int) event.getX();
lastDragY = (int) event.getY();
lastDrag = System.currentTimeMillis();
// Calculate distance so far -- have we dragged enough to scroll?
final int dragX = (int) event.getX() - startDragX;
final int dragY = (int) event.getY() - startDragY;
double distance = Math.abs(Math.sqrt((dragX * dragX) + (dragY * dragY)));
int scrollDistX = lastDragStepX;
int scrollDistY = lastDragStepY;
if (!clickThresholdBroken && distance > CLICK_THRESHOLD) {
clickThresholdBroken = true;
scrollDistX = dragX;
scrollDistY = dragY;
}
if (clickThresholdBroken) {
Event.fireEvent(event.getTarget(), new ScrollEvent(
ScrollEvent.SCROLL,
scrollDistX, scrollDistY,
scrollDistX, scrollDistY,
event.isShiftDown(), event.isControlDown(), event.isAltDown(), event.isMetaDown(),
true, false,
event.getX(), event.getY(),
event.getSceneX(), event.getSceneY(),
ScrollEvent.HorizontalTextScrollUnits.NONE, 0,
ScrollEvent.VerticalTextScrollUnits.NONE, 0, 0, null));
}
});
setOnMouseReleased((MouseEvent event) -> {
handleRelease(event);
});
setOnMouseClicked((MouseEvent event) -> {
final long time = System.currentTimeMillis();
if (clickThresholdBroken || (lastClickTime != -1 && (time - lastClickTime) < CLICK_TIME_THRESHOLD)) {
event.consume();
}
lastClickTime = time;
});
}
private void handleRelease(final MouseEvent me) {
if (clickThresholdBroken) {
// Calculate last instantaneous velocity. User may have stopped moving
// before they let go of the mouse.
final long time = System.currentTimeMillis() - lastDrag;
dragVelocityX = (double) lastDragStepX / (time + lastDragDelta);
dragVelocityY = (double) lastDragStepY / (time + lastDragDelta);
// determin if click or drag/flick
final int dragX = (int) me.getX() - startDragX;
final int dragY = (int) me.getY() - startDragY;
// calculate complete time from start to end of drag
final long totalTime = System.currentTimeMillis() - startDrag;
// if time is less than 300ms then considered a quick flick and whole time is used
final boolean quick = totalTime < 300;
// calculate velocity
double velocityX = quick ? (double) dragX / (double) totalTime : dragVelocityX; // pixels/ms
double velocityY = quick ? (double) dragY / (double) totalTime : dragVelocityY; // pixels/ms
final int distanceX = (int) (velocityX * INERTIA_DURATION); // distance
final int distanceY = (int) (velocityY * INERTIA_DURATION); // distance
//
DoubleProperty animatePosition = new SimpleDoubleProperty() {
double lastMouseX = me.getX();
double lastMouseY = me.getY();
#Override
protected void invalidated() {
final double mouseX = me.getX() + (distanceX * get());
final double mouseY = me.getY() + (distanceY * get());
final double dragStepX = mouseX - lastMouseX;
final double dragStepY = mouseY - lastMouseY;
if (Math.abs(dragStepX) >= 1.0 || Math.abs(dragStepY) >= 1.0) {
Event.fireEvent(me.getTarget(), new ScrollEvent(
ScrollEvent.SCROLL,
dragStepX, dragStepY,
(distanceX * get()), (distanceY * get()),
me.isShiftDown(), me.isControlDown(), me.isAltDown(), me.isMetaDown(),
true, true,
me.getX(), me.getY(),
me.getSceneX(), me.getSceneY(),
ScrollEvent.HorizontalTextScrollUnits.NONE, 0,
ScrollEvent.VerticalTextScrollUnits.NONE, 0,
0, null));
}
lastMouseX = mouseX;
lastMouseY = mouseY;
}
};
// animate a slow down from current velocity to zero
inertiaTimeline = TimelineBuilder.create()
.keyFrames(
new KeyFrame(Duration.ZERO, new KeyValue(animatePosition, 0)),
new KeyFrame(Duration.millis(INERTIA_DURATION), new KeyValue(animatePosition, 1d, Interpolator.SPLINE(0.0513, 0.1131, 0.1368, 1.0000)))
).build();
inertiaTimeline.play();
}
}
private class ContentPane extends FlowPane {
private ArrayList getList() {
String[] list = {
"Kerrie Batts", "Raina Huffstutler", "Kip Kukowski", "Trish Sullivan", "Kyla Hollingsworth", "Gearldine Leavy", "Major Langdon", "Avery Rusin", "Hedy Messina", "Audry Felps", "Tianna Robbins", "Marian Tranmer", "Lashaunda Bivona", "Leighann Schwab", "Emanuel Volpe", "Neida Geist", "Edda Placencia", "Olevia Hippe", "Fernando Cohen", "Danette Dorsett"};
ArrayList<String> nameList = new ArrayList();
nameList.addAll(Arrays.asList(list));
return nameList;
}
public ContentPane() {
setPrefSize(215, 271);
ArrayList<String> nameList = getList();
Element[] element = new Element[nameList.size()];
for (int i = 0; i < nameList.size(); i++) {
String name = nameList.get(i);
Element el = element[i] = new Element(210, 25, name);
getChildren().add(el);
}
}
}
private class Element extends AnchorPane {
private double width;
private double height;
private String name;
public Element(double width, double height, String name) {
this.width = width;
this.height = height;
this.name = name;
init();
}
private Label createName() {
Label label = new Label(name);
label.setPrefSize(width, height);
label.setAlignment(Pos.CENTER_LEFT);
AnchorPane.setLeftAnchor(label, 5.0);
label.setStyle("-fx-font-family: Calibri; -fx-font-size: 14;");
return label;
}
private void init() {
setPrefSize(width, height);
getChildren().add(createName());
}
public void setPrefSize(double width, double height) {
this.width = width;
this.height = height;
}
public void setName(String name) {
this.name = name;
}
}
}
I figured out myself. There is two classes. 1st one is for calculate the velocity of the movement.
VelocityTracker.java
import javafx.scene.input.MouseEvent;
public final class VelocityTracker {
private static final boolean DEBUG = false;
private static final boolean localLOGV = DEBUG;
private static final int NUM_PAST = 10;
private static final int MAX_AGE_MILLISECONDS = 200;
private static final int POINTER_POOL_CAPACITY = 20;
private static Pointer sRecycledPointerListHead;
private static int sRecycledPointerCount;
private static final class Pointer {
public Pointer next;
public int id;
public float xVelocity;
public float yVelocity;
public final float[] pastX = new float[NUM_PAST];
public final float[] pastY = new float[NUM_PAST];
public final long[] pastTime = new long[NUM_PAST]; // uses Long.MIN_VALUE as a sentinel
}
private Pointer mPointerListHead; // sorted by id in increasing order
private int mLastTouchIndex;
public VelocityTracker() {
clear();
}
public void clear() {
releasePointerList(mPointerListHead);
mPointerListHead = null;
mLastTouchIndex = 0;
}
public void addMovement(MouseEvent ev) {
final int historySize = 0;
final int lastTouchIndex = mLastTouchIndex;
final int nextTouchIndex = (lastTouchIndex + 1) % NUM_PAST;
final int finalTouchIndex = (nextTouchIndex + historySize) % NUM_PAST;
mLastTouchIndex = finalTouchIndex;
if (mPointerListHead == null) {
mPointerListHead = obtainPointer();
}
final float[] pastX = mPointerListHead.pastX;
final float[] pastY = mPointerListHead.pastY;
final long[] pastTime = mPointerListHead.pastTime;
pastX[finalTouchIndex] = (float) ev.getX();
pastY[finalTouchIndex] = (float) ev.getY();
pastTime[finalTouchIndex] = System.currentTimeMillis();
}
public void computeCurrentVelocity(int units) {
computeCurrentVelocity(units, Float.MAX_VALUE);
}
public void computeCurrentVelocity(int units, float maxVelocity) {
final int lastTouchIndex = mLastTouchIndex;
for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) {
final long[] pastTime = pointer.pastTime;
int oldestTouchIndex = lastTouchIndex;
int numTouches = 1;
final long minTime = pastTime[lastTouchIndex] - MAX_AGE_MILLISECONDS;
while (numTouches < NUM_PAST) {
final int nextOldestTouchIndex = (oldestTouchIndex + NUM_PAST - 1) % NUM_PAST;
final long nextOldestTime = pastTime[nextOldestTouchIndex];
if (nextOldestTime < minTime) { // also handles end of trace sentinel
break;
}
oldestTouchIndex = nextOldestTouchIndex;
numTouches += 1;
}
if (numTouches > 3) {
numTouches -= 1;
}
final float[] pastX = pointer.pastX;
final float[] pastY = pointer.pastY;
final float oldestX = pastX[oldestTouchIndex];
final float oldestY = pastY[oldestTouchIndex];
final long oldestTime = pastTime[oldestTouchIndex];
float accumX = 0;
float accumY = 0;
for (int i = 1; i < numTouches; i++) {
final int touchIndex = (oldestTouchIndex + i) % NUM_PAST;
final int duration = (int) (pastTime[touchIndex] - oldestTime);
if (duration == 0) {
continue;
}
float delta = pastX[touchIndex] - oldestX;
float velocity = (delta / duration) * units; // pixels/frame.
accumX = (accumX == 0) ? velocity : (accumX + velocity) * .5f;
delta = pastY[touchIndex] - oldestY;
velocity = (delta / duration) * units; // pixels/frame.
accumY = (accumY == 0) ? velocity : (accumY + velocity) * .5f;
}
if (accumX < -maxVelocity) {
accumX = -maxVelocity;
} else if (accumX > maxVelocity) {
accumX = maxVelocity;
}
if (accumY < -maxVelocity) {
accumY = -maxVelocity;
} else if (accumY > maxVelocity) {
accumY = maxVelocity;
}
pointer.xVelocity = accumX;
pointer.yVelocity = accumY;
}
}
public float getXVelocity() {
Pointer pointer = getPointer(0);
return pointer != null ? pointer.xVelocity : 0;
}
public float getYVelocity() {
Pointer pointer = getPointer(0);
return pointer != null ? pointer.yVelocity : 0;
}
public float getXVelocity(int id) {
Pointer pointer = getPointer(id);
return pointer != null ? pointer.xVelocity : 0;
}
public float getYVelocity(int id) {
Pointer pointer = getPointer(id);
return pointer != null ? pointer.yVelocity : 0;
}
private Pointer getPointer(int id) {
for (Pointer pointer = mPointerListHead; pointer != null; pointer = pointer.next) {
if (pointer.id == id) {
return pointer;
}
}
return null;
}
private static Pointer obtainPointer() {
if (sRecycledPointerCount != 0) {
Pointer element = sRecycledPointerListHead;
sRecycledPointerCount -= 1;
sRecycledPointerListHead = element.next;
element.next = null;
return element;
}
return new Pointer();
}
private static void releasePointer(Pointer pointer) {
if (sRecycledPointerCount < POINTER_POOL_CAPACITY) {
pointer.next = sRecycledPointerListHead;
sRecycledPointerCount += 1;
sRecycledPointerListHead = pointer;
}
}
private static void releasePointerList(Pointer pointer) {
if (pointer != null) {
int count = sRecycledPointerCount;
if (count >= POINTER_POOL_CAPACITY) {
return;
}
Pointer tail = pointer;
for (;;) {
count += 1;
if (count >= POINTER_POOL_CAPACITY) {
break;
}
Pointer next = tail.next;
if (next == null) {
break;
}
tail = next;
}
tail.next = sRecycledPointerListHead;
sRecycledPointerCount = count;
sRecycledPointerListHead = pointer;
}
}
}
And this is second class
import java.util.concurrent.atomic.AtomicReference;
import javafx.animation.FadeTransition;
import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Bounds;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Region;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.util.Duration;
public class VerticlePane extends Region {
private ObjectProperty<Node> content;
private final VelocityTracker tracker = new VelocityTracker();
private final Rectangle clipRect = new Rectangle();
private Rectangle scrollNode;
private boolean magnet, autoTranslate = true;
private DoubleProperty targetY = new SimpleDoubleProperty(), controlHeight = new SimpleDoubleProperty(), viewHeight = new SimpleDoubleProperty();
private double startValue, endValue;
private HBox indicator;
private StringProperty indicatorValue = new SimpleStringProperty("Pull Up to Update...");
public VerticlePane() {
setFocusTraversable(false);
setClip(clipRect);
contentProperty().addListener((ObservableValue<? extends Node> observable, Node oldValue, Node newValue) -> {
getChildren().clear();
if (newValue != null) {
getChildren().addAll(newValue, createRectangle());
}
layout();
});
final AtomicReference<MouseEvent> deltaEvent = new AtomicReference<>();
final AtomicReference<TranslateTransition> currentTransition1 = new AtomicReference<>();
final AtomicReference<TranslateTransition> currentTransition2 = new AtomicReference<>();
final AtomicReference<Timeline> timeline = new AtomicReference<>();
setOnMousePressed((me) -> {
tracker.addMovement(me);
deltaEvent.set(me);
startValue = me.getY();
if (currentTransition1.get() != null) {
currentTransition1.get().stop();
}
if (currentTransition2.get() != null) {
currentTransition2.get().stop();
}
if (timeline.get() != null) {
timeline.get().stop();
}
});
setOnMouseDragged((event) -> {
tracker.addMovement(event);
double delta = event.getY() - deltaEvent.get().getY();
targetY.set(content.get().getTranslateY() + delta);
content.get().setTranslateY(targetY.get());
controlHeight.set(content.get().getLayoutBounds().getHeight());
viewHeight.set(getHeight());
double scrollTargetY = targetY.divide(controlHeight.divide(viewHeight.get()).get()).get();
double lastInstanceHeight = controlHeight.subtract(viewHeight.get()).multiply(-1).get();
scrollNode.relocate(1.0, (getHeight() - 5.0));
scrollNode.setArcHeight(5.0);
scrollNode.setArcWidth(5.0);
scrollNode.setHeight(viewHeight.divide(controlHeight.divide(viewHeight.get()).get()).get());
scrollNode.setVisible(true);
scrollNode.setOpacity(0.25);
if (targetY.lessThan(0).and(targetY.greaterThan(lastInstanceHeight)).get()) {
scrollNode.setTranslateY(Math.abs(scrollTargetY));
} else if (targetY.greaterThanOrEqualTo(0).get()) {
scrollNode.setHeight(scrollNode.getHeight() - targetY.get());
}
if (targetY.get() < lastInstanceHeight) {
double scrollNodeHeight = scrollNode.getHeight() - (lastInstanceHeight - targetY.get());
double scrollNodeTranslateY = viewHeight.subtract(viewHeight.divide(controlHeight.divide(viewHeight.get()).get()).get()).add(lastInstanceHeight - targetY.get()).get();
scrollNode.setHeight(scrollNodeHeight);
scrollNode.setTranslateY(scrollNodeTranslateY);
}
deltaEvent.set(event);
});
setOnMouseReleased((me) -> {
FadeTransition ft = new FadeTransition(Duration.millis(300), scrollNode);
ft.setFromValue(0.25);
ft.setToValue(0.00);
tracker.addMovement(me);
tracker.computeCurrentVelocity(500);
endValue = me.getY();
controlHeight.set(content.get().getLayoutBounds().getHeight());
viewHeight.set(getHeight());
float velocityY = tracker.getYVelocity();
targetY.set(scrollNode(velocityY, currentTransition1, content.get()));
TranslateTransition tt = bb(currentTransition2, scrollNode, Math.abs((targetY.divide(controlHeight.divide(viewHeight.get()).get()).get())));
tt.setOnFinished((ae) -> {
ft.play();
});
});
}
public double getStartValue() {
return startValue;
}
public double getEndValue() {
return endValue;
}
public double getControlHeight() {
return controlHeight.get();
}
public double getViewHeight() {
return viewHeight.get();
}
public VerticlePane(double prefWidth, double prefHeight) {
this();
setPrefSize(prefWidth, prefHeight);
}
public VerticlePane(double prefWidth, double prefHeight, boolean magnet) {
this(prefWidth, prefHeight);
setMagnet(magnet);
}
public final void setMagnet(boolean magnet) {
this.magnet = magnet;
}
private TranslateTransition bb(AtomicReference<TranslateTransition> currentTransition, Node node, Double targetY) {
TranslateTransition translate = new TranslateTransition(new Duration(1000), node);
if (node != null) {
translate.setInterpolator(Interpolator.SPLINE(0.0513, 0.1131, 0.1368, 1.0000));
if (targetY != null) {
translate.setFromY(node.getTranslateY());
translate.setToY(targetY);
}
translate.play();
currentTransition.set(translate);
}
return translate;
}
private Double scrollNode(float velocityY, AtomicReference<TranslateTransition> currentTransition, Node node) {
final Bounds b = node.getLayoutBounds();
Double backBouncingY = null;
Double targetY = null;
if (node != null) {
TranslateTransition translate = new TranslateTransition(new Duration(1000), node);
translate.setInterpolator(Interpolator.SPLINE(0.0513, 0.1131, 0.1368, 1.0000));
if (Math.abs(velocityY) < 10) {
velocityY = 0;
}
targetY = node.getTranslateY();
double controlHeight = b.getHeight() - indicator.heightProperty().add(10).get();
double viewHeight = getHeight();
if (controlHeight < viewHeight && targetY < controlHeight) {
targetY = 0.0;
} else if (targetY > 0) {
targetY = 0.0;
} else if ((targetY < (controlHeight - viewHeight) * -1)) {
targetY = (controlHeight - viewHeight) * -1;
} else {
targetY += velocityY;
if (controlHeight < viewHeight && targetY < controlHeight) {
targetY = -25.0;
backBouncingY = 0.0;
} else if (targetY > 0) {
targetY = 25.0;
backBouncingY = 0.0;
} else if (targetY < (controlHeight - viewHeight) * -1) {
targetY = (controlHeight - viewHeight) * -1 - 25;
backBouncingY = (controlHeight - viewHeight) * -1;
}
}
//Magnet
if (magnet) {
double dragRegion = (viewHeight / 2) * -1;
double instances = controlHeight / viewHeight;
double lastInstance = ((controlHeight - viewHeight) * -1);
double newInstanceValue = dragRegion;
if (targetY > dragRegion) {
targetY = 0.0;
}
if (instances > 1) {
for (int i = 1; i < instances - 1; i++) {
double instanceValue = (viewHeight * i) * -1;
if (targetY < newInstanceValue && targetY > instanceValue || targetY < instanceValue && targetY > (instanceValue + dragRegion)) {
targetY = instanceValue;
}
newInstanceValue += (viewHeight * -1);
}
}
if (targetY < (lastInstance - dragRegion) && targetY > lastInstance) {
targetY = lastInstance;
}
}
//
if (targetY != null) {
translate.setFromY(node.getTranslateY());
translate.setToY(targetY);
}
if (backBouncingY != null) {
final Double fbackFlingY = backBouncingY;
translate.setOnFinished((ae) -> {
currentTransition.set(null);
TranslateTransition translate1 = new TranslateTransition(new Duration(300), node);
if (fbackFlingY != null) {
translate1.setFromY(node.getTranslateY());
translate1.setToY(fbackFlingY);
}
translate1.play();
currentTransition.set(translate1);
});
} else {
translate.setOnFinished((ae) -> {
currentTransition.set(null);
});
}
translate.play();
currentTransition.set(translate);
}
return targetY;
}
private Rectangle createRectangle() {
if (scrollNode == null) {
scrollNode = new Rectangle(4.0, 4.0, Color.BLACK);
}
scrollNode.setVisible(false);
return scrollNode;
}
public ObjectProperty<Node> contentProperty() {
if (content == null) {
content = new SimpleObjectProperty<>(this, "content");
}
return content;
}
public final void setContent(Node value) {
contentProperty().set(
new VBox(10) {
{
getChildren().addAll(value, indicator());
}
}
);
contentProperty().get().layoutBoundsProperty().addListener((ObservableValue<? extends Bounds> obs, Bounds ov, Bounds nv) -> {
Double containerHeight = nv.getHeight();
Double flingHeight = prefHeightProperty().get();
if (autoTranslate) {
if (flingHeight <= containerHeight) {
contentProperty().get().setTranslateY((containerHeight - flingHeight - 34) * -1);
}
}
});
}
private HBox indicator() {
return indicator = new HBox(10) {
{
setVisible(false);
setAlignment(Pos.CENTER);
getChildren().addAll(
new ImageView(new Image(getClass().getResourceAsStream("Indicator.gif"))),
new Label() {
{
textProperty().bind(indicatorValue);
setStyle("-fx-font-family: Roboto; -fx-font-size: 14px;");
}
}
);
}
};
}
public void setAutoTranslate(Boolean autoTranslate) {
this.autoTranslate = autoTranslate;
}
public void setTranslateZero() {
this.contentProperty().get().setTranslateY(0);
}
public HBox getIndicator() {
return indicator;
}
public void showIndicator() {
indicator.setVisible(true);
}
public void hideIndicator() {
indicator.setVisible(false);
}
public void setIndicatorValue(String value) {
indicatorValue.setValue(value);
}
public final Node getContent() {
return content == null ? null : content.get();
}
#Override
protected void layoutChildren() {
super.layoutChildren();
clipRect.setWidth(getWidth());
clipRect.setHeight(getHeight());
}
}
Scroll Bar disabled why?
It should not extend:
public class VerticlePane extends Control