Move tile by tile with dynamic speed - java

I'm using java with slick2d library and trying to move tile by tile with dynamic speed. I have tried a couple methods but none of them can move with dynamic speed between the tiles. Can someone help me with that and give some examples?
edit:
this two methods have I tried
move with out delta
movementSpeed = 2;
//decide direction
if(targetX != x)
{
animation.update(delta);
if(originalX < targetX)
x += movementSpeed;
else if(originalX > targetX)
x -= movementSpeed;
}
if(targetY != y)
{
animation.update(delta);
if(originalY < targetY)
y += movementSpeed;
else if(originalY > targetY)
y -= movementSpeed;
}
lerp
public static float lerp(float start, float stop, float t)
{
if (t < 0)
return start;
return start + t * (stop - start);
}
public void move(long delta)
{
if (procentMoved == 0)
{
if (getSpeed(targetX, targetY) != 0)
{
movementSpeed = getSpeed(targetX, targetY);
} else
{
targetX = originalX;
targetY = originalY;
}
}
if (procentMoved < 1)
{
animation.update(delta);
// movementSpeed = getSpeed(targetX, targetY);
procentMoved += movementSpeed;
} else if (procentMoved > 1)
{
animation.update(delta);
//TODO fix bouncing bug
procentMoved = 1;
}
+ movementSpeed);
x = lerp(originalX, targetX, procentMoved);
y = lerp(originalY, targetY, procentMoved);
if (x == targetX)
;
originalY = x;
if (y == targetY)
;
originalY = y;
}

It seems as if this could be your issue. Your if statements are just closing and not really doing its part. Also, you're variables are mixed up as well.
if (x == targetX)
; // This will skip the If statement
originalY = x;
if (y == targetY)
; // This will skip the If statement
originalY = y;
}
In all reality you're saying
orginalY = x; // Y = X?
orginalY = y; // Y = Y
Please do not take this to heart. I'm still having this issue as well, however I'm having to do some corrections and auto placements in order for this to work correctly.

Related

Program is not checking the second condition

When I run my game it works fine on the bottom portion of the object collision but, it will not distguish that one and the other if. It is not reading the second one. I took a picture and you can see the (x, y) coords and it meets the condition but, I can still move.
IMG: http://i.stack.imgur.com/PjcHB.png
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
public class Player{
int x = 1; // Location of player
int y = 314; // location of player
int xa = 0; // Representation of where the player goes
int ya = 0; // Representation of where the player goes
int playerWeight = 115;
private int speed = 2;
int[] playerPos = {x, y};
private static final int WIDTH = 30;
private static final int HEIGHT = 30;
private Game game;
public Player(Game game){
this.game=game;
}
public void move(){
System.out.println(x + ", " + y);
x = x + xa;
y = y + ya;
if(x + xa < 0) // Left Bounds
xa = 0;
if (x + xa > game.getWidth() - WIDTH) // Right Bounds
xa = 0;
if (y + ya < 0) // Top Bounds
ya = 0;
if(y + ya > game.getHeight() - WIDTH)
ya = 0;
if (collision()) // Tile bounds
y = y - 4;
if (collision2()){
if(x > 370 && x < 531 && y < 286){ // Check for 3 values
y = y + 4;
System.out.println("-x");
/*
* Use the gravity() method to determine player fall rate
*/
}
else if(x > 370 && x < 531 && y > 223){ // Check for 3 values
ya = 0;
System.out.println("+x");
/*
* Use the gravity() method to determine player fall rate
*/
}
}
}
// Method to find where player is located
public int[] Playerposition(){
x = 1;
y = 300;
return playerPos;
}
public void Gravity(){
}
public void paint(Graphics2D g2d){
//Draws player to screen
g2d.drawImage(getPlayerImg(), x, y, null);
}
public Image getPlayerImg(){
ImageIcon ic = new ImageIcon("C:/Users/AncientPandas/Desktop/KingsQuest/Misc/Images/Sprites/player.png");
return ic.getImage();
}
public void keyReleased(KeyEvent e){
xa = 0;
ya = 0;
}
public void keyPressed(KeyEvent e){
if (e.getKeyCode() == KeyEvent.VK_S)
xa = -speed;
if (e.getKeyCode() == KeyEvent.VK_F)
xa = speed;
if (e.getKeyCode() == KeyEvent.VK_E)
ya = -speed;
if (e.getKeyCode() == KeyEvent.VK_D)
ya = speed;
}
public Rectangle getBoundsPlayer(){
return new Rectangle(x, y, WIDTH, HEIGHT);
}
private boolean collision(){
return game.maplayout.getBoundsBlock().intersects(getBoundsPlayer());
}
private boolean collision2(){
return game.maplayout.getBoundsBlock2().intersects(getBoundsPlayer());
}
}
Change:
else if(x > 370 && x < 531 && y > 223){ // Check for 3 values
ya = 0;
System.out.println("+x");
/*
* Use the gravity() method to determine player fall rate
*/
}
to:
if(x > 370 && x < 531 && y < 286){ // Check for 3 values
y = y + 4;
System.out.println("-x");
/*
* Use the gravity() method to determine player fall rate
*/
}
if(x > 370 && x < 531 && y > 223){ // Check for 3 values
ya = 0;
System.out.println("+x");
/*
* Use the gravity() method to determine player fall rate
*/
}
Reason being is that the keyword "else" will only execute code within it's block if the above "if" statement's condition fails/requirements are not met. For example:
boolean anInteger = 9;
if (anInteger == 1999) {
// ...
} else {
// If 'anInteger' is not equal to 9, then execute the following code (within this block)
// ...
}

