Finding cause of jitter in collision detection - java

I'm looking for help in finding the source of jitter when using collision detection.
I've implemented a java game (using eclipse and slick2d) and have been loosely following this guide:
http://katyscode.wordpress.com/2013/01/18/2d-platform-games-collision-detection-for-dummies
but of course changing bits where necessary to suit my game and java not cpp.
From the research I have done I think the root cause of my jitter is coming from rounding errors.
Despite that being my main suspect, I still haven't been able to identify where it's occurring.
Sorry if the indentation isn't quite right there, had a little trouble using the code block recognition.
Basically I'm creating variables in the class.
In init() I set up most of the resources.
In render() all the drawing takes place. Note the graphics translation so the camera follows the player.
In update I'm of course updating the position of the player according to user input, gravity and friction.
I also call my collision detection from this method.
Collision detection is working on a penetration resolution method.
(Yes I know I'm exhaustively comparing with every single world object. I will be improving my efficiency with AABB's when I have sorted more fundamental problems out. Like jitter!)
My method first calculates how much the player expects to move in each axis, then for each world object it checks for intersection with the players bounding points (floating point values that represent coordinates around the player). It checks this in each direction and uses the result to determine in which axis the collision occurred, if any, so that the appropriate action can be taken.
Sorry it's a put load of code, but it's collision detection after all, which isn't a small thing.
Here is my Play class where all the updating goes on for the game:
package GameFiles;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import org.newdawn.slick.*;
import org.newdawn.slick.state.*;
import java.awt.Rectangle;
//import java.awt.geom.Rectangle2D;
public class Play extends BasicGameState{
static int tileSize = 32;
File levelMap;
SpriteSheet spriteSheet;
int[][] currentMap;
Image[] groundTiles = new Image[4];
//List<Rectangle2D> levelBounds = new ArrayList<Rectangle2D>();
List<Rectangle> levelBounds = new ArrayList<Rectangle>();
Player player;
float playerX, playerY;
int dir;
float acc, mov, friction, gravity;
float runSpeed;
float maxAcc;
boolean inAir, jumping, keyDown;
boolean exitFlag;
int mapHeight, mapWidth;
float mapX, mapY;
float speedX, speedY;
int worldObjectCount;
int iterations;
public Play(int state){
}
public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
playerX = Game.scrWidth/2;
playerY = Game.scrHeight - tileSize - tileSize;
player = new Player(playerX, playerY);
levelMap = new File("maps/lvl1.txt");
spriteSheet = new SpriteSheet("res/tiles/tilesets/DungeonCrawlTilesetBW.png", tileSize, tileSize);
try
{
currentMap = readMap(levelMap);
}
catch (IOException e)
{
System.out.println("Array size mismatch when copying arrays.");
e.printStackTrace();
}
levelBounds.clear();
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++){
if(currentMap[x][y] == 1){
levelBounds.add(new Rectangle(x*tileSize, Game.scrHeight - mapHeight*tileSize + y*tileSize, tileSize, tileSize));
//levelBounds.add(new Rectangle2D.Float(x*tileSize, Game.scrHeight - mapHeight*tileSize + y*tileSize, tileSize, tileSize));
System.out.println("Added new bounding box: " + (x*tileSize) + ", " + (Game.scrHeight - mapHeight*tileSize + y*tileSize) + ", " + tileSize);
}
}
}
worldObjectCount = levelBounds.size();
System.out.println("World object count: " + worldObjectCount);
groundTiles[0] = spriteSheet.getSubImage(4, 16);
groundTiles[1] = spriteSheet.getSubImage(13, 19);
dir = 1;
acc = 0.0f;
mov = 0.0f;
friction = 4f;
gravity = 4f;
runSpeed = 0.6f;
maxAcc = -1f;
inAir = false;
jumping = false;
keyDown = false;
exitFlag = false;
speedX = 0.0f;
speedY = 0.0f;
iterations = 3;
}
public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
//determine cameraX and cameraY
float cameraX, cameraY;
cameraX = player.getX() - Game.scrWidth/2;
cameraY = player.getY() - (Game.scrHeight/2 - tileSize - tileSize);
g.translate(-cameraX, -cameraY);
player.render(g);
for(int x = 0; x < mapWidth; x++)
{
for(int y = 0; y < mapHeight; y++){
if(currentMap[x][y] == 1){
groundTiles[0].draw(x*tileSize, Game.scrHeight - mapHeight*tileSize + y*tileSize);
}
}
}
g.translate(cameraX, cameraY);
}
public void update(GameContainer gc, StateBasedGame sbg, int delta) throws SlickException{
Input input = gc.getInput();
float secondsElapsed = delta/1000.0f;
checkCollisions(secondsElapsed);
player.setX((player.getX() + speedX));
player.setY((player.getY() - speedY));
//check inputs
checkKeyEvents(input);
//slow down / friction
if(!keyDown){
if(mov < 0)
mov += friction * secondsElapsed;
else
mov -= friction * secondsElapsed;
}
speedX = mov;
if (speedX > 0 && speedX < friction * secondsElapsed) speedX = 0;
if (speedX < 0 && speedX > -friction * secondsElapsed) speedX = 0;
//jump or fall
acc -= gravity * secondsElapsed;
if (acc < maxAcc){
acc = maxAcc;
}
speedY = acc;
//exit when exitFlag true
if(exitFlag){
gc.exit();
}
}
public void checkCollisions(float secondsElapsed){
boolean contactX = true, contactYbottom = true, contactYtop = true;
// Keep iterating the contact solver until the maximum number of iterations is reached
// or no collisions are detected
for (int iteration = 0; iteration < iterations && (contactX || contactYbottom || contactYtop); iteration++)
{
float nextMoveX = speedX * secondsElapsed;
float nextMoveY = speedY * secondsElapsed;
contactX = contactYbottom = contactYtop = false;
float projectedMoveX, projectedMoveY, originalMoveX, originalMoveY;
originalMoveX = nextMoveX;
originalMoveY = nextMoveY;
for (int o = 0; o < worldObjectCount && !contactX && !contactYbottom && !contactYtop; o++)
{
for (int dir = 0; dir < 6; dir++)
{
//top, bottom, left, left, right, right.
if (dir == 0 && nextMoveY < 0) continue;
if (dir == 1 && nextMoveY > 0) continue;
if (dir == 2 && nextMoveX > 0) continue;
if (dir == 3 && nextMoveX > 0) continue;
if (dir == 4 && nextMoveX < 0) continue;
if (dir == 5 && nextMoveX < 0) continue;
projectedMoveX = (dir >= 2? nextMoveX : 0);
projectedMoveY = (dir < 2? nextMoveY : 0);
float[][] collisionPoint = player.getBounds();
Rectangle curRect = new Rectangle(levelBounds.get(o).x, levelBounds.get(o).y, levelBounds.get(o).width, levelBounds.get(o).height);
//Rectangle2D curRect = levelBounds.get(o).getBounds2D();
while (curRect.contains(collisionPoint[dir][0] + projectedMoveX, collisionPoint[dir][1] + projectedMoveY)
|| curRect.intersects(collisionPoint[dir][0] + projectedMoveX, collisionPoint[dir][1] + projectedMoveY, 1, 1))
{
if (dir == 0) projectedMoveY += 0.05f; //top collision
if (dir == 1) projectedMoveY -= 0.05f; //bottom collision
if (dir == 2) projectedMoveX += 0.05f; //left collision
if (dir == 3) projectedMoveX += 0.05f;
if (dir == 4) projectedMoveX -= 0.05f; //right collision
if (dir == 5) projectedMoveX -= 0.05f;
}
if (dir >= 2 && dir <= 5)
nextMoveX = projectedMoveX;
if (dir >= 0 && dir <= 1)
nextMoveY = projectedMoveY;
}
if (nextMoveY > originalMoveY && originalMoveY != 0)
{
contactYtop = true;
}
if (nextMoveY < originalMoveY && originalMoveY != 0)
{
contactYbottom = true;
}
if (Math.abs(nextMoveX - originalMoveX) > 0.01f)
{
contactX = true;
}
if (contactX && contactYtop && speedY > 0)
speedY = nextMoveY = 0;
}
if (contactYbottom || contactYtop)
{
player.setY(player.getY() + nextMoveY);
speedY = 0;
acc = 0;
if (contactYbottom)
jumping = false;
}
if (contactX)
{
player.setX(player.getX() + nextMoveX);
speedX = 0;
mov = 0;
}
}//end collisions
}
public int[][] readMap(File level) throws IOException, SlickException{
BufferedReader br = new BufferedReader(new FileReader(level));
mapWidth = Integer.parseInt(br.readLine());
mapHeight = Integer.parseInt(br.readLine());
int[][] map = new int[mapWidth][mapHeight];
for(int row = 0; row < mapHeight; row++)
{
String line = br.readLine();
if(line == null || line.isEmpty())
{
System.out.println("Line is empty or null");
}
else
{
String[] tileValues = line.split(",");
for(int col = 0; col < mapWidth; col++)
{
map[col][row] = Integer.parseInt(tileValues[col]);
}
}
}
br.close();
return map;
}
public void checkKeyEvents(Input input){
//key input events
if(input.isKeyPressed(Input.KEY_DOWN)){
}
if(input.isKeyPressed(Input.KEY_UP)){
if(!jumping){
acc = 1f;
}
jumping = true;
}
if(input.isKeyDown(Input.KEY_LEFT) && !input.isKeyDown(Input.KEY_RIGHT)){
keyDown = false;
mov -= 0.006f;
if (mov < -runSpeed){
mov = -runSpeed;
}
}
if(input.isKeyDown(Input.KEY_RIGHT) && !input.isKeyDown(Input.KEY_LEFT)){
keyDown = false;
mov += 0.006f;
if (mov > runSpeed){
mov = runSpeed;
}
}
if(input.isKeyPressed(Input.KEY_ESCAPE)){
exitFlag = true;
}
}
public int getID(){
return 1;
}
}
Since I can't predict what more info a potential helper might need, I'll leave it at that for now, but of course I can provide any more info when/where needed.
Thanks,
J.

