Archive for Januar, 2009

Was für für ein “bescheidener” Tag :(

Ich hätte heute lieber im Bett bleiben sollen. Wegen der Geburtstagsfeier meines Bruders schon recht wenig Schlaf bekommen, wollte ich den Tag eigentlich eher ruhig angehen. Aber das Schicksal hatte etwas anderes mit mir vor.

Die schon zwei mal erwähnten Probleme mit meinem Rechner nahmen noch vor dem ersten Kaffee des Tages einen dauerhaften Zustand an. Da half kein Auseiander- und wieder Zusammenbauen mehr. Er will einfach nicht mehr. Ab und zu brachte er ja noch den gequälten Ansatz eines Piepens zu stande, das war es dann aber auch schon.

Zum Glück kann ich mich per iPod noch um meine Mails und den (oder schreibt man “das Blog”?) Blog kümmern, ich hoffe aber wirklich das der Eee PC am Dienstag hier eintrudelt! Denn bis ich das Geld für ein neues Mainboard nebst passender Cpu zusammen habe werden wohl 1 – 2 Monate vergehen.

Januar 26th, 2009

GORC – Pixel ohne Fahrschein

Was habe ich mich heute den ganzen Tag über tot gesucht *Kopf-schüttel*

Rahmen für Menüs und Dialoge wurden ohne Probleme gezeichnet, ok… machen wir noch schnell das Hauptmenü fertig und dann Feierabend. Nix da… Irgendwie passten entweder die Menüpunkte nicht in das Fenster, oder das Fenster war zu groß. Aber was kann man falsch machen, wenn ein Rahmenteil genau 8×10 Pixel groß ist und ein Buchstabe der Schriftart genauso groß ist? Simple Mathematik und doch passt irgendetwas nicht!

Ich musste tatsächlich erst ein paar Buchstaben der Schriftart mitteln Paint einen Rahmen verpassen um den Fehler zu sehen. Bis dahin hatte ich meinen Quellcode sicherlich schon an die tausend Mal ergebnislos korrektur gelesen. Die Standardfunktion von Löve für Bitmapschriftarten fügt (was ich natürlich nicht wusste) immer einen Pixel zwischen zwei Buchstaben ein. Aber zum Glück gab es auch noch eine Funktion, dank der ich diesen dummen Pixel abstellen konnte ;)

Nun gut, ich habe jetzt erst einmal genug vom Programmieren. Das Menü kann jetzt warten, da wird schließlich heute noch wer 18 und ist schon kräftig ohne mich am Feiern.

Herzlichen Glückwunsch, Brüderchen!

2 comments Januar 24th, 2009

GORC – Spielobjekt Klassen fertig, wie weiter?

Vorwort: Mir ist aufgefallen das ich meinen GORC Thread im Game of Robot Forum mittlerweile als Devblog mißbrauche. Dem werd ich jetzt mal dagegen wirken und meine Fortschritte und Gedanken hier im Blog posten… wo sie eigentlich auch hingehören ;)

So… habe die letzte Woche genutzt und alle Spielelemente in Klassen gestopft. Der Inhalt einer Szene steckt nun nicht mehr in einem 2D Array, sondern in zwei Lua Tabellen. Eine für die Roboter, später kommen eventuell auch alle anderen NPCs hier rein. Und in der anderen Tabelle stecken alle weiteren Elemente (Mauern, Gold, etc.).

Sinn und Zweck des ganzen ist es die Spiellogik überschaubarer zu gestalten. Anstelle langer if-then-else Blöcke steckt nun die gesamte Logik für ein bestimmtes Objekt in seiner Klasseninstanz. Mal ein Beispiel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
Gold = Class("Gold", Object)
 
GoldImage = love.graphics.newImage("images/gold-0.png")
GoldImage:setCenter(0, 0)
 
GoldSound = love.audio.newSound("sounds/gold.wav")
 
function Gold:init(x, y, params)
	self.super:init(x, y)
 
	self.ani = GoldImage
end
 
function Gold:canEnter(obj)
	-- kann nur vom Spieler betreten werden
	if not Player:made(obj) then return false end
	return true
end
 
function Gold:onEntered(obj)
	if not Player:made(obj) then return end
 
	self:remove()
	spieler.gold = spieler.gold + 1
	love.audio.play(GoldSound)
end

Ok. Ein sammelbares Objekt ist nun keine wirklich skripttechnische Herausforderung. Aber wie wäre es mit etwas komplizierteren?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
Isolator = Class("Isolator", Moving)
 
IsolatorImage = love.graphics.newAnimation(love.graphics.newImage("images/isolator-0.png"), 16, 12, 0.1, 0)
IsolatorImage:setCenter(8, 6)
 
