movement with CatmullRom spline on a Map

Share your advanced PureBasic knowledge/code with the community.
User avatar
thyphoon
Enthusiast
Enthusiast
Posts: 355
Joined: Sat Dec 25, 2004 2:37 pm

movement with CatmullRom spline on a Map

Post by thyphoon »

Hello,

excuse me for my bad english. I would like to share with you my code to move on map with Catmullrom spline
I hope you will like this code
regards

Code: Select all

Procedure CatmullRomSpline(t.f,*result.POINT,*p0.Point,*p1.Point,*p2.point,*p3.point)
  t2.f = t * t
  t3.f = t2 * t
  *result\x= 0.5 * ( ( 2.0 * *p1\x ) + ( -*p0\x + *p2\x ) * t + ( 2.0 * *p0\x - 5.0 * *p1\x + 4 * *p2\x - *p3\x ) * t2 + ( -*p0\x + 3.0 * *p1\x - 3.0 * *p2\x + *p3\x ) * t3 )
  *result\y= 0.5 * ( ( 2.0 * *p1\y ) + ( -*p0\y + *p2\y ) * t + ( 2.0 * *p0\y - 5.0 * *p1\y + 4 * *p2\y - *p3\y ) * t2 + ( -*p0\y + 3.0 * *p1\y - 3.0 * *p2\y + *p3\y ) * t3 )
EndProcedure

#tileWidth=48
;-Characters
Structure chara
  ;reel chara coord
  worldPixelX.l
  worldPixelY.l
  ;the target where you want to go
  ToWorldPixelX.l
  ToWorldPixelY.l
 
  pathSize.l;tile number in path
  num.l ; pointer on path
  startTime.l ; time to move
  startWorldPixelX.l; to save the start coord
  startWorldPixelY.l
EndStructure

chara.chara
;init characters position
chara\worldPixelX=10
chara\worldPixelY=10

;je fais comme si on voulait aller a un autre endroit
;c'est pas tres loin du point de depart, mais le faux pathfinding
;un peu plus loin fera un detour
chara\ToWorldPixelX=10
chara\ToWorldPixelY=42

;-Le path
Structure path
  x.l
  y.l
EndStructure

NewList path.path()


If InitSprite() = 0
  MessageRequester("Error", "Can't open screen & sprite enviroment!", 0)
  End
EndIf

