PDA

View Full Version : snapping sprite to tilemap



leniz
23-04-2007, 04:49 PM
hi everybody,
i'm new here, so go easy on me :)
so the thing is, that i'm trying to create a game like zelda, but much simplier. i'm using an engine(made from Traveler's tutorial) which uses bmps to tile my map, and now i want the sprite to snap to each tile.
i know it's easy, but it's new to me, so i'm stuck

best regards, leniz

WILL
23-04-2007, 05:23 PM
Hi leniz, welcome to PGD! :)

Well if you want to have a defined grid which the player will stick to you could change the X/Y value which he is not being moved in.

ie.

if (Player.Moving = movingLeft) or (Player.Moving = movingRight) then
Player.Y := FindClosestY(Player.X, Player.Y);

FindClosestY would be a function that finds what the closest grid position the character is most closest to and returns it's value.

I'll assume that you've already figured out how to draw the tiles properly. So remember how you had to multiply by the tilesize to get it to display on the spot you wanted? Well now you have to divide by that same size to convert from the character's real location to the grid location.

The best way to do this is to create functions that will figure out what the real location is in the grid.

Here are the functions that I use in Subject 33...

{Convert Location on Screen to Game Position}
function XPos(X: Integer): Integer;
begin
XPos := Round(X / Game_TileSize - 0.4444);
end;
function YPos(Y: Integer): Integer;
begin
YPos := Round(Y / Game_TileSize - 0.4444);
end;

{Convert Game Position to Actual Screen Location}
function XLoc(X: Integer): Integer;
begin
XLoc := X * Game_TileSize;
end;
function YLoc(Y: Integer): Integer;
begin
YLoc := Y * Game_TileSize;
end;


Game Position is what I've been calling the 'grid' location. Actual Screen Location is only actual if you don't scroll your map, otherwise think of it as the real map location instead. Same concept though. :)


Seeing as this topic is more about game design in general, I'll move this thread to the General forum.

leniz
24-04-2007, 02:16 PM
This idea crossed my mind when I was writing the first post, but I'm embarassed to admit that I have no clue how to write the "FindClosestY/X" function :oops:

WILL
24-04-2007, 03:40 PM
Just use XPos and YPos to find your grid location from actual location. Then use XLoc and YLoc on that returned value to do the actual 'snapping'.

Think of it like rounding a decimal value.

jdarling
24-04-2007, 03:57 PM
Here is a simple sample:function FindClosestY(WorldY : Real) : Integer;
begin
result := WorldY div TileHeight;
result := result * TileHeight;
end;

function FindClosestX(WorldX : Real) : Integer;
begin
result := WorldX div TileWidth;
result := result * TileWidth;
end;

function FindWorldTile(WorldPosition : TPoint) : TPoint;
begin
result.X := WorldPosition.X div TileWidth;
result.X := result.X * TileWidth;
result.Y := WorldPosition.Y div TileHeight;
result.Y := result.Y * TileHeight;
end;

Depending on if your world position starts at tile 0 or 1 you might have to subtract 1 from the final result of the methods.

leniz
24-04-2007, 06:06 PM
Ok, now that we're settled with this, another question came upon me, that I have completely forgoten(lack of sleep can do that):
Apparently I need the sprite to move from tile to tile, but not a continuos movement like this:
sprite.x:= sprite.x + tilesize;
No, I need it to walk somehow like this:
Walk one tile and stop, walk one tile and stop.
I really hope you understand.

Best Regards, leniz

WILL
24-04-2007, 06:33 PM
Oh yeah, this is really common on the old NES games so I'm quite familiar with what you are trying to do.

Basically what you want to do is to have your character or player object stop at the next tilespace.

There are a few ways to do this, but I think the easiest might be to have a movement flag. (Boolean variable) When this flag is up (True) your character is moving, and when down (False) it is not.

What this will allow you to do is keep track of when he is moving in the code that determines when to stop him. Also by using this flag instead of direct user input, you are allowing the person controlling the character to release the button while the character continues to move until it is time to stop. This will allow your character to stick to the tiles when not moving.


The only thing left to figure out is how one figures out when to stop. Not too hard...

One way is to keep track of the OldX/OldY grid location of your character and when they are different you allow him to stop by checking if the user's walk buttons are released. If so then he should stop so you set the Moving flag to false and snap the player into the new tile before it is drawn. It will look just like he walked into the tilespace and stopped.

leniz
03-05-2007, 03:44 PM
So I've been offline for a while and decided to throw away the tile by tile moving idea, atleast for now. Right now I want my 'hero' to walk only on tiles of grass and path, so I used this for staying off water:
If (isRight in form20.DXInput1.keyboard.States) Then
begin
oldx:=hero.X;
oldy:=hero.Y;
hero.x:=hero.x + 4;
tempy:=round(hero.Y/tilesize - 0.4444);
hero.y:=tempy*tilesize;
if tileinfo[rx, ry].tilenr = 2 then
begin
hero.X:=oldx;
hero.Y:=oldy;
end;
end;

Well, it does its thing with a minor glitch - after walking on water tile, my 'hero' stops responding to controls. Any other thoughts on how to solve this minor problem, because I hate it whan my 'hero' steps on water like Jesus Christ...
BTW: I know this code of mine is totaly lame, but what can I do :oops:

jdarling
03-05-2007, 04:36 PM
Before you let your hero move, check the tile that he is moving to to see if its valid. If not, then don't allow the move. The problem your having is that your checking after you move :).

Basically (psudo code):

If RightKeyPressed and OkToWalkOn(TileToRightOfHero) then
ProcessMove()

leniz
03-05-2007, 06:10 PM
Oh man, I'm so embarssed. Well thank you for your answer, I'll try it right away :)

leniz
23-05-2007, 01:50 PM
Hi, it's me again with another problem.
After some consideration I've decided to (re)make my 'game' using gamestate and all was good untill I needed to draw my sprite on screen. I create my sprite on dxtimer initialization or right after 'New Game' is pressed and I try to draw it on my doGame procedure, right after I finish my tiling, but alas... That stupid sprite won't even appear on my screen.
If anyone knows what's wrong with it, mI'm always open to ideas...

Thanks in advance
best regards, Leniz

WILL
23-05-2007, 02:02 PM
Hi leniz,

If your are having a graphics problem, I'd recommend starting a new thread to discuss it in the forum that best fits it. (ie. if you are using a specific library like JEDI-SDL or UnDelphiX or just talking graphics in general)

People will be able to see and help you more directly this way.