function Isolator:init(x, y, params)
	self.super:init(x, y)
 
	self.ani = IsolatorImage
 
	self.speed = spieler.speed
end
 
function Isolator:canEnter(obj)
	local dx, dy
 
	-- kann nur vom Spieler betreten werden
	if not Player:made(obj) then return false end
 
	-- bewegt sich der Isolator bereits, 
	-- können wir ihn nicht betreten, bzw. in seine Richtung gehen
	-- da wir sonst durch ihn hindurch laufen
 
	if self:isMoving() then return false end
 
	dx = self.x - obj.x
	dy = self.y - obj.y
 
	return self:canMoveTo(dx, dy)
end
 
function Isolator:canMoveTo(dx, dy)
	local feld = Szenen:current():get(self.x + dx, self.y + dy)
 
	if #feld == 0 then 
		self:setTarget(dx * 16, dy * 12)
		return true 
	end
 
	for i, e in pairs(feld) do
		if not Isolator:made(e.obj) and not Barbwire:made(e.obj) then
			return false
		else
			if e.obj:canMoveTo(dx, dy) then
				self:setTarget(dx * 16, dy * 12)
				return true
			end
		end
	end
 
	return false
end

Ein anderer positiver Nebeneffekt ist die Möglichkeit nun mehrere Objekte auf dem selben Feld zu haben. Wenn man eine Szene das erste mal betritt, befindet sich im Normalfall nur jeweils ein Objekt auf einem Feld. Wer aber Game of Robot schon gespielt hat, weiss das irgendwann der Zeitpunkt gekommen ist, um sein Inventar auszumisten. Tada! Was liegt da näher als alles was im Moment nicht benötigt wird, einfach auf einen Haufen zu legen? Und wenn man es wieder benötigt, einfach auf das Feld laufen und man sammelt automagisch alles ein.

Leider Gottes kann ich mich nicht so wirklich über meine kleine “Errungenschaft” freuen, denn sie kostet Frames :( Das Intro mit seinen knapp 1000 Mauern ist von 60 FPS auf knapp unter 50 gefallen. In den Szenen hält es sich zwar noch in Grenzen (300 bis 400 Objekte) aber sobald man die Isolatoren herum schubst, kann man auch hier bis zu 10 Frames verschwinden sehen.

Habe zwar noch die ein oder andere Idee, wie ich den Verlust eingrenzen kann. Aber auf lange Sicht, sollte ich doch lieber nach einer etwas performanteren Lösung suchen. Welche aber auf keinen Fall das kompfortable Skripten der Objekte verkompliziert…

Jetzt möchte ich mir aber noch nicht den Kopf darüber zerbrechen, und überlege schon mich der GUI von GORC zu widment. Schliesslich wären das die Spielmenüs, die Messageboxen und vor allem das Inventar. Mal schaun, die Nacht hat ja gerade erst angefangen xD

Januar 22nd, 2009

Rechner wollte schon wieder nicht starten :(

Diesmal war es nicht das Netzwerkkabel, sondern die Stromzufuhr vom Netzteil zum Mainboard an der ich Hand anlegen musste. Natürlich kam ich genau auf diese Idee erst nachdem ich das ganze Prozedere vom letzten Mal durchgezogen hatte… diesmal vergeblich.

Bleibt die Frage: Warum?

Liegt es vielleicht daran, das ich nachdem der Rechner runtergefahren ist, die Steckdosenleiste ausschalte? Wenn ich das nicht mache bekommen meine USB Geräte noch Saft vom angeblich abgeschalteten PC und leuchten die ganze Nacht fröhlich vor sich her. Und einen Wackelkontakt kann ich mir irgendwie nicht so recht vorstellen, da die Tür geschlossen ist kommt nicht einmal mein Kater in die Nähe des Rechners.

Januar 21st, 2009

CamStudio und ein GORC Video

Mußte mich eben mal ein wenig ablenken und habe mich auf die Suche nach einer Freeware zum Bildschirmvideos aufzeichnen gemacht. Sie sollte nicht zu verspielt sein, schließlich will ich doch nur ab und zu was aufzeichnen und vielleicht auf Youtube laden. Gesucht… gefunden :)

-> CamStudio <-

Entpackt, Videoformat auf MPG4 gestellt und auf Aufnahme gedrückt. Und schon hatte ich mein erstes Video von GORC:

Wirklich nettes Programm :) Was mir aber noch irgendwie fehlt sind die richtigen Einstellungen zum mitschneiden von Sound und Musik des gefilmten Programmes und die Möglichkeit das zu filmende Fenster direkt auswählen zu können. Bei CamStudio kann ich wie es scheint nur den Bereich auswählen. Dabei nehme ich dann entweder zu viel oder zu wenig vom Fenster auf.

