hapsburgabsinth
|
 |
«
Posted
2011-12-01 02:11:11 » |
|
So I have this tile based game, with each tile being 20x20 pixels, and I draw them on a canvas in a loop like this: 1 2 3 4 5 6 7
| for(int y = 0; y < 24; y++){ for(int x = 0; x < 42; x++){ int yOffset = 0; position.setX(x + player.getPosition().getX()-21); position.setY(y + player.getPosition().getY()-12); } |
I now wonder how to make my player move smoothly from tile to tile when I press a button on my keyboard Any ideas how to start? To get me going? 
|
|
|
|
gbeebe
|
 |
«
Reply #1 - Posted
2011-12-01 05:17:03 » |
|
When the player presses a key to move, figure out where on the next tile the player is to stop, this is your destination X and Y. Each loop move him closer to that position, Ignore movement key presses until the player's X and Y are equal to the destination X and Y.
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #2 - Posted
2011-12-01 08:31:03 » |
|
That part I have done, I can move from tile to tile, but I can't make it smooth movement  Sorry for not being clear about that 
|
|
|
|
Games published by our own members! Check 'em out!
|
|
Gornova
|
 |
«
Reply #3 - Posted
2011-12-01 09:02:21 » |
|
as gbeebe suggest, try (pseudocode!): 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| boolean moveUp = false; boolean moveDown = false; boolean moveLeft = false; boolean moveRight = false; Point current = null; Point target = null; int stepX = TILE_SIZE_HORIZONTAL; int stepY = TILE_SIZE_VERTICAL;
gameLoop(){ if (!playerMoving){ checkPlayerInput(); } else { updatePlayerPosition(); } }
checkPlayerInput(){ if (player press UP){ moveUp = true; move(0,-stepY); } else if (player press DOWN){ moveDown = true; move(0,stepY); } else if (player press LEFT){ moveLeft = true; move(-stepX,0); } else if (player press RIGHT){ moveRight = true; move(stepX,0); } }
move(int dx, int dy){ current = player.getCurrentPoint(); target = new Point(current.x + dx, current.y +dy); } |
To update smoothly player position, my suggestion is to have some sort of Tween class. I have implemented a Tween logic for MarteEngine, see here TweenTest and here a webstart example. Let me know if you need help!
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #4 - Posted
2011-12-01 12:25:08 » |
|
Thanks so far, I will look into your suggestions 
|
|
|
|
bach
|
 |
«
Reply #5 - Posted
2011-12-02 01:03:33 » |
|
General approach described by others is ok. However, make sure you implement some sort of time based movement rather then pixel based. So, rather then saying every update move the character 1px you'd want to implement something like move character 1 tile / second. Usually you'd have a delta time between the last update and the current one. As Gornova suggested there are stacks of tween type libs out there that will make this stuff trivial. I suggest however that for basic character movement you just implement your own. If you need more advanced tweening stuff have a look at http://code.google.com/p/java-universal-tween-engine/. It's brilliant. Cheers, Bach
|
|
|
|
Gornova
|
 |
«
Reply #6 - Posted
2011-12-02 10:28:25 » |
|
@bach: java Universal Tweet engine is great, thanks for link!
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #7 - Posted
2011-12-04 17:32:12 » |
|
I really want to implement all of the game myself, not using pre-coded stuff, but thanks for the link, will look into it...  But I think this is a really hard part to do, I might be back for more help 
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #8 - Posted
2011-12-04 23:17:06 » |
|
This is my move method so far, it's kind of teleporting from one tile to another... I can't figure out to do those tweens, as my draw method draws in tiles, and not pixels. How do I get started?  1 2 3 4 5 6 7 8 9 10 11 12 13
| public boolean moveUnitTo(Position from, Position to) { if(isAllowedUnitPosition(to)){ Unit unit = this.tileMap.getUnitAt(from); this.tileMap.removeUnit(from); unit.setDirection(new Vector(to.getX() + from.getX(), to.getY() + from.getY())); unit.setPosition(to); this.tileMap.addUnitAt(to, unit); this.tileMap.getTileAt(from).setOccupied(false); this.tileMap.getTileAt(to).setOccupied(true); return true; } return false; } |
|
|
|
|
gbeebe
|
 |
«
Reply #9 - Posted
2011-12-04 23:36:56 » |
|
unit.setPosition(to) sets the unit on the next tile, no? You need to just set the unit's position (say) 1 pixel towards the destination.
|
|
|
|
Games published by our own members! Check 'em out!
|
|
hapsburgabsinth
|
 |
«
Reply #10 - Posted
2011-12-04 23:39:26 » |
|
unit.setPosition(to) sets the unit on the next tile, no? You need to just set the unit's position (say) 1 pixel towards the destination.
Yes it does, it is that which gives the teleporting effect, but I think my problem is, that I draw not in pixels, but tiles: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| public void render() { Graphics2D bbg = (Graphics2D) this.backBuffer.getGraphics(); BufferedImage image = null;
this.player = this.game.getTileMap().getPlayer(); this.inventory = player.getInventory(); nullTile = new Tile(position, "WATER"); for(int y = 0; y < 24; y++){ for(int x = 0; x < 42; x++){ int yOffset = 0; position.setX(x + player.getPosition().getX()-21); position.setY(y + player.getPosition().getY()-12); Tile tile = this.game.getTileMap().getTileAt(position); if(tile != null){ image = tile.getImage(); }else{ image = nullTile.getImage(); }
Item item = this.game.getTileMap().getItemAt(position); if(item != null){ image = item.getImage(); }
Building building = this.game.getTileMap().getBuildingAt(position); if(building != null){ image = building.getImage(); }
Unit unit = this.game.getTileMap().getUnitAt(position); if(unit != null){ image = unit.getImage(); yOffset = -40; }
bbg.drawImage(image, x*20, y*20+yOffset, this);
} }
bbg.drawImage(inventory.getImage(), 400, 480, this);
bbg.setColor(Color.WHITE); bbg.fillRect(0, 580, 40, 20); bbg.setColor(Color.BLACK); bbg.drawString(String.valueOf(gui.getFps()), 10, 595);
bbg.dispose(); } |
Or am I totally wrong?  I really want a bomberman like movement. If you press a movement key, then it animates a movement between tiles...
|
|
|
|
gbeebe
|
 |
«
Reply #11 - Posted
2011-12-05 00:03:06 » |
|
Yes, that is why. make an array for your untis: 1
| ArrayList<Unit> unit = new ArrayList(); |
Unit can have: 1 2 3 4 5 6
| int currentX; int currentY; int currentTileX; int currentTileY; int destTileX; int destTileY; |
Create your unit: 1 2
| unit.add(new Unit); int lastUnit = unit.size() -1; |
Then you can set the Unit's properties: 1 2
| unit.get(lastUnit).currentTileX = tx; unit.get(lastUnit).currentX = tx * yourTileWidht; |
1 2 3 4 5 6 7
| for (int uc = 0; uc < unit.size(); uc++) { image = unit.getImage(); yOffset = -40; bbg.drawImage(image, unit.get(uc).currentX, unit.get(uc).currentY*20+yOffset, this); }
|
the drawing of units would go right above: 1
| bbg.drawImage(inventory.getImage(), 400, 480, this); |
I'm not going to code the whole thing for you, but for starters: To move the unit towards the destination tile, simply add or subtract from the unit's currentX or currentY.
|
|
|
|
bach
|
 |
«
Reply #12 - Posted
2011-12-05 00:13:02 » |
|
Hey, I'd recommend you dig into some of the underlying math behind this kind of stuff. Once you know how to solve this mathematically I don't think you'd have any problems coding it. Have a read through this tutorial here: http://blog.wolfire.com/2009/07/linear-algebra-for-game-developers-part-1/It beautifully explains how to work with Vectors etc. Basic requirements needed for any kind of game. Cheers, Bach
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #13 - Posted
2011-12-05 08:55:37 » |
|
This is now my render method: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| public void render() { Graphics2D bbg = (Graphics2D) this.backBuffer.getGraphics(); BufferedImage image = null;
this.player = this.game.getTileMap().getPlayer(); this.units = this.game.getTileMap().getUnits(); this.inventory = player.getInventory(); nullTile = new Tile(position, "WATER"); for(int y = 0; y < 24; y++){ for(int x = 0; x < 42; x++){ position.setX(x + player.getPosition().getX()-xOffset); position.setY(y + player.getPosition().getY()-yOffset); Tile tile = this.game.getTileMap().getTileAt(position); if(tile != null){ image = tile.getImage(); }else{ image = nullTile.getImage(); }
Item item = this.game.getTileMap().getItemAt(position); if(item != null){ image = item.getImage(); }
Building building = this.game.getTileMap().getBuildingAt(position); if(building != null){ image = building.getImage(); }
bbg.drawImage(image, x*tileDimension, y*tileDimension, this);
} } for(Unit unit : units){ image = unit.getImage(); bbg.drawImage(image, unit.getPosition().getX() + unit.getCurrentPixelX() + (xOffset * tileDimension), unit.getPosition().getY() + unit.getCurrentPixelY() + (yOffset * tileDimension) - unitHeightOffset, this); }
bbg.drawImage(inventory.getImage(), 400, 480, this);
bbg.setColor(Color.WHITE); bbg.fillRect(0, 580, 40, 20); bbg.setColor(Color.BLACK); bbg.drawString(String.valueOf(gui.getFps()), 10, 595);
bbg.dispose(); } |
My move method: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| public boolean moveUnitToAnimated(Position from, Position to){ Tween tween = new Tween(); if(isAllowedUnitPosition(to)){ Unit unit = this.tileMap.getUnitAt(from); this.tileMap.removeUnit(from); unit.setDirection(new Vector(to.getX() + from.getX(), to.getY() + from.getY())); if(to.getX() < from.getX() && to.getY() == from.getY()){ tween.tweenUnitLeft(unit); } else if(to.getX() > from.getX() && to.getY() == from.getY()){ tween.tweenUnitLRight(unit); } else if(to.getX() == from.getX() && to.getY() < from.getY()){ tween.tweenUnitUp(unit); } else if(to.getX() == from.getX() && to.getY() > from.getY()){ tween.tweenUnitDown(unit); } this.tileMap.addUnitAt(to, unit); this.tileMap.getTileAt(from).setOccupied(false); this.tileMap.getTileAt(to).setOccupied(true); return true; } return false; } |
And my tween class: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| public class Tween {
public void tweenUnitLeft(Unit unit){ for(int i = 20; i > 0; i--){ unit.setCurrentPixelX(i); } unit.setPosition(new Position(unit.getPosition().getX() - 1, unit.getPosition().getY())); unit.setCurrentPixelX(0); } public void tweenUnitLRight(Unit unit){ for(int i = 0; i < 0; i++){ unit.setCurrentPixelX(i); } unit.setPosition(new Position(unit.getPosition().getX() + 1, unit.getPosition().getY())); unit.setCurrentPixelX(0); } public void tweenUnitUp(Unit unit){ for(int i = 20; i > 0; i--){ unit.setCurrentPixelY(i); } unit.setPosition(new Position(unit.getPosition().getX(), unit.getPosition().getY() - 1)); unit.setCurrentPixelY(0); } public void tweenUnitDown(Unit unit){ for(int i = 0; i < 20; i++){ unit.setCurrentPixelX(i); } unit.setPosition(new Position(unit.getPosition().getX(), unit.getPosition().getY() + 1)); unit.setCurrentPixelY(0); } } |
Is that anything what you meant? 
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #14 - Posted
2011-12-06 04:52:11 » |
|
So I'm back to square one, tried to draw units in a separate loop, but couldn't get it to work. Is there any other approach, or would you get me started at drawing them the correct way? This is my "old" render method: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| public void render() { Graphics2D bbg = (Graphics2D) this.backBuffer.getGraphics(); BufferedImage image = null;
this.player = this.game.getTileMap().getPlayer(); this.inventory = player.getInventory(); nullTile = new Tile(position, "WATER"); this.unitHeightOffset = 0; for(int y = 0; y < 24; y++){ for(int x = 0; x < 42; x++){ int unitHeightOffset = 0; position.setX(x + player.getPosition().getX() - this.xOffset); position.setY(y + player.getPosition().getY() - this.yOffset); Tile tile = this.game.getTileMap().getTileAt(position); if(tile != null){ image = tile.getImage(); }else{ image = nullTile.getImage(); }
Item item = this.game.getTileMap().getItemAt(position); if(item != null){ image = item.getImage(); }
Building building = this.game.getTileMap().getBuildingAt(position); if(building != null){ image = building.getImage(); }
Unit unit = this.game.getTileMap().getUnitAt(position); if(unit != null){ image = unit.getImage(); unitHeightOffset = -40; unit.setVisible(true); }
bbg.drawImage(image, x*tileDimension, y*tileDimension+unitHeightOffset, this);
} }
bbg.drawImage(inventory.getImage(), 400, 480, this);
bbg.setColor(Color.WHITE); bbg.fillRect(0, 580, 40, 20); bbg.setColor(Color.BLACK); bbg.drawString(String.valueOf(gui.getFps()), 10, 595);
bbg.dispose(); } |
|
|
|
|
gbeebe
|
 |
«
Reply #15 - Posted
2011-12-06 22:57:26 » |
|
What's your unit class look like?
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #16 - Posted
2011-12-06 23:01:58 » |
|
This is my unit class, and the getters and setters for each field: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public abstract class Unit implements WorldObject{ private Position currentPosition; private Position destinationPosition; private String name; private String type; private int strength; private int agility; private int vitality; private int xp; private int level; private int chips; private double health; private double attackDamage; private double dodgeRating; private int luck; private int attackRange; private double maxHealth; private String unitClass; private Vector direction; private int energy; private BufferedImage image; private int currentPixelX; private int currentPixelY; private boolean visible; private boolean isMoving;
public Unit(Position p, String name, String type) { this.currentPosition = p; this.setCurrentPixelX(0); this.setCurrentPixelY(0); this.name = name; this.type = type; this.direction = new Vector(1,0); loadImage(); }
private void loadImage() { this.image = null; try{ this.image = ImageIO.read(new File("bin/image/unit/" + this.type + ".png")); }catch (Exception e) { System.out.println("Couldn't find " + this.type + "'s image file"); } } } |
|
|
|
|
gbeebe
|
 |
«
Reply #17 - Posted
2011-12-06 23:34:09 » |
|
Maybe you could put a headTowards function in your Unit class. which would simply store the (x, y) the the next tile to go to call this destinationX and destinationY. Then have an advance() command in the Unit class that would simply check to see if the currentPixelX and Y is equal to the destinationX and Y. If not, add or subtract 1 from currentPixelX or Y . NO LOOPS GO IN THAT CODE. When drawing you draw the unit at the currentPixelX and Y.
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #18 - Posted
2011-12-07 01:25:59 » |
|
[EDIT] Well it kinda works!
My only problem is that it never stops moving now :S Can't figure out where to put the check if the destination is reached....?
|
|
|
|
gbeebe
|
 |
«
Reply #19 - Posted
2011-12-07 01:39:59 » |
|
If you implemented it the way I said to, it should work how you want. in pseudo code your main loop moves the units: 1 2 3 4 5 6 7 8
| unit.advance() if (player is pressing UP) { if (unit.currentPixelX = unit.destinationX && unit.currentPixelY = unit.destinationY) { unit.headTowards(newX, newY); } } |
The player only has to tap UP to start the unit movement, if the unit is ready to move again(by checking to see if it's resting on its destination). In the .advance() function, you should first check to see if the unit has arrived at it's destination... If not, move one pixel towards it. If it has reached it destination, do nothing. I wouldn't worry about fancy tweening or smooth/time based movement until you at least get this right.
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #20 - Posted
2011-12-07 01:44:34 » |
|
yes I did that: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public void headTowardsDestination(){ if(!this.destinationReached){ int currentX = this.currentPosition.getX(); int currentY = this.currentPosition.getY(); int destinationX = this.destinationPosition.getX(); int destinationY = this.destinationPosition.getY(); if(currentX < destinationX){ this.currentPixelX++; }else if(currentX > destinationX){ this.currentPixelX--; }else if(currentY < destinationY){ this.currentPixelY++; }else if(currentY > destinationY){ this.currentPixelY--; } } } |
But where should should I assign destinationReached = false; ?
|
|
|
|
gbeebe
|
 |
«
Reply #21 - Posted
2011-12-07 01:52:04 » |
|
public void headTowardsDestination(){ this.destinationReached = false; if(!(this.destinationPosition.getX() == this.currentPosition.getX()) || !(this.destinationPosition.getY() == this.currentPosition.getY())) { int currentX = this.currentPosition.getX(); int currentY = this.currentPosition.getY(); int destinationX = this.destinationPosition.getX(); int destinationY = this.destinationPosition.getY(); if(currentX < destinationX){ this.currentPixelX++; }else if(currentX > destinationX){ this.currentPixelX--; }else if(currentY < destinationY){ this.currentPixelY++; }else if(currentY > destinationY){ this.currentPixelY--; } } }else{ this.destinationReached = true; } }
also, where ever you set your new destination set .destinationReached to false.
|
|
|
|
hapsburgabsinth
|
 |
«
Reply #22 - Posted
2011-12-07 02:20:00 » |
|
I think it works, cant test it yet though, cause I have some bug in my code, the units moves downwards by default, and never reaches their destination, but I have given you an appreciate 
|
|
|
|
ra4king
|
 |
«
Reply #23 - Posted
2011-12-09 00:47:36 » |
|
gbeebe, please use code tags: [code] code goes here [/code]
|
|
|
|
gbeebe
|
 |
«
Reply #24 - Posted
2011-12-09 03:05:45 » |
|
@ra4king... Really?
|
|
|
|
ra4king
|
 |
«
Reply #25 - Posted
2011-12-09 04:25:34 » |
|
@ra4king... Really?
Yes, really 
|
|
|
|
sproingie
|
 |
«
Reply #26 - Posted
2011-12-09 17:49:41 » |
|
Out of curiosity, how do you escape the bbcode tags themselves?
|
|
|
|
Z-Man
|
 |
«
Reply #27 - Posted
2011-12-09 21:50:34 » |
|
Out of curiosity, how do you escape the bbcode tags themselves?
Well this is how ra4king did it 1
| [color=black][[/color]code] code goes here [color=black][[/color]/code] |
|
|
|
|
ra4king
|
 |
«
Reply #28 - Posted
2011-12-12 07:02:40 » |
|
It's a clever hack I discovered in a moment of need 
|
|
|
|
|