Posted: 28th Jun 2007 19:11
I am working on a small 2D-sidescrolling-jump-and-run-game and wanted to include portals, because I am so fascinated of the videos of portal 2.

So I tried to program a small, simple 2D-Portal-Algorithm, so that in my game characters or objects can fall into a portal and out of the other one, with their correct rotation, speed etc.
It works well so far, but doesn't look very good... just come circles and lines in my test-program.

First an image of the examplecode:



And here the code itself:

+ Code Snippet
set display mode 800,600,32
sync on : sync rate 30
set window off
randomize timer()

rem Setup

global Gravity as float : Gravity = 0.5

global PortalCount as integer : PortalCount = 0
dim Portal(0) as Portaltp
type Portaltp
   X as integer
   Y as integer
   Angle as integer
endtype
SetupPortals()

global ObjectCount as integer : ObjectCount = 0
dim Object(0) as Objecttp
type Objecttp
   X as float
   Y as float
   Xmove as float
   Ymove as float
   LastPortal as dword `Timer value of portal-time
endtype
global LastObject as integer
global ObjectDelay as integer : ObjectDelay = 1000
global Object_PortalDelay as integer : Object_PortalDelay = 300
global Object_MoveX


do
   cls rgb(100,100,255)
   print "FPS: ", screen fps()
   print "Objects: ", ObjectCount
   print "Key: ", scancode()
   print "Object-Move-X: ", Object_MoveX
   print
   print "Press 1 or 2 to move portals, rightclick to rotate."
   print "Leftclick to create objects"
   print "Change Object-Move-X with right/leftkey"
   print "Press P to create new Portal"

   CreatePortals()
   ManagePortals()
   DrawPortals()

   CreateObjects()
   ManageObjects()
   DrawObjects()

   rem Object-Move-x
   rl = rightkey()-leftkey()
   if rl <> 0
      inc Object_MoveX, rl
      wait 200
   endif

   sync
loop


function SetupPortals()
   for p = 1 to 2
      inc PortalCount
      array insert at bottom Portal(0), p
      Portal(p).X = rnd(800)
      Portal(p).Y = rnd(600)
      Portal(p).Angle = rnd(360)
   next p
endfunction

function CreatePortals()
   i$ = inkey$()
   if i$ = "p"
      inc PortalCount
      array insert at bottom Portal(0), PortalCount
      Portal(PortalCount).X = rnd(800)
      Portal(PortalCount).Y = rnd(600)
      Portal(PortalCount).Angle = 180
   endif
endfunction

function ManagePortals()
   s = scancode()-1
   if s => 1  and s <= PortalCount
      Portal(s).X = mousex()
      Portal(s).Y = mousey()
      if mouseclick()=2 then Portal(s).Angle = wrapvalue(Portal(s).Angle+mousemovex())
   endif
endfunction

function DrawPortals()
   ink rgb(255,128,64),0
   for p = 1 to PortalCount
      circle Portal(p).X, Portal(p).Y, 50
      line Portal(p).X, Portal(p).Y, Portal(p).X+50*sin(Portal(p).Angle), Portal(p).Y+50*cos(Portal(p).Angle)
      line Portal(p).X-50*sin(Portal(p).Angle+90), Portal(p).Y-50*cos(Portal(p).Angle+90), Portal(p).X+50*sin(Portal(p).Angle+90), Portal(p).Y+50*cos(Portal(p).Angle+90)
   next p
endfunction

function CreateObjects()
   if mouseclick()=1
      t = timer()
      if t-LastObject > ObjectDelay
         LastObject = t
         inc ObjectCount
         array insert at bottom Object(0), ObjectCount
         Object(ObjectCount).X = mousex()
         Object(ObjectCount).Y = mousey()
         Object(ObjectCount).Xmove = Object_MoveX
         Object(ObjectCount).Ymove = 2 - rnd(40)/10.0
      endif
   endif
endfunction

function ManageObjects()
   time = timer()
   for o = 1 to ObjectCount
      rem Position-Update
      inc Object(o).Ymove, Gravity
      inc Object(o).Y, Object(o).Ymove
      inc Object(o).X, Object(o).Xmove
      rem Delete if outside screen
      if Object(o).Y > 700
         dec ObjectCount
         array delete element Object(0), o
         exit
      endif
      rem Portal-Collision
      if time-Object(o).LastPortal > Object_PortalDelay
         for p = 1 to PortalCount
            rem Check distance... you should change this algorithm
            XDis = Object(o).X-Portal(p).X
            YDis = Object(o).Y-Portal(p).Y
            Dis = XDis^2+YDis^2
            rem Object in Portal
            if Dis < 6400 `80^2
               p2 = TargetPortal(p)
               Object(o).X = Portal(p2).x
               Object(o).Y = Portal(p2).y
               Portal_Angle = Portal(p2).Angle - Portal(p).Angle
               Res_AngleAdd = Portal_Angle-180
               ActAngle# = atanfull(Object(o).Xmove, Object(o).Ymove)
               ResAngle# = ActAngle# + Res_AngleAdd
               Speed# = sqrt(Object(o).Xmove^2+Object(o).Ymove^2)
               Object(o).Xmove = Speed#*sin(ResAngle#)
               Object(o).Ymove = Speed#*cos(ResAngle#)
               Object(o).LastPortal = timer()
               exit
            endif
         next p
      endif
   next o
endfunction

function DrawObjects()
   ink 0,0
   for o = 1 to ObjectCount
      circle Object(o).X, Object(o).Y, 30
   next o
endfunction

function TargetPortal(p)
   if PortalCount = 1
      r = 1
   else
      repeat
         r = 1 + rnd(PortalCount-1)
      until p <> r
   endif
endfunction r


At first there are just two portals, you can position them by pressing the number key (1 or 2 in this case), and rotate them by also pressing the right mouse button and move the mouse.
Objects can be created with leftclicks, the "Object-X-Move"-Variable defines their start-direction (X-Speed).
You can create new portals by pressing 'p' and edit them with the key, whichs ascii-number is 1 higher then the portal-number (so first 10 portals on key 0-9 at the top).

Maybe it helps someone..
Looking forward to any comments, ideas etc..
Posted: 28th Jun 2007 21:40
Where did this "Portal 2" come from because theres no such thing. All there is is Halflife 2's Portal or Valve's Portal theres no sequel. Anyway, what a great idea, 2d portals would be so much easier than 3d. Can't think of any idea's now but i'll keep track of this. Keep up the good work
Posted: 28th Jun 2007 22:16
Yes, right, my friend also informed me that it's just "Portal" and not "Portal 2". However, seems like you knew what I mean.
I'll try to get an animated sprite for the portals, and then try to include the whole system into my game.. should be funny.