I'm making a 2D platformer and just added gravity & jumping.
It works like it should, however, if the space bar is still held down after the player finishes a jump, the player just keeps jumping while in mid-air.
I know I need to check for whether or not the player is actually on the ground, but when I do it always returns as 'false', as described in my jumping method:
// Controls both falling and the jumping action.
// The MapObject list is a collection of every object the player can
// collide with on that map. Currently it only contains a single 'ground' object.
public void fall(ArrayList<MapObject> objects)
{
int distance = 0;
if (jumpTicks > 0)
{
float jumpHeight = jumpSpeed * (jumpTicks / maxJumpTicks);
System.out.println(jumpTicks + "/" + maxJumpTicks + " = " + jumpHeight);
y -= jumpHeight;
jumpTicks--;
}
else
{
for (MapObject obj : objects)
{
if (this.y + this.height >= obj.y)
{
// This cancels falling if the player's feet are on top
// of the ground, but for some reason setting an 'isOnGround'
// boolean to 'true' here and checking for it in the 'jump()'
// method does not work, it's always 'false'.
return;
}
distance = obj.y - (this.y + this.height);
}
if (distance > fallSpeed)
{
y += fallSpeed;
}
else
{
y += distance;
}
}
}
// This doesn't make the player jump, it just adds jump time to the player
// if it's not already jumping.
public void jump()
{
if (jumpTicks > 0)
{
return;
}
this.jumpTicks = maxJumpTicks;
this.jumpSpeed = 10;
}
Before you change his speed, check his y value for the floor
function jump() {
if (jumpTicks > 0) {
return;
}
if (this.y === floorY) {
this.jumpTicks = maxJumpTicks;
this.jumpSpeed = 10;
}
}
Related
NOOBIE Question... please help! I have a tile-based game I'm building where I'm moving an icon up down left and right. The dimensions of the game is 15 tiles x 15 tiles. When I'm approaching the boundaries, how can I prevent the icon from moving off the "map". I'm using W (up) A (left) S (down) and D (right) for directional input.
What would be a good way to prevent that icon from going off the map once it's reached the maximum point on the X or Y axis? I defined PlayerY and PlayerX as points where the player exists on the map, but this is the code i currently have for movement.
if (choice.equals("w")){
playerY--;
}
else if (choice.equals("s")){
playerY++;
}
else if (choice.equals("d")){
playerX++;
}
else if (choice.equals("a")){
playerX--;
}
Would you put something here where you say something like player is at max value and d inputted, do nothing? But I don't know how you'd say "do nothing"...
if (player Y == 15 && choice.equals("d")){
________;
}
Sorry again for the dumb question... I'm relatively new to Java and still trying to get my bearings
I suggest maintaining some constants for the maximum x and y size. Then, add logic which checks the boundaries before making any move:
final int X_DIM = 15; // assuming the board be represented by an array, then 14 is the
final int Y_DIM = 15; // maximum index
if (choice.equals("w")) {
if (playerY > 0) {
playerY--;
}
else {
System.out.println("Error: Cannot make an off-board move");
}
}
else if (choice.equals("s")) {
if (playerY < Y_DIM - 1) {
playerY++;
}
else {
System.out.println("Error: Cannot make an off-board move");
}
}
else if (choice.equals("d")) {
if (playerX < Y_DIM - 1) {
playerX++;
}
else {
System.out.println("Error: Cannot make an off-board move");
}
}
else if (choice.equals("a")) {
if (playerX > 0) {
playerX--;
}
else {
System.out.println("Error: Cannot make an off-board move");
}
}
Before make an move, you have to check whether the move is valid or not. If the move is valid, move it. If not, don't make the move and optionally show a warning for the player.
boolean isValidMove(choice){
int nextX, nextY;
if (choice.equals("w")){
nextY = playerY-1;
}
else if (choice.equals("s")){
nextY = playerY+1;
}
else if (choice.equals("d")){
nextX = playerX+1;
}
else if (choice.equals("a")){
nextX = playerX-1;
}
//immediately return false if X or Y out of board
if(nextX<0||nextX>=15) return false;
if(nextY<0||nextY>=15) return false;
return true; //return true if nextX and nextY is in the board
}
In main method where run the game:
choice = //user input
if(isValidMove(choice)){
//do the move request and represent board game
} else{
//optionally show a warning to players
}
I suggest starting with a helper method to determine whether or not any given position is on the map or not:
private boolean isOnMap(int x, int y) {
return x >= 0 && x < 15
&& y >= 0 && y < 15;
}
Then, you can use that helper method to decide whether or not the move the user requested is valid, and only make the move if it is. I'd split the logic into two steps to make this easier to work with: first step is to naively calculate the new position that the user wants to move to, and then the second step is to decide if that new position is a valid move or not
// Step 1: calculate new position from requested move
int newX = playerX;
int newY = playerY;
if (choice.equals("w")){
newY--;
}
else if (choice.equals("s")){
newY++;
}
else if (choice.equals("d")){
newX++;
}
else if (choice.equals("a")){
newY--;
}
// Step 2: apply the new position, but only if the move is valid
if (isOnMap(newX, newY)) {
playerX = newX;
playerY = newY;
}
Just check if it is on the last or first tiles or not, like this:
if (choice.equals("w")){
if ( playerY - 1 >= 0 ) { // if the next player move in Y axis is positive, then move
playerY--;
}
}
else if (choice.equals("s")){
if ( playerY + 1 < 15 ) { // if the next player move in Y axis is less than 15 (because you have 15 tiles), then move
playerY++;
}
}
else if (choice.equals("d")){
if ( playerX + 1 < 15 ) { // if the next player move in X axis is less than 15 (because you have 15 tiles), then move
playerX++;
}
}
else if (choice.equals("a")){
if ( playerX - 1 >= 0 ) { // if the next player move in X axis is positive, then move
playerX--;
}
}
The collision detection system I have for my small game sort of works. It's able to tell when the player goes straight into a wall. However when the player goes diagonal, it clips through the wall. I really don't understand where the issue is occurring.
The below code is from the class that handles the player:
public void run()
{
running = true;
while(running)
{
//Get the key/s pressed
controls.update();
//Move down
if (controls.down)
{
movePlayerDown(this.thisPlayer.getSpeed());
}
//Move up
if (controls.up)
{
movePlayerUp(this.thisPlayer.getSpeed());
}
//Move right
if (controls.right)
{
movePlayerRight(this.thisPlayer.getSpeed());
}
//Move left
else if (controls.left)
{
movePlayerLeft(this.thisPlayer.getSpeed());
}
try
{
Thread.sleep(this.sleep);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
public void movePlayerRight(int dx)
{
//Gets the tile at what would be the new coordinates of the player
Tile tile = currentLevel.getTile(this.thisPlayer.getX() + dx + this.thisPlayer.getWidth(), this.thisPlayer.getY());
//IF the tile is null or not solid then the player is actually moved
if (tile == null || !tile.isSolid())
{
this.thisPlayer.setX(this.thisPlayer.getX() + dx);
}
}
public void movePlayerLeft(int dx)
{
//Gets the tile at what would be the new coordinates of the player
Tile tile = currentLevel.getTile(this.thisPlayer.getX() - dx, this.thisPlayer.getY());
//IF the tile is null or not solid then the player is actually moved
if (tile == null || !tile.isSolid())
{
this.thisPlayer.setX(this.thisPlayer.getX() - dx);
}
}
public void movePlayerDown(int dy)
{
//Gets the tile at what would be the new coordinates of the player
Tile tile = currentLevel.getTile(this.thisPlayer.getX(), this.thisPlayer.getY() + dy + this.thisPlayer.getHeight());
//IF the tile is null or not solid then the player is actually moved
if (tile == null || !tile.isSolid())
{
this.thisPlayer.setY(this.thisPlayer.getY() + dy);
}
}
public void movePlayerUp(int dy)
{
//Gets the tile at what would be the new coordinates of the player
Tile tile = currentLevel.getTile(this.thisPlayer.getX(), this.thisPlayer.getY() - dy);
//IF the tile is null or not solid then the player is actually moved
if (tile == null || !tile.isSolid())
{
this.thisPlayer.setY(this.thisPlayer.getY() - dy);
}
}
The next block of code is the getTile() method:
public Tile getTile(int x, int y)
{
for (int r = 0; r < worldTiles.length; r++)
{
for (int c = 0; c < worldTiles[r].length; c++)
{
if (worldTiles[r][c] != null)
{
int right = worldTiles[r][c].getX() + worldTiles[r][c].getWidth();
int bottom = worldTiles[r][c].getY() + worldTiles[r][c].getHeight();
if (x > worldTiles[r][c].getX() && x < right && y > worldTiles[r][c].getY() && y < bottom)
{
return worldTiles[r][c];
}
}
}
}
a) you dont define a condition where tile==null - thats for further consideration
b) the logic to test for each event is as follows - one key at a time
//Move down
if (down)
{
movePlayerDown(this.thisPlayer.getSpeed());
}
//Move up
else if (up)
{
movePlayerUp(this.thisPlayer.getSpeed());
}
//Move right
else if (right)
{
movePlayerRight(this.thisPlayer.getSpeed());
}
//Move left
else if (left)
{
movePlayerLeft(this.thisPlayer.getSpeed());
}
The sleep should be removed from there because it ties down the program and possibly missing events.
c) The events should be fired from the key event handler and not have some one to go there and fetch them.
In fact I would reverse the whole logic as follows:
void keyPressed(event) {
sendEvent(event)
}
where
void sendEvent(event) {
if(event==down) ......
.......
}
replaces your while loop.
Synopsis
Well, I'm making a little top-down JRPG and today I was like 'Yeah, I'm gonna bust out this whole map collision thing!'. I failed.
Problem
So I went on the internet and looked up 'LibGDX Tiled Map Collision Detection' and found a really neat post about Map Objects so I added in a map object layer and did all that biz and came out with this little method to ensure the player can move freely around the map but at the same time can't exit it but each time I've tried it ends up with a horrible result such as the player moving off the screen. The latest error is that the player gets stuck doing a walk animation and can't move anywhere else!
Code
package com.darkbyte.games.tfa.game.entity.entities;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.math.Rectangle;
import com.darkbyte.games.tfa.game.entity.Entity;
import com.darkbyte.games.tfa.game.entity.SpriteSheet;
import com.darkbyte.games.tfa.game.world.map.MapManager;
import com.darkbyte.games.tfa.render.Batch;
import com.darkbyte.games.tfa.render.Camera;
public class Player extends Entity {
// The constructor for the player class
public Player(String name, SpriteSheet spriteSheet) {
super(name, spriteSheet);
direction = Direction.DOWN;
collisionBox = new Rectangle(x, y, 64, 64);
}
// A flag to see if the player is moving
private boolean isMoving;
// The variable that holds the state time
private float stateTime;
// The player's walking animations
private Animation[] walkAnimations = {
spriteSheet.getAnimation(8, 8, 1 / 16f),
spriteSheet.getAnimation(9, 8, 1 / 16f),
spriteSheet.getAnimation(10, 8, 1 / 16f),
spriteSheet.getAnimation(11, 8, 1 / 16f) };
// The player's static frames
private TextureRegion[] staticFrames = {
spriteSheet.getTexture(8, 0),
spriteSheet.getTexture(9, 0),
spriteSheet.getTexture(10, 0),
spriteSheet.getTexture(11, 0) };
// The render code for the player
#Override
public void render() {
// Makes the camera follow the player
Camera.setCameraPosition(x, y);
Batch.getGameBatch().setProjectionMatrix(Camera.getCamera().combined);
// Updates the state time
stateTime += Gdx.graphics.getDeltaTime();
// Gets the player's direction, if the player's moving, it sets the
// current frame to the frame that would be played at the current moment
// based on the state time
// If the player isn't moving, it sets the current frame to the static
// frame associated to the direction
switch (direction) {
case UP:
if(isMoving) {
currentFrame = walkAnimations[0].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[0];
break;
case LEFT:
if(isMoving) {
currentFrame = walkAnimations[1].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[1];
break;
case DOWN:
if(isMoving) {
currentFrame = walkAnimations[2].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[2];
break;
case RIGHT:
if(isMoving) {
currentFrame = walkAnimations[3].getKeyFrame(stateTime, true);
} else
currentFrame = staticFrames[3];
break;
}
}
// The tick code for the player
#Override
public void tick() {
// The object to represent the bounds of the land on the map
RectangleMapObject land = (RectangleMapObject) MapManager.getCurrentMap().getMap().getLayers().get("collision").getObjects().get("land");
// Checks if the player is within the bounds of the map
if(land.getRectangle().contains(collisionBox)) {
// If the player is moving but the arrow keys aren't pressed, sets isMoving to false
isMoving = (isMoving && (Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)
|| Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)
|| Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)
|| Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)));
// Checks to see if the arrow / WASD keys are pressed and moves the
// player in the correct direction at the speed of 1.5 pixels/tick
// (45/second)
// It also sets the players state to moving and corresponds it's
// direction to the key pressed
// Doesn't move if opposing keys are pressed
if(Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP)) {
if(!(Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN))) {
direction = Direction.UP;
y += 1.5f;
isMoving = true;
}
}
if(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT)) {
if(!(Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT))) {
direction = Direction.LEFT;
isMoving = true;
x -= 1.5f;
}
}
if(Gdx.input.isKeyPressed(Keys.S) || Gdx.input.isKeyPressed(Keys.DOWN)) {
if(!(Gdx.input.isKeyPressed(Keys.W) || Gdx.input.isKeyPressed(Keys.UP))) {
direction = Direction.DOWN;
y -= 1.5f;
isMoving = true;
}
}
if(Gdx.input.isKeyPressed(Keys.D) || Gdx.input.isKeyPressed(Keys.RIGHT)) {
if(!(Gdx.input.isKeyPressed(Keys.A) || Gdx.input.isKeyPressed(Keys.LEFT))) {
direction = Direction.RIGHT;
x += 1.5f;
isMoving = true;
}
}
} else {
if(!isMoving) {
// If the player's just spawned puts the player to the map's spawn point
x = MapManager.getCurrentMap().getPlayerSpawnX();
y = MapManager.getCurrentMap().getPlayerSpawnY();
} else { // If not, it just moves them back till they're no longer out of the map
if(x > (land.getRectangle().getX() + land.getRectangle().getWidth())) x -= 1.5;
if(y > (land.getRectangle().getY() + land.getRectangle().getHeight())) y -= 1.5;
}
}
// Synchronises the collision box with the player's x and y position
collisionBox.x = x;
collisionBox.y = y;
}
// Returns if the player is moving
public boolean isMoving() {
return isMoving;
}
}
Can you guys make it so that when he reaches the border that he stops but he can still keep moving in other directions instead of staying static!
Thanks for reading!
At the moment it sounds you just copy/pasted it and you need to familiarize yourself with it first. If you don't know what it does then you should learn or stop the project imho.
Anyway, from what I can tell it's just a player class that handles the animation frames based on which direction it is moving. Nothing to do with collision detection at all. It does update some kind of collisionBox but functionality for this is handled elsewhere, perhaps in the parent class Entity?
My guess is that this is a tile map and units are restricted to the grid. It's pretty easy to detect if A tile exists or not.
private boolean tileExists(int tileX, int tileY, tile[][] map)
{
return tileX >= 0 && tileY >= 0 &&
tileX < map.length && tileY < map[0].length;
}
Now whenever a entity requests a move you should check if the destination is within the map bounds.
private void moveRequest(int destinationX, int destinationY, Tile[][] map)
{
//Just return if the tile is outside of the map
if (!tileExists(destinationX, destinationY, map) return;
//Same goes for your other checks...
//Return if the tile is not walkable
if (!tileIsWalkable(destinationX, destinationY, map) return;
//Return if the tile is already occupied
if (tileIsOccupied(destinationX, destinationY, otherEntities) return;
//etc..
//Now the move is valid and you can set it's state to moving in that direction.
}
Tile maps are not very hard to understand. I will make an attempt to give you some better insight into tile maps. You have a 2D array where you store your tiles in. Tiles have a width and a height and from that you can make your own tile engine:
//Find out which tiles to draw based on the camera position and viewport size.
int startX = (int)(camera.position.x - camera.viewportWidth / 2) / tileWidth;
int startY = (int)(camera.position.y - camera.viewportHeight / 2) / tileHeight;
int endX = (int)(startX + camera.viewportWidth / tileWidth) + 1;
int endY = (int)(startY + camera.viewportHeight / tileHeight) + 1;
//Loop using this data as boundaries
for (int y = startY; y < endY; y++)
{
for (int x = startX; x < endX; x++)
{
//If out of bounds continue to next tile.
if (!tileExists(x, y, map) continue;
//Now all we need to draw the on screen tiles properly:
//x == tile position x in array
//y == tile position y in array
//World position of this tile:
//worldX = x * tileWidth;
//worldY = y * tileHeight;
//Let's draw:
batch.draw(map[x][y].getTexture, worldX, worldY,
tileWidth, tileHeight)
}
}
There really is no magic involved here at all. Drawing only what is on screen like in the above example is very important for larger maps. Other then that you should draw thing in the back first. You have several options to do this, the easiest but least versatile is just a separate the ground from the objects that can obscure things and draw this later.
Characters, creatures or other entities can just use a world position and be easily converted back to tile position.
tileX = worldX / tileWidth;
tileY = worldY / tileHeight;
So if you want to move something with the world position calculate it's tile position first using the aforementioned method. Then lookup if this tile is valid to move to. Then block that tile for other and move to it.
onTouch method of my View:
public boolean onTouch(View view, MotionEvent event) {
Log.d("Touch", "Touch");
int mNewX = (int) Math.floor(event.getX());
int mNewY = (int) Math.floor(event.getY());
boolean isPositionFree = isPositionFree(mNewX, mNewY);
if (!isPositionFree) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
int i = 0;
for (Point point : points) {
if (point.spotted) {
points.remove(i);
invalidate();
break;
}
i++;
}
} else if (event.getAction() == MotionEvent.ACTION_MOVE) {
int i = 0;
for (Point point : points) {
if (point.spotted) {
points.remove(i);
Point p = new Point(mNewX, mNewY, point.TYPE);
points.add(i, p);
invalidate();
break;
}
i++;
}
}
}
}
There are multiple items in the canvas. Their positions are saved in "points". They get drawn to the canvas in a onDraw method via the position of those "points", means Point point.x and point.y.
Now, when I click an item (a point on the canvas), it should disappear.
Then, when the MotionEvent.ACTION_MOVE is true, I want to move the point, depending on the event.getX() and event.getY().
the method "isPositionFree(newX,newY)" checks if the point.x and point.y equals newX and newY (the position I just touched on the screen).
if the position is taken (means, there is an item where I just clicked), I'll get to the motionevent-IFs.
Here comes the problem:
my code removes the point before I can actually move it. I didnt find any way I could fix this problem for hours. :/ I find it difficult, since the onTouch is always called from the beginning, means ACTION_DOWN and ACTION_MOVE never take place at the same time.
Do you know any fix for this?
thanks in advance, Sebastian
Got it to work!
For everbody having the same issue, feel free to take this sample code as a help :)
Stuff I declared in the beginning
Vector<Point> points = new Vector<Point>();
Bitmap[] monsterTypes = new Bitmap[3];
Vector<Integer> distanceMovedX = new Vector<Integer>();
Vector<Integer> distanceMovedY = new Vector<Integer>();
int mNewX = -1;
int mNewY = -1;
OnTouch-Method
public boolean onTouch(View view, MotionEvent event) {
mNewX = (int) FloatMath.floor(event.getX());
mNewY = (int) FloatMath.floor(event.getY());
boolean touchedPoint = touchedPoint(mNewX, mNewY);
switch (event.getAction()) {
case MotionEvent.ACTION_MOVE:
distanceMovedX.add(mNewX);
distanceMovedY.add(mNewY);
break;
case MotionEvent.ACTION_UP:
isMoveEvent = isMoveEvent();
if (isMoveEvent) {
for (Point point : points) {
if (point.spotted) {
// Your code
}
i++;
}
} else {
if (touchedPoint) {
for (Point point : points) {
if (point.spotted) {
// Your code
}
}
}
}
distanceMovedX.clear();
distanceMovedY.clear();
return true;
}
return true;
}
touchedPoint-Method
public boolean touchedPoint(int mNewX, int mNewY) {
boolean touchedPoint = false;
int height = 0;
int width = 0;
for (Point point : points) {
height = monsterTypes[point.TYPE - 1].getHeight();
width = monsterTypes[point.TYPE - 1].getWidth();
if (point.x + width < mNewX || point.x > mNewX + width
|| point.y + height < mNewY || point.y > mNewY + height) {
touchedPoint = false;
point.spotted = false;
} else {
touchedPoint = true;
point.spotted = true;
return touchedPoint;
}
}
return touchedPoint;
}
isMoveEvent-Method
public boolean isMoveEvent() {
boolean isMoveEvent = false;
boolean isMoveEventX = false;
boolean isMoveEventY = false;
for (int i = 0; i <= (points.size() -1); i++) {
Log.d("point", "for loop entered");
if (!distanceMovedY.isEmpty()) {
Log.d("point.x", "distanceMovedY is not empty");
int dMY = distanceMovedY.get(distanceMovedY.size() - 1) - distanceMovedY.get(0);
if ((dMY > 50 || dMY <= 0) && dMY != 0) {
Log.d("point.y", "is move event");
Log.d("point.y", "dMY: " + dMY);
isMoveEventY = true;
} else {
Log.d("point.x", "is no move event");
Log.d("point.x", "dMY: " + dMY);
isMoveEvent = false;
return isMoveEvent;
}
}
if (!distanceMovedX.isEmpty()) {
Log.d("point.x", "distanceMovedX is not empty");
int dMX = distanceMovedX.get(distanceMovedX.size() - 1) - distanceMovedX.get(0);
if (dMX <= 50 && dMX >= -50 && dMX != 0) {
Log.d("point.x", "is move event");
Log.d("point.x", "dMX: " + dMX);
isMoveEventX = true;
} else {
Log.d("point.x", "is no move event");
Log.d("point.x", "dMX: " + dMX);
isMoveEvent = false;
return isMoveEvent;
}
}
if (isMoveEventX && isMoveEventY) {
Log.d("point", "is move event");
isMoveEvent = true;
return isMoveEvent;
}
}
Log.d("point", "is no move event");
return isMoveEvent;
}
Point Class
class Point {
int x, y;
int TYPE;
boolean spotted;
boolean halfSpotted;
public Point() {
}
public Point(int x, int y, int t) {
this.x = x;
this.y = y;
this.TYPE = t;
}
#Override
public String toString() {
return x + ", " + y;
}
}
EXPLANATION:
Point:
we got a class Point. All those points declared in the Vector are x- and y-coordinates on your canvas. They help us to check the position we clicked.
monsterTypes:
its the different graphics I use. If you only use one graphic that you draw onto the canvas, change it to your needs
distanceMovedX & Y:
saves all the X and Y Coordinates of your "ACTION_MOVE". From pos 0 (the first touched point) to pos Z (the last touched point, where ACTION_UP occurs). Though its not the original X and Y position. Its the result of posZ - pos0.
With these values you can determine, after what distance travelled you wanna invoke "onMove" and BELOW which distance "onClick" should be invoked.
mNewX & Y:
the currently position of your onTouch-Method. Everytime you move your finger, newX & Y become overwritten.
Methods:
onTouch():
First, we'll overwrite mNewX and Y to the current position touched. Then we check if we clicked on an existing spot (in my case some 48px*48px area)
Next we record the taken distance in ACTION_MOVE.
After that we continue with ACTION_UP, where we check if we just performed some moveEvent or clickEvent.
touchedPoint():
calculates if we touched some existing point on the canvas, or not. returns true or false
isMoveEvent():
checks if we moved the certain distance. in my case i wanna move down, 50px or more. though im not allowed to move sidewards -50px or +50px. If its NOT a move event, the last spot touched still has to be on the in the giving distance (in my case in the 48px*48px range of the point).
Thats it. took me days to only figure out that option ;/ ashamed of that ... though I coded it pretty fast, what makes me feeling better again :D
I'm just suggesting some walk-around :
Instead of removing the point when clicking it,
make a privata Point in your class, where you currently remove the point, just set your new Variable Point to the Point you would remove...
Then, after using it in action or action move, the last place you would use it,
check if your private variable is not null, if so, remove it, then, set it to null.
try using a switch case statement:
switch finger_action:
case(ACTION_MOVE)
{
//move code
return false;
}
case(ACTION_TOUCH)
{
//dissappear code
return false;
}
note the up above code is pseudo code, but what it does it checks to see if you are moving the dot before just touching it. this way the dot will attempt a move first instead of being removed first.
thanks,
Alex
I'm trying to move sprites to stop the frames in center(or move them to certain x position) when right or left pressed on screen. There are 3 sprites created using box.java in the view, placed one after another with padding, stored in arraylist.
The problem: No smooth movement and doesn't stop in the center of each frames after movement has begun, sometimes all boxes are moving on top of each others, padding is totally lost. Please let me know what I'm doing wrong, thanks a lot!
//BEGINING OF BOX.JAVA >> The problem is in this class!
//This goes in Update();
private void boxMove()
{
int get_moved_pos = getMovedPos(); //get moved pos
int sprite_size = view.getSpriteSize(); //get sprite arraylist size
currentDirection = view.getDirection(); //get direction "left" or "right" from view
if(currentDirection == "right" && isMoving == false)
{
setSpriteMovedNext();
}else
if(currentDirection == "left" && isMoving == false)
{
setSpriteMovedPrev();
}
if(currentDirection != lastDirection)
{
lastDirection = currentDirection;
//MOVE RIGHT
if(currentDirection == "right" && get_moved_pos > 0) //move left and make sure that moved pos isn't overlapping / or moving to empty space
{
//Animate left until it reaches the new x position
if(x > get_new_pos_left)
{
x -= pSpeedX;
}
Log.d("RIGHT","POS: " + get_moved_pos);
}else
//MOVE LEFT
if(currentDirection == "left" && get_moved_pos < sprite_size-1) //move left and make sure that moved pos isn't overlapping / or moving to empty space
{
//Animate right until it reaches the new x position
if(x < get_new_pos_right)
{
x += pSpeedX;
}
}
}
}
//Call when screen is touched (in View.java), to set a new position to move to.
public void resetMoving()
{
isMoving = false;
this.lastDirection = "";
Log.d("RESET", "MOVING RESET");
}
public int getMovedPos()
{
return this.smoved_pos;
}
private void setSpriteMovedNext()
{
int get_max_moved = getMovedPos();
int s_size = view.getSpriteSize();
if (isMoving == false) //take a break between movements
{
if(get_max_moved < s_size-1)
{
Log.d("NEXT", "CALLED");
this.get_new_pos_right = x + view.getNextPosX(); //current x and next stop position
this.smoved_pos += 1;
this.isMoving = true; //set to avoid double touch
Log.d("NEXT", "X POS SET: " + get_max_moved);
}
}
}
private void setSpriteMovedPrev()
{
int get_max_moved = getMovedPos();
if (isMoving == false) //take a break between movements
{
if(get_max_moved > 0)
{
Log.d("PREV", "CALLED");
this.get_new_pos_left = x - view.getNextPosX(); //get current x pos and prev stop position
this.smoved_pos -= 1; //to limit the movements
this.isMoving = true; //set to avoid double touch
Log.d("PREV", "X POS SET: " + get_max_moved);
}
}
}
//END OF BOX.JAVA
//VIEW
//Add boxes
public void addBox()
{
int TOTAL_BOXES = 3;
int padding_left = 200;
int padding_tmp = this.getWidth()/2;
box.clear(); //clear old
//Box 1
box.add(new Boxes(box, this, "box1",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 0, 0));
padding_tmp += boxSpriteImage.getWidth()/TOTAL_BOXES + padding_left;
//Box 2
box.add(new Boxes(box, this, "box2",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 1, 1));
padding_tmp += boxSpriteImage.getWidth()/TOTAL_BOXES + padding_left;
//Box 3
box.add(new Boxes(box, this, "box3",
padding_tmp,
this.getHeight()/2,
boxSpriteImage, 1, 2, 2, 1));
}
public boolean onTouchEvent(MotionEvent event){
if (System.currentTimeMillis() - lastClick > 100){
lastClick = System.currentTimeMillis();
float x = event.getX();
float y = event.getY();
synchronized (getHolder())
{
if(isBoxWindow() == true)
{
if(x >= this.getWidth()/2)
{
Direction = "right";
}else
{
Direction = "left";
}
}
}
}
//called in box.java to get next x pos to move
public float getNextPosX()
{
int PADDING = 200; //padding between frames
next_pos_x = boxSprite.getWidth()/TOTAL_COLUMNS + PADDING;
return next_pos_x;
}
I think your error is in the if statements, where you compare currentDirection and lastDirection (I'm assuming that lastDirection is a String) with other Strings using the == operator. The == almost operator never works when you want to compare Objects for equality. You should use the equals() method.
For eg.
if(currentDirection != lastDirection)
should be written as:
if(!currentDirection.equals(lastDirection)
Make such changes in your code(They are needed at many places!) and I think your problem should be solved.
A good debugging practice would be logging data about your app, from each of the if blocks, to see if each of them is executed. You could have found out if your if statements are being executed.
EDIT: Why have you put this code?
if (System.currentTimeMillis() - lastClick > 100)
This means onTouchEvents are only interpreted after 100ms. remove it and check, probably that's what is causing the problem.
Alrite, decided to use onFling() method and call via View instead of adding the animations separately into the class itself, works really well when called box.get(i).update() in a loop of all added boxes, all of them animated equally. Thanks udiboy.