Import mojo Extern Function realTime()="(new Date()).getTime" Public Function DrawArrow(x1#,y1#,x2#,y2#,l#=5) Local an#=ATan2(y2-y1,x2-x1) DrawLine x1,y1,x2,y2 Local mx#=(x1+x2)/2, my#=(y1+y2)/2 DrawLine mx,my,mx+Cos(an+150)*l,my+Sin(an+150)*l DrawLine mx,my,mx+Cos(an-150)*l,my+Sin(an-150)*l End 'returns True if p1 and p2 are on the same side of the line a->b Function sameside:Bool(p1x#,p1y#,p2x#,p2y#,ax#,ay#,bx#,by#) Return ((bx-ax)*(p1y-ay)-(p1x-ax)*(by-ay))*((bx-ax)*(p2y-ay)-(p2x-ax)*(by-ay)) >= 0 End Function Class World Field width#,height# Field flipTop:Bool=True, flipSide:Bool=True Field things:List Method New(_width#,_height#) width=_width height=_height things = New List End Method Update() Local t:Thing For t=Eachin things t.Update Next For t=Eachin things While t.x<-width/2 t.x+=width If flipSide t.y=-t.y t.vy=-t.vy t.an=-t.an t.van=-t.van t.flip=-t.flip Endif Wend While t.x>width/2 t.x-=width If flipSide t.y=-t.y t.vy=-t.vy t.an=-t.an t.van=-t.van t.flip=-t.flip Endif Wend While t.y<-height/2 t.y+=height If flipTop t.x=-t.x t.vx=-t.vx t.an=180-t.an t.van=-t.van t.flip=-t.flip Endif Wend While t.y>height/2 t.y-=height If flipTop t.x=-t.x t.vx=-t.vx t.an=180-t.an t.van=-t.van t.flip=-t.flip Endif Wend Next End Method geodesic#[](t1:Thing,t2:Thing) Return geodesic(t1.x,t1.y,t2.x,t2.y) End Method geodesic#[](x1#,y1#,x2#,y2#) Local x3#,y3#,x4#,y4# Local mx#,my#,mdx#,mdy# 'top or bottom If flipTop Then x3 = -x2 Else x3=x2 y3 = y2-Sgn(y2)*height 'left or right x4 = x2-Sgn(x2)*width If flipSide Then y4 = -y2 Else y4=y2 mx=(x3+x2)/2 my=(y3+y2)/2 mdx=Sgn(y2) mdy=-Sgn(y2)*(x3-x2)/(y3-y2) 'decide between real and top/bottom If sameside(x1,y1,x2,y2,mx,my,mx+mdx,my+mdy) 'real point 'so decide between real and left/right mx=(x4+x2)/2 my=(y4+y2)/2 mdx = -Sgn(x2)*(y4-y2)/(x4-x2) mdy = Sgn(x2) If sameside(x1,y1,x2,y2,mx,my,mx+mdx,my+mdy) 'real point Return [x2-x1,y2-y1] Else 'left/right point Return [x4-x1,y4-y1] Endif Else 'top/bottom point 'so decide between top/bottom and left/right mx = (x4+x3)/2 my = (y4+y3)/2 mdx = -(y4-y3)/(x4-x3) mdy = 1 If sameside(x1,y1,x3,y3,mx,my,mx+mdx,my+mdy) 'top/bottom point Return [x3-x1,y3-y1] Else 'left/right point Return [x4-x1,y4-y1] Endif Endif End Method Draw() Local fx,fy If flipTop fx=-1 Else fx=1 If flipSide fy=-1 Else fy=1 'normal view in centre PushMatrix DrawAll PopMatrix 'flipped vertically on sides PushMatrix Scale 1,fy Translate -width,0 DrawAll Translate 2*width,0 DrawAll PopMatrix 'flipped horizontally on top and bottom PushMatrix Scale fx,1 Translate 0,-height DrawAll Translate 0,2*height DrawAll PopMatrix 'flipped both ways on corners PushMatrix Scale fx,fy Translate width,height DrawAll Translate -2*width,0 DrawAll Translate 0,-2*height DrawAll Translate 2*width,0 DrawAll PopMatrix End Method DrawAll() SetColor 100,100,100 If flipTop DrawArrow width/2,-height/2,-width/2,-height/2,15 Else DrawArrow -width/2,-height/2,width/2,-height/2,15 Endif If flipSide DrawArrow -width/2,height/2,-width/2,-height/2,15 Else DrawArrow -width/2,-height/2,-width/2,height/2,15 Endif DrawArrow width/2,-height/2,width/2,height/2,15 DrawArrow -width/2,height/2,width/2,height/2,15 For Local t:=Eachin things PushMatrix Translate t.x,t.y Rotate -t.an Scale 1,t.flip t.Draw PopMatrix Next End End Class Thing Field world:World Field an#,van# Field vx#,vy# Field x#,y# Field flip=1 Method New(_world:World) world=_world world.things.AddLast Self End Method Update() End Method Draw() Abstract End Class Target Extends Thing Method New(_world:World) Super.New(_world) End Method Draw() SetColor 255,0,0 DrawLine -3,-3,3,3 DrawLine 3,-3,-3,3 End End Class Ship Extends Thing Field target:Thing Method New(_world:World) Super.New(_world) End Method Update() x+=vx y+=vy vx*=.99 vy*=.99 Local diff#[] = world.geodesic(Self,target) Local dx#,dy#,d# dx=diff[0] dy=diff[1] d=Sqrt(dx*dx+dy*dy) Local wan# = (ATan2(dy,dx)-an) Mod 360 If wan<-180 wan+=360 If wan>180 wan-=360 If Abs(wan)>3 wan=3*Sgn(wan) Endif 'If TouchDown(0) an+=wan vx += Cos(an)*.1 vy += Sin(an)*.1 'Endif End Method Draw() SetColor 255,255,255 SetAlpha .1 DrawCircle 0,0,20 SetAlpha 1 DrawPoly([6.0,0.0,-3.0,3.0,0.0,0.0,-3.0,-3.0]) End End Class Asteroid Extends Thing Field poly#[] Method New(_world:World) Super.New(_world) x=Rnd(-.5,.5)*world.width y=Rnd(-.5,.5)*world.height vx=Rnd(-1,1) vy=Rnd(-1,1) van=Rnd(-3,3) Local n=Rnd(6,10) Local r#[n] For Local i=0 To n-1 r[i]=Rnd(10,20) Next poly=New Float[n*2] For Local i=0 To n-1 poly[i*2]=Cos(i*360/n)*r[i] poly[i*2+1]=Sin(i*360/n)*r[i] Next End Method Method Update() x+=vx y+=vy an=(an+van) Mod 360 End Method Draw() SetColor 255,0,0 DrawPoly poly SetColor 0,0,0 Scale .95,.95 DrawPoly poly End End Class AsteroidApp Extends App Field screenMatrix#[] Field mx#,my# Field world:World Field dude:Ship,target:Target Field scale#=.9 Field x1#,y1# Method OnCreate() Seed = realTime() SetUpdateRate 60 world = New World(DeviceWidth,DeviceHeight) target=New Target(world) dude = New Ship(world) dude.target = target End Method OnUpdate() PushMatrix Translate DeviceWidth/2,DeviceHeight/2 Local s# If DeviceWidth/world.width>DeviceHeight/world.height s=scale*DeviceHeight/world.height Else s=scale*DeviceWidth/world.width Endif Scale s,s screenMatrix = GetMatrix() Local mouse#[]=InvTransform([MouseX(),MouseY()]) mx=mouse[0] my=mouse[1] PopMatrix target.x=mx target.y=my scale += (KeyDown(KEY_UP)-KeyDown(KEY_DOWN))*.05 If KeyHit(KEY_T) world.flipTop = Not world.flipTop Endif If KeyHit(KEY_L) world.flipSide = Not world.flipSide Endif If TouchHit(0) New Asteroid(world) Endif world.Update End Method OnRender() Cls SetColor 255,255,255 PushMatrix SetMatrix screenMatrix world.Draw PopMatrix DrawText MouseX(),0,60 DrawText MouseY(),0,75 SetColor 255,255,255 DrawText "Press T to change top/bottom flip.",0,0 DrawText "Press L to change left/right side flip",0,15 DrawText "Press up or down to zoom",0,30 End End Function Main() New AsteroidApp End