If OpenWindow(0, 0, 0, 800, 600, "A screen in a window...", #PB_Window_SystemMenu |  #PB_Window_ScreenCentered)
  CreateStatusBar(0, WindowID(0))
  AddStatusBarField(320)
 
  If OpenWindowedScreen(WindowID(0), 0, 0, 800, 600, 1, 0, 20)
   
   
   
    Repeat
      ; It's very important to process all the events remaining in the queue at each frame
      ;
      Repeat
        Event = WaitWindowEvent(10)
       
        If Event = #PB_Event_CloseWindow
          End
        EndIf
      Until Event = 0
      ;-Deplacement
      ;if current coord <> targ pos you must found a path
      If (chara\ToWorldPixelX<>chara\worldPixelX Or chara\ToWorldPixelY<>chara\worldPixelY) And chara\pathSize=0
        ;ici on utilise un pathfinding normalement
       
        tileX=Int(chara\worldPixelX/#tileWidth)
        tileY=Int(chara\worldPixelY/#tileWidth)
        toTileX=Int(chara\ToWorldPixelX/#tileWidth)
        toTileY=Int(chara\ToWorldPixelY/#tileWidth)
        ;pathfinding simulation
        AddElement(path()):path()\x=1:path()\y=0
        AddElement(path()):path()\x=1:path()\y=1
        AddElement(path()):path()\x=2:path()\y=1
        AddElement(path()):path()\x=3:path()\y=1
        AddElement(path()):path()\x=4:path()\y=1
        AddElement(path()):path()\x=5:path()\y=2
        AddElement(path()):path()\x=6:path()\y=3
        AddElement(path()):path()\x=6:path()\y=4
        AddElement(path()):path()\x=6:path()\y=5
        AddElement(path()):path()\x=6:path()\y=6
        AddElement(path()):path()\x=7:path()\y=6
        AddElement(path()):path()\x=8:path()\y=6
        AddElement(path()):path()\x=9:path()\y=7
        AddElement(path()):path()\x=9:path()\y=8
        AddElement(path()):path()\x=8:path()\y=9
        AddElement(path()):path()\x=7:path()\y=10
        AddElement(path()):path()\x=6:path()\y=10
        AddElement(path()):path()\x=5:path()\y=10
        AddElement(path()):path()\x=5:path()\y=9
        AddElement(path()):path()\x=4:path()\y=8
        AddElement(path()):path()\x=3:path()\y=7
        AddElement(path()):path()\x=3:path()\y=6
        AddElement(path()):path()\x=3:path()\y=5
        AddElement(path()):path()\x=3:path()\y=4
        AddElement(path()):path()\x=3:path()\y=3
        AddElement(path()):path()\x=2:path()\y=2
        AddElement(path()):path()\x=1:path()\y=1
        AddElement(path()):path()\x=0:path()\y=1
        chara\pathSize=ListSize(path()) ;tile number in the path
        chara\startTime=ElapsedMilliseconds() ;time to move
        chara\num=-1 ;    init my path pointer
        chara\startWorldPixelX=chara\worldPixelX ; save the start coord
        chara\startWorldPixelY=chara\worldPixelY ;
        ;End
      EndIf   
     
     
      ;si on a un path alors hop on avance
      If chara\pathSize>0
       
        t.f=(ElapsedMilliseconds()-chara\startTime)/1000 ;t= 0 last tile => 1  next tile
       
        move=1 ;we move
        ;if next tile
        If t>=1
          t=1
         
          If chara\num>chara\pathSize-2 ;the end
            Debug "end";
            ;clear the path
            ClearList(path())
            move=0 ;no move
            chara\pathSize=0
            chara\num=0
            chara\worldPixelX=chara\ToWorldPixelX ;on est bien arrivé au point qu'on voulait
            chara\worldPixelY=chara\ToWorldPixelY
          EndIf
          chara\startTime=ElapsedMilliseconds(): ;je memorise le temps
        EndIf
      EndIf
     
      If move=1  ; if we must move
        Dim p.point(3) ;to know position on a catmull rom, i must know 4 points
        For z=0 To 3
          num=chara\num+z-1
          If num<0:
            num=-1
          EndIf
          If num>chara\pathSize-1
            num=chara\pathSize-1
          EndIf
          Select num
            Case -1
              p(z)\x=chara\startWorldPixelX
              p(z)\y=chara\startWorldPixelY
            Case chara\pathSize-1
              p(z)\x= chara\ToWorldPixelX
              p(z)\y= chara\ToWorldPixelY
            Default
              SelectElement(path(),num)
              p(z)\x=path()\x*#tileWidth+#tileWidth/2
              p(z)\y=path()\y*#tileWidth+#tileWidth/2
          EndSelect
        Next
        result.point
       
        CatmullRomSpline(t,result,p(0),p(1),p(2),p(3))
       
        If t>=1 ;if next tile
          chara\num+1:;next path tile
        EndIf

        ;new coord to to caracters
        chara\worldPixelX=result\x
        chara\worldPixelY=result\y
       
       
      EndIf
     
      FlipBuffers()
      ClearScreen(0) ; A blue background
      StartDrawing(ScreenOutput())
      For x=1 To 20
        LineXY(x*#tileWidth,0,x*#tileWidth,600,#White)
      Next
      For y=0 To 20
        LineXY(0,y*#tileWidth,800,y*#tileWidth,#White)
      Next
      ForEach path()
        Box(path()\x*#tileWidth,path()\y*#tileWidth,#tileWidth,#tileWidth,RGB(50,50,50))
      Next
       
      Circle(chara\worldPixelX,chara\worldPixelY,5,#Red)
      StopDrawing()
    ForEver
   
  Else
    MessageRequester("Error", "Can't open windowed screen!", 0)
  EndIf
EndIf
IdeasVacuum
Always Here
Always Here
Posts: 6426
Joined: Fri Oct 23, 2009 2:33 am
Location: Wales, UK
Contact:

Re: movement with CatmullRom spline on a Map

Post by IdeasVacuum »

Completely different genre of programming to mine but that looks very clever indeed!

Nice work and thank you for sharing 8)
IdeasVacuum
If it sounds simple, you have not grasped the complexity.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: movement with CatmullRom spline on a Map

Post by rsts »

Very nice.

Not to worry about your English. The code speaks for itself :)

Thanks for sharing.

cheers
Post Reply