TGC Codebase Backup



Simple Raycaster. by Cliff Mellangard 3DEGS

6th Nov 2011 15:47
Summary

A simple raycaster like the original wolfenstein engine.



Description

use an 640x480 resolution.
you nead an background image in any size.
you nead an 128x128 texture in size.
Check my agk thread for updates.



Code
                                    ` This code was downloaded from The Game Creators
                                    ` It is reproduced here with full permission
                                    ` http://www.thegamecreators.com
                                    
                                    remstart
////////////////////////////////////////////////////////////////////////////////
// Raycast engine for AGK //////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/////// Open source ////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
      By
Cliff Mellangård
    Sweden

   Forum id
Cliff Mellangard 3DEGS
////////////////////////////////////////////////////////////////////////////////
Link to usefull sites. /////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
http://www.permadi.com/tutorial/raycast/index.html

http://dev.opera.com/articles/view/creating-pseudo-3d-games-with-html-5-can-1/
////////////////////////////////////////////////////////////////////////////////
remend


global AngDummy
AngDummy = CreateSprite ( 0 )

SetSyncRate ( 0, 1 )
SetVirtualResolution ( GetDeviceWidth(), GetDeviceHeight() )
//setsorttextures(0)
global IMG
IMG = LoadImage ( "128x128.png" )

global IMG_Back
IMG_Back = LoadImage ( "Back.png" )

// number of map blocks in x-direction
#constant mapWidth 32
// number of map blocks in y-direction
#constant mapHeight 24

// how many pixels to draw a map block
#constant miniMapScale 4

// The same as minimap scale and is only used to get the right texture column for the screen column
#constant TextureScale 128

global dim map [mapWidth,mapHeight] as integer

Random_Map ()

// Number of rays we use
#Constant numRays 210
// this is 60/numrays
#Constant rayspeed 0.2857142
#Constant PI 3.1415926535
// not used yet
#Constant View_Distance 1.0
// screen width divided by numrays
#constant Column_Width 3
// Create our rays //////////////////
type sRay
	x as float
    y as float
    Angle as float
    Dot as integer
endtype

global dim Ray[numRays] as sRay

for t=0 to numRays
      i = CreateSprite ( 0 )
      SetSpriteSize ( i , Column_Width , 2 )
      SetSpritePosition ( i, -100, -100 )
      SetSpriteColor ( i, 0 , 0 , 0 , 255 )
      Ray [t].Dot=i
next t

i = CreateSprite ( IMG_Back )
SetSpritePosition ( i , 5 , 0 )
SetSpriteSize ( i , Column_Width*numRays , 480 )

/////////////////////////////////////////////
// Create our screen columns ////////////////
/////////////////////////////////////////////
type sColumn
	ID as integer
	IMG as integer
    Height as integer
endtype

global dim Columns [numRays] as sColumn

for t=1 to numRays
      if t=1
      i = CreateSprite ( IMG )
      SetSpriteSize ( i , Column_Width , 120 )
      //SetSpriteColor ( i, 255 , 255 , 255 , 255 )
      SetSpriteAnimation ( i, 1, TextureScale, TextureScale )
      else
        i = clonesprite(Columns [1].ID)
        SetSpritePosition ( i, 260+(t*Column_Width), 180 )
      endif
      Columns [t].ID=i
next t

global dim Block [mapWidth*mapHeight]

for t=1 to (mapWidth*mapHeight)
      i = CreateSprite ( 0 )
      SetSpriteSize ( i , miniMapScale , miniMapScale )
      SetSpriteColor ( i, 255 , 255 , 255 , 255 )
      Block[t]=i
next t
/////////////////////////////////////////
// Create our player ////////////////////
////////////////////////////////////////
type sPlayer
	ID as integer
    x as float
    y as float
    dir as integer
    rot as float
    speed as integer
    moveSpeed as float
    rotSpeed as float
endtype

global Player as sPlayer
// current x, y position of the player
Player.x = 16 : Player.y = 10
// the direction that the player is turning, either -1 for left or 1 for right.
Player.dir = 0
// the current angle of rotation
Player.rot = 0
// is the playing moving forward (speed = 1) or backwards (speed = -1).
Player.speed = 0
// how far (in map units) does the player move each step/update( its this number * frame time )
Player.moveSpeed = 2.0
// old ////// ( Number math.PI ) how much does the player rotate each step/update (in radians)
Player.rotSpeed = 120.0

i = CreateSprite ( 0 )
SetSpriteSize ( i , miniMapScale , miniMapScale )
SetSpriteColor ( i, 0 , 0 , 0 , 255 )
SetSpritePosition ( i, Player.x*miniMapScale, Player.y*miniMapScale )
Player.ID = i


Draw_MiniMap ()
global GFT#
do
   GFT# = GetFrameTime()
   Check_keys ()
   Move_Player ()
   Raycast()
   if GetRawKeyPressed( 9 )
     Random_Map ()
     Draw_MiniMap ()
   endif
   if GetRawKeyPressed( 32 ) then inc floor_on
   print("                                "+str( Screenfps() ) )
   Sync()
loop

function Random_Map ()
for x = 0 to mapWidth-1
    for y = 0 to mapHeight-1
    map [ x , y ]=0
    if Random(0,10)=1
        map [ x , y ]=1
        map [ x+1 , y ]=1
    if x-1>0 then map [ x-1 , y ]=1
    if x+2<mapWidth then map [ x+2 , y ]=1
    endif
    if Random(0,10)=1
        if y-1>0 then map [ x , y-1 ]=1
        map [ x , y+1 ]=1
    if y+2<mapHeight then map [ x , y+2 ]=1
    map [ x , y ]=1
    endif
    if x=0 or x=mapWidth-1 then map [ x , y ]=1
    if y=0 or y=mapHeight-1 then map [ x , y ]=1
    next y
next x

endfunction

function Check_keys ()
   Player.speed = 0
   if GetRawKeystate( 38 ) then Player.speed = 1
   if GetRawKeystate( 40 ) then Player.speed = -1
   Player.dir = 0
   if GetRawKeystate( 39 ) then Player.dir = 1
   if GetRawKeystate( 37 ) then Player.dir = -1
endfunction

function Move_Player ()
    // player will move this far along the current direction vector
    moveStep# = player.speed * (player.moveSpeed*GFT#)
    // add rotation if player is rotating (player.dir != 0)
    player.rot = player.rot+(player.dir * (player.rotSpeed*GFT#))
    // calculate new player position with simple trigonometry
    newX# = player.x + (cos(player.rot) * moveStep#)
    newY# = player.y + (Sin(player.rot) * moveStep#)
    // Basic wall collision
    newX=newX#
    newY=newY#
    //if map [newX,newY]>0 then ExitFunction
    // set new position
    player.x = newX#
    player.y = newY#

    SetSpritePosition ( Player.ID, Player.x*miniMapScale, Player.y*miniMapScale )
    setspriteangle (Player.ID,player.rot)
//print("                          "+str(WrapAngle(player.rot)))
endfunction


function Raycast()
  PLx# = player.x*32
  PLy# = player.y*32
  StartAngle#=WrapAngle(player.rot-30)
  rayspd#=0.0

  for i = 1 to numRays
    //setspriteangle (DotRay [i],StartAngle#)
    cosAng#=cos(StartAngle#)
    sinAng#=Sin(StartAngle#)
    move#=0.0

    target=0
    while target=0
       move# = move#+0.025
       newX = player.x + ( cosAng# * move#)
       newY = player.y + ( sinAng# * move#)
       target=1

       select ( map [newX,newY] )
         case 0:
           target = 0
         endcase
       endselect

     endwhile

     // Backtrack to make it smooth
     target=0
     while target=0
        move#=move#-0.01
        newX = player.x + ( cosAng# * move#)
        newY = player.y + ( sinAng# * move#)
        if newX<0 then newX=0
        if newY<0 then newY=0
        select ( map [newX,newY] )
            case 0:
              target=1
              newX# = (player.x + ( cosAng# * move#))
              newY# = (player.y + ( sinAng# * move#))
              Ray[i].x =  newX#*32
              Ray[i].y =  newY#*32
            endcase
         endselect

      endwhile
      // (newx#-y#)+3 to be displayed right on the minimap,screws up raycast

      TextureX#=newX#*TextureScale
      TextureY#=newY#*TextureScale
      TextureX#=TextureX#-(newX*TextureScale)
      TextureY#=TextureY#-(newY*TextureScale)
      // convert it to an integer
      TextureX=TextureX#+(TextureScale/2)
      TextureY=TextureY#+(TextureScale/2)

      //hitting top or bottom
      GetTexture( i , TextureY , TextureX )
      //hitting left or right
      GetTexture( i , TextureX , TextureY )

      Remstart
      64 is the size of the wall blocks.
      277 the viewing plane .
      distance = (( 64 / Actual distance *cos( angle in the fov ))) * 277)
      remend

      Columns [i].Height = ( (64 / ( Distance ( PLx# , PLy# , Ray[i].x , Ray[i].y ) *cos( WrapAngle(30-rayspd#) )))*300 )

      fade=Columns [i].Height/2
      if fade>255 then fade=255
      SetSpriteColor ( Columns [i].ID , fade , fade , fade , 255 )
      SetSpriteFrame(Columns [i].ID , Columns [i].IMG )
      setspritesize(Columns [i].ID ,Column_Width, Columns [i].Height )
      SetSpritePosition ( Columns [i].ID , 2+(i*Column_Width), 240-( Columns [i].Height/2 ) )

      StartAngle#=WrapAngle(StartAngle#+rayspeed)
      rayspd#=rayspd#+rayspeed
   next i

endfunction

// used to get pixel on floor
function getGrid(x,y)
  Tile_size=64
  ``converts it to an grid grid nr
  X1=x/Tile_size
  Y1=y/Tile_size
  ``converts it to an world position
  X2=(X1*Tile_size)-Tile_size
  Y2=(Y1*Tile_size)-Tile_size
  ``here do we get an pixel cord inside that tile
  X3=((x-X2)-Tile_size)//+1
  Y3=((y-Y2)-Tile_size)//+1
result=X3+(Y3*Tile_size)
ENDFUNCTION result

function GetTexture( Column , Source , Target )
    select ( Source )

      case 0:
         Columns [Column].IMG = Target
      endcase

      case 1:
         Columns [Column].IMG = Target
      endcase

      case 127:
         Columns [Column].IMG = Target
      endcase

      case TextureScale:
         Columns [Column].IMG = Target
      endcase

    endselect
endfunction

function Distance (x#,y#,x2#,y2#)
    distX# = x# - x2#
    distY# = y# - y2#
    dist# = sqrt ( ( distX# * distX# ) + ( distY# * distY# ) )
endfunction dist#

function WrapAngle(ang#)
    setspriteangle(AngDummy,ang#)
    result#=getspriteangle(AngDummy)
endfunction result#

/////////////////////////////////////////////////////////////////////
function Draw_MiniMap ()
   rect=1
   for y = 0 to mapHeight-1
      for x = 0 to mapWidth-1
         if map [ x , y ] = 1
            SetSpriteColor ( Block[rect], 155 , 155 , 155 , 255 )
            SetSpritePosition ( Block[rect], x*miniMapScale, y*miniMapScale )
            inc rect
         else
            SetSpriteColor ( Block[rect], 255 , 255 , 255 , 255 )
            SetSpritePosition ( Block[rect], x*miniMapScale, y*miniMapScale )
            inc rect
         endif
      next x
   next y
endfunction