Thread: tile engine view area

  1. #1
    Registered User
    Join Date
    Oct 2005
    Posts
    5

    tile engine view area

    i wrote a tile engine and it is completely working.
    i am making a turn based game so the players move 1 tile each move (not 1 pixel) and the current tiles are 32x32 pixels
    what i am trying to do is make a slightly more realistic tile engine and add some strategy to it.
    i want to make it so if there is an opaque tile in front of the player, such as a tree, they will not be able to see the tiles behind it.

    such as:
    G G G _ G G G
    G G G _ G G G
    G G G O G G G
    G G G P G G G
    G G G G G G G
    G G G G G O G
    G G G G G G _
    G = basic grass tiles
    P = player
    O = opaque object that the player cannot see through
    _ = area that isnt displayed

    i have spent alot of time thinking about this and i cannot find a way to correctly calculate the tiles that should not be shown

  2. #2
    Registered User Dante Shamest's Avatar
    Join Date
    Apr 2003
    Posts
    970
    Use different layers of tiles?

  3. #3
    Unregistered User
    Join Date
    Sep 2005
    Location
    Antarctica
    Posts
    341
    Are you talking about blacking out any tiles that the user should not be able to see? Like the old versions of Ultima? If this is so (God I hated that feature of ultima), you should be able to do some sort of line checking, such as move up on the Y axis, if you hit an opaque object, keep moving up the y axis and draw black tiles in place of the remaining tiles.

  4. #4
    Registered User
    Join Date
    Oct 2005
    Posts
    5
    Dante Shamest: there is only one layer of tiles, each tile stores a moveable variable to detect player collision

    rockytriton: i have never played ultima, but it is probobly what i am trying to do. the problem with moving up the y axis and blacking out the tiles after opaque objects is if there is an opaque object diagonal to the player or to the left of the player it would not work. i am thinking that i will need to use triginometry for this, though its been years since i learned about triginometry

  5. #5
    Unregistered User
    Join Date
    Sep 2005
    Location
    Antarctica
    Posts
    341
    it shouldn't be too hard an algorithm to figure out if things are diagonal as well, it's simple x,y coordinates.

  6. #6
    Registered User
    Join Date
    Oct 2005
    Posts
    5
    ah i got it, im just going to find the player coordinates and the coordinates of the opaque object then do a simple y=mx+b thing and loop through it to find all the tiles that need to be not shown

  7. #7
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    y=mx+b AHHH ALGEBRA HATE IT ARHGGG

    lol :d

  8. #8
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Cast enough rays to fit the resolution of your tile map. Based on ray intersection information you can determine whether or not a tile is visible or not.

    You will need these:

    tan(theta)=opposite/adjacent
    cos(theta)=adjacent/hypotenuse
    sin(theta)=opposite/hypotenuse

    tan(a)=x/y
    cos(a)=y/h
    sin(a)=x/h

    so:

    You can step through your map using tan() instead of cos/sin. On a 100x100 tile grid, cos and sin method will force you to search 100x100 intersections. Not good.

    Here is the basis for tangent ray casting.

    tan(angle)=x/y

    Well you know that x is your horizontal cell or tile size.
    You also know that y is your vertical cell or tile size.

    So you split the ray cast into two parts: Cast on X or horizontal, and cast on Y or vertical.

    Y cast
    tan(angle)=x/y
    tan(angle)*y=x
    Code:
    float stepsizex=tanf(angle)*(float)cellheight;
    X cast
    tan(angle)=x/y
    tan(angle)/x=y
    Code:
    float stepsizey=tanf(angle)/(float)cellwidth;
    or
    Code:
    float oneOverCellWidth=1.0f/cellwidth;
    float stepsizey=tanf(angle)*oneOverCellWidth;
    To figure out what angle is in the equation
    HFOV=Horizontal Field Of View
    Code:
    float LeftRayAngle=PlayerHeading-(HFOV*0.5f);
    if (LeftRayAngle<=0.0f) LeftRayAngle+=360.0f;
    
    float RightRayAngle=LeftRayAngle+HFOV;
    if (RightRayAngle>=360.0f) RightRayAngle-=360.0f;
    Now you need to decide on the resolution of your raycast. If you wish to cast out a lot of rays, your cast will be more precise, but will take longer. For a tile map you shouldn't need a huge resolution. I'd say 90 rays would suffice.

    So:

    Code:
    ....
    float AngleStep=NumberOfRays/360.0f;
    or

    Code:
    float oneOver360=1.0f/360.0f;
    float AngleStep=NumberOfRays*oneOver360;

    Now just create two loops, one to raycast on x and one on y. If TileMap(x,y) is an opaque object, exit the loop, increment the ray angle, and continue. If not, continue stepping in ray direction until opaque tile is hit. You could render an entire scene this way. Start out with a black screen and render. Darken the correct vertices of the quad that is the last one visible and you will have a 'fog of war' Command and Conquer type effect.

    Instead of doing this using anglestep you could use linear interpolation.

    Code:
    float Lerp(float v1,float v2,float interpamount)
    {
      return (v1+interpamount*(v2-v1));
    }
    
    float LerpASM(float v1,float v2,float interpamount)
    {
      float result=0.0f;
      asm {
    
        ;load v2 into st(0)
        fld [v2]
    
        ;subtract v1 from st(0)
        fsub [v1]
    
        ;multiply st(0) by interpamount
        fmul [interpamount]
    
        ;add v1 to st(0)
        fadd [v1]
    
        ;pop st(0) off stack into result
        ;only necessary to get along with function prototypes
        fstp [result]
      }
      return result; 
    }
    Now instead of using stepangle you can use an interpolation amount to interpolate from one ray angle to the next or from LeftRayAngle to RightRayAngle. Since the HFOV is usually 60 degrees, and interpamount of 0.5f would be roughly halfway or 30 degrees.

    Note that in the last function I had to specifcally return a value even though the result is left in st(0). I had to do this because the compiler sees the float return type and even though my code does in fact leave the correct value in st(0), the compiler has no way of knowing that. If this function was coded in pure asm, the prototype would still be float LerpASM(), but I would not have to return anything since the correct value is left in st(0) and the compiler would pick that up automatically. For more information consult an assembly language book.
    Last edited by VirtualAce; 10-19-2005 at 11:55 PM.

  9. #9
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    Quite a post there Bubba :d

  10. #10
    Registered User
    Join Date
    Oct 2005
    Posts
    5
    WOW thanks Bubba

  11. #11
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well I didn't invent the idea. You can thank John Carmack and DOOM 1 for the idea. That is essentially how Carmack and ID software got a 3D 'looking' first-person shooter to run on an old 386 w/o a math co-processor. They used raycasting.

    Pretty simple process.

    Cast a ray.
    When it hits a wall or a non-zero element in the array, compute the distance to the point. This can be done w/o using square root by using the law of similar triangles. Then decide on a wall height. Divide wall height by distance. Divide the final result by 2.

    StartLineY=CenterOfScreenY-height2;
    EndLineY=CenterOfScreenY+height2;

    Doing textures is easy because you just find out how far into each cell you are - this is a simple calculation and you use the float value you get to index into the texture. You only need u since v never changes. This is also perspective correct texture mapping because the raycast takes care of the divide by z. To do characters you simply raycast and when you reach a cell where a character is, you stick the current X location of the cast and the ID of the character into memory. Then on a second pass you start at that location and draw the sprite centered vertically on the screen. Doors are done much the same way.
    You should try it some time. It's easy to code and it's very very fast on modern computers.

    But raycasting can also be used for doing voxel engines like Novalogic's Delta Force 1 and 2. It is used in 3D games to do bullet trajectories and computations and many many other things.

    A ray cast is as simple as this:

    RayEndX=RayOriginX+cos(RayAngle)*RayCastDistance;
    RayEndY=RayOriginY+sin(RayAngle)*RayCastDistance;

    But you can also use the tangent form to speed your engine up.

    Do some research on raycasting and if you are interested, non-orthogonal raycasting methods.

  12. #12
    Absent Minded Programmer
    Join Date
    May 2005
    Posts
    968
    A friend of mine made a 3d looking game on Basic.. with sins and cos and etc etc....


    it really looks 3d, using trig calculations for perspective n stuff, in BASIC :d, its pretty wild, TOO much math for me :d

  13. #13
    Registered User
    Join Date
    Oct 2005
    Posts
    5
    thanks Bubba, looks like i need to stop sleeping through geometry :P

  14. #14
    Crazy Fool Perspective's Avatar
    Join Date
    Jan 2003
    Location
    Canada
    Posts
    2,640
    >>You can thank John Carmack and DOOM 1 for the idea.

    You mean Wolfentstein3D ... and then DooM

  15. #15

    Join Date
    May 2005
    Posts
    1,042
    That's the reason why the horizontal field of view in those games was 45 degrees: tan(45) = 1, allowed them to take out some math.
    I'm not immature, I'm refined in the opposite direction.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Need testers for editor
    By VirtualAce in forum Game Programming
    Replies: 43
    Last Post: 07-10-2006, 08:00 AM
  2. DirectX engine nearing completion
    By VirtualAce in forum Game Programming
    Replies: 2
    Last Post: 01-12-2004, 05:07 PM
  3. Tile Engine Scripting Idea. Suggestions?
    By napkin111 in forum Game Programming
    Replies: 8
    Last Post: 07-28-2003, 02:01 PM
  4. Tile Engine Problems with Video Memory
    By Tommaso in forum Game Programming
    Replies: 8
    Last Post: 03-07-2003, 08:26 PM
  5. Need lots of help with tile engine
    By VirtualAce in forum A Brief History of Cprogramming.com
    Replies: 0
    Last Post: 06-12-2002, 01:54 AM