The forums have permanently moved to forum.kirupa.com. This forum will be kept around in read-only mode for archival purposes. To learn how to continue using your existing account on the new forums, check out this thread.


Results 1 to 10 of 10

Thread: "Between tiles" in tile based games

  1. #1

    "Between tiles" in tile based games

    Let's say you have a tile based game such as "Snake" (also known as "Nibbles") or this game where you can only "be" on one tile at a time. (compared to, say, the old Mario games where the level may be composed of tiles, but you can have an "x" and "y" position that does not snap to the nearest tile and you can stand wherever you want)

    If you wanted to move to the tile to your right, you could instantly "jump" over to the right tile, or you could take a certain amount of time to "move" toward the right until you land on the next tile (like PacMan).

    Assuming you can't move diagonally, and only move between two adjacent tiles, how would you keep track of this "transition between two tiles" in code? (keeping track of "global" x and y positions feels dirty if you are sitting on a grid and forced to "stick" to the grid when you stop moving)

    In the transition, which tile should you consider the player to be "on"?

    Does anyone know of a working game with open code that uses these types of mechanics that I can study from?


    I run into this problem quite a bit, and usually hack together some ugly solution for which I should be flogged. But I'm looking for something more "elegant".
    Blog article of the month: Why My One Line 'if' Statements Are Unusual
    Twitter: @IQAndreas
    GitHub: IQAndreas

  2. #2
    There was one solution I used recently where the player can push blocks. When they moved, their new "grid location" was immediately set to one space to the right (if possible) and all blocks that they pushed were also immediately set to their "new grid location". It took 0.3 seconds for the player to move, and under that time the board stood still and nothing happened except for the animation of the player and all blocks from the "old tile" to the "new tile".

    The "movement" was a simple tween, and although the player looked like it was between blocks, in the code it was already standing on the "target tile".


    That works in some cases, but let's say you add an "enemy" that takes 0.5 seconds to move between tiles. The enemy may start to move while the player is standing still, or may move while the player is in the middle of moving. In such a case, the grid cannot be "locked down" from changing while the tweens are running.
    Blog article of the month: Why My One Line 'if' Statements Are Unusual
    Twitter: @IQAndreas
    GitHub: IQAndreas

  3. #3
    TheCanadian's Avatar
    10,305
    posts
    Noo doot aboot it, eh?
    So assuming your characters aren't cats and thus can't be in two places at once, collision detection should be as simple as detecting whether the characters are in the same place at the same time. It seems to me like you're trying to fit your game where characters can exist between tiles into the mould of one where they cannot.
    Proud Montanadian
    We tolerate living and breathing. And niches.

    Name Brand Watches

    Maybe getTimer() or TweenMax is the answer to your problem . . .

  4. #4
    Quote Originally Posted by TheCanadian View Post
    So assuming your characters aren't cats and thus can't be in two places at once
    http://stickerish.com/wp-content/upl...WithTextSS.png

    Quote Originally Posted by TheCanadian View Post
    It seems to me like you're trying to fit your game where characters can exist between tiles into the mould of one where they cannot.
    The characters can't stay between two tiles, but they need some way to move between them over a set amount of time.

    In games like Sokoban you "are" on a specific tile, and "smooth moving" between tiles is purely aesthetic and doesn't affect game logic. Games where there is only one player affecting the board and everything moves at once are simple.

    But imagine if Sokoban had an "enemy" character running around. The player and the enemy cannot ever be on the same tile.
    Name:  tiled-game-01.png
Views: 303
Size:  14.3 KB

    The player and the enemy move separately, and don't have to be "synchronized" and move at the same time.
    Name:  tiled-game-02.png
Views: 309
Size:  14.2 KB

    If the player is in the way, the enemy cannot move to that tile, but if the player is in the way, the enemy cannot move to that tile. If the player is moving toward a tile, the enemy cannot move onto that same tile.
    Name:  tiled-game-03.png
Views: 308
Size:  18.6 KB

    I could write in the code that the player is both on the tile it is moving from, and the tile it is moving to. When the "movement" time has finished passing, the player is removed from the tile it was moving from.

    This runs into several issues. If one empty tile has a button on it (which the player can stand on to activate) the player could theoretically be pressing two buttons at once (not good).

    Also, if an enemy is following right behind a player (or vice versa), the enemy is allowed to step onto the tile the player is moving off of (which is not allowed if the player is occupying both the space it is stepping off of and onto)
    Name:  tiled-game-04.png