Naja, nobody is perfect *lach*

Januar 20th, 2009

Klassen in Lua

Ich hatte vor ein paar Tagen angefangen flüssige Bewegungen in GORC einzubauen und versucht den Quellcode ein wenig übersichtlicher zu gestalten. Da z.B. Charlie und die Roboter ziemlich ähnlich gestrickt waren, lag nichts näher als beide Objekte auch die gleichen Funktionen (zeichnen, bewegen, …) nutzen zu lassen. Dabei war in etwa folgendes herausgekommen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function movable_create()
    m = {}
    m.x = 0
    m.y = 0
    return m
end
 
function movable_setPosition(m, x, y)
    m.x = x
    m.y = y
end
 
-- Beispiel:
spieler = movable_create()
movable_setPosition(spieler, 2, 2)

Funktionierte auch alles ziemlich gut. Aber vorhin wurde ich nachdenklich. Wäre es nicht interessant das ganze objektorientiert aufzubauen? Aber wie stellt man das in Lua an? Nach einer Menge googeln und herumspielen bin ich zu folgendem Ergebnis gekommen:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
-- class.lua
 
function Class(baseClass)
	local new_class = {}
	local class_mt = {__index = new_class}
 
	function new_class:new(self, ...)
		local newinst = {}
		setmetatable(newinst, class_mt)
		newinst:init()
		return newinst
	end
 
	if nil ~= baseClass then
		setmetatable(new_class, {__index = baseClass, __call  = function(self,...) return self:new(...) end})
	end
 
	function new_class:class()
		return new_class
	end
 
	function new_class:super()
		return baseClass
	end
 
	function new_class:init()
	end
 
	function new_class:is(theClass)
		local b_isa = false
 
		local cur_class = new_class
 
        while ( nil ~= cur_class ) and ( false == b_isa ) do
            if cur_class == theClass then
                b_isa = true
            else
                cur_class = cur_class:superClass()
            end
        end
 
        return b_isa
	end
 
	return new_class
end

Am besten in eine eigene Datei, z.B. “class.lua“, speichern. Im Einsatz sieht das ganze dann so aus:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
love.filesystem.require("class.lua")
 
-- Standard Objekt
 
Object = Class(nil)
 
function Object:init()
	-- Gridposition
	self.x = 0
	self.y = 0
 
	-- Sprite / Animation
	self.ani = 0
end
 
function Object:setPosition(x, y)
	self.x = x
	self.y = y
end
 
-- Bewegliche Objekte
 
Moveable = Class(Object)
 
function Moveable:init()
	self.super():init()
 
	-- Ziel Gridposition
	self.nx = 0
	self.ny = 0
 
	-- Bewegungsrichtung (entfernen!)
	self.dir = 0
 
	self.ani_x = 0
	self.ani_y = 0
 
	-- Felder pro Sekunde
	self.speed = 4
	self.last_update = 0
end
 
function Moveable:draw()
	local x, y
 
	x = (self.x - 1) * 16 + self.ani_x
	y = self.y * 12 + self.ani_y
 
	love.graphics.draw(self.ani, x, y)
end
 
...
 
-- Beispiel:
 
mauer = Objekt()
mauer:setPosition(10, 15)
 
spieler = Movable()
spieler:setPosition(2, 2)

Fragt mich jetzt aber nicht wie genau das ganze funktioniert ;) Für mich zählt DAS es geht. Wer trotzdem an der Funktionsweise interessiert ist, kann sich ja auf folgenden Seiten schlau lesen:

Januar 19th, 2009

Game of Robot Video bei Youtube

Anfang Dezember hatte herc aus dem Game of Robot Forum ein ca. 8 minütiges Gameplay Video der Robot Junior Episode bei Youtube reingestellt. Vielleicht weckt es ja bei dem ein oder anderen Interesse die Robot Spiele mal auszuprobieren?

Als quasi alter Game of Robot Hase muss ich eingestehen das ich den Trick mit dem Blockieren von Gegnern mittels Säurefläschen noch nicht kannte *lach* Das erleichtert doch gleich viele kniffelige Stellen. Danke herc :)

Januar 17th, 2009

Teeworlds, Pfeffi gegen Blasentee

Bin ja eigentlich eher so der gemütliche, aber Teeworlds hat es mir die letzten zwei Stunden echt angetan :)

Lauter bunte kugelige Kerlchen bekriegen sich in farbenfrohen Karten. Mit den WASD Tasten lenkt man sein Kugelviech und zielt mit der Maus. Linksklick feuert die Waffe ab, Mausrad wechselt diese. Mittels Leerstaste wird gehüpft, gut getimet geht auch ein etwas höherer Sprung. Und das Sahnehäubchen ist der Haken, mittels Rechtsklick, mit dem man nach ein wenig Training in ungeahnte Höhen emporsteigen kann.

