Ich dachte mir mal für die jenigen die schon immer mal ein Programm / Spiel
selbst Coden wollen ist das die Chance!
Ich persönlich "programmiere" LUA für die PSP seit des Releases des LUAPlayer für die Sony PSP. LUA ist eine Scriptsprache, was den Vorteil hat, dass man seinen Code nicht kompilieren muss, d.h. nicht in Maschinencode umwandeln oder eben für das Gerät verständlich machen muss. Zudem ist LUA sehr einfach zu erlernen und gibt auch Leuten eine Chance, die noch nie in ihrem Leben Code geschrieben haben. Soll heißen, man braucht absolut keine Erfahrung mit anderen Programmiersprachen.
Allerdings sind die Möglichkeiten von LUA begrenzt. Wer absolut grenzenlos programmieren will, muss den schweren, steinigen Weg zu C/C++ einschlagen, eine waschechte, recht anfängerunfreundliche Programmiersprache. Dieses Tutorial soll einen kleinen Einblick in Lua geben. Es werden die Grundlagen vermittelt, ein Beispielprojekt wird geschrieben und es gibt eine große Funktionsrefrenz zum Nachschlagen. Genug gelabert, wollen wir doch loslegen...
1. Was braucht man?
- Lua Player for PSP [um das spiel abspielen zu können Download im anhang]
- GeCrackte / GeHackte PSP um den Lua Player drauf zu packen^^
- Brain.exe [Leider nicht im anhang muss man selbst erstellen unter
Körper -> Kopf -> Heiße Luft ]
- Einfachen Text Editor
2. Hello World
Nun beginnen wir mit unserem Programm. Dabei soll der Text "Hello world" auf dem PSP Bildschirm dargestellt werden. Das Programm ist auch bekannt als "Hello World"-Programm und ist so ziemlich immer der erste Schritt in einer Programmiersprache. Der Befehl zum Ausgeben von Text auf dem Bildschirm lautet
Code:
screen:print(x,y, "dein Text hier", farbe)
Code:
farbe = Color.new(255,255,255) screen:print(1,1,"Hallo welt", farbe) screen.flip() screen.waitVblankStart(300)
Code:
farbe = Color.new(255,255,255) screen:print(1,1,"Hallo welt", farbe) while true do screen.flip() screen.waitVblankStart() end
3. Variabelen
Variablen braucht man in jeder Programmiersprache, man kann Werte aus ihnen auslesen oder sogar Werte in ihnen speichern. Das kann sehr nützlich sein. In LUA sind Variablen gleich doppelt einfach zu benutzen, denn man muss ihren Typ nicht mitangeben. Soll heißen, mann muss nicht festlegen, welche Wertemenge sie einschliessen. Zudem kann man in LUA normale Variablen kinderleicht in Zeichenketten, auch "Strings" genannt, umwandeln. Beginnen wir doch gleich einmal mit einem String:
Code:
farbe = Color.new(255,255,255 text1 = "Hallo" text2 = "Welt" while true do screen:print(1,1,text1.." "..text2, farbe) screen.flip() screen.waitVblankStart() end
Code:
farbe = Color.new(255,255,255) a = 5 b= 3 c=a*b while true do screen:print(1,1,a*b+c, farbe) screen.flip() screen.waitVblankStart() end
4. Blöcke und Schleifen
Schleifen gehören ebenso zu den Dingen, um die man in LUA nie herumkommen wird, sind aber sowieso recht einfach. Zu den Schleifen & Blocks in LUA gehören die if-Blocks, die for-Schleifen, die while-Schleifen und die repeat-until-Schleifen. Ich werde hier nur näher auf die if-Blocks eingehen, aber trotzdem kurz erklären, welche Schleife was bedeutet:
Code:
for a=1,5 do screen:print(0,0,"a ist kleinergleich 5 und groeßergleich 1 !", farbe) end ->für z.B eine Zahl a von 1 bis 5 tue blablabla... while a==2 do screen:print(0,0"a ist 2",farbe) end
repeat a = a + 1 until a = 5 end
->wiederhole a ist a + 1 bis a gleich 5 ist...
Das waren ein paar kleine Beispiele. Jetzt zum if-Block, den man am häufigsten braucht:
Code:
farbe = Color.new(255,255,255) a=5b=3c=a*b while true do if a*b+c == 30 then screen:print(1,1,a*b+c, farbe) end if a*b+c > 30 then screen:print(1,1,"da stimmt was nicht", farbe) end screen.flip() screen.waitVblankStart() end
Code:
if a*b+c == 30 then screen:print(1,1,a*b+c, farbe) else screen:print(1,1,"da stimmt was nicht", farbe) end
Code:
if a*b+c == 30 then screen:print(1,1,a*b+c, farbe) elseif a*b+c > 30 then screen:print(1,1,"da stimmt was nicht", farbe) end
5. Tasten
Jetzt kannst du schon beachtlich viel, du hast schon eine ganze Menge an Code hinter dir...aber so ein richtiges Programm kann man ja noch nicht machen, oder? Ohne Tasten geht es einem ziemlich schlecht...Dem können wir Abhilfe schaffen. Denn in LUA ist das auch wieder ziemlich leicht. So wie alles andere auch. Zuerst, was man zur Tasten-Benutzung wissen sollte:
Mit pad = Controls.read() öffnet man sozusagen die Schnittstelle zu den Tasten. Es gibt folgende Tasten:
Code:
pad:cross() pad:triangle() pad:circle() pad:square() pad:up() pad:down() pad:left() pad:right() pad:l() pad:r() pad:start() pad:home() pad:select() pad:note() pad:analogX() pad:analogY()
Code:
müsli = Controls.read()
Code:
müsli:cross()
Code:
black = Color.new(0,0,0) white = Color.new(255,255,255) while true do screen:clear(black) pad = Controls.read() if pad:cross() then screen:print(10,10,"Es geht!",white) end screen.flip() screen.waitVblankStart() end
6. Bild ausgabe
Soweit so gut, mit deinen bisherigen Kenntnissen solltest du mittlerweile in der Lage sein, ein eigenes Programm mit LUA zuschreiben. Aber ein Programm nur mit Schrift? Das ist doch ein wenig arg langweilig...viel schöner wären doch auch Bilder. Dann könntest du deine Anwendung auch grafisch gestalten. Und das geht natürlich auch.
Der Befehl zur Bildausgabe sieht so aus:
Code:
screen:blit(x,y,bild, transparent=ja/nein[true/false])
Code:
bild = Image.load("wasweissich.png") while true do screen:blit(0,0,bild,true) screen.waitVblankStart() screen:flip() end
7. Funktionen
Da du jetzt alles Grundlegende durchgekaut hast, können wir uns nun an das "optionale" wagen: die Funktionen. So richtig "optional" sind sie nun doch nicht. Aber für einfache Anwendungen braucht man sie dann auch nicht unbedingt. Mit Funktionen kann man den Code übersichtlicher und etwas aufgeräumter gestalten. Und man kann sich mit ihrer Hilfe auch viele Zeilen Code sparen. Eine Funktionen beinhaltet einen bestimmten Code, der irgendetwas bewirkt. Wenn man zum Beispiel in einer Anwendung mit verschiedenen Tasten immer ein und den selben Code ausführen will, müsste man ja jedesmal für jede Taste den Code schreiben. Mit Funktionen muss man diesen Code nur einmal schreiben. Man ruft die Funktion halt dann einfach mit den entsprechenden Tasten auf. Vielleicht ist es verständlicher, wenn ich mal ein konkretes Codebeispiel bringe:
Code:
bild = Image.load("bild.png") function Viereck() screen:blit(0,0,bild,false) end while true do pad = Controls.read() if pad:cross() then Viereck() end if pad:square() then Viereck() end screen.flip() screen.waitVblankstart() end
Code:
function name() dein code hier end
Code:
bild1 = Image.load("bild1.png") bild2 = Image.load("bild2.png") bild3 = Image.load("bild3.png") function Viereck(x,y,bild) screen:blit(x,y,bild,false) end while true do pad = Controls.read() if pad:cross() then Viereck(0,0,bild1) end if pad:circle() then Viereck(150,150,bild2) end if pad:triangle() then Viereck(300,120,bild3) end screen.flip() screen.waitVblankstart() end
8. Arbeiten mit dateien
Für ein hochwertiges Programm braucht man meist auch andere Dateien,sei es der Übersicht halber oder aus reinerFunktionalität. Aufjedenfall gibt es dafür wieder einige verschiedene Methoden. Wenn man einfach nur eine weitere Datei, die LUA-Code enthält, ins Script einbinden will, dann eignet sich "dofile" ganz gut. Dieser Befehl muss dann an gewünschter Stelle eingebunden werden:
dofile ("hallo.lua")
...bei mir könnte ich z.B. in meiner script.lua auf die Datei"hallo.lua", die sich im selben Ordner befindet, zugreifen. In "hallo.lua" könnten dann z.B Funktionen enthalten sein. Da dofile aber etwas "buggy" ist, also auch zu Programmabstürzen führen kann, bevorzuge ich diese Methode:
datei = loadFile("hallo.txt")
datei()
...dieser kleine Codeblock ist stabiler als "dofile". Mit loadFile() lade ich erst eine Datei und erstelle dabei eine Art Funktion, die ich sofort danach mit "datei()" ausführe. Die eleganteste Methode meiner Meinung nach ist allerdings folgende:
require "datei"
Damit wird eine .lua Datei namens "datei" ins Script miteingebunden. Wichtig ist dabei, dass das nur mit .lua-Dateien oder mit so genannten Libraries funktioniert und dabei die Dateiendung nicht mitangegeben werden darf.
Mit diesen Methoden kann ich also Dateien einlesen, aber nur mit funktionierenden, fehlerfreien LUA-Code. Wenn man jetzt selber Dateien erstellen will oder bestimmte Dateiformate mit genauer Zeile auslesen will, gibt es folgende Methode:
Code:
datei = io.open("huhu.txt", "r") zeile = datei:read() datei:close()
*n - Liest eine Zahl ein. Bsp.: datei:read("*n")
*a - Liest die ganze Datei ab der Momentanen Position, bsp.: datei:read("*a")
*l - Liest die nächste Zeile, ist standardmäßig auch ohne Parameter eingestellt., bsp.: datei:read("*l")
zahl - Liest eine Zeichenkette mit der angegebenen Zeichzahl ein, bsp.: datei:read(5)
Jetzt kann man Dateien aber nicht nur lesen, sondern auch schreiben. Dazu vorweg eine kleine Liste mit den dazugehörigen "Commands". Wer sich vorher gefragt hat, was das "r" in der Klammer von io.open soll, erfährt es jetzt:
r - Lesemodus (read mode)
w - Schreibmodus, überschreibt kompletten Inhalt (write mode)
a - Fügt zum existierenden Inhalt hinzu (append mode)
b - Binärmodus (binary mode)
r+ - Updatemodus (existierende Daten bleiben)
w+ - Updatemodus(existierende Daten bleiben)
a+ - Zufüg -und Updatemodus (existierende Daten bleiben, fügt nur am Ende hinzu)
Wie kann man dann etwas in eine Datei schreiben?
Code:
datei = io.open("huhu.txt","w") datei:write("hallo") datei:close()
Code:
function readAllLines(datei) zeilen = {} datei = io.open(datei,"r") for line in datei:lines() do zeilen[line] = line end datei:close() end
Code:
function printAllLines(datei,color) y=10 zeilen = {} datei = io.open(datei,"r") for line in datei:lines() do zeilen[line] = liney=y+10 screen:print(0,y,zeilen[line],color) end datei:close() end
9. Musik und Sound
Wer ein Spielchen programmiert, wird wohl nicht auf Musik oder Sounds verzichten können. Deshalb kümmern wir uns hier darum, wie und wo man Sounds oder Musik einbindet. Zudem gibt es auch gleich ein kleines Tutorial, wie man in das gewünschte Format konvertiert. Vorweg sei aber gesagt, dass so ziemlich jeder Luaplayer andere Befehle für Musik und Sound hat, sowie auch andere Dateiformate unterstützt.
Der "normale" LUAPlayer (hier speziell Luaplayer Mod1-4 von Cools) kann folgende Formate abspielen: UNI, IT, XM, S3M, MOD, MTM, STM, DSM, MED, FAR, ULT oder 669 für Musik. WAV kann nur für Sounds verwendet werden. Die obigen Formate können direkt aus dem MIDI-Format konvertiert werden. Dazu gibt es ein schönes Programm namens MadTracker, erhältlich auf . Nun zum eigentlichen Code (Achtung, diese Befehle gelten NUR für die Luaplayer Mod1-4 von Cools)
Code:
Music.playFile("lied.xm", true) --...spielt Musik ab, true/false aktiviert/deaktiviert den Loop-Modus. Music.pause() --...pausiert ein Lied, also hält es nur an. Music.stop() --...beendet ein Lied. Music.resume() --...setzt die Wiedergabe fort nach der Pausierung. Music.playing() --...ermittelt, ob gerade ein Lied läuft. Music.volume(Zahl) --...legt die Lautstärke fest, Zahl kann einen Wert von 0 bis 128
Soviel zum Abspielen von Musik, wollen wir uns doch nun um Sounds kümmern. Wie schon gesagt, für Sounds eignet sich nur das Format WAV. Ins WAV-Format kann man z.B. mit Audacity konvertieren, dass es auf gibt.
Code:
sound = Sound.load("bing.wav",false) --...lädt eine WAV-Datei, der Loop ist deaktiviert(false!) sound:play() --...spielt eine Sounddatei ab. sound:stop() --...beendet die Wiedergabe der Sounddatei sound:pause() --...pausiert die Soundwiedergabe sound:resume() --...setzt die Soundwiedergabe fort sound:playing()
Speziell beim LUAPlayer Mod 4 kann man aber dann doch MP3 abspielen mit den folgenden Befehlen:
Code:
Mp3.load("song.mp3") --...lädt eine MP3-datei Mp3.play() --...spielt den MP3-Song ab Mp3.pause() --...pausiert das Abspielen Mp3.stop() --...stoppt das Abspielen und löscht den Song aus dem RAM Mp3.EndOfStream() --...ermittelt, ob der Song vorüber ist, gibt true oder false zurück Mp3.getTime() --...zeigt die MP3-Spielzeit an, Anzeige mittels einem String (Zeichenkette) Mp3.volume(zahl) --...stellt die MP3-Lautstärke ein
Mp3/Ogg-Befehle (Standard Mp3-Funktionen) sind:
Code:
Mp3.load("datei.mp3") --Achtung, es kann maximal eine Mp3 geladen und zur selben Zeit abgespielt werden Mp3.stop() Mp3.pause() Mp3.play() --braucht keine Parameter, da sowieso nur eine Mp3 abgespielt werden kann Mp3.EndOfStream() Mp3.getTime() Mp3.songTime() Mp3.artist() Mp3.title() Mp3.album() Mp3.genre() Mp3.year() Mp3.trackNumber() Mp3.layer() Mp3.kbit() Mp3.mode() Ogg.load() --Achtung, es kann maximal eine Ogg geladen und zur selben Zeit abgespielt werden Ogg.stop() Ogg.pause() Ogg.play() --braucht keine Parameter, da sowieso nur eine Ogg abgespielt werden kann Ogg.EndOfStream() Ogg.songTime() Ogg.artist() Ogg.title() Ogg.album() Ogg.genre() Ogg.year() Ogg.trackNumber() Ogg.layer() Ogg.kbit() Ogg.mode()
Code:
Aa3me.load() --Achtung, es kann maximal eine Aa3 geladen und zur selben Zeit abgespielt werden Aa3me.play() --braucht keine Parameter, da sowieso nur eine Aa3 abgespielt werden kann Aa3me.stop() Aa3me.eos() Aa3me.gettime() Aa3me.percent() Aa3me.pause() Aa3me.songTime() Aa3me.artist() Aa3me.title() Aa3me.album() Aa3me.genre() Aa3me.year() Aa3me.trackNumber() Aa3me.layer() Aa3me.kbit() Aa3me.mode() Aa3me.rawSongTime() Aa3me.instantBitrate() Aa3me.vis() Mp3me.load() --Achtung, es kann maximal eine Mp3 geladen und zur selben Zeit abgespielt werden Mp3me.play() --braucht keine Parameter, da sowieso nur eine Mp3 abgespielt werden kann Mp3me.stop() Mp3me.eos() Mp3me.gettime() Mp3me.percent() Mp3me.pause() Mp3me.songTime() Mp3me.artist() Mp3me.title() Mp3me.album() Mp3me.genre() Mp3me.year() Mp3me.trackNumber() Mp3me.layer() Mp3me.kbit() Mp3me.mode() Mp3me.rawSongTime() Mp3me.instantBitrate() Mp3me.vis()
System.oaenable()
--Aktiviert die Wiedergabe von Sounds
System.oadisable()
--Deaktiviert die Wiedergabe von Sounds
Zwischen diesen beiden Befehlen können dann Sounds wiedergegeben werden:
Code:
Sound.play(meinsound)
Code:
meinsound = Sound.load("achso.wav")
Code:
SoundSystem.SFXVolume() SoundSystem.reverb() SoundSystem.panoramicSeparation() sound:gc() sound:tostring()
10. Timer
Für manche Games kann man auch einen Timer gut gebrauchen, SuperMario ist ein gutes Beispiel. Timer sind recht einfach zubenutzen. Aber auch wie bei den meisten anderen LuaPlayer-abhängigen Befehlen muss man hier beachten, dass die Befehle teilweise etwas anders lauten können. Hier wird die Funktion von Timern anhand der LuaPlayer Mod 4 Funktionen erläutert.
Zuerst erstellen wir einen neuen Timer:
Code:
zaehler = Timer.new()
Code:
zaehler:start()
Code:
runtime = zaehler:time()
Code:
zaehler:reset(zahl)
Code:
zaehler:stop()
Code:
color = Color.new(255,255,255) zaehler = Timer.new() while true do zaehler:start() runtime = zaehler:time() screen:print(0,0,runtime,color) if runtime > 1000 then zaehler:reset(0) end screen.flip() screen.waitVblankStart() end
11. Tables
Bei Tables denkt sich so manch einer "Für was sollen die bitte gut sein?". Ich hab mir das zu Beginn meiner Lua-Karriere zumindest gedacht. Mit der Zeit wird man aber nicht nur Älter, sondern auch klüger. Damit meine ich, dass man irgendwann ihren Sinn und ihre Nützlichkeit begreift.
Zuallererst bekommt man immer wieder eingetrichtert, dass sie etwas Übersicht in den Code bringen und man deshalb mit "tables" arbeiten sollte. Nun, ich arbeitete generell gern unübersichtlich und total durcheinander, drum kamen "tables" bei mir gar nicht in Frage. Bis ich dann begriffen habe, dass man mit ihnen noch viel mehr machen kann. Man kann sie nämlich, im Gegensatz zu if-Blöcken, mittels for-Schleifen komplett durchlaufen lassen. Sprich man kann automatisiert jeden Wert auslesen und mit ihm anstellen, was man will. Das spart viel Zeit und ist in manchen Fällen sogar zwingend erforderlich.
Wie sehen Tables denn eigentlich aus?
Code:
table = {}
Code:
table = {"hallo,"," du","lernst ","gerade ","tables ","kennen."}
Code:
color= Color.new(255,255,255) table = {"hallo,", " du", "lernst ", "gerade ", "tables ", "kennen."} screen:print(0,0,table[1]..table[2]..table[3]..table[4]..table[5]..table[6],color)
Code:
table.concat (table , zwischentext , ab wann , bis wo) --...verbindet die Werte einer table. table.foreach (table, funktion) --...geht alle Felder einer table durch und übergibt sie ggf an eine Funktion. table.getn (table) --...ermittelt die Anzahl der Tablefelder. table.sort (table , funktion) --...sortiert eine table. Ist keine Funktion gegeben wird nach groesser/kleiner Prinzip sortiert. table.insert (table, position, wert) --...fügt ein Feld in eine vorhandene table ein. table.remove (table , position) --...loescht ein Feld einer table table.setn (table, felderanzahl) --...setzt die Anzahl der Tablefelder.
Code:
limit = table.getn(table) y = 0 for i=1,limit do y=y+10 screen:print(0,y,table[i],color) end
Code:
screen:print(0,0,table[1],color) screen:print(0,10,table[2],color) screen:print(0,20,table[3],color) screen:print(0,30,table[4],color) screen:print(0,40,table[5],color) screen:print(0,50,table[6],color)
z.B bei einem Baller spiel wo ihr mit z.B L die waffe wechelt das er dann nicht 100 mal in der sek. die waffe wechselt
12. IrDA
Die PSP hat ja bekanntlich auch einen Infrarotport. Und mit dem kann man auch so allerhand Sachen anstellen. Was damit alles möglich ist zeigt IrDA Games von alex705 (). Man kann spannende Multiplayerspiele erstellen, oder auch multifunktionale Homebrews. Und es ist sogar ziemlich einfach. Zu beachten ist lediglich, dass die IrDA-Funktionen vom jeweiligen LuaPlayer abhängen. Dies hier sind die IrDA-Funktionen des LuaPlayer Mod4 von Cools.
Zuallererst muss einmal das Ir-Modul aktiviert werden:
Code:
System.irdaInit()
Arbeiten mit Fremdgeräten(z.B. Fernbedienung): Die PSP muss Signale vom Fremdgerät bekommen. Falls dann ein Signal kommt, kann man dann mittels if-Blöcken die Aktionen Regeln. Ein kleines Codebeispiel:
Code:
color=Color.new(255,255,255) add = 0 System.irdaInit() while true do remote = System.irdaRead() remotelength = string.len(remote) screen:print(0,0,add,color) if remotelength>1 then add = add+1 end screen.flip() screen.waitVblankStart() end
Arbeiten mit anderen PSPs: Das läuft auch nicht viel anders ab als mit einer Fernbedienung. Es ist genau das selbe Schema, nur muss eine andere PSP ein Signal senden. Dafür gibt es auch einen ganz simplen Befehl. Die Signale kann man auch wieder mittels if-Blöcke auswerten:
Code:
color=Color.new(255,255,255) add = 0System.irdaInit() while true do pad=Controls.read() remote = System.irdaRead() remotelength = string.len(remote) screen:print(0,0,add,color) if pad:cross() then System.irdaWrite("hallo") end if remotelength>0 then add = add+1 end screen.flip() screen.waitVblankStart() end
13. Wlan
Der Luaplayer bietet über den Ir-Port hinaus noch Befehle für den WLAN-Port. Somit kann man auch auf das Internet zugreifen bzw. Online arbeiten. Das kann man z.B. für ein Multiplayergame ausnutzen. Ich werde nun die einzelnen Wlan- WLAN-Befehle nacheinander auflisten und erläutern. Das ganze natürlich in der Reihenfolge, wie sie in einem Script verwendet werden muss. Zu beachten ist wiederum, dass die Befehle je nach LuaPlayer unterschiedlich lauten. Dazu hilft dann auch die jeweilige readme.txt des Luaplayers weiter.
Code:
Wlan.init()
Code:
Wlan.getConnectionConfigs()
Code:
verbindungen = Wlan.getConnectionConfigs()
Code:
verbindungen = {verbindung1,verbindung2,verbindung3}
Code:
Wlan.useConnectionConfig(1)
Code:
Wlan.getIPAddress()
Code:
ip = Wlan.getIPAddress() screen:print(0,0,ip,farbe)
Code:
if not Wlan.getIPAddress() then System.sleep(100)
Code:
Socket.connect(host, port)
Code:
neuersocket = Socket.connect("http://www.elitepvpers.com", 80)
Code:
neuersocket:isConnected()
Code:
if neuersocket:isConnected() == false then System.sleep(100) end
Code:
neuersocket:recv()
Code:
data = neuersocket:recv()
Code:
neuersocket:send(zeichenkette)
neuersocket:send("GET /index.html HTTP/1.0\r\n")
GET /index.html teilt dem Host mit, dass wir die index.html haben wollen. Das HTTP/1.0\r\n sagt dem Host, dass wirdas HTTP-Protokoll benutzen, also WWW.
Code:
neuersocket:close()
Code:
Wlan.term()
14. 3D Gu
Lua unterstützt sogar die Arbeit mit 3D Objekten, insofern im LuaPlayer eine "3D Gu" enthalten ist. Ich empfehle allerdings, dass Anfänger die Finger davon lassen, denn die Arbeit mit der 3D Gu ist recht schwer. Zuerst einmal sollte man wissen, dass es in 3D nicht nur die x und y Achsen gibt, sondern x,y, und z Achse. Also Höhe, Breite und Tiefe. Zudem kann man in der 3D Guauch nicht von "blit" reden, da ja kein Bild in der 2 Dimensionalen Ebene dargestellt wird, sondern ein 3-dimensionalesObjekt. Die Funktion hierfür heisst Gum.translate(x,y,z). Desweiteren läuft eine 3D-Darstellung auch etwas anders ab als eine 2-dimensionale.
Grundlegend kann man in jedes Lua-Script die 3D Gu, insofern der LuaPlayer es abspielen kann, einbetten. Die 3D Gu muss gestartet und auch wieder geschlossen werden:
Code:
Gu.start3d() --der Code für das Objekt Gu.end3d()
Code:
Gu.clearColor(farbe) --...legt die Füllfarbe fest Gu.clearDepth(0) --...legt die Farbtiefe fest, von 0 bis 255(0=kein Farbtiefe,255=größte Farbtiefe) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) --...weist dem Objekt die eingegebene Farbe und Farbtiefe zu
Code:
farbe = Color.new(255,0,255) Gu.start3d() Gu.clearColor(farbe) Gu.clearDepth(0) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) Gu.end3d()
Code:
Gum.matrixMode(Gu.PROJECTION) Gum.loadIdentity() Gum.perspective(50, 16/9, 0.5, 1000)
Folglich sieht der gesamte 3D Gu Code so aus:
Code:
farbe =Color.new(255,0,255) Gu.start3d() Gu.clearColor(farbe) Gu.clearDepth(0) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) Gum.matrixMode(Gu.PROJECTION) Gum.loadIdentity() Gum.perspective(50, 16/9, 0.5, 1000) Gu.end3d()
Code:
farbe = Color.new(255,0,255) Gu.start3d() Gu.clearColor(farbe) Gu.clearDepth(0) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) Gum.matrixMode(Gu.PROJECTION) Gum.loadIdentity() Gum.perspective(50, 16/9, 0.5, 1000) Gum.matrixMode(Gu.VIEW) Gum.loadIdentity() Gu.end3d()
Code:
Gu.POINTS- zeichnet Punkte. Gu.LINES- zeichnet Linien. Gu.LINES_STRIP- Zeichnet aneinandergereihte Linien. Gu.TRIANGLES- Zeichnet Dreiecke. Gu.TRIANGLES_STRIP- zeichnet aneinandergehängte Dreiecke. Gu.TRIANGLES_FAN- zeichnet ebenfalls aneinandergehängte Dreicke, allerdings an 2 andere Eckpunkte. Gu.SPRITES- zeichnet Quader.
Code:
farbe = Color.new(255,0,255) Gu.start3d() Gu.clearColor(farbe) Gu.clearDepth(0) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) Gum.matrixMode(Gu.PROJECTION) Gum.loadIdentity() Gum.perspective(50, 16/9, 0.5, 1000) Gum.matrixMode(Gu.VIEW) Gum.loadIdentity() Gum.matrixMode(Gu.MODEL) Gum.loadIdentity() Gum.translate(0, 0, -3) Gu.disable(Gu.TEXTURE_2D) Gu.end3d()
Code:
triangle = { {red,3,-2,0}, --eckpunkt 1 {red,-3,-2,-2}, --eckpunkt 2 {red,3,3,-1}, --eckpunkt 3} }
Code:
table = { {farbe,x,y,z} }
Code:
Gum.drawArray(Gu.TRIANGLES, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D, triangle)
Code:
red = Color.new(255,0,0) triangle = { {red,3,-2,0}, --eckpunkt 1 {red,-3,-2,-2}, --eckpunkt 2 {red,3,3,-1}, --eckpunkt 3 } farbe =Color.new(255,0,255) Gu.start3d() Gu.clearColor(farbe) Gu.clearDepth(0) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) Gum.matrixMode(Gu.PROJECTION) Gum.loadIdentity() Gum.perspective(50, 16/9, 0.5, 1000) Gum.matrixMode(Gu.VIEW) Gum.loadIdentity() Gum.matrixMode(Gu.MODEL) Gum.loadIdentity() Gum.translate(0, 0, -3) Gu.disable(Gu.TEXTURE_2D) Gum.drawArray(Gu.TRIANGLES, Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D, triangle) Gu.end3d()
Code:
Gum.rotateXYZ(x* (Gu.PI/180),y* (Gu.PI/180),z* (Gu.PI/180))
Code:
Gum.translate()
Code:
Gum.lookAt(vonwox,vonwoy,vonwoz,nachx,nachy,nachz,0,1,0)
--Das 0,1,0 am Ende muss man nicht verändern.
Und nun noch das Verwenden von Texturen:
Code:
Gu.enable(Gu.BLEND) Gu.blendFunc(Gu.ADD, Gu.SRC_ALPHA, Gu.ONE_MINUS_SRC_ALPHA, 0, 0) Gu.enable(Gu.TEXTURE_2D);
Code:
Gu.texImage(bild)
Nun noch ein paar Zeilen Code, die man vorerst nicht verstehen muss und die man so lassen kann. Lediglich die Farbe "white" sollte auch richtig definiert sein:
Code:
Gu.texFunc(Gu.TFX_MODULATE, Gu.TCC_RGBA) Gu.texEnvColor(white) Gu.texFilter(Gu.LINEAR, Gu.LINEAR) Gu.texScale(1, 1) Gu.texOffset(0, 0) Gu.ambientColor(white)
Code:
Gum.drawArray(Gu.TRIANGLES, Gu.TEXTURE_32BITF+Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D,table)
Code:
white = Color.new(255,255,255) red = Color.new(255,0,0) bild = Image.load("bild.png") triangle = { {0,0,red,0,0,0}, {1,0,red,1,0,0}, {1,1,red,1,-1,0}, {0,0,red,0,0,0}, {0,1,red,0,-1,0}, {1,1,red,1,-1,0} }
Code:
farbe =Color.new(255,0,255) Gu.start3d() Gu.clearColor(farbe) Gu.clearDepth(0) Gu.clear(Gu.COLOR_BUFFER_BIT+Gu.DEPTH_BUFFER_BIT) Gum.matrixMode(Gu.PROJECTION) Gum.loadIdentity() Gum.perspective(50, 16/9, 0.5, 1000) Gum.matrixMode(Gu.VIEW) Gum.loadIdentity() Gu.enable(Gu.BLEND) Gu.blendFunc(Gu.ADD, Gu.SRC_ALPHA, Gu.ONE_MINUS_SRC_ALPHA, 0, 0) Gu.enable(Gu.TEXTURE_2D) Gu.texImage(bild) Gu.texFunc(Gu.TFX_MODULATE, Gu.TCC_RGBA) Gu.texEnvColor(farbe) Gu.texFilter(Gu.LINEAR, Gu.LINEAR) Gu.texScale(1, 1) Gu.texOffset(0, 0) Gu.ambientColor(farbe) Gum.matrixMode(Gu.MODEL) Gum.loadIdentity() Gum.translate(0, 0, -3) Gum.drawArray(Gu.TRIANGLES, Gu.TEXTURE_32BITF+Gu.COLOR_8888+Gu.VERTEX_32BITF+Gu.TRANSFORM_3D,triangle) Gu.end3d()
15. TileMaps
Tile Maps - was zur Hölle ist denn das?"...das werden sich wohl einige von euch denken.
Die Erklärung ist denkbar einfach: Tile Maps sind Maps, die aus aneinandergereihten Grafiken mit allesamt der gleichen Größe aufgebaut sind. Man kann/braucht sie zum Großteil in RPG's (Roleplay Games). Das ganze kann man ganz einfach mit folgender Grafik veranschaulichen:
Eine Tilemap ist sozusagen ein Raster bzw eine Tabelle. Jedes Feld in diesem Raster kann man beispielsweise mit einer Grafik "belegen". Dabei entsteht eine Tilemap, wie man sie eben von RPG's kennt. Für Lua bedeutet das: man kann damit beispielsweise eine Karte für ein 2D-Spiel erstellen. Wollen wir uns nun doch jetzt einmal an den Code wagen...
In diesem kleinen Projekt sieht die Sache so aus, wir haben 2 Grafiken, beide mit der Auflösung 32x32.
Wir wollen den ganzen Bildschirm mit der Gras-Grafik füllen und an ein bestimmten Positionen das Gras mit der Pflanze auch noch unterbringen.
Code:
a=Image.load("tilebild1.png") b=Image.load("tilebild2.png") map={ {a,a,a,a,a,b,a,a,a,b,a,a,a,b,a}, --Zeile 1 {b,a,a,a,a,a,a,a,a,a,a,a,a,b,a}, --Zeile 2 {a,a,b,a,a,b,a,a,a,a,a,b,a,b,a}, --Zeile 3 {a,a,a,a,a,a,a,a,a,a,a,a,a,b,a}, --Zeile 4 {a,a,b,a,a,b,a,a,a,a,a,b,a,b,a}, --Zeile 5 {a,a,a,b,a,a,a,a,a,b,a,a,a,b,a}, --Zeile 6 {a,b,a,a,a,b,a,b,a,a,a,b,a,b,a}, --Zeile 7 {a,a,a,b,a,a,a,b,a,a,b,a,a,b,a} --Zeile 8 } while true do for c=1,8 do for d=1,15 do screen:blit(d*32,c*32,map[c][d],false) end end screen.flip() screen.waitVblankStart() end
Code:
map = { , , , , , , , }
Der Mainloop sollte einem bekannt sein, aber was zur Hölle soll diese kompliziert ausschauende for-Schleife? Nun, genau diese for-Schleife erstellt unsere Tilemap, mithilfe der Tabelle "map". Hier arbeiten wir außerdem mit 2 for-Schleifen, die 2. ist nämlich in die 1. eingebettet. Um das zu verstehen, müssen wir die Schleife mal zerstückeln:
Code:
for c=1,8 do end
Code:
for c=1,8 do --durchläuft alle 8 Zeilen der Tabelle "map" for d=1,15 do --durchläuft den Inhalt der jeweiligen Zeile screen:blit(d*32,c*32,map[c][d],false) --gibt die Bilder aus end end
Code:
screen:blit(d*32,c*32,map[c][d],false)
Code:
screen:blit(7*32,3*32,map[3][7],false)
Code:
screen:blit(224,96,a,false)
16. Kollisionen
Eine Kollision im echten Leben, das wäre zum Beispiel der Zusammenprall zweier Gegenstände. Auch beim Programmieren kann bzw. braucht man manchmal "Kollisionen". Was Kollisionen in Lua sind und wann man sie braucht, das erfahrt ihr in diesem kleinen Tutorial:
Nehmen wir einfach mal an, wir haben das Bild eines Balles geladen und geben den Ball mit den vorher definierten Variablen x und y aus. Im Mainloop vergrößern wir x ständig, das hat zur Folge, dass der Ball immer weiter nach rechts gelangt, solange, bis wir einschreiten und ihm einen Riegel vorschieben. Wir teilen dem Luaplayer mittels eines if-Blocks mit, dass der Wert von x ab einer bestimmten Position nicht mehr vergrößert wird bzw ihm sogar im Gegensatz wieder etwasabgezogen wird. Dadurch entsteht sozusagen eine unsichtbare Mauer, an der der Ball abprallt. Unsere erste kleine "Kollision"!
Code:
if x > 480 then x=480 end
Code:
ball = Image.load("ball.png") x = 100 y = 100 modus = 0 while true do if modus == 0 then x = x + 1 end if x>480 then modus = 1 end if modus == 1 then x = x - 1 end if x < 0 then modus = 0 end screen.flip() screen.waitVblankStart() end
Hier sieht das alles noch recht einfach aus, was es zweifellos auch ist. Die Kollisionsabfrage wird erst bei verschiedenen Flächenformen wie Kreise, Ellipsen oder Dreiecken relativ schwer...
17. SIO
SIO steht für Serial Input/Output. An der PSP ist das die Schnittstelle neben der Kopfhörerbuchse. Mit dem SIO-Port der PSP hätte man ungeahnte neue Möglichkeiten, denn der Port eröffnet die Möglichkeit, mit anderen Geräten aller Art zu kommunizieren...so könnte man beispielsweise ein Modem an den SIO Port anschliessen und mit dem richtigem passenden Homebrew eine Verbindung herstellen. Es gibt auch schon zahlreiche Erfindungen für diesen Port, wie z.B Standardmäßig das HPRM (das Socom Headset) oder das PSP Motion Kit. Allerdings kann man in LUA nicht viel mit dem SIO Port anfangen. Man braucht nämlich immer den LuaPlayer mit der passenden Library dazu.
Trotzdem eine kleine Einführung in die Arbeit mit dem SIO-Port: Bevor man Daten vom SIO-Port lesen bzw senden kann, muss man den Port ersteinmal initialisieren:
Code:
System.sioInit(Baudrate)
Code:
System.sioRead() System.sioWrite("text")
18. Das Erste Projekt
Genaugenommen hast du jetzt die Basics von LUA drauf. Aber wie macht man denn nun ein Programm? Darauf möchte ich euch eine Antwort geben. Und zwar anhand eines simplen Malprogramms. Ich möchte jetzt allerdings nicht daraufhin hundert verschiedene Mini-Malprogramme auftauchen sehen.
Machen wir uns doch zuerst einmal Gedanken darüber, was man so alles brauchen könnte für das Malprogramm. Für ein simples Malprogramm brauchen wir:
1. Eine Malfläche
2. Einen Cursor
3. Tasten
4. Malfunktion
Vielleicht klingt das jetzt erstmal fürchterlich aufwendig, ist es aber gar nicht. Der Code sollte recht einfach zu verstehen sein. Der DPad-Code wird aber vielleicht für Verwirrung sorgen. Bei Fragen dazu einfach ins Forum posten. Den Cursor soll man nämlich mit dem DPad steuern. Für das DPad gibt es einen Standardcode, den wir auch hier verwenden. Nun aber zum Code:
Code:
weiss = Color.new(255,255,255) --definiert die farbe weiss schwarz = Color.new(0,0,0) --definiert die farbe weiss
Code:
malflaeche = Image.createEmpty(480,272)
Code:
malflaeche:clear(weiss)
Code:
cursor = Image.load("cursor.png")
Code:
cursor_x = 100
Code:
cursor_y = 100
Code:
while true do --Mainloop pad = Controls.read() --DPad-Code...muss man nicht verstehen. Fragen bitte ins Forum posten dx = pad:analogX() dy = pad:analogY() if dx > 30 then cursor_x = cursor_x + (math.abs(pad:analogX())/64) end if dx < -30 then cursor_x = cursor_x - (math.abs(pad:analogX())/64) end if dy > 30 then cursor_y = cursor_y + (math.abs(pad:analogY())/64) end if dy < -30 then cursor_y = cursor_y - (math.abs(pad:analogY())/64) end --DPad-Code ENDE screen:blit(0,0,malflaeche) --zeigt die Malfläche an screen:blit(cursor_x, cursor_y, cursor, true) --zeigt das cursor auf cursor_x und cursor_y an if pad:cross() then malflaeche:drawLine(cursor_x, cursor_y,cursor_x, cursor_y,schwarz) end screen.flip() screen.waitVblankStart() end
Das waren die ersten schritte zu deinem eigenen spiel!
Falls ich euch geholfen habe gebt mir bitte ein Thx schadet ja niemanden^^