Views: 304
Size:  14.8 KB


    I can't seem to get these rules to work elegantly in code (theoretical code for now, still working it out in my head). I really wish I had some example code to look off of.


    Sorry if I'm repeating information I already wrote, but I'm trying to re-word things to be clearer of what I'm trying to achieve.
    Blog article of the month: Why My One Line 'if' Statements Are Unusual
    Twitter: @IQAndreas
    GitHub: IQAndreas

  5. #5
    1,391
    posts
    Registered User
    i understand where you're trying to go, i've built similar systems for some path finding AI - i usually went with storing the intended target as being occupied by the caller at the time of the decision - then either, as the object arrives at it's destination, or when leaving the grid coordinate sector, removing occupation from the previous location - if something changes during the transition, reverse direction to the last known occupied location and remove the intended target occupation

    but i think that C's point is that in the example case - collision is collision regardless when that happens - if it occurs during the tween transition, just reverse the entity tweens - in this way you don't really need to 'check' to see if a location is occupied before moving, you can attempt to move to any location, the collision is what determines the resulting action whenever it happens

    this also allows for player-enemy 'contact' where damage may result - whereas, a system which determines that you 'can not' move into an occupied space prevents contact between entities

  6. #6
    Here is the code I have on my Entity class to control it's movement:
    Code:
    //move variables
    protected var speed:Number                 = 4;
    protected var moving:Boolean             = false;
    protected var movingEnded:Boolean         = false;
    private var elapsedTime:Number             = 0;
    private var movingBetweenTiles:Boolean     = false;
    protected var needAttach:Boolean             = false;		private var _nextTile:Tile;
    private var origin:Point;
    private var dest:Point;
    
    
    public function update(p_transport:Object):void
    {
        processMovement(p_transport);
    }
    private function processMovement(p_transport:Object)
    {
        if(moving){
            elapsedTime += p_transport.time;
            if ( !movingBetweenTiles )
            {
                origin = new Point(0, 0);
                dest = new Point( (_nextTile.gridX * Map.mapGridSize) - (gridX * Map.mapGridSize), (_nextTile.gridY * Map.mapGridSize) - (gridY * Map.mapGridSize) );
                
                movingBetweenTiles = true;
                
                var distance : Number = Point.distance(origin, dest);
                
                if ( distance > 0 )
                {
                    elapsedTime    = 0;
                }
                
                verifyCharacterAngle();
            }
            else
            {
                var displacement:Number = calcDisplacement();
                
                if ( displacement == 0 )
                {
                    teleportToTile( _nextTile );
                }
            }
        }
    }
    
    
    private function verifyCharacterAngle() : void
    {
        if ( _nextTile )
        {
            var diffX : Number = _nextTile.gridX - gridX;
            var diffY : Number = _nextTile.gridY - gridY;
            
            var _up     : Boolean = diffX == 0 && diffY == -1;
            var _right     : Boolean = diffX == 1 && diffY == 0;
            var _down     : Boolean = diffX == 0 && diffY == 1;
            var _left     : Boolean = diffX == -1 && diffY == 0;
            
            if ( _left ) 
            {
                needAttach = true;
            }
            else if ( _up ) 
            {
                needAttach = true;
            }
            else if ( _right ) 
            {
                getCurTile().removeEntity();
                _nextTile.addEntity(this);
                
                this.x = -Map.mapGridSize;
                origin.x -= Map.mapGridSize;
                dest.x -= Map.mapGridSize;
            }
            else if ( _down ) 
            {
                getCurTile().removeEntity();
                _nextTile.addEntity(this);
                
                this.y = -Map.mapGridSize;
                origin.y -= Map.mapGridSize;
                dest.y -= Map.mapGridSize;
            }
        }
    }
    
    
    private function calcDisplacement() : Number
    {
        var iDelta     : Number;
        var newPos    : Point;
        
        iDelta = 1 - ( (speed / 1000) * elapsedTime );
        
        if ( iDelta < 0 )
            iDelta = 0;
        
        newPos = Point.interpolate( origin, dest, iDelta );
        
        this.x = int( newPos.x );
        this.y = int( newPos.y );
        
        return iDelta;
    }
    
    
    protected function teleportToTile( p_tile : Object ):void
    {
        //trace("done moving");
        
        movingBetweenTiles = false;
        moving = false;
        
        if((this as MovieClip).getChildByName("mcAnim"))
            (this as MovieClip).mcAnim.gotoAndStop("idle");
        
        this.x = 0;
        this.y = 0;
        if (needAttach){
            getCurTile().removeEntity();
            _nextTile.addEntity(this);
        }
        needAttach = false;
        
        _nextTile = null;
        movingEnded = true;
    }
    Hope this helps, I don't knwo if a I need to post a snippet from any other clas as well.

  7. #7
    Forgot to mention, even though I only attach the entity to a tile in certain cases, I change the obstacles Array for the pathfinding, so the entities know that that entity is no longer in that tile...I guess it got a little confusing..sorry.

  8. #8
    Not sure what you are asking but if you need a good book for tile based game let know.

  9. #9
    It sounds like you simply haven't decided how you want your game to play.

  10. #10
    Hmm, I am currently writing a top-down RPG game which is using tiles as its map structure. Something similar to say FF7, or Zelda (NES). I am not sure if this is the similar idea of what you are wanting to do. For me, my map (tiles) and the player/enemy/objects are on a completely different plane. For starters I have my map, which is effectively a pieced together bitmap. Next as my code is assembling the map, should there be an objects, enemies, NPCs, these get put into an array as a new object (of class dependent on their type). My collisions are then based on my Player (which is independent of the collision array or the bitmap) and the bitmap and if there are any hits going on between the two bitmaps (in both the player and the array at the index i am looking at). This works quite well in that it allows the enemy to "follow" the player, ie, move to the location the player just was; and vica versa with the player following the enemy.

    Once again, I am not sure if this helps any. It works for me game.

Thread Information

Users Browsing this Thread

There are currently 1 users browsing this thread. (0 members and 1 guests)

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

Home About kirupa.com Meet the Moderators Advertise

 Link to Us

 Credits

Copyright 1999 - 2012