Anstelle ins Bett, geh ich mal fleissig weiter Punkten *winke*

Januar 16th, 2009

Beinahe Herzinfakt – PC tot

Wie jeden Morgen gab ich meinem PC Strom und wanderte weiter Richtung Küche und frischem Kaffee. Nur diesmal wich jegliche Farbe aus meinem noch recht verschlafenem Gesicht, als ich zurück zum Rechner kam. Er summte voller Tatendrang, zeigte aber kein Bild. Für den Stromsparmodus des Monitores war ich nicht lange genug in der Küche. Er ist doch nicht etwa kaputt? Wehe!

In den letzten anderthalb Stunden habe ich meinem armen PC Stück für Stück ausgeschlachtet, um dem Fehler auf die Spur zu kommen. Mehrmals den CMOS gelöscht, alles raus. Nichts :( Lüfter sprangen zwar an, aber es gab nicht einmal das “Kein Speicher” Piepen. Innerlich rechnete ich schon aus wann ich genug für ein neues Mainboard, eine neue CPU oder gar beides zusammen gespart hätte.

Das einzigste das ich bisher noch nicht abgezogen hatte, war das Netzwerkkabel. Und ratet mal was passierte als ich eben jenes im letzten Akt meiner Verzweifelung entfernte? Bieeeeep Bieeeeep, da wollte doch wer Speicher :) :) :) Also Stück für Stück wieder alles rein… Rechner fährt hoch. Netzwerkkabel probeweise auch wieder ran, Rechner fährt trotzdem hoch :)

Bitte lieber PC, mach sowas NIE wieder mit mir!

Januar 15th, 2009

Mehrsprachige iPhone App

Stellt euch vor ihr habt gerade ein kleines Spiel fürs iPhone geschrieben und zwar in deutsch. Da ihr aber ein möglichst großes Publikum ansprechen wollt, sollte es auch eine englische Version geben. Wie aber geht man das Problem an? Ich habe mal ein wenig gegoogelt.

In eurem Xcode Projektverzeichnis legt ihr zwei Verzeichnisse an: “de.lproj” und “en.lproj”

crusher_locale_dirs.jpg

Nun fügt ihr eurem Projekt mittels Add -> New File … -> Other -> Strings File zwei neue Dateien “Localizable.strings” hinzu. Eins in das “de.lproj” und die andere in das “en.lproj” Verzeichnis.

crusher_locale_newfile.jpg crusher_locale_newfile_en.jpg crusher_locale_newfile_de.jpg

Eure Projektansicht sollte nun so aussehen:

crusher_locale_xcode_0.jpg

Ich habe als Beispiel mal ein Hauptmenü genommen, der Code sieht noch wie folgt aus:

1
2
3
4
5
6
7
MenuItem *start =
    [MenuItemFont itemFromString:@"Starte Spiel"
    target:self selector:@selector(startGame:)];
 
MenuItem *help =
    [MenuItemFont itemFromString:@"Hilfe"
    target:self selector:@selector(help:)];

Die Strings “Starte Spiel” und “Hilfe” ersetzen wir nun durch die NSLocalizedString() Funktion. StartGameKey und HelpKey geben an welchen String wir an der besagten Stelle haben möchten, übersetzt natürlich ;)

1
2
3
4
5
6
7
8
9
MenuItem *start =
    [MenuItemFont itemFromString:
    NSLocalizedString(@"StartGameKey", @"")
    target:self selector:@selector(startGame:)];
 
MenuItem *help =
    [MenuItemFont itemFromString:
    NSLocalizedString(@"HelpKey", @"")
    target:self selector:@selector(help:)];

Noch unsere beiden Localizable.strings Dateien bearbeiten, denn aus diesen holt sich unser Programm später die Übersetzten Strings.

Für Deutsch:

1
2
"StartGameKey" = "Starte Spiel";
"HelpKey" = "Hilfe";

und Englisch:

1
2
"StartGameKey" = "Start Game";
"HelpKey" = "Help";

Und schon bekommen wir je nach Spracheinstellung der iPhones die passenden Übersetzungen geliefert :) Sollte eine Sprache eingestellt sein, für die wir keine Übersetzung anbieten wird anscheinend die Englische Übersetzung genommen, was in den meisten Fällen völlig ok ist.

Januar 13th, 2009


Translator

Seiten

Letzte Artikel

Kategorien

Archiv

Meta


Page optimized by WP Minify WordPress Plugin