Archiv der Kategorie: 2D Game SDK / Framework

Monkey-X: Game Template

Import mojo
Function Main()
	New Game
End

Class Game Extends App

	'summary:The OnCreate Method is called when mojo has been initialized and the application has been successfully created.
	Method OnCreate()
	
		'Set how many times per second the game should update and render itself
		SetUpdateRate(60)
	
	End
	
	'summary: This method is automatically called when the application's update timer ticks. 
	Method OnUpdate()
		
	End
	
	'summary: This method is automatically called when the application should render itself, such as when the application first starts, or following an OnUpdate call. 
	Method OnRender()
		
	End

	'summary: This method is called instead of OnRender when the application should render itself, but there are still resources such as images or sounds in the process of being loaded. 
	Method OnLoading()
		
	End
	
	'summary: This method is called when the application's device window size changes. 
	Method OnResize()
		
	End
	
	'#REGION Code to handle susped status of the game goes here
	
	'summary: OnSuspend is called when your application is about to be suspended. 
	Method OnSuspend()
	
	End
	
	'summary: OnResume is called when your application is made active again after having been in a suspended state. 
	Method OnResume()
		
	End	
	'#END REGION
	
	'#REGION Code to handle game closing goes here:
	
	'summary: This method is called when the application's 'close' button is pressed. 
	Method OnClose()
		Super.OnClose()
	End

	'summary:This method is called when the application's 'back' button is pressed. 
	Method OnBack()
		Super.OnBack()
	End
	
	'#END REGION

End

Quelle: Template

Monkey-X: Template Command line tool

Import commandlineapp

'summary: This is the command line tool starting point:
Function Main()	
	Local tool:= New CommandLineTool()
End

'summary: This class handles the launching and parameters of the command line tool
Class CommandLineTool Extends CommandLineApp

	'summary: This is called when the command line tool launches.
	Method New()
	
		#REM
		Notice there are several field defined in this class, such as assemblyLocation, assemblyName and  parameters.
			- Self.assemblyName contains the name of the tool executable file (IE. the EXE file in windows os)
			- Self.assemblyLocation contains the path in the filesystem where the tool is located.
			- Self.paramters is a string array with any parameter passed to the tool. If no parameter is present, this array is of length zero.
		#END
		
		'Place the command line tool code here:
		
	End

End
Import brl.filepath
Import os

'summary: This class handles the launching and parameters of the command line tool
Class CommandLineApp Abstract

	'summary: This field contains the name of this tool assembly. That is, in windows, the EXE file of this tool.
	Field assemblyName:String

	'summary: This field contains the location in the file system where this tool is stored.
	Field assemblyLocation:String

	'summary: This array of strings contains all the paramters passed to this command line tool from the terminal or console.<br>If none is passed, this array will be of length zero.
	Field parameters:String[]

	Method New()
	
		'this is the tool executable name (on windows, the EXE file name):
		assemblyName = filepath.StripDir(os.AppArgs[0])
	
		'This is the tool executable path, the folder where the assembly is located:
		assemblyLocation = filepath.ExtractDir(os.AppArgs[0])
		
		'We get the list of parameters
		parameters = os.AppArgs[1 ..]
	
	End

	'summary: Use this method to abruptly end current application.<br>The "success" parameter may be set to true or false depending of the cause of the tool being ended.
	Method EndApplication(success:Bool)
		If success Then os.ExitApp(0) Else os.ExitApp(-1)
	End
	
End

 

Quelle: Templates

Monkey-X: Monkey einmal ganz anders

Eigentlich wollte ich ein weiteres Gamereview über Monkey-X Entwicklungen schreiben, und nun kommt es komplett anders ;-)

Im Monkey-X Forum bin ich über folgenden Beitrag gestolpert in dem über eine App berichtet wird die Monkey nicht nutzt um ein Spiel zu programmieren. bodewo7 ist eine Präsentations-App für einen Bodenbelaghersteller die eindrucksvoll beweist wie man Monkey-X auch anders nutzen kann. Sehr gut umgesetzt mit Mojo und einer erweiterten Version des fantomEngine 2d Game Frameworks.

[slideshow_deploy id=’1493′]

Monkey-X: AdMob für iOS und Android Apps