Collision method gone crazy;

I am building a 2d tile based game, similiar to a Legend of Zelda game, and my collision method is not working properly. The method will return collisions when the player is far below an impassable tile. There must be a logic error I do not see here. This is in Java.
From static collision class:
public static boolean collisionAbovePlayer(TileGrid grid, float x, float y, int width, int height) {
boolean collision = false;
for (Tile[] row : grid.map) {
for (Tile t : row) {
// Each Tile t in map:
if (t.getType().getPassable() == false) {
// Each impassable tile:
if ( (x-t.getX() > 0 && x - t.getX() < t.getWidth()) || (x - t.getX() < 0 && Math.abs(x - t.getX()) < width )) {
// Tile is within collision x range
if ((t.getY() + t.getHeight() + 1) - y < Math.abs(5)) {
collision = true;
} else {
collision = false;
}
} else {
collision = false;
}
}
}
}
return collision;
}
This is being called by this method in my Player class (I haven't implemented collision methods for the other directions yet):
public void Update() {
if (first)
first = false;
else {
if ((Keyboard.isKeyDown(Keyboard.KEY_W)) && (!collisionAbovePlayer(grid, x, y, width, height))) {
y -= Delta() * speed;
}
if (Keyboard.isKeyDown(Keyboard.KEY_A)) {
x -= Delta() * speed;
}
if (Keyboard.isKeyDown(Keyboard.KEY_S)) {
y += Delta() * speed;
}
if (Keyboard.isKeyDown(Keyboard.KEY_D)) {
x += Delta() * speed;
}
}
}
Let me know if you need to see more of the code, thanks for your time.
Fixed:
public static boolean collisionAbovePlayer(TileGrid grid, float x, float y, int width, int height) {
for (Tile[] row : grid.map) {
for (Tile t : row) {
// Each Tile t in map:
if (!t.getType().getPassable()) {
// Each impassable tile:
if ((x - t.getX() > 0 && x - t.getX() < t.getWidth()) || (x - t.getX() < 0 && Math.abs(x - t.getX()) < width )) {
// Tile is within collision x range
System.out.println("IN X RANGE");
if (Math.abs((t.getY() + t.getHeight() + 1) - y) < 2) {
return true;
}
}
}
}
}
return false;
}
In the original code it only returned the last tile that set 'boolean collision' to true, and the final statement checking the Y required Math.abs() around the first value.

Transition 2D player Position A to B on JAVA

Am having issues trying to figure out how to translate or 'animate' my player's position to a new tile, this is what am doing :
if (input.right){
x += 1;
Right now am listening for key.inputs and then x++/x-- or y++/y-- on my players position that makes him move pixel by pixel, but i want my player to move exactly to the next tile(32 pixels) with one hit of the key with like a linear transition from the player's tile position to the next tile over time?
Something like (pseudo code i think..)
if input && walking false
walking = true
increment 1 by 1 32 ints to X over time?
after completed walking = false
I still cant even figure out the logic behind something like that.
An example is the movement in a game called Tibia.
Now Some bits of my code (player related)..
GAMECLASS >
public Game()
player = new Player(playerSpawn.x(), playerSpawn.y(), key);
player.init(level);
public void run()
....
render();
frames++;
....
public void update()
key.update();
player.update();
level.update();
public void render()
.....
int xScroll = ( player.x + 32) - screen.width / 2;
int yScroll = ( player.y + 32) - screen.height / 2;
level.render(xScroll, yScroll, screen);
player.render(screen);
for (int i =0; i < pixels.length; i++){
pixels[i] = screen.pixels[i];
}
SCREENCLASS >
......
public int[] pixels;
public int[] tiles = new int[VIEW_SIZE * VIEW_SIZE];
.....
public void renderTile(int xp, int yp, Tile tile){
xp -= xOffset;
yp -= yOffset;
for (int y = 0; y < tile.sprite.SIZE; y++){
int ya = y + yp;
for (int x = 0; x < tile.sprite.SIZE; x++){
int xa = x + xp;
if (xa < -tile.sprite.SIZE || xa >= width || ya < 0 || ya >= height) break;
if (xa < 0) xa = 0;
pixels[xa + ya * width] = tile.sprite.pixels[x + y * tile.sprite.SIZE];
}
}
}
//THIS IS THE METHOD CALLED TO RENDER THE PLAYER > SEE BELLOW AT THE PLAYER CLASS FOR THE CALL
public void renderMob(int xp, int yp, Mob mob){
xp -= xOffset;
yp -= yOffset;
for (int y = 0; y < 64; y++){
int ya = y + yp;
int ys = y;
for (int x = 0; x < 64; x++){
int xa = x + xp;
int xs = x;
if (xa < -64 || xa >= width || ya < 0 || ya >= height) break;
if (xa < 0) xa = 0;
int col = mob.getSprite().pixels[xs + ys * 64];
if (mob instanceof Chazer && col == 0xFF9b0000) col = 0xff54ff00;
if (col != 0xFFFF00FF) pixels[xa + ya * width] = col;
}
}
}
PLAYERCLASS >
public Player(int x , int y, Keyboard input){
this.x = x;
this.y = y;
this.input = input;
}
//PLAYER UPDATE
public void update(){
if (anim < 7500) anim++;
else anim = 0;
if (input.down) ya = 1;
if (input.up) ya = -1;
if (input.left) xa = -1;
if (input.right) xa = 1;
//CHECK BELLOW TO THIS MOVE METHOD
if (xa != 0){
move(xa, 0);
} else if(ya != 0){
move(0, ya);
}
}
clear();
}
//HERE ANIMATION AND CHOOSE WHAT SPRITE = WHERE PLAYER IS LOOKING AT
public void render(Screen screen){
if (dir == 0) {
sprite = Sprite.player_n;
if (walking) {
if (anim % 20 > 10){
sprite = sprite.player_n1;
} else {
sprite = sprite.player_n2;
}
}
}
if (dir == 1) {
sprite = Sprite.player_e;
if (walking) {
if (anim % 20 > 10){
sprite = sprite.player_e1;
} else {
sprite = sprite.player_e2;
}
}
}
if (dir == 2) {
sprite = Sprite.player_s;
if (walking) {
if (anim % 20 > 10){
sprite = sprite.player_s1;
} else {
sprite = sprite.player_s2;
}
}
}
if (dir == 3) {
sprite = Sprite.player_w;
if (walking) {
if (anim % 20 > 10){
sprite = sprite.player_w1;
} else {
sprite = sprite.player_w2;
}
}
}
// ADDING OFFSET CUZ THE PLAYER IS DOUBLE THE SIZE OF THE TILE
int xx = x - 42;
int yy = y - 42;
screen.renderMob(xx, yy, sprite);
}
//THIS IS HOW I MOVE THE PLAYER
public void move(int xa, int ya){
if (xa != 0 && ya != 0){
move(xa, 0);
move(0, ya);
return;
}
if (xa > 0) dir = 1;
if (xa < 0) dir = 3;
if (ya > 0) dir = 2;
if (ya < 0) dir = 0;
if(!collision(xa, 0)){
x += xa;
}
if(!collision(0, ya)){
y += ya;
}
}
Thanks alooot!
**Run method!
public void run() {
long xlastTime = System.nanoTime();
long timer = System.currentTimeMillis();
final double xns = 1000000000.0 / 60.0;
double delta = 0;
int frames = 0;
requestFocus();
while(running){
long xnow = System.nanoTime();
delta += (xnow-xlastTime) / xns;
xlastTime = xnow;
while (delta >= 1) {
update();
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000){
timer += 1000;
frame.setTitle(title + " | " + frames + " fps");
frames = 0;
}
}
stop();
}
What I would do is declare two int fields in the player class:
private float xToMove = 0;
private float yToMove = 0;
Then, under your input event:
if (input.down && yToMove == 0)
yToMove = -32;
if (input.up && yToMove == 0)
yToMove = 32;
if (input.left && xToMove == 0)
xToMove = -32;
if (input.right && xToMove == 0)
xToMove = 32;
And finally, in your Player class's update method:
public void update()
{
if (xToMove > 0)
{
xToMove--;
x++;
}
if (xToMove < 0)
{
xToMove++;
x--;
}
if (yToMove > 0)
{
yToMove--;
y++;
}
if (yToMove < 0)
{
yToMove++;
y--;
}
}
Of course this is simplified a bit but the concept is there
EDIT: to change the speed. Note that xToMove and yToMove have been changed to floats.
You can use a float to represent the amount of time 1 move takes
float period = 1000; //The time one move takes in milliseconds
Somewhere you should calculate the number of pixels to be moved each frame. You could make a calculateSpeed() method or just throw it into the constructor or something. Depends on if you want speed to change during the game.
float speed = 32f / (fps * (period / 1000f)); //fps should be obtained dynamically and should be a float
Then when you update you should do this:
if (xToMove > 0)
{
xToMove -= speed;
x += speed;
if (xToMove <= 0)
{
//Set these guys to nice even numbers to prevent problems
xToMove = 0;
x = (float) Math.round(x);
}
}
Also make sure that x and y are floats.
EDIT 2: fps
int frames = 0;
int fps = 60;
requestFocus();
while(running){
long xnow = System.nanoTime();
delta += (xnow-xlastTime) / xns;
xlastTime = xnow;
while (delta >= 1) {
update();
delta--;
}
render();
frames++;
if (System.currentTimeMillis() - timer > 1000){
timer += 1000;
fps = frames;
frame.setTitle(title + " | " + fps + " fps");
frames = 0;
}
}
stop();

Libgdx Accelerometer not working?

for some reason the block is not moving when I tilt the screen, and I don't know what's wrong. Just to clarify, I set the cfg.accelerometer to true, but the cfg.compass to false. Here's the source code-
public void update()
{
x += velX;
y += velY;
//movement
//left
if (Gdx.input.isKeyPressed(Keys.LEFT))
{
velX = -speed;
}
//right
if (Gdx.input.isKeyPressed(Keys.RIGHT))
{
velX = speed;
}
//up
if (Gdx.input.isKeyPressed(Keys.UP))
{
velY = -speed;
}
//down
if (Gdx.input.isKeyPressed(Keys.DOWN))
{
velY = speed;
}
if (Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer))
{
velX = Gdx.input.getAccelerometerX();
velY = Gdx.input.getAccelerometerY();
}
//stop
if (!Gdx.input.isKeyPressed(Keys.LEFT) && !Gdx.input.isKeyPressed(Keys.RIGHT))
{
velX = 0;
}
if (!Gdx.input.isKeyPressed(Keys.UP) && !Gdx.input.isKeyPressed(Keys.DOWN))
{
velY = 0;
}
//collision with edges of screen
if (x <= 0)
{
x = 0;
}
if (x >= 1920 - width)
{
x = 1920 - width;
}
if (y <= 0)
{
y = 0;
}
if (y >= 1080 - height)
{
y = 1080 - height;
}
long recoveryElapsed = (System.nanoTime() - recoveryTimer)/1000000;
if (recoveryElapsed > 2000)
{
recovering = false;
recoveryTimer = 0;
}
System.out.println(lives+ " lives, recovering, "+recovering);
}
Help would be much appreciated, thanks. There are no tutorials that I have found with a working example shown, so I don't really know if what I am doing is correct, but I can't see anything wrong with it.
You are setting the Accel values, and then if the keys are not pressed you are setting them to 0 again. Do it like this:
//stop
if (!Gdx.input.isKeyPressed(Keys.LEFT) && !Gdx.input.isKeyPressed(Keys.RIGHT))
{
velX = 0;
}
if (!Gdx.input.isKeyPressed(Keys.UP) && !Gdx.input.isKeyPressed(Keys.DOWN))
{
velY = 0;
}
if (Gdx.input.isPeripheralAvailable(Input.Peripheral.Accelerometer))
{
velX = Gdx.input.getAccelerometerX();
velY = Gdx.input.getAccelerometerY();
}

How can I simplify this code? (Chess game obstruction testing)

I'm making a chess game in Java, and testing to make sure there are no pieces blocking the path of the piece being moved. The piece moves from (srcX,srcY) to (dstX,dstY).
I've written this code which checks if there are any obstructions for a rook:
if(dstY == srcY) {
// No change on Y axis, so moving east or west
if(dstX > srcX) {
// Moving east
// Test every cell the piece will pass over
for(int x = srcX+1; x < dstX; x++) {
// Is the cell set?
if(isPiece(x, srcY)) {
return true;
}
}
} else {
// Must be moving west
// Test every cell the piece will pass over
for(int x = srcX-1; x > dstX; x--) {
// Is the cell set?
if(isPiece(x, srcY)) {
return true;
}
}
}
} else if(dstX == srcX) {
// No change on X axis, so moving north or south
if(dstY > srcY) {
// Moving north
// Test every cell the piece will pass over
for(int y = srcY+1; y < dstY; y++) {
// Is the cell set?
if(isPiece(srcX, y)) {
return true;
}
}
} else {
// Must be moving south
// Test every cell the piece will pass over
for(int y = srcY-1; y > dstY; y--) {
// Is the cell set?
if(isPiece(srcX, y)) {
return true;
}
}
}
}
but it's a bit big and I'm sure it can be simplied.. any ideas?
ps, this is ONLY obstruction testing. I've already validated everything else.
Once you've tested for direction, you can set dx, dy values (e.g. dx=1, dy=0 for east). Then you can have a single for loop for all cases and just increment x and y by dx and dy respectively at each iteration.
You can then simplify the direction checking into the following:
if dstY == srcY: dy = 0
else: dy = (dstY - srcY) / abs(dstY - srcY)
if dstX == srcX: dx = 0
else: dx = (dstX - srcX) / abs(dstX - srcX)
Code:
int dx, dy;
if (dstY == srcY) dy = 0;
else dy = (dstY - srcY) / Math.abs(dstY - srcY);
if (dstX == srcX) dx = 0;
else dx = (dstX - srcX) / Math.abs(dstX - srcX);
while (srcX != dstX || srcY != dstY) {
srcX += dx; srcY += dy;
if (isPiece(srcX, srcY))
return true;
}
return false;
Also beware that this code (and yours) will fail if the move is not horizontal, vertical or diagonal.
You could do something along these lines (untested as I don't have a compiler to hand):
int dx = 0;
int dy = 0;
if (dstX != srcX) {
dx = (dstX > srcX) ? 1 : -1;
} else if (dstY != srcY) {
dy = (dstY > srcY) ? 1 : -1;
}
int x = srcX + dx;
int y = srcY + dy;
while (x != dstX || y != dstY) {
if (isPiece(x, y)) return true;
x += dx;
y += dy;
}
First, write tests. Lots and lots of tests. That way you can be confident that you're simplifying without changing the meaning of the code.
Refactoring without unit tests is like walking a high wire without a safety net.
Nearly the same, but with for loops:
// move along x axis
for (int x = 1; x < Math.abs(srcX - dstX); x++) {
int curX = (srcX - dstX) < 0 ? srcX - x : srcX + x;
if (isPiece(curX, srcY))
return true;
}
// move along y axis
for (int y = 1; y <= Math.abs(srcY - dstY); y++) {
int curY = (srcY - dstY) < 0 ? srcY - y : srcY + y;
if (isPiece(srcX, curY))
return true;
}
My soultion would be: introduce a direction class, and then do the check in this style:
isBlocked(startPossition, direction, numberOfFields)
I have done a little example, using 3 Classes.
Direction - an enum to represent the 8 directions (2 horizontal, 2 vertical, 4 diagonal)
Position - the x and y value of an position
LinarMove - represent one linear Move(startPossition, direction, numberOfFields) and contains the isBlockedMethod
The Enum:
public enum Direction {
UP(0, 1),
DOWN(0, -1),
LEFT(1, 0),
RIGHT(-1, 0),
UP_LEFT(UP, LEFT),
UP_RIGTH(UP, RIGHT),
DOWN_LEFT(DOWN, LEFT),
DOWN_RIGHT(
DOWN, RIGHT);
private final int incrementX;
private final int incrementY;
private Direction(int incrementX, int incrementY) {
this.incrementX = incrementX;
this.incrementY = incrementY;
}
private Direction(Direction sub1, Direction sub2) {
this.incrementX = sub1.incrementX + sub2.incrementX;
this.incrementY = sub1.incrementY + sub2.incrementY;
}
public Position oneField(Position start) {
return new Position(start.getX() + this.incrementX, start.getY()
+ this.incrementY);
}
}
The purpuse of second constructor is only that it alowes to write the diagonal moves in a more readable way.
public class Position {
private final int x;
private final int y;
public Position(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
#Override
public String toString() {
return "x:" + x + ", y:" + y;
}
}
The Move contains the isBlocked Method -- you can see how small it get, and how readable it become. At least there is no single direction related if statement left.
The name LinareMove sugget that there is possible an other kind of move for the knight.
public class LinearMove {
private final Position start;
private final Direction direction;
/** Length of the move. */
private final int numberOfFields;
public LinearMove(Position start, Direction direction, int numberOfFields) {
super();
this.start = start;
this.direction = direction;
this.numberOfFields = numberOfFields;
}
boolean isBlocked() {
Position pos = this.start;
for (int i = 0; i < (this.numberOfFields - 1); i++) {
pos = this.direction.oneField(pos);
if (isPiece(pos)) {
return true;
}
}
return false;
}
boolean isPiece(Position pos) {
//Dummy;
System.out.println(pos);
return false;
}
}
And this is how it works:
public static void main(String[] args) {
new LinearMove(new Position(1, 1), Direction.RIGHT, 3).isBlocked();
}
You maybe noticed, that the knights move is some kind of probem. With this soultion you could model it in two ways:
- 4 special Directions
- an other kind of move class (this is the more cleaner way, because you could always return true, in the isBockedMethod)

Categories

Resources