Verschiedenes
25.12.2011 - Das dynamische Trio Teil 2
War fast zu erwarten, Apple hat iMAME ein schnelles Ende gesetzt, gab wohl rechtliche Probleme
wegen der ROMs. Hat mich gewundert, dass der Emulator es überhaupt in den iTunes-Store geschafft hat.
Aaaaaber, wohl dem, der entweder ein jailbraked Gerät besitzt (dort kann man iMAME einfach wieder drauf kopieren)
oder noch besser, wenn man eine Dev-Licence von Apple hat :-). Also alles kein Problem, schnell den Source-Code von
iMAME besorgt, Xcode angeworfen, kurz compiliert, die ROMs wieder mit dem iExplorer aufs iPad kopiert und
schon kann der Spaß weiter gehen. Es versteht sich wohl von selbst, dass man die original ROMs besitzten muss, ansonsten
verstößt man gehen das Urheberrecht!
24.12.2011 - Das dynamische Trio
Ich wußte, dass das iPad für was zu gebrauchen ist. Pünktlich zu Weihnachten ist endlich mein iCade gekommen
und was soll ich sagen, das Ding ist der absolute Hammer. Endlich macht das Daddeln am iPad so richtig Laune.
Wenn man sich die Screenshots im Internet anschaut, könnte man meinen, dass solche Klassiker wie Donkey-Kong oder
Frogger im Store zu haben sind, aber weit gefehlt. Lediglich die Atari-Classics gibts dort und was soll ich sagen, die
sind mir dann doch ein wenig zu Retro. Abhilfe schafft mal wieder MAME (iMAME), dass es zur Zeit kostenlos im Store gibt.
Das Programm funktioniert wunderbar mit dem iCade, schnell noch ein paar ROMs mit dem iExplorer auf's iPad geladen und schon
kann der Spaß beginnen. Die Klassiker machten am Mac schon Spaß, aber erst mit dem iCade kommt das richtige Cabinet-Feeling rüber.
Nach ner Stunde, musste ich erst mal ne Pasue einlegen, da ne Sehnenscheidenentzündung nicht grad Spaß macht :-)
Der iCade ist erstaunlich gut gemacht, die Steuerung und die Knöpfe sind absolut robust und bringen das Feeling recht gut rüber.
Einzig bei so Spielen wie Hyper-Olympics braucht man ne zweite Person (macht alleine eh nicht so viel Fun), die den Kasten fest hält
da beim 100-Meter Lauf sonst das Teil vom Tisch fallen würde :-)
Also fassen wir kurz zusammen. Wer den ultimativen Retro-Spaß sucht, braucht unbedingt
- iCade
- iMAME
- iExplorer
recht schnell iCade-kompatibel hin bekommt iCade SDK.
Also: On your mark, get set, go go go go go goooooooooooooo!
12.11.2011 - Mac OS X 10.6 und der Fullscreenmode
Da haben uns die Jungs von Apple ein schönes Ei gelegt. Das Erzeugen und Umschalten in einen Fullscreen-Modus war bis < 10.6 leicht zu machen://Modus holen CFDictionaryRef newMode = CGDisplayBestModeForParameters(kCGDirectMainDisplay, 24, _screenWidth, _screenHeight, NULL);
if(err != CGDisplayNoErr)
{
NSLog(@"Fehler: CGDisplayBestModeForParameters");
return NO;
}
//In Modus umschalten
err = CGDisplaySwitchToMode(kCGDirectMainDisplay, newMode);
if(err != CGDisplayNoErr)
{
NSLog(@"Fehler: CGDisplaySwitchToMode");
return NO;
}
Nun sind die beiden Funktionen:
CGDisplayBestModeForParametersund
CGDisplaySwitchToModedeprecated und ein einfacher Ersatz leider nicht zu finden. Folgende Methode macht im Prinzip genau das Selbe:
-(void) createCGLFullscreen:(unsigned int)width
height:(unsigned int)height
depth:(unsigned int)depth
{
boolean_t exactMatch = 0;
// Kopie des aktuellen Displaymode holen
CGDisplayModeRef displayMode = CGDisplayCopyDisplayMode(kCGDirectMainDisplay);
// Durch alle verfügbaren Display-Modes laufen und den passenden holen
CFArrayRef allModes = CGDisplayCopyAllDisplayModes(kCGDirectMainDisplay, NULL);
for(int i = 0; i < CFArrayGetCount(allModes); i++)
{
CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
NSLog(@"%dx%d %dbpp",
CGDisplayModeGetWidth(mode),
CGDisplayModeGetHeight(mode), [self bitDepthFromDisplayMode:mode]);
if([self bitDepthFromDisplayMode:mode] != depth)
continue;
if((CGDisplayModeGetWidth(mode) >= width) && (CGDisplayModeGetHeight(mode) >= height))
{
displayMode = mode;
exactMatch = 1;
break;
}
}
// Keine passende depth gefunden
if(!exactMatch)
{
for(int i = 0; i < CFArrayGetCount(allModes); i++)
{ CGDisplayModeRef mode = (CGDisplayModeRef)CFArrayGetValueAtIndex(allModes, i);
if([self bitDepthFromDisplayMode:mode] >= depth)
continue;
if((CGDisplayModeGetWidth(mode) >= width) && (CGDisplayModeGetHeight(mode) >= height))
{
displayMode = mode;
exactMatch = 1;
break;
}
}
}
reqWidth = CGDisplayModeGetWidth(displayMode);
reqHeight = CGDisplayModeGetHeight(displayMode);
reqDepth = [self bitDepthFromDisplayMode:displayMode];
}
Lustig dazu ist auch der Verweis von Apple, wie man ab 10.6 einen Fullscreen-Modus erstellen soll.
Doku (Creating a Full-Screen Application in Mac OS X v10.6).
Was Apple dort aber zeigt, ist keine echte Fullscreen-Anwendung (weil man keine Auflösung angeben kann),
sondern nur eine gefakte Fenster-Anwendung die sich über den gesamten Bildschirm legt.
Leute haaaaallllooooo, ist das alles ??
Ist für micht ziemlich "lieblos" das Thema Spieleprogrammierung (bzw. OpenGL) am Mac, aber das hatten wir ja schon.
Man schaue sich nur mal die aktuell unterstützte OpenGL-Version an, traurig traurig.
Anscheinend sehen das andere auch so: guckst du.
15.10.2011 - Game-Loop mal anders
Die klassische Game-Loop mal anders. Typischerweise sieht sie in etwa so aus:- (void)enterMainLoop
{
while(stayInGame)
{
//TimeDelta berechnen
_start = [NSDate timeIntervalSinceReferenceDate];
_deltaTime = _end-_start;
_deltaTime =-_deltaTime;
_end = _start;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(_cameraPosition.x, _cameraPosition.y, _cameraPosition.z,
_cameraPosition.x, _cameraPosition.y, _cameraPosition.z-1.0,
0.0, 1.0, 0.0);
[self renderBackground];
[self renderGameObjects];
[self renderParticleSystems];
[self renderHUD];
[self checkEvents];
}
}
Je nach Umfang des Spiels ist das auch ok und bleibt mehr oder weniger übersichtlich. Nehmen wir mal an, das Spiel ist ein simpler Shooter in dem es ein einziges Level gibt, ohne Startscreen, Highscore, usw... . Wir müssen also nicht unterscheiden, ob wir im Spiel an sich sind, oder vielleicht gerade einen Highscore eingeben, oder ein Bonus-Level rendern müssen. Soweit also kein Problem.
Wird das Projekt umfangreicher, wird die oben gezeigte Methode schnell unübersichtlich und fast nicht mehr handhabbar. Nehmen wir mal an wir haben "nur":
- Splashscreen
- Auswahlschirm (Hilfe anzeigen, Highscore anzeigen, Level wählen)
- Level
- Bonuslevel
- Win-Screen
- Game-Over Screen
- Highscore eintragen
- Abspann
- usw...
- (void)checkEvents
{
NSEvent *event;
event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode dequeue:YES];
switch(_gameState)
{
case splashScreen:
{
.........
};
case level:
{
.........
};
case highscore:
{
...........
};
}
}
Oder aber die Renderroutine:
switch(_gameState)
{
case splashScreen:
{
[self renderSplashScreen];
......
};
case level:
{
[self updateGameObjects:_deltaTime];
[self renderGameObjects];
.........
};
case highscore:
{
[self renderHighscoreBackground];
[self renderGlyps];
..........
};
}
Das Alles ähnelt sehr einem C-Programm mit einfachen Funktionsaufrufen. Ein anderer Ansatz (OOP) den ich auch in meinem aktuellen Projekt verwende ist folgender:
Für jedes Element (also Splashscreen, Level, Bonuslevel, Highsore eintragen, usw...) gibt es ein eigenes Objekt, sprich die komplette Funktionalität wird jeweils in eine eigene Klasse ausgelagert, womit die eigentlich Game-Loop sehr schlank und übersichtlich bleibt. Ein großer Vorteil darin ist z.B. das das Event-Handling direkt an die entsprechende Klasse weitergegeben wird, ungefähr so:
- (void)checkEvents
{
NSEvent *event;
event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode dequeue:YES];
[[self currentGameElement] sendEvent:event];
}
Wobei [self currentGameElement] das ist, was aktuell auf dem Schirm zu sehen ist. Somit entfallen die switch-Konstrukte von oben und alles bleibt sehr übersichtlich, da die Klasse selbst entscheidet was sie mit dem Event anfängt oder auch nicht. Tatsächlich sieht die Game-Loop dann z.B. so aus:
- (void)enterMainLoop
{
while(stayInGame)
{
//TimeDelta berechnen
_start = [NSDate timeIntervalSinceReferenceDate];
_deltaTime = _end-_start;
_deltaTime =-_deltaTime;
_end = _start;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
gluLookAt(_cameraPosition.x, _cameraPosition.y, _cameraPosition.z,
_cameraPosition.x, _cameraPosition.y, _cameraPosition.z-1.0,
0.0, 1.0, 0.0);
[[self currentGameElement] update_deltaTime];
[[self currentGameElement] render];
}
}
28.09.2011 - Neues OpenGL für Lion
Lange hats gedauert, bis wir endlich mal eine relativ neue OpenGL-Version bekommen. Apple hat mit Lion OpenGL 3.2 an den Start gebracht! Wie zu erwarten war, wurden viele alte Zöpfe über Board geschmissen, die Fixed-Function Pipeline gehört nun endgültig der Vergangenheit an. Sachen wir glBegin() bzw. glEnd() gibts nicht mehr. Stört eigentlich nicht weiter, da man sich seit OpenGL ES 2.0 eh dran gewöhnt hat. Schade ist aber, dass wie ich finde die Lernkurve nun enorm gestiegen ist, wenn man sich mit dem Thema beschäftigen will (oder muss). Die vielen verschiedenen Buffer die es nun gibt, können am Anfang doch sehr für Verwirrung sorgen, genau so, dass es keine Matrix-Stacks mehr gibt und nun alle Transformationen im Shader (selbständig) gemacht werden müssen. Fühlt sich alles nach OpenGL ES 2.0 an. Irgendwie ist nun alles "besser", schneller und vor allem "programmierbarer" geworden. Die Shader-Programmierung ist nun ein elementarer Bestandteil, wenn man sich mit OpenGL beschäftigen will. Wie gesagt, macht es das nicht gerade einfacher, da man sich nun mit 2 Dingen gleichzeitig beschäftigen muss. Sachen die früher die CPU gemacht hat, werden nun an die GPU abgegeben. Das bedeutet aber nun auch, das man vergleichsweise mehr Code zu schreiben hat (OpenGL-Code und Shader-Code). Alle Transformationen und Beleuchtungen werden komplett im Shader abgebildet. Mit Sicherheit ist das ein wichtiger Schritt für Apple gewesen, wenn sie nicht ganz den Anschluss verpassen wollen (auf der Dose gibts ja schon OpenGL 4.0).21.09.2011 - DirectX für den Mac ?
Die aktuellen WWDC 2011 Videos zum Thema Spiele-Entwicklung stimmen optimistisch.- OpenGL neue Version (wurde auch echt Zeit)
- OpenAL (naja, das hatten wir ja schon)
- Gamecenter
- AV-Foundation
- Core-Image, Core Animation, ...
- usw. usw.