Monkey X DokumentationNach längerer Zeit wollte ich meine in Monkey X entwickelte App BuChao mit dem neuen iOS 7 SDK auf den aktuellen Stand bringen. Damals musste ich AdMob noch von Hand in das Xcode Projekt integrieren.

Natürlich sollte auch eine aktualisierte AdMob Version Verwendung finden. Die aktuelle Version war schon runter geladen und ich war mitten drin dieses wieder manuell einzubinden.

Doch irgendwo im Hinterstübchen konnte ich mich daran erinnern dass in Monkey X AdMob integriert wurde. Also ab ins Forum und die Suche bemüht und nichts gefunden? Auch Google lieferte irgendwie kein befriedigendes Ergebnis ;-( Unter „Monkey X AdMob Tutorial“, weder unter „Monkey X AdMob Example“ war irgend etwas zu finden…?

In solchen Fällen ist man immer am Zweifeln, ob man selbst zu blöd ist etwas zu finden oder ob andere so schlau sind dass keine Fragen aufkommen und deswegen nirgends etwas zu finden ist.

Die Lösung war aber so einfach und trivial das man sich auf die Stirn klatschen könnte. Der gute alte Ted (der Editor von Monkey) bietet eine Suchfunktion in der Monkey X Dokumentation und in Sekundenschnelle war die Doku samt Beispiel gefunden.

So, und jetzt habe ich extra einen Blogpost samt Sourcecode geschrieben damit Google auch was zum indizieren findet, damit der nächste Monkey X Entwickler schneller fündig wird als ich ;-)

#If TARGET<>"android" And TARGET<>"ios"
#Error "Admob is only supported on Android and iOS targets"
#End

#ADMOB_PUBLISHER_ID="abcdabcdabcdabc"                           'from your admob account
#ADMOB_ANDROID_TEST_DEVICE1="TEST_EMULATOR"
#ADMOB_ANDROID_TEST_DEVICE2="ABCDABCDABCDABCDABCDABCDABCDABCD"  'your device's admob ID for test mode

Import mojo
Import brl.admob

Class MyApp Extends App

    Field admob:Admob
    Field layout:=1
    Field enabled:=True

    Method OnCreate()
        admob=Admob.GetAdmob()
        admob.ShowAdView 1,layout
        SetUpdateRate 60
    End

    Method OnUpdate()
        If MouseHit( 0 )
            If enabled
                admob.HideAdView
                enabled=False
            Else
                layout+=1
                If layout=7 layout=1
                admob.ShowAdView 1,layout
                enabled=True
            Endif
        End
    End

    Method OnRender()
        Cls
        DrawText "Click to toggle ads!",DeviceWidth/2,DeviceHeight/2,.5,.5
    End

End

Function Main()
    New MyApp
End

 

Monkey: Debugging im GLFW Target mit Monkey

Monkey ist eine geniale Programmiersprache. Doch vor einiger Zeit bei meinem zweiten Monkey Projekt, in dem ich an irgendeiner Stelle eine nicht auffindbare Endlosschleife eingebaut habe, ist mir der Spaß ein wenig vergangen und ich habe Monkey bei Seite gelegt.

Und die Lösung war so nah, aber ich habe diese nicht erkannt obwohl diese vor meiner Nase lag. Letzthin als ich diesem Fehler wieder auf den Grund gehen wollte fiel es mir wie Schuppen von den Augen ;-)

monkey-glfw-debugging

Im GLFW und C++ Target kann nämlich der Debugger genutzt werden! Da ich aber immer im HTML5 Target getestet habe ist mir das nie richtig aufgefallen. Vor dem kompilieren im Editor muß der Modus von Release auf Debug umgestellt werden. Der Debugger selbst wird durch den Befehl „DebugStop“ im Quellcode aktiviert. Dabei wird die Ausführung des Programmes gestoppt. Im Anschluss können im Ted Debug Fenster alle Objekte und Variablenwerte inspiziert werden.

Damit werde ich hoffentlich bald dem Fehler auf die Schliche kommen und mein Projekt weiter voran treiben…

Monkey: Target Android

Monkey ist einfach genial. Nach erfolgreichen probieren der HTML5 und iOS Targets wollte ich mal etwas über den Tellerrand zu Android schauen.

Ein Android Target mit Monkey zu erzeugen ist ja kein Problem. Aber was wird alles benötigt um für Android zu entwickeln? Zu aller erst organisiert man sich das Android SDK für die entsprechende Plattform. In meinem Fall war es für Mac OS X (intel).

So weit so gut, was kommt als nächstes. Unter OS X muss in dem Android SDK Ordner „tools“ das Kommandozeilenprogramm „android“ gestartet werden. Es erscheint dann der „Android SDK and AVD Manager“. Nun lädtman sich im nächsten Schritt die gewünschte Android SDK Platform.

Ist das erledigt ist es ratsam unter „Virtual devices“ ein AVD anzulegen. Dieses stellt dann einen Android Simulator zur Verfügung. Die ersten Weichen sind gestellt.

Monkey & Netbeans

Das SDK ist eingerichtet, Monkey hat ein Android Target Projekt erzeugt, aber was nun? Nach ein wenig suche, wenn man die bekannten Java IDE’s abklappert, wird man bei Netbeans fündig (wenn ich ehrlich bin habe ich nur nach Netbeans gesucht).

Für die Netbeans IDE gibt es das „nbandroid“ Plugin. Dieses steht nicht selbst über das Netbeans Repository zur Verfügung. Um dieses zu installieren muss im „Plugins Fenster“ unter „Settings“ eine weitere Update Center Quelle angelegt werden. Dies wird hier sehr gut beschrieben.

Nach erfolgreicher installation kann man direkt aus Netbeans heraus Android Projekte erzeugen/starten, compilieren, usw.

Monkey hat dies aber schon erledigt und Netbeans muss nicht mehr dazu bemüht werden. Netbeans wird jetzt dazu gebraucht das Android Target zu kompilieren und entweder auf ein echtes oder auf ein simuliertes Device zu kopieren.

Und schon steckt man ganz tief in der Welt von Android und Java ;o) Bei meinen ersten Versuchen war ich bis jetzt noch nicht erfolgreich mein Monkey Projekt unter Android zum laufen zu bewegen, snif.

Monkey: Target iOS

Exportiert man auf die iOS Plattform wird über ein Template ein Xcode 3 Projekt erzeugt. Dieses kann auch ohne weiteres mit Xcode 4 geöffnet werden.

Im Moment wird das Projekt mit dem Namen „MonkeyGame“ erzeugt. Dieser kann angeblich über eine Config Datei eingestellt werden. Da alles aber über Xcode selbst eingestellt werden kann habe ich mich auch noch nicht richtig auf die Suche gemacht ;o)

In Xcode müssen/können noch kleine Änderungen wie Default Screen, zu verwendende Icons sowie die Device Orientation eingestellt werden. Auch ob die Titlebar angezeigt werden soll oder nicht kann nachtröglich noch geöndert werden.

Tiefergreifende Änderungen können natürlich noch in Xcode vorgenommen werden. Der bessere Weg wäre natürlich weitere iOS Funktionen als Modul Monkey zur Verfügung zu stellen.

Monkey: Target HTML5

In der Monkey Demoversion ist HTML5 die einzige Zielplattform die ausgewählt werden kann. Erst in der Vollversion stehen alle andere Plattformen zur Verfügung.

HTML5 ist unter Monkey die schnellste Zielplattform auf der man seine Apps ausprobieren kann. Diese braucht keinen Simulator und muss auch nicht kompiliert werden. Schlichtweg ein möglichst modernen Browser mit guter HTML5 Unterstützung reicht hier aus.

Google Chrome liegt sehr hoch in der Gunst der Monkey Entwickler. Safari und Firefox stehen aber Chrome sicher in nichts nach.

Monk startet komischerweise einen eigenen lokalen Webserver um die HTML5 App zu starten. Erfahrungsgemäß läuft dieser aber, zumindest bei mir, nicht sehr stabil und stürzt gerne hin und wieder ab.

Dieser ist nicht unbedingt notwendig. Die erzeugte HTML Datei kann logischerweise auch direkt mit dem Browser geöffnet werden.

Update: Ein direktes öffnen ist mittlerweile nicht mehr möglich. Das HTML5 Target benötigt den lokalen Webserver.

Mehr gibt es eigentlich hier nicht zu berichten. Die erzeugten Dateien können so wie diese sind auf eine bestehende Homepage übernommen werden.

TYPO3: Extension t3monkey

Irgendwie wollte ich meine Begeisterung von Monkey und TYPO3 [die für T3 ist mittlerweile am abklingen ;-)] zusammen bringen und habe eine kleine Extension für TYPO3 entwickelt, mit der man das HTML5 Target von Monkey über ein Plugin in die TYPO3 Seite integrieren kann.

t3monkey-demo-config

Einfach den Build Ordner von Monkey in den fileadmin hoch laden, das Plugin auf einer beliebigen Seite einfügen und dann in der Plugin Flexform auf diesen Ordner verweisen => fertig!

t3monkey-demo

Nur leider musste ich feststellen das meine Extension einer Aufräumaktion zum Opfer gefallen war und diese nun nicht mehr im TYPO3 Repository zu finden ist. Warum auch immer? Einfach so ohne Kommentar, das hat mich ein bisschen geärgert! Und deswegen werde ich mir auch nicht mehr die Mühe machen diese ins TER hoch zu laden.

Trotzdem will ich aber den letzten Stand auf meiner Seite zur Verfügung stellen! Diese liegt nun „nur“ als zip-Datei vor, da das neue TYPO3 6 aus dem Extensionmanager „nur“ noch zip-Files und keine t3x-Files mehr exportiert..?

[wpdm_file id=13]

Monkey: asteroids game example

Strict

Import mojo

Global game:MyGame

Function Main:Int()
    game = New MyGame
    Return 0
End Function

Const PDM_smlparticle%=0
Const PDM_medparticle%=1
Const PDM_bigparticle%=2
Const PDM_spark%=3

Global ASTEROIDS_NUM% = 6
Global ASTEROIDS_SIZE% = 4

' Store the device width and height
Global SCREEN_WIDTH%
Global SCREEN_HEIGHT%
' Half of SCREEN_WIDTH and HEIGHT
Global SCREEN_WIDTH2%
Global SCREEN_HEIGHT2%

' Used for delta timing movement
Global dt:DeltaTimer

' Screen states
Const STATE_TITLE% = 1
Const STATE_GAME% = 2
Const STATE_GAME_OVER% = 3

Class MyGame Extends App

Field player:Player
Field cg%, cr%, cb%
Field level% = 1
Field score% = 0
Field bestScore% = 0

Field FPS% = 60
' Current game state
Global gameState:Int = STATE_TITLE

Method OnCreate:Int()
    ' Store the device width and height
    SCREEN_WIDTH = DeviceWidth()
    SCREEN_HEIGHT = DeviceHeight()
    SCREEN_WIDTH2 = SCREEN_WIDTH / 2
    SCREEN_HEIGHT2 = SCREEN_HEIGHT / 2
    ' Set the Random seed
    Seed = Millisecs()
    ' Create the delta timer
    dt = New DeltaTimer(FPS)
    SetUpdateRate FPS

    reset()
    Return 0   
End Method

Method OnLoading:Int()
    Cls 0,0,0
    DrawText("Loading", SCREEN_WIDTH2, SCREEN_HEIGHT2, 0.5, 0)
    Return 0
End Method

Method OnUpdate:Int()
    FPSCounter.update()
    dt.UpdateDelta()

    Select gameState
    Case STATE_TITLE
        Asteroid.updateAll()
        If KeyHit(KEY_SPACE)
           setState(STATE_GAME)
        Endif   
    Case STATE_GAME
        player.Update()
        Bullet.updateAll()
        Asteroid.updateAll()
        Particle.updateAll()
        checkCollisions()
        clscolor()
    Case STATE_GAME_OVER
        Asteroid.updateAll()
        Particle.updateAll()   
        If KeyHit(KEY_SPACE)
           setState(STATE_TITLE)
            reset()
        Endif
    End Select

    Return 0
End Method

Method OnRender:Int()
    Select gameState
    Case STATE_TITLE
    Cls 0, 0, 0
    Asteroid.drawAll()
    DrawText ("ASTEROIDS - MONKEY STYLE!", SCREEN_WIDTH2, SCREEN_HEIGHT2, 0.5, 0.5)
    DrawText ("BEST SCORE: "+Self.bestScore, SCREEN_WIDTH2, SCREEN_HEIGHT2 + 30, 0.5, 0.5)
    DrawText ("PRESS <space> TO PLAY", SCREEN_WIDTH2, SCREEN_HEIGHT2 + 60, 0.5, 0.5)
    Case STATE_GAME 
    Cls cr, cg, cb
    player.draw()
    Bullet.drawAll()
    Asteroid.drawAll()
    Particle.drawAll()
    drawHUD()
    Case STATE_GAME_OVER
    Cls 0, 0, 0
    Asteroid.drawAll()
    Particle.drawAll()
    DrawText ("GAME OVER!", SCREEN_WIDTH2, SCREEN_HEIGHT2, 0.5, 0.5)
    DrawText ("SCORE: "+score, SCREEN_WIDTH2, SCREEN_HEIGHT2 + 30, 0.5, 0.5)
    DrawText ("BEST SCORE: "+Self.bestScore, SCREEN_WIDTH2, SCREEN_HEIGHT2 + 60, 0.5, 0.5)
    DrawText ("PRESS <space> TO RETURN TO THE TITLE SCREEN", SCREEN_WIDTH2, SCREEN_HEIGHT2 + 90, 0.5, 0.5)
    End Select
    Return 0
End Method

Method setState:Void(state:Int)
    gameState = state
End

Method clscolor:Void()
    If cr > 0
    cr-=2*dt.delta
    Else
    cr = 0
    Endif
End Method

Method reset:Void()
    Bullet.list.Clear()
    Asteroid.list.Clear()
    Particle.list.Clear()
    cg = 0
    cr = 0
    cb = 0
    level = 1
    ASTEROIDS_NUM = 6
    ASTEROIDS_SIZE = 4
    score = 0
    player = New Player(SCREEN_WIDTH2, SCREEN_HEIGHT2)
    fillAsteroids(ASTEROIDS_NUM, ASTEROIDS_SIZE)   
End Method

Method checkCollisions:Void()
    For Local a:Asteroid = Eachin Asteroid.list

        If dist(player.x, player.y, a.x, a.y) <= a.avgrad
        If cr = 0 Then cr = Rnd(100, 155)
        player.shield-=2
        Endif

        For Local b:Bullet = Eachin Bullet.list 
            If a <> Null Then
                If dist(b.x, b.y, a.x, a.y) <= a.avgrad
                    a.life = a.life - 1
                    b.life = 0
                    For Local t%=1 To 4
                        New Particle(a.x, a.y, Rnd(-8,8), Rnd(-8,8), 0.95, 30, PDM_spark, 255, 192, 64, 16)
                    Next
                    For Local t%=1 To 4
                        New Particle(a.x, a.y, Rnd(-4,4), Rnd(-4,4), 0.95, 60, PDM_smlparticle, 160, 160, 160, 0)
                    Next
                Endif
                If a.life <= 0

                For Local t%=1 To 8
                    New Particle(a.x,a.y,Rnd(-10,10),Rnd(-10,10),0.95,30,PDM_spark,255,192,64,64)
                Next
                For Local t%=1 To 6
                    New Particle(a.x,a.y,Rnd(-6,6),Rnd(-6,6),0.95,30,PDM_medparticle,255,192,64,128)
                Next
                For Local t%=1 To 6
                    New Particle(a.x,a.y,Rnd(-8,8),Rnd(-8,8),0.99,60,PDM_smlparticle,160,160,160,0)
                Next
                For Local t%=1 To 5
                    New Particle(a.x,a.y,Rnd(-6,6),Rnd(-6,6),0.99,60,PDM_medparticle,160,160,160,0)
                Next
                For Local t%=1 To 4
                    New Particle(a.x,a.y,Rnd(-4,4),Rnd(-4,4),0.99,60,PDM_bigparticle,160,160,160,0)
                Next

                If a.size > 1
                    For Local t% = 1 To 2
                        New Asteroid(a.x, a.y, Rnd(-5,5), Rnd(-5,5), a.size-1)
                    Next
                Endif
                Asteroid.list.Remove(a)
                a = Null
                score+=5
                Endif
            Endif
        Next
    Next
    If Asteroid.list.Count() = 0
        level+=1
        ASTEROIDS_SIZE+=1
        ASTEROIDS_NUM+=1
        fillAsteroids(ASTEROIDS_NUM, ASTEROIDS_SIZE)
    Endif
End Method

    Method drawHUD:Void()
        DrawText ("LEVEL: "+level, 0, 0)
        DrawText("SCORE: "+score, SCREEN_WIDTH, 0, 1, 0)

        FPSCounter.draw(SCREEN_WIDTH,SCREEN_HEIGHT, 1, 1)
    End Method

    Method fillAsteroids:Void(num%, size%)
        Local tx#
        Local ty#
        For Local t% = 1 To num
            Repeat
                tx=Rnd(640)
                ty=Rnd(480)
            Until ( tx<280 or="" tx="">360 ) And ( ty<200 or="" ty="">280 )
            New Asteroid(tx, ty, Rnd(-3,3), Rnd(-3,3), size+Rnd(1))
        Next
    End Method
End Class

Class Sprite
    Field xv# ,yv#
    Field x#, y# 
    Field rotation#
End Class

Class Player Extends Sprite
    Field angVel#
    Field velmul#
    Field vel#
    Field acc#
    Field drag#
    'Field xv#,yv#
    Field xa#,ya#
    Field firedel#

    Field ship_angvel#
    Field ship_acc#
    Field ship_velmul#
    Field ship_firedel#

    Field shield#=100

    Method New(x#, y#)
        Self.x = x
        Self.y = y
        ship_angvel = 6
        ship_acc = 0.16
        ship_velmul = -0.0005
        ship_firedel = 4
        shield = 100
    End Method

    Method Update:Void()

        If KeyDown(KEY_UP)
            acc =  ship_acc
            drag = vel * ship_velmul
        Else If KeyDown(KEY_DOWN)
            drag = vel * ship_velmul * 50
        Else
            acc = 0
            drag = 0
        End If 
        If KeyDown(KEY_LEFT)
            rotation+=ship_angvel * dt.delta
        End If
        If KeyDown(KEY_RIGHT)
            rotation-=ship_angvel * dt.delta
        End If

        If KeyDown(KEY_SPACE) And Self.firedel<=0
            Local tang#=Rnd(-4,4)
            New Bullet(x - (Sin(rotation)*8), y-(Cos(rotation)*8), xv - (Sin(rotation + tang ) *12), yv-(Cos(rotation + tang ) *12), 45, 255-Rnd(4), 192+Rnd(-4,4), 64+Rnd(4,4))
            firedel = ship_firedel
        Endif
        firedel-=dt.delta

        xa = (drag * xv) - (Sin(rotation) * acc)
        ya = (drag * yv) - (Cos(rotation) * acc)
        xv = xv + xa *dt.delta
        yv = yv + ya * dt.delta
        x = x + xv * dt.delta
        y = y + yv * dt.delta
        vel = dist(0, 0, xv, yv)
        '   
        If x < 0 x = SCREEN_WIDTH
        If x > SCREEN_WIDTH x = 0
        If y < 0 y = SCREEN_HEIGHT
        If y > SCREEN_HEIGHT y = 0

        If shield <= 0
        For Local t%=1 To 18
            New Particle( x, y,Rnd(-10,10),Rnd(-10,10),0.95,130,PDM_spark,255,192,64,64)
        Next
        For Local t%=1 To 16
            New Particle( x, y,Rnd(-6,6),Rnd(-6,6),0.95,130,PDM_medparticle,255,192,64,128)
        Next
        For Local t%=1 To 16
            New Particle( x, y,Rnd(-8,8),Rnd(-8,8),0.99,160,PDM_smlparticle,160,160,160,0)
        Next
        For Local t%=1 To 15
            New Particle( x, y,Rnd(-6,6),Rnd(-6,6),0.99,160,PDM_medparticle,160,160,160,0)
        Next
        For Local t%=1 To 14
            New Particle( x, y,Rnd(-4,4),Rnd(-4,4),0.99,160,PDM_bigparticle,160,160,160,0)
        Next

        If game.score>game.bestScore
            game.bestScore = game.score
        Endif

        game.setState(STATE_GAME_OVER)
        Endif
    End Method

    Method draw:Void()
        Local x1# = x-(Sin(rotation) * 10)
        Local y1# = y-(Cos(rotation) * 10)
        Local x2# = x-(Sin(rotation + 140 ) * 8)
        Local y2# = y-(Cos(rotation + 140 ) * 8)
        Local x3# = x-(Sin(rotation - 140 ) * 8)
        Local y3# = y-(Cos(rotation - 140 ) * 8)
        SetColor 255, 255, 255
        DrawLine x1, y1, x2, y2
        DrawLine x2, y2, x3, y3
        DrawLine x3, y3, x1, y1

        SetAlpha 0.5
        If shield < 50 Then SetColor 255,0,0
        DrawRect 10,SCREEN_HEIGHT - 15, Self.shield, 10
        SetAlpha 1
        SetColor 255,0,0
    End Method

End Class

Class Bullet Extends Sprite
    Global list:List<bullet> = New List<bullet>

    Field life#
    Field cr%, cg%, cb%

    Method New(x#,y#,xv#,yv#,life#,cr%,cg%,cb%)
        Self.x = x
        Self.y = y
        Self.xv = xv
        Self.yv = yv
        Self.life = life
        Self.cr = cr
        Self.cg = cg
        Self.cb = cb

        list.AddLast Self
    End Method

    Function updateAll:Void()
        If Not list Return
        For Local b:Bullet = Eachin list
            b.update()
            If b.life < 0
                Bullet.list.Remove(b)
            b = Null
        Endif

        Next
    End Function

    Method update:Void()
        x = x + xv * dt.delta
        y = y + yv * dt.delta

        life-=dt.delta
        If x < 0 x = SCREEN_WIDTH
        If x > SCREEN_WIDTH x = 0
        If y < 0 y = SCREEN_HEIGHT
        If y > SCREEN_HEIGHT y = 0
    End Method

    Function drawAll:Void()
        If Not list Return
        For Local b:Bullet = Eachin list
            b.draw()
        Next   
    End Function

    Method draw:Void()
    Local tmul#
    If life <= 15.0
    tmul = life / 15.0
    Else
    tmul = 1.0
    Endif
    SetColor cr*tmul, cg*tmul, cb*tmul
    DrawLine x, y, x + xv, y + yv
    End Method
End Class

Class Asteroid Extends Sprite
    Global list:List<asteroid> = New List<asteroid>

    Field ang#,angvel#
    Field rad#[9]
    Field avgrad#
    Field size%
    Field life%
    Field cr%, cg%, cb% 

    Method New(x#,y#,xv#,yv#,size%)
        Self.x =x 
        Self.y =y 
        Self.xv =xv 
        Self.yv =yv 
        Self.ang =Rnd(360)
        Self.angvel =Rnd(-6,6)
        Self.size=size
        Self.life=size
        Local tcol% = Rnd(-48,48)
        Self.cr=128+tcol
        Self.cg=128+tcol
        Self.cb=128+tcol
        ' Create "Rockiness"
        Self.avgrad =0
        For Local t% = 0 To 7
            Self.rad [t]=size*8.0+Rnd(-size*4.0,size*4.0)
            Self.avgrad =Self.avgrad +Self.rad[t]
        Next
        Self.avgrad =Self.avgrad /6.0
        Self.rad[8] = Self.rad[0]

        list.AddLast Self
    End Method

    Function drawAll:Void()
        If Not list Return
            For Local b:Asteroid = Eachin list
            b.draw()
        Next   
    End Function

    Function updateAll:Void()
        If Not list Return
            For Local b:Asteroid = Eachin list
            b.update() 
        Next
    End Function

    Method update:Void()
        Self.x =Self.x +Self.xv * dt.delta 
        Self.y =Self.y +Self.yv * dt.delta 
        Self.rotation =Self.rotation +Self.angvel * dt.delta 

        If Self.x <-Self.avgrad  Then Self.x =Self.x + SCREEN_WIDTH + Self.avgrad *2
        If Self.x >SCREEN_WIDTH+Self.avgrad  Then Self.x =Self.x - SCREEN_WIDTH - Self.avgrad *2
        If Self.y <-Self.avgrad  Then Self.y =Self.y + SCREEN_HEIGHT + Self.avgrad *2
        If Self.y >SCREEN_HEIGHT+Self.avgrad  Then Self.y =Self.y - SCREEN_HEIGHT - Self.avgrad *2
    End Method

    Method draw:Void()
        Local tmul# = 360.0 / 8.0
        SetColor cr, cg, cb
        For Local t% = 0 To 7
            DrawLine x-(Sin(rotation+(t)*tmul)*rad[t]),y-(Cos(rotation+(t)*tmul)*rad[t]),x-(Sin(rotation+(t+1)*tmul)*rad[t+1]),y-(Cos(rotation+(t+1)*tmul)*rad[t+1])
        Next
    End Method
End Class

Class Particle Extends Sprite
    Global list:List<particle> = New List<particle>

    Field vm#
    Field life#,mlife#
    Field drawmode%
    Field cr%,cg%,cb%
    Field cflash%

    Method New(x#,y#,xv#,yv#,vm#,life#,drawmode%,cr%,cg%,cb%,cflash%)
        Self.x=x
        Self.y=y
        Self.xv=xv
        Self.yv=yv
        Self.vm=vm
        Self.life=life
        Self.mlife=life
        Self.drawmode=drawmode
        Self.cr=cr
        Self.cg=cg
        Self.cb=cb
        Self.cflash=cflash

        list.AddLast Self
    End Method

    Function updateAll:Void()
        If Not list Return
        For Local b:Particle = Eachin list
            b.update() 
        Next
    End Function

    Function drawAll:Void()
        If Not list Return
        For Local b:Particle = Eachin list
            b.draw()
        Next   
        End Function

    Method update:Void()
        Self.x =Self.x +Self.xv *dt.delta
        Self.y =Self.y +Self.yv *dt.delta
        Self.xv =Self.xv *(1.0-(1.0-Self.vm )*dt.delta )
        Self.yv =Self.yv *(1.0-(1.0-Self.vm )*dt.delta )
        Self.life =Self.life -dt.delta
        If Self.life <0 then="" selflife="0" if="" listremoveself="" endif="" end="" method="" draw:void="" local="" tmul="Self.life" selfmlife="" tfls="Rnd(-Self.cflash,Self.cflash)" setcolor="" limit="" selfcrtmul="" tfls0255limit="" selfcgtmul="" selfcb="" tmultfls0255="" select="" selfdrawmode="" case="" pdm_smlparticle="" drawrect="" selfx="" selfy="" 1="" pdm_medparticle="" drawoval="" -1selfy="" -133="" pdm_bigparticle="" -2selfy="" -255="" pdm_spark="" drawline="" selfxv="" selfyv="" class="" fpscounter="" abstract="" global="" fpscount:int="" starttime:int="" totalfps:int="" function="" update:void="" millisecs="" -="" starttime="">= 1000
            totalFPS = fpsCount
            fpsCount = 0
            startTime = Millisecs()
        Else
            fpsCount+=1
        Endif
    End Function

    Function draw:Void(x% = 0, y% = 0, ax# = 0, ay# = 0)
        DrawText("FPS: " + totalFPS, x, y, ax, ay)
    End Function
End Class

' From James Boyd
Class DeltaTimer
    Field targetfps:Float = 60
    Field currentticks:Float
    Field lastticks:Float
    Field frametime:Float
    Field delta:Float

    Method New (fps:Float)
        targetfps = fps
        lastticks = Millisecs()
    End

    Method UpdateDelta:Void()
        currentticks = Millisecs()
        frametime = currentticks - lastticks
        delta = frametime / (1000.0 / targetfps)
        lastticks = currentticks
    End
End

Function dist#(x1#,y1#,x2#,y2#)
    Return Sqrt(Pow((x1-x2),2) + Pow((y1-y2),2))
End Function

Function limit#(value#,low#,high#)
    If value < low Then Return low
    If value > high Then Return high
    Return value
End Function
</particle></particle></asteroid></asteroid></bullet></bullet></space></space>