Related

How to constrain sprite movement within isometric boundaries in libgdx?

I am currently generating an isometric map which should allow some sprites to move randomly within its bounds. My sprites, or 'humans' do move within a specified constraint however it is not the correct boundaries I wish to set it to. Below is my code.
public class Human implements Entity {
private int[][] map;
public static final int TILE_WIDTH = 34;
public static final int TILE_HEIGHT = 34;
private int min = 100;
private int max = 200;
private Texture img;
// position variable
private Vector2 pos;
private float time;
public Human() {
img = new Texture(Gdx.files.internal("humanFF.png"));
// coordinates of human initial position
pos = new Vector2(9, 220);
// for locking movement if need be.
time = 2;
map = randomGenerator();
}
#Override
public void render(SpriteBatch batch) {
batch.draw(img, pos.x, pos.y);
}
#Override
public void update(float delta) {
time += delta;
Random rand = new Random();
int upperbound = 2;
double double_random = rand.nextDouble(upperbound);
// lock human, can only move once every 2 secs.
if (time > 0) {
move();
time = 0;
}
}
private void move() {
/** Calculation **/
for (int row = map.length - 1; row >= 0; row--) {
for (int col = map.length - 1; col >= 0; col--) {
float x = (col - row) * (TILE_WIDTH / 2f - 2);
float y = (col + row) * (TILE_HEIGHT / 4f);
}
}
// after calculation, mapWidth is 525 pixels.
int mapWidth = map.length * (TILE_WIDTH / 2 - 2);
// after calculation, mapHeight is 280 pixels.
int mapHeight = map.length * (TILE_HEIGHT / 4);
// Calculate the minimum and maximum x-coordinates.
float minX = 0;
float maxX = mapWidth - TILE_WIDTH;
if (maxX < 0) {
maxX = 0;
}
// max-x coordinate is 491.0. min-x coordinate is 0.0.
// Calculate the minimum and maximum y-coordinates.
float minY = 0;
float maxY = mapHeight - TILE_HEIGHT;
if (maxY < 0) {
maxY = 0;
}
// check the position of human against map boundaries
if (pos.x < minX) {
pos.x = minX;
} else if (pos.x > maxX) {
pos.x = maxX;
}
if (pos.y < minY) {
pos.y = minY;
} else if (pos.y > maxY) {
pos.y = maxY;
}
// min-y coordinate is 0.0, max-y coordinate is 246.0.
// a variable to store a random generated value between 100 and 200.
int a = (int) (Math.random() * (max - min + 1) + min);
float newX = pos.x;
float newY = pos.y;
// move up
if (a <= 125) {
newX -= 15;
newY += 8.5;
}
// move down
else if (a <= 150 && a > 125) {
newX += 15;
newY -= 8.5;
}
// move left
else if (a <= 175 && a > 150) {
newX -= 15;
newY -= 8.5;
}
// move right
else if (a <= 200 && a > 175) {
newX += 15;
newY += 8.5;
}
if (newX >= minX && newX <= maxX && newY >= minY && newY <= maxY) {
pos.x = newX;
pos.y = newY;
}
}
public int[][] randomGenerator() {
Random r = new Random();
int Size = r.nextInt(35, 36);
int[][] map = new int[Size][Size];
for(int row = 0; row < map.length; row++) {
for(int col = 0; col < map.length; col++) {
int Number = r.nextInt(10);
if(Number == 0) {
map[row][col] = 0;
} else if (Number == 1) {
map[row][col] = 1;
}
else if (Number == 2) {
map[row][col] = 2;
}
else if (Number == 3) {
map[row][col] = 3;
}
else if (Number == 4) {
map[row][col] = 4;
}
else if (Number == 5) {
map[row][col] = 5;
}
else if (Number < 8) {
map[row][col] = 6;
}
else {
map[row][col] = 7;
}
}
}
map[0][0] = 1;
return map;
}
}
Based on the above, I am generating a random value which defines the movement of my 'humans' thus adding or subtracting from their x and y positions. In my attempt to tackle the problem of these sprites moving outside of my isometric map, I tried to calculate my mapWidth, mapHeight, min-x, max-x, min-y and max-x and then checking the position of my human against these boundaries to determine their movement.
Although these sprites now move within a constraint, it is not same dimension as my isometric map, but are now constrained to a rectangular-shaped boundary. How do I modify my code so that the sprites only move within the isometric map I have generated?
Below is a photo for visualisation.
The coordinate system you use for Human enties is ordinary orthogonal, you don't map these coordinates to an isometric view but you -have to- map them onto the isometric background. Screen coordinate system is basically different from the isometric one. When you render you need to map coordinates so that
(0,0)-> left corner
(0,maxY)->top corner
(maxX,maxY)->right corner
(maxX,0)->bottom corner
See here for to and back(map screen touch events to the map etc) conversion LibGdx render a sprite on top of a isometric tile

Java A* path finding algorithm not working?

I'm developing a game in Java and i'm having issues using and implementing my A* path finding algorithm. Currently, i have entities set up so that an entity can't exist outside of a level(each entity has access to the current level). for this reason, i stored the algorithm method 'findPath' in the base Level class. Below is the algorithm code, and the movement code for the entity, which as you can see calls the find path method in level. My issue is that when I run the code, I move the player towards the entity and the entity does nothing. I've put in some debug print lines (i'll leave those in so you can see), and the list path that is returned constantly returns just []. I've been through everything and can;'t figure it out. Hope someone can help!
Thanks
code:
in Level.java class:
private Comparator<Node> nodeSorter = new Comparator<Node>() {
public int compare(Node n0, Node n1) {
if (n1.fCost < n0.fCost) return +1;
if (n1.fCost > n0.fCost) return -1;
return 0;
}
};
public List<Node> findPath(Vector2i start, Vector2i goal) {
List<Node> openList = new ArrayList<Node>();
List<Node> closedList = new ArrayList<Node>();
Node current = new Node(start, null, 0, getDistance(start, goal));
openList.add(current);
while (openList.size() > 0) {
Collections.sort(openList, nodeSorter);
current = openList.get(0);
if (current.tile.equals(goal)) {
List<Node> path = new ArrayList<Node>();
while (current.parent != null) {
path.add(current);
current = current.parent;
}
openList.clear();
closedList.clear();
return path;
}
openList.remove(current);
closedList.add(current);
for (int i = 0; i < 9; i ++){
if (i == 4) continue;
int x = current.tile.getX();
int y = current.tile.getY();
int xi = (i % 3) - 1;
int yi = (i / 3) - 1;
Tile at = getTile(x + xi, y + yi);
if (at == null) continue;
if (at.solid()) continue;
Vector2i a = new Vector2i(x + xi, y + yi);
double gCost = current.gCost + getDistance(current.tile, a);
double hCost = getDistance(a, goal);
Node node = new Node(a, current, gCost, hCost);
if (vecInList(closedList, a) && gCost >= node.gCost) continue;
if (!vecInList(openList, a) || gCost < node.gCost) openList.add(node);
}
}
closedList.clear();
return null;
}
And in my "Wizard.java", which extends Mob, and in turn entity:
private List<Node> path = null;
public Wizard(int x, int y) {
this.x = x << 4;
this.y = y << 4;
sprite = animSprite.getSprite();
}
private void move() {
xa = 0;
ya = 0;
int px = (int)level.getPlayerAt(0).getX();
int py = (int)level.getPlayerAt(0).getY();
Vector2i start = new Vector2i((int)getX() >> 4, (int)getY() >> 4);
Vector2i destination = new Vector2i(px >> 4, py >> 4);
if (time % 60 == 0) path = level.findPath(start, destination);
if (path != null){
if (path.size() > 0){
Vector2i vec = path.get(path.size() -1).tile;
if (x < vec.getX() << 4) xa += speed;
if (x > vec.getX() << 4) xa -= speed;
if (y < vec.getY() << 4) ya += speed;
if (y > vec.getY() << 4) ya -= speed;
}
}
if (xa != 0 || ya != 0) {
move(xa, ya);
walking = true;
} else
walking = false;
}
public void update() {
time++;
if (!collision(xa, ya)){
move();
}
move();
if (walking) animSprite.update();
else
animSprite.setFrameRate(0);
if (ya < 0) {
animSprite = up;
dir = Direction.UP;
} else if (ya > 0) {
animSprite = down;
dir = Direction.DOWN;
}
if (xa < 0) {
animSprite = left;
dir = Direction.LEFT;
} else if (xa > 0) {
animSprite = right;
dir = Direction.RIGHT;
}
}
public void render(Screen screen) {
sprite = animSprite.getSprite();
if (level.getTile((int)x, (int)y).solid()){
x += 16;
y += 16;
}
screen.renderMob((int)(x - 16), (int)(y - 16), this);
}
Node equals code:
public boolean equals(Object object){
if(!(object instanceof Vector2i)) return false;
Vector2i vec = (Vector2i) object;
if (vec.getX() == this.getX() && vec.getY() == this.getY()) return true;
else return false;
}

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)
// ...
}

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();

Move tile by tile with dynamic speed

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.

Categories

Resources