Jump to content
Unity Insider Forum

Blogs

Featured Entries

  • Mark

    UltraTerrain Dev Diary #2

    By Mark

    Nachdem die Tests nun immer umfangreicher werden wächst auch die Funktionsvielfalt.

    Im letzten Post habe ich den PageDataHandler erwähnt, dieser ist nun fast vollständig implementiert, dazu musste aber einiges gemacht werden.

    Der PageDataHandler soll wie der Name bereits andeutet in der Lage sein die Daten einer Page zu handhaben/verwalten, darunter fällt wie bereits erwähnt das Laden der Daten.

    Das Laden der Daten basiert auf 2 Schritten:

    1. Wenn noch keine komprimierten (zip) Daten im Objekt vorhanden sind dann wird das dem System zugehörige VirtuelleFileSystem nach den passenden Page Daten gefragt. Das VirtuelleFilesystem ist das VFS aus SaveIt und kann in einer Datei verschiedene Unterdateien speichern und lesen, das ganze ohne jedesmal die gesamte Datei in den Speicher zu laden. Die Daten wurden vorher komprimiert in das VFS abgelegt.

    2. Sind die komprimierten Daten vorhanden werden diese dekomprimiert und in die Datenarrays gelegt die ein PageDataHandler hat. Das sind aktuell nur 2 Arrays, einmal die VoxelValues welche angeben wir einflussreich ein Voxel ist (0.0 bedeutet kein VoxelEinfluss und 1.0 bedeutet vollen Einfluss) und die BlendValues, welche angeben wie die verschiedenen Texturen später miteinander verschmelen werden.

    Der 2. Schritt ist gesondert vom ersten aus folgendem Grund: Der PageDataHandler soll wenn eine Page längere Zeit unverändert bleibt die Daten zwischenspeichern können um Speicherplatz zu sparen um später wenn die Page noch viel länger unangetastet blieb diese Daten in das VFS zu speichern. Dies soll später dafür sorgen dass nur die Voxeldaten in Speicher verbleiben die unbedingt nötig sind um entweder schnelle änderungen zu ermöglichen oder wieder schnell parat zu sein um änderungen vorzunehmen.

    Intern arbeiten die Load und LowerMemorConsumption Methoden mit Asynchronen Operationen die jeder Zeit abgebrochen werden können um zB wärend eine Page grade die Daten komprimiert diese Operation abzubrechen da ich die Daten spontan doch unkomprimiert benötige.

    Das System für diese Asynchronen Operationen basiert auf den Unity Threading Helper.

    Bestimmte Aktionen können allerdings nicht abgebrochen werden und sind damit auch synchron und nicht asynchron, zB das löschen aller Daten bei dem es keinen Zwischenschritt gibt der noch abgebrochen werden könnte.

    Das System zu laden und Speichern der VoxelDaten bedarf aber noch einen weiteren Zwischenschritt um Versionsupdates auf neuere UltraTerrain Versionen zu ermöglichen, aus diesem Grund wird in den Page Daten später noch die Version des Dateiformates (unabhängig vom VFS Format) abgespeichert werden und basierend auf dieser Version werden dann die geeignetesten Speichermethoden gewählt.
    • 0 comments
    • 466 views
 

"Das Unity-Buch" - gibt's jetzt endlich zu kaufen ;-)

Die Geschichte dieses Buches ist eine ziemlich lange (angefangen habe ich mit diesem Projekt 2010) - aber das möchte hier nicht ausbreiten, bei Interesse findet Ihr die wichtigsten Stationen im [url="http://unity-buch.de/blog"]Blog auf der Webseite zum Buch[/url].

Die gute Nachricht: Das Buch ist jetzt fertig gedruckt und über [url="http://www.buecher.de/shop/fachbuecher/das-unity-buch/chittesh-jashan/products_products/detail/prod_id/42104802/"]buecher.de[/url] und [url="http://www.amazon.de/gp/product/3864902320/"]Amazon[/url] bestellbar (einige Buchläden müssten es auch schon haben). Bisher hab ich's selbst gedruckt noch nicht in den Händen gehalten - heute ist's zwar bei mir angekommen (hat mir meine Freundin erzählt), aber ich bin seit gestern in Seattle. Da muss ich mich jetzt also noch knapp zwei Wochen gedulden.

Zu dem Buch gibt es auch ein Fragen-Forum, das ein wenig an StackOverflow bzw. auch Unity Answers angelehnt ist. Das ist aber natürlich nicht als Konkurrenz zum Unity Insider Forum gedacht, sondern speziell für Fragen zum Buch. Daher verweise ich auch gleich auf der Startseite der Webseite zum Buch auf hier und bin hier natürlich auch weiterhin aktiv (die Forum-Software, die ich auf der Webseite zum Buch verwende hat auch noch Bugs, die trotz Open Source leider schwieriger zu beheben sind, als ich dachte ... oh well ;-) ).

Auf der Webseite zum Buch habe ich eine Menge Tutorials, die auch ohne das Buch funktionieren sollten - wenn Ihr Lust habt, schaut da ruhig mal vorbei: [url="http://unity-buch.de/screencasts/videos/tutorials"]Screencasts zu Das Unity-Buch[/url]. Mindestens einer davon war übrigens von einer Frage im Forum inspiriert (und ist dementsprechend natürlich auch schon lange von hier aus verlinkt). Die Arbeit an der Website zum Buch ist noch nicht abgeschlossen, Ihr findet dort aber bereits jetzt eine Vielzahl von [url="http://unity-buch.de/links"]Links[/url], die zwar nach den Kapiteln gruppiert sind, aber auch so interessant sein sollten.

Jetzt hoffe ich, dass Carsten nicht an seinen Verkaufszahlen merkt, dass es zwei deutsche Unity-Bücher gibt. Viel besser ist, wenn einfach mehr Leute Unity lernen. [url="http://www.amazon.de/gp/product/3446439390/"]Sein Buch[/url] habe ich zwar bisher noch nicht komplett gelesen (sorry, hatte einfach nicht die Zeit - ist aber soweit ich's gesehen habe ein echt gutes Buch) ... und ich denke die Bücher sind verschieden genug, dass es sich lohnt, beide zu kaufen ;-)

Über Feedback freue ich mich natürlich - nach der ersten Auflage ist vor der zweiten Auflage, und da ich Webseite und Buch recht eng verknüpft habe, kann ich Erweiterungen und Ergänzungen auch zwischendrin gut nachliefern.

Und natürlich wünsche ich denen, die sich das Buch kaufen viel Freude beim Lesen und hoffe, dass die Arbeit mit Unity während und nach der Lektüre noch mehr Spaß macht!

[center][i][b]Enjoy! :-)[/b][/i][/center]


Source: [url="http://forum.unity-community.de/topic/9533-das-unity-buch-gibts-jetzt-endlich-zu-kaufen/page__view__findpost__p__72592"]"Das Unity-Buch" - gibt's jetzt endlich zu kaufen ;-)[/url]

jashan

jashan

 

#7 Tabl - Sprint Alpha #1

Heyho Tabl,

na!! Alles klar bei dir? In meinen (privat) GameDev Projekt geht es wirklich heiß her! Erst vergangenen Dienstag hatten wir ein krass geiles Teammeeting. Nee...ehrlich jetzt...

Es war das alle erste Teammeeting seit der Gründung des Teams

Naja was heisst hier Gründung...wir haben mal mit 8 Leuten angefangen (naja...es war noch quasi vor dem Anfang. Bevor dir erste Zeile Code gescriptet wurde - wie dem auch sei! Wir haben mal mit vielen angefangen und nun sind wir nur noch 3

Ein Programmierer, eine Grafikdesignerin und ein 3D Modellierer! Naja und wenn man meine kleine Tochter (Malen und Basteln xD) mit dazu zählt sind es sogar 4

Noch kann ich nicht viel zu dem Spiel sagen. Das Team gibt es zwar schon ne weile, aber wir haben viel hin und her gemacht, um unsere Fähigkeiten erstmal auszubauen. So habe ich mich mit Projektplanung und Programmierung beschäftigt, während die anderen beiden Ihre jeweiligen Talente weiterausgebaut haben. Die Grafikdesignerin hat viel auf Papier gezeichnet und mit Photoshop rumhantiert und der 3D Modellierer hat mit Autodesk Maya krass geile Scheisse umgesetzt

Jedenfalls haben wir hier und da auch kleine Game-Projekte gehabt. Wie nen geiles Tetris. Netzwerk sowie Ranked TicTacToe. Oder 3D Mini Shooter like AngryBots aber halt selfmade und das mit First Person und Third Person Ansicht

Jedenfalls arbeiten wir nun seit kurzem an unserem ersten echten Projekt. Aber hey bevor man anfängt braucht man ein ordentliches Konzept und genau das haben wir in dem Meeting gemacht. Naja wir haben mehrere Sachen gemacht. Hier mal eine Liste:[list]
[*]Kick Off Meeting
[*]Konzept Planung
[*]Einführung in Projekt Planung - na wie wir nun alles durch ziehen:
[list]
[*]Trello als Taskboard
[*]BitBucket (Git) zur Versionierung (Bitbucket Wiki für Dokumentation)
[*]Raw Assets im Dropbox
[*]Skype/Whatsapp/Telefon für Kommunikation
[/list][*]Wir haben alle zusammen Raclette gegessen (Mann war das Lecker)
[*]Und zum Abschluss haben wir unseren ersten Meilenstein definiert - die sogenannte Alpha #1
[/list]
Das Meeting war am Dienstag. Heute ist Freitag. Was soll ich sagen - Version 0.0.2 ist nach drei Tagen bereits vorhanden xD. Version 0.0.1 war Mittwoch Nacht schon vorhanden, sprich:[list]
[*]erste Version des Terrains
[*]Charakter Steuerung
[*]Charakter Attribute (diverse Status Attribute)
[*]Beleuchtung
[*]System Prefab
[/list]
Mit Version 0.0.2 kam nun:[list]
[*]Charakter HUD
[*]Charakter Inventar
[*]Charakter Audios
[*]Charakter Events
[*]Super geiler GUI Skin
[*]Eigenes Font
[*]Sprites für Status Attribute
[*]Sprites für erstes Gegenstände
[*]zweite Version des Terrains
[*]Erweiterung der System Prefab (hier liegen alle wesentlichen System Dienste (Manager)
[*]Diverse Game Objekte Items usw
[*]uvm
[/list]
Tjo, Tabl, wie du siehst. Bei mir geht es ab!

Mach heute nicht zu lang

[font=courier new,courier,monospace]Lösung Post Rätsel #5: [i]"Der Fahrstuhl"[/i][/font]
[font=courier new,courier,monospace]Lösung Post Rätsel #6: [i]"Der Zahnarzt."[/i][/font]

[font=courier new,courier,monospace]Post Rätsel: [i]"Wer hört alles und sagt nichts?"[/i][/font]

Nax

Nax

 

#1 UnCat - Video Tutorials?

Moin lieber Leser,

ich frage dich, ob es gut wäre neben meinen kleinen Skripten hier im Blog, auch das eine oder andere Video Tutorial bereitzustellen.

Ich habe extra für dich eine Umfrage gestartet. Denn mich interessiert es wirklich was du von dieser Idee denkst. Natürlich steht es dir frei einen Kommentar zu schreiben.

Bis denne

Nax

Nax

 

#2 CharakterSkripte - GUI für CharacterStats

Jo heyho Leute,

hier kommt #2 der CharakterSkripte

Heute geht es darum für das Skript "CharacterStats" - vom letzten Beitrag ([url="http://forum.unity-community.de/blog/41/entry-99-1-charakterskripte-characterstats/"]#1 CharacterStats[/url]) - ein weiteres Skript zu erstellen, sodass die Status Attribute, welche durch "CharacterStats" beeinflusst werden, auch anzuzeigen

Wir machen es uns ganz gaaaannnzz einfach! Wir wollen einfach die vier Attribute[list]
[*]Health
[*]Hunger
[*]Thirst
[*]Stamina
[/list]
oben links auf dem Bildschirm dargestellt werden.

Hinweis: Damit das ganze auch in Unity funktioniert solltet ihr die Skripte einfach dem FPSController hinzufügen (also via Add Component > Scripts > usw...).

Ok hier noch Kleinigkeiten, die wir für das GUI Skript festhalten:[list]
[*]Wir können bei bedarf ein GUISkin anfügen
[*]Die allgemeine Größe soll definierbar sein
[*]Die Position für folgende Attribute sollen Variabel sein:
[list]
[*]Health
[*]Hunger
[*]Thirst
[*]Stamina
[/list][*]Und jedes der o.g. Attribute soll mit schicken Texturen ergänzt werden können (so farbige Balken oder so ^^)
[/list]
Daraus ergibt sich, das wir so um die 14 Attribute brauchen ^^.

Hier kommen sie:

[CODE]
#pragma strict
var guiSkin : GUISkin;
// Default Bar Size
var size : Vector2 = new Vector2(200, 20);
// View for Health
var healthPos : Vector2 = new Vector2(20, 10);
var healthBarEmpty : Texture2D;
var healthBarFull : Texture2D;
// View for Hunger
var hungerPos : Vector2 = new Vector2(20, 40);
var hungerBarEmpty : Texture2D;
var hungerBarFull : Texture2D;
// View for Thirst
var thirstPos : Vector2 = new Vector2(20, 70);
var thirstBarEmpty : Texture2D;
var thirstBarFull : Texture2D;
// View for Stamina
var staminaPos : Vector2 = new Vector2(20, 100);
var staminaBarEmpty : Texture2D;
var staminaBarFull : Texture2D;
[/CODE]

Ok sieht super aus ;-). Nun können wir die Attribute auch über den Editor anpassen. Top!

Nun brauchen wir noch ein Attribut. Die Verbindung zu den CharacterStats!

[CODE]
// Character Stats
private var characterStats : CharacterStats;
function Start() {
characterStats = GetComponent(CharacterStats);
}
[/CODE]

Damit wir nun nicht viermal dasselbe schreiben für jedes Attribut basteln wir uns eine Methode welches die dementsprechenden Elemente auf der GUI erzeugt (für jedes Attribut halt..).

[CODE]
function CreateGUIBoxForAttribute(pos:Vector2, display:float, empty:Texture2D, full:Texture2D) {
// GUI for Attribute
GUI.BeginGroup(new Rect(pos.x, pos.y, size.x, size.y));
GUI.Box(Rect(0, 0, size.x, size.y), empty);
GUI.BeginGroup(new Rect(0, 0, size.x * display, size.y));
GUI.Box(Rect(0, 0, size.x, size.y), full);
GUI.EndGroup();
GUI.EndGroup();
}
[/CODE]

Hui, waren das viele Parameter

Nun wird es gaaaannnz einfach. Wir brauchen einfach die OnGUI Methode implementieren und alles funktioniert!

(Nicht vergessen, wir haben noch den GUI Skin!)

[CODE]
function OnGUI() {
if(guiSkin) {
GUI.skin = guiSkin;
}
CreateGUIBoxForAttribute(healthPos, characterStats.health, healthBarEmpty, healthBarFull);
CreateGUIBoxForAttribute(hungerPos, characterStats.hunger, hungerBarEmpty, hungerBarFull);
CreateGUIBoxForAttribute(thirstPos, characterStats.thirst, thirstBarEmpty, thirstBarFull);
CreateGUIBoxForAttribute(staminaPos, characterStats.stamina, staminaBarEmpty, staminaBarFull);
}
[/CODE]

Na ist das nicht EASY?????

Nun können wir das Skript einfach dem FPSController beifügen und schon haben wir die Attribute auf der Oberfläche angezeigt ;-).

Solltet ihr passende Texturen haben (halt solche Balken oder so xD) könnt ihr die noch beifügen ;D

Viel Spaß damit!

Nax

Nax

 

#3 Snippets - Globales Event System

Heyho Leute,

mal wieder habe ich ein neues Snippet oder Skript für euch am Start. Diesmal geht es um ein Globales Event System. Sprich ein Ort, wo ich Events ablegen kann, um später mit Listener darauf zu horchen, falls irgendwas ansteht. Z.B. der Charakter springt und es soll eine Audio Datei für das Springen abgespielt werden. Oder der Charakter hebt ein Item auf und der Sound des Items soll abgespielt werden.

Also mal direkt ins kalte Wasser. Hier ist das Skript für die Datei "GlobalEventSystem.js":

[CODE]
#pragma strict
import System;
public class GlobalEventSystem {
// Singleton / Class
private static var _instance : GlobalEventSystem = new GlobalEventSystem();
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
private function GlobalEventSystem() {
//if the constructor must be public, you can do this:
if (_instance != null) {
throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
}
}
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
}
[/CODE]

So hier kommt die Erklärung!

Der Anfang ist denk ich mal selbsterklärend. Wir definieren eine neue Klasse namens GlobalEventSystem und importieren System, da wir etwas daraus benötigen.

[CODE]
#pragma strict
import System;
public class GlobalEventSystem {
[/CODE]

Da wir ein Globales Event System wollen, darf das Objekt dieser Klasse im gesamten Spielablauf auch nur einmal vorkommen. Die einfachste Möglichkeit sowas zu realisieren, sind Singletons! Mehr zu Singleton erfahrt ihr von Dr. Google

Hier seht ihr auch, das wenn jemand versucht ein Objekt der Klasse durch den Kontruktor zu erzeugen, das eine Exception geworfen wird (dafür der Import von System).

[CODE]
// Singleton / Class
private static var _instance : GlobalEventSystem = new GlobalEventSystem();
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
private function GlobalEventSystem() {
//if the constructor must be public, you can do this:
if (_instance != null) {
throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
}
}
[/CODE]

Nun kommt der Interessante Part! Die Instance
[CODE]
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
[/CODE]

Wir definieren:[list]
[*]ein Attribut, das alle unsere Events und deren Listener festhält.
[*]eine Instanz Methode zum hinzufügen eines Listeners
[*]eine Instanz Methode zum senden eines Events
[/list]
Beim Triggern (absenden/auslösen) von Events können wir eine Hashtable mit Argumenten mit geben, welche an die Listener Funktionen übergeben wird. (das Löschen von Listenern, ist aktuell nicht vorgesehen )

Aber wir benutzen wir das ganze nun? Gute Frage!

Man stelle sich vor wir haben eine Datei "Example.js", welche darauf wartet eine Audio Datei abzuspielen. Dabei ruft sie vom Event System die Methode "On" mit einem Schlüssel (hier "PlaySoundEvent") auf und übergibt zusätzlich eine Callback Funktion. Eine Funktion die ausgeführt werden soll, wenn das Event ausgelöst wird.

[CODE]
#pragma strict
var anySound : AudioClip;
private var eventSystem : GlobalEventSystem = GlobalEventSystem.GetInstance();
private var audioSource : AudioSource;
function Start () {
audioSource = GetComponent(AudioSource);
eventSystem.On("PlaySoundEvent", function(args) {
PlaySound();
});
}
function PlaySound() : void {
audioSource.clip = anySound;
audioSource.Play();
}
[/CODE]

Irgendwo anders in unserem Spiel sagen wir, das wenn irgendwas passiert (z.B. die Leertaste gedrückt wird), dann soll dieses Event ausgelöst werden.

[CODE]
#pragma strict
private var eventSystem : GlobalEventSystem = GlobalEventSystem.GetInstance();
function Update() {
if(Input.GetKeyDown(KeyCode.Space)) {
eventSystem.Broadcast('PlaySoundEvent", new Hashtable());
}
}
[/CODE]

Und "BÄÄMMM" passiert es

Ich hoffe es gefällt euch.

Wieso ich das geschrieben habe?

Als ich über Unity und Events via Google auf dieser Seite gelandet bin: [url="http://unity3d.com/learn/tutorials/modules/intermediate/scripting/events"]http://unity3d.com/l...cripting/events[/url]

Las ich folgendes unter JS Source:
[quote]
[color=#708090]//Javascript doesn't have a built-in "event". Instead,[/color][color=#708090]//you will need to use C# to gain this functionality.[/color][color=#708090]//Other scripts written in Javascript can still subscribe[/color][color=#708090]//to events created in C#.[/color]
[/quote]

Schrecklich oder?

EDIT: 20.03.2015 - 21:12 Uhr

Heyho - ich hab wirklich nen miesen Bug in der ganzen Sache gefunden. Beim wieder laden von Szenen kann/wird es passieren das Instanzen der Singleton mehrfach existieren, da sie beim wechseln einer Szene nicht die Static Member eine Klasse entfernen xD ist das nicht schrecklich. Man glaub nen leeren/neuen Kontext zu bekommen, aber das ist nur augenscheinlich der Fall. Jedenfalls soll mich das nicht stören. Ich hab die Klasse wesentlich angepasst, damit es in die Kategorie MonoBehaviour Objekt fällt und somit vom GC beachtet wird.

Im groben sieht es nun so aus:

[CODE]
#pragma strict
import System;
import UnityEngine;
public class GlobalEventSystem extends MonoBehaviour {
// Singleton / Class
private static var _instance : GlobalEventSystem; // = new GlobalEventSystem()
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
function Awake() : void {
_instance = this;
}
// private function GlobalEventSystem() {
// //if the constructor must be public, you can do this:
// if (_instance != null) {
// throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
// }
// }
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String) {
Broadcast(eventName, null);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(args == null) args = new Hashtable();
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
}
[/CODE]

Damit das ganze läuft hab ich mir einfach ne System Prefab gebastelt, die alle meine Szenenweiten System Singleton Skripte hält ;-). Diese einfach in die Szene einzubinden sollte ja wohl easy sein xD

So Far - Nax

Nax

Nax

 

#6 Tabl - Krank -.-

Heyho [b]Tabl [/b]

ich schreibe dich nun zum dritten mal an, in der Hoffnung das dieser Post endlich mal stehen bleibt...

Ich drücke immer eine mir vom Mac bekannte Tastenkombination, welche hier auf Windows wohl die vorherige Seite lädt. Wirklich ätzend

Naja was wollte ich dir schreiben?

Achja! Sind dir die anderen Beiträge aufgefallen? Toll oder? Nein nicht nur damit du mehr Gesellschaft hast. Ich dachte mir einfach, wenn ich irgendwelche tollen Skripte habe, welche ich ruhig einfach mal posten kann so mach ich das auch einfach.

Ja...ich sag doch das ist toll

Natürlich kann ich das nicht andauernd machen...zu mal ich auch seit heute morgen mega Kopf- und Nackenschmerzen habe. Dazu noch dieser verdammte Schnupfen...

Hast du eigentlich gewusst, das die Insider hier hin und wieder eine Challenge Veranstalten. Also eine Herausforderung meine ich. In was? Natürlich wird ein Spiel entwickelt. Überall auf der Welt finden solche kleinen Turniere statt und was dabei rauskommt ist manchmal wirklich verdammt cool.

Ich frage mich schon die ganze Zeit was das Thema der nächsten Challenge wird. Wie ich das mit dem Thema meine? Naja, irgendjemand setzt grobe Eigenschaften, welche die eingereichten Spiele, die sich für die Challenge anmelden erfüllen müssen. Soll es 2D oder 3D sein. Sollen bestimmte Skripte oder Assets verwendet werden. Oder soll eine zentrale Schlüsselfigur Bestandteil der Handlung sein. Es gibt viele Wege die Challenge möglichst spannend zu gestalten und für die Teilnehmer soll natürlich auch ein diverser Lohn bei rausspringen. Zum Beispiel diverse Schlüssel zum Freischalten von Spielen auf der Plattform Steam oder so. Schließlich muss man die Entwickler doch mit irgendwas locken. So wie die Maus mit dem Käse

Naja bis zum nächsten mal [b]Tabl[/b]


[font=courier new,courier,monospace]Post Rätsel: [/font][i]"[font=courier new,courier,monospace]Wer lebt von der Hand im Mund?"[/font][/i]

Nax

Nax

 

#2 Snippets - Internationalisierung

Heyho,

ich hab einbissl mit Internationalisierung herumgespielt und dabei ist folgendes rausgekommen

([url="https://gist.github.com/Naxmeify/8519ae9dde7857a26585"]Github Gist[/url])

Nehmen wir an, wir haben eine Datei für die englische Sprache:

[CODE]
#pragma strict

public class English {
public static var lang : Hashtable = {
// General
"game_name": "My Awesome Game"

// Menus
, "new_game" : "New Game"
, "save_game" : "Save Game"
, "load_game" : "Load Game"
, "quit_game" : "Quit Game"
, "end_game" : "End Game"
, "settings" : "Settings"

};
}
[/CODE]

Und erstellen nun auch eine Datei für die deutsche Sprache:

[CODE]
#pragma strict
public class German {
public static var lang : Hashtable = {
// General
"game_name": "Mein ehrfürchtiges Spiel"
// Menus
, "new_game" : "Neues Spiel"
, "save_game" : "Spiel speichern"
, "load_game" : "Spiel laden"
, "quit_game" : "Spiel verlassen"
, "end_game" : "Spiel beenden"
, "settings" : "Einstellungen"
};
}
[/CODE]

Und möchten nun die passende Übersetzung ganz einfach benutzen, z.B. so:

[CODE]
#pragma strict
function Start() {
Debug.Log(I18N.Get('game_name'));
}
[/CODE]

Dann brauchen wir was dahinter, das es uns einfach macht. Z.B. sowas:

[CODE]
#pragma strict
public class I18N {
private static var defaultLang : String = "en";
private static var gameLang : String = "";
private static var noTranslationText : String = "Translation missing for {0}";
private static var langs : Hashtable = {
"en": English.lang,
"de": German.lang
};
private static function CheckAndSetUserLanguage() : boolean {
switch(Application.systemLanguage) {
case SystemLanguage.Afrikaans: SetLang("af"); break;
case SystemLanguage.Arabic: SetLang("ar"); break;
case SystemLanguage.Basque: SetLang("eu"); break;
case SystemLanguage.Belarusian: SetLang("be"); break;
case SystemLanguage.Bulgarian: SetLang("bg"); break;
case SystemLanguage.Catalan: SetLang("ca"); break;
case SystemLanguage.Chinese: SetLang("zh"); break;
case SystemLanguage.Czech: SetLang("cs"); break;
case SystemLanguage.Danish: SetLang("da"); break;
case SystemLanguage.Dutch: SetLang("nl"); break;
case SystemLanguage.English: SetLang("en"); break;
case SystemLanguage.Estonian: SetLang("et"); break;
case SystemLanguage.Faroese: SetLang("fo"); break;
case SystemLanguage.Finnish: SetLang("fu"); break;
case SystemLanguage.French: SetLang("fr"); break;
case SystemLanguage.German: SetLang("de"); break;
case SystemLanguage.Greek: SetLang("el"); break;
case SystemLanguage.Hebrew: SetLang("he"); break;
case SystemLanguage.Icelandic: SetLang("is"); break;
case SystemLanguage.Indonesian: SetLang("id"); break;
case SystemLanguage.Italian: SetLang("it"); break;
case SystemLanguage.Japanese: SetLang("ja"); break;
case SystemLanguage.Korean: SetLang("ko"); break;
case SystemLanguage.Latvian: SetLang("lv"); break;
case SystemLanguage.Lithuanian: SetLang("lt"); break;
case SystemLanguage.Norwegian: SetLang("nn"); break; // TODO: Check
case SystemLanguage.Polish: SetLang("pl"); break;
case SystemLanguage.Portuguese: SetLang("pt"); break;
case SystemLanguage.Romanian: SetLang("ro"); break;
case SystemLanguage.Russian: SetLang("ru"); break;
case SystemLanguage.SerboCroatian: SetLang("sr"); break; // TODO: Check
case SystemLanguage.Slovak: SetLang("sk"); break;
case SystemLanguage.Slovenian: SetLang("sl"); break;
case SystemLanguage.Spanish: SetLang("es"); break;
case SystemLanguage.Swedish: SetLang("sv"); break;
case SystemLanguage.Thai: SetLang("th"); break;
case SystemLanguage.Turkish: SetLang("tr"); break;
case SystemLanguage.Ukrainian: SetLang("uk"); break;
case SystemLanguage.Vietnamese: SetLang("vi"); break;
case SystemLanguage.ChineseSimplified: SetLang("zh_Hans"); break;
case SystemLanguage.ChineseTraditional: SetLang("zh_Hant"); break;
case SystemLanguage.Unknown: SetLang(defaultLang); break; // Unknow Fallback to defaultLang
case SystemLanguage.Hungarian: SetLang("hu"); break;
};
if(gameLang.length > 0) {
return true;
}
return false;
}
public static function GetCurrentLang() : String {
CheckAndSetUserLanguage();
return gameLang;
}
public static function SetLang(lang:String) : void {
if(langs.ContainsKey(lang)) {
gameLang = lang;
} else {
gameLang = defaultLang;
}
}
/**
* Example use: I18N.Get("game_name") -> "My Awesome Game"
*/
public static function Get(key:String) : String {
return Get(key, {});
}
public static function Get(key:String, args:Hashtable) : String {
var lang : Hashtable = langs[GetCurrentLang()] as Hashtable;
var value : String = lang[key] as String;

if(value.length == 0) {
return String.Format(noTranslationText, key);
} else {
return StringManipulation.Format(value, args);
}
}
}
[/CODE]

Ich hoffe es gefällt euch - bis denne

Nax

Nax

 

#1 CharakterSkripte - CharacterStats

Jo hier möchte ich ein einfach Charakter Skript vorstellen. Dieses Skript kann dem Charakter (Spieler/Player bzw. FPSController/CharakterController) angefügt werden.

Das Skript soll Charakter Informationen festhalten und im Verlauf der Zeit auch aktualisieren. Ein Beispiel ist ein Ãœberlebensspiel (Survival Game), wie Rust oder Stranded Deep.

Halten wir fest, das wir folgende Status-Attribute steuern wollen:[list]
[*]Leben (Health)
[*]Hunger (Hunger)
[*]Durst (Thirst)
[*]Ausdauer (Stamina)
[/list]
Halten wir ebenfalls fest, das Hunger und Durst sich im Verlauf der Zeit reduzieren und Ausdauer durch Anstrengungen reduziert wird, wie z.B laufen oder springen.

Wir erstellen also ein neues Skript (JavaScript) und beginnen erstmal ganz stupide mit:

[CODE]
#pragma strict
[/CODE]

Super! Nun können wir unsere Attribute (Variablen) definieren (die vier o.g.) - wir wollen das diese auch Variable sind (nicht private):

[CODE]
// Health
var health : float = 1;
var healthFallRate : int = 150;

// Hunger
var hunger : float = 1;
var hungerFallRate : int = 150;

// Thirst
var thirst : float = 1;
var thirstFallRate : int = 100;

// Stamina
var stamina : float = 1;
var staminaFallRate : int = 35;
var staminaFallRateSwim : int = 60;
var staminaFallRateJump : int = 3;
[/CODE]

Sollte unser Charakter sterben, weil er kein Leben hat, muss entschieden werden, was danach passiert. Lassen wir doch einfach ein anderen Level laden (also eine andere Szene). Ganz einfach die "Start" Szene. Natürlich machen wir das als Attribute und Variable, damit man im Editor das noch anpassen kann.

[CODE]
// Level to Load if Character die
var characterDeathLevel : String = "Start";
[/CODE]

Die nun erwähnten Attribute halten wir fest, für die nächsten Blog Beiträge (#3 und #4):

[CODE]
private var characterMovCon: CharacterMovementCondition;
private var characterHeaCon: CharacterHealthCondition;
[/CODE]

[b]CharacterMovementCondition[/b] wird uns Informationen liefern, ob und wie sich unser Charakter gerade bewegt.
[b]CharacterHealthCondition[/b] gibt uns diverse Informationen über den Gesundheitlichen Zustand unseres Charakters.

Damit diese beiden deklarierten Variablen auch initiale Werte erhalten benutzen wir die Start Funktion (wir gehen davon aus, das die Komponenten am selben GameObject hängen):

[CODE]
function Start() {
characterMovCon = GetComponent(CharacterMovementCondition);
characterHeaCon = GetComponent(CharacterHealthCondition);
}
[/CODE]

Die Update Funktion nutzen wir zur stetigen Aktualisierung der Status-Attribute:

[CODE]
function Update() {
HealthControl();
HungerControl();
ThirstControl();
StaminaControl();
}
[/CODE]

Erstellen wir unsere Hilfsfunktionen bevor wir die Kontrolfunktionen definieren. Wir brauchen:[list]
[*]Eine Funktion zur Normalisierung unserer Attribute (Alle Status-Attribute sind niemals über 1 oder unter 0)
[*]Eine Funktion für die kontinuierliche Reduzierung eines Status-Attributes
[*]Eine Funktion, welche beim Tod die nächste Szene lädt
[/list]
[CODE]
function Normalize(min:int, max:int, value:float) {
value = value <= min ? min : value;
value = value >= max ? max : value;
return value;
}
function StatFall(stat:float, fallRate:int) {
if(stat >= 0) {
stat -= Time.deltaTime / fallRate;
}
return stat;
}
function CharacterDeath() {
Application.LoadLevel(characterDeathLevel);
}
[/CODE]

Und nun schreiben wir uns die dementsprechenden Kontrollfunktionen!

Als erstes Die Kontrollfunktion für das Leben. Wir wollen, das das Leben sich reduziert, wenn:[list]
[*]Der Charakter hungrig ist
[*]Der Charakter durstig ist
[*]Wenn hungrig und durstig, dann doppelt so schnell
[/list]
Sollte das Leben auf 0 sinken, ist der Charakter tot...

[CODE]
function HealthControl() {
if(hunger <= 0 && thirst <= 0) {
health -= Time.deltaTime / healthFallRate * 2;
} else {
if(hunger <= 0 || thirst <= 0) {
health -= Time.deltaTime / healthFallRate;
}
}
if(health <= 0) {
CharacterDeath();
}
}
[/CODE]

Geil! Nun wollen wir dafür sorgen, das der Charakter auch hungrig wird. Wir wollen das der Charakter kontinuierlich hungriger wird:

[CODE]
function HungerControl() {
hunger = StatFall(hunger, hungerFallRate);
hunger = Normalize(0, 1, hunger);
}
[/CODE]

Das selbe gilt natürlich für den Durst:

[CODE]
function ThirstControl() {
thirst = StatFall(thirst, thirstFallRate);
thirst = Normalize(0, 1, thirst);
}
[/CODE]

Bei der Ausdauer machen wir einwenig mehr. Wir wollen das der Charakter bei Anstrengungen seine Ausdauer reduziert bis diese Erschöpft ist. Nach muss er warten bis er genug Ausdauer hat, um seine Anstrengungen fortsetzen zu können. Wie z.B. laufen und springen.

Fassen wir zusammen:[list]
[*]Wenn der Charakter normal geht oder steht lädt sich seine Ausdauer auf
[*]Wenn der Charakter läuft wird seine Ausdauer reduziert
[*]Wenn der Charakter springt wird seine Ausdauer reduziert
[*]Wenn seine Ausdauer zu niedrig ist kann nicht laufen und auch nicht springen
[/list]
[CODE]
function StaminaControl() {
if(characterMovCon.isRunning) {
stamina -= Time.deltaTime / staminaFallRate;
} else if(characterMovCon.isSwimming) {
if(characterMovCon.isFastSwimming) {
stamina -= Time.deltaTime / staminaFallRateSwim * 2;
} else {
stamina -= Time.deltaTime / staminaFallRateSwim;
}
} else {
stamina += Time.deltaTime / staminaFallRate;
}
if(characterMovCon.isJumping) {
stamina -= Time.deltaTime / staminaFallRateJump;
while(characterMovCon.isJumping) {
yield WaitForSeconds(0.1);
}
//stamina -= Time.deltaTime / staminaFallRateJump;
}
if(stamina <= (Time.deltaTime / staminaFallRateJump)) {
characterMovCon.denyJumping();
} else {
characterMovCon.allowJumping();
}
if(stamina <= (Time.deltaTime / staminaFallRate)) {
characterMovCon.denyRunning();
} else {
characterMovCon.allowRunning();
}
stamina = Normalize(0, 1, stamina);
}
[/CODE]

Na wenn das mal nicht gut aussieht ;-)

Ich hab euch das Skript in den Anhang gelegt. Viel spaß damit, und natürlich viel spaß beim erweitern

Nächstes CharakterSkript wird CharacterStatsGUI - da visualisieren wir dann die Stats

Nax

Nax

 

#1 Snippets - Vorlagen Texte in Unity?

Jo hi,

ich hab ein kleines Snippet erstellt, um Vorlagen in Unity3D gerendert dazustellen. Mit "gerendert" meinte ich natürlich den Texte in seiner Endgültigen Version.

Beispielsweise haben wir einen Text in dem Platzhalter versteckt sind, so können mit dem normalen "String.Format" Platzhalter, Komma-Separiert angefügt werden. Beispiel:

[CODE]
var text = "Hallo {0}, wie geht es dir? Heute haben wir {1}. Wie geht es eigentlich {2}? Bis dann {0}.";
var result = String.Format(text, "Thomas", "Regen", "Julia");
// Result = "Hallo Thomas, wie geht es dir? Heute haben wir Regen. Wie geht es eigentlich Julia? Bis dann Thomas."
[/CODE]

Doch was wäre wenn wir sowas haben:

sometext:
[CODE]
Sehr geehrter Herr {0},
Wir haben mit dem Kaufvertrag vom {1} die Lieferung eines
{2} zum {3} fix vereinbart. Der Liefertermin
ist nun über {6} Tage verstrichen, aber Sie haben nicht geliefert.
Deshalb treten wir hiermit vom Kaufvertrag zurück und verzichten auch
auf eine spätere Lieferung.
Stattdessen mussten wir uns kurzfristig einen PKW-Anhänger leihen und
werden später bei einem anderen Lieferanten bestellen.
Die Kosten für die Ausleihe sowie eventuelle Mehrkosten für
die neue Beschaffung, werden wir Ihnen belasten.

Mit freundlichen Grüßen
{7}
[/CODE]

Man stelle sich vor, man hätte mehrere Lange Texte mit Variablen Inhalt, dann immer String.Format passend aufzurufen wäre verdammt nervig...besonders wenn man alle Parameter dafür zwar zu Hand hat, vielleicht sogar noch viele weitere, und dann muss man den entsprechenden Quellcode dafür schreiben. Meiner Meinung nach, viel zu viel.

Besser wäre da eine extrem einfache Vorlagen Lösung, die die passenden Stellen im Text identifiziert und aus einer Tabeller möglicher Variablen herausnimmt. Der Text könnte dann so aussehen:

[CODE]
Sehr geehrter Herr {spielername},
Wir haben mit dem Kaufvertrag vom {kauf_datum} die Lieferung eines
{produkt_genetiv} zum {liefer_datum} fix vereinbart. Der Liefertermin
ist nun über {tage_ueberfaellig} Tage verstrichen, aber Sie haben nicht geliefert.
Deshalb treten wir hiermit vom Kaufvertrag zurück und verzichten auch
auf eine spätere Lieferung.
Stattdessen mussten wir uns kurzfristig einen PKW-Anhänger leihen und
werden später bei einem anderen Lieferanten bestellen.
Die Kosten für die Ausleihe sowie eventuelle Mehrkosten für
die neue Beschaffung, werden wir Ihnen belasten.

Mit freundlichen Grüßen
{absender}
[/CODE]

Nun brauchen wir quasi nur noch eine Tabelle mit passenden Werten. Die könnte so aussehen:

[CODE]
{
"spielername": "Max",
"produkt_genetiv": "Autos",

"kauf_datum": "01.02.2015"
"liefer_datum": "11.02.2015",

"tage_ueberfaellig": "10",

"absender": "Horst Walter",

"id": "123123",
"produkt_id": "123123",
"blabla": "blub blub"
}
[/CODE]

Wenn ein Schlüssel nicht vorhanden ist, wird ein entsprechender Platzhalter Text hinterlegt und andere Schlüssel werden einfach Ignoriert.

Hier die Lösung für einfach String Manipulation ([url="https://gist.github.com/Naxmeify/899685a556a9f4a12ff4"]Github Gist[/url]):

[CODE]
#pragma strict
import System.Text.RegularExpressions;
public class StringManipulation {
private static var interpolate : String = "\\{(.+?)\\}";
/**
* Example use: StringManipulation.Format("{name} {weather}", {
"name": "Tom",
"weather": "Rain"
}); -> "Tom Rain"
*/
public static function Format(value:String, args:Hashtable) : String {
var match = Regex.Match(value, interpolate);
while(match.Success) {
var key : String = match.Groups[1].Value;
var replacement : String = args[key] as String;
if(replacement.length > 0) {
value = value.Replace(match.Value, replacement);
}
// Debug.Log("Value: "+value);
// Debug.Log("Key: "+key);
// Debug.Log("Replacement: "+replacement);
// Debug.Log("Match: " + match.Value + " Success: "+match.Success);
// Debug.Log("============================================");
match = match.NextMatch();
}
return value;
}
}
[/CODE]

Bis zum nächsten Snippet

Nax

Nax

 

#5 Tabl - Return of Nax

Heyho [b]Tabl[/b],

was geht? Wir haben uns ja schon ewig nicht mehr gesprochen. Ist alles klar bei dir? Schon fast 1 Jahr her unser letztes treffen oder?

Du glaubst nicht, was in diesem (fast) Jahr passiert ist . Neuer Job in anderer Firma. Unendlich viele Stunden nur Fehleranalyse und Debugging. Weg von GWT und Spring. Dafür Grails und Angular. Bei Unity unzählige Skripte geschrieben. Seit einer kurzen Weile Unity5. Seit einer weile entwickle ich selbst ein feines Spiel und das [url="https://github.com/Ninevillage/u3d"]U3D-CLI[/url] Tool ist schon richtig krass .

Das Tool unterstützt neben einfach starten und initialisieren nun auch das Bauen der Projekte. Wenn ich das Testen fertig habe, ist das eine saubere Grundlage für CI sowie Automatische Veröffentlichung, und der Asset Manager nimmt auch langsam aber stetig Form an .

Gerade arbeite ich noch einbissl an dem View für den Asset Manager, aber die Richtung in die das ganze laufen wird gefällt mir .

Achja, ich hatte erwähnt, das ich selbst seit einer Weile ein Spiel entwickle. Joa so langsam bin ich bei Unity gut dabei. Aber ich mache das nicht allein. Nein, nein. Meine Freundin als Grafikerin mischt gut mit und meine kleine Tochter hat unglaubliche Ideen. Hin und wieder glotze ich sogar Dokus mit ihr, um an diversen Stellen vom Spiel der Realität näher zu kommen. Worum es dabei geht? Nein, nein. Das verrate ich noch nicht . Achja, und wir haben noch jemanden im Boot. Jemand der sich verdammt gut mit 3D Modellen auskennt. Der macht wirklich Hammer Modelle .

Wirklich ein kleines gutes Team.

Bis dann [b]Tabl[/b]

[font=courier new,courier,monospace]Rätsel Post #3 Tabl war: [font=courier new,courier,monospace][i]"Welche Brille trägt man nicht auf der Nase?"[/i][/font][/font]
[font=courier new,courier,monospace]Die Antwort lautet: [i]"Die Klobrille[/i][/font][i]"[/i]

[font=courier new,courier,monospace]Rätsel Post #4 Tabl: [/font][i]"[i][font=courier new,courier,monospace]Welcher Fisch ist der höflichste?"[/font][/i][/i]
[font=courier new,courier,monospace]Die Antwort lautet: [/font][i]"[font=courier new,courier,monospace]Der Bückling"[/font][/i]

[font=courier new,courier,monospace]Post Rätsel: Welcher Stuhl hat keine Beine und kommt doch hoch hinaus?[/font]

Nax

Nax

 

2Fast2Curious Blender Exporter And Unity Prefab Generator

Schablagoo Ladies,

ich habe ja mich ewig lange darüber beschwert, dass ich die einzelnen UV-Maps meiner 3D-Modelle in Blender nicht per Hand exportieren will. Ich habe ca. 600 Objekte ... *hust*

Jedenfalls habe ich mal ein Script für Blender geschrieben. Damit kann man die UV-Maps automatisch exportieren lassen. Dabei werden die Bilddateien nach dem 3D-Modell benannt zu dem sie gehören. Also, das Objekt <Link-Wall-A-3> erstellt eine <Link-Wall-A-3.png> etc.

Blöderweise ist es nicht als Thread, da ich mich in Python 0 auskenne ... vielleicht kann einer von euch das mal erweitern. Und ihr müsst beim Export noch den "File Name" löschen ... es sollte nur der Pfad existieren. Ich wette, das ist in 10 Sekunden gelöst, aber wie gesagt ... 0 Ahnung von Python und die Doku für Blender ist ja mal lame².

Zusätzlich habe ich, auch mit Hilfe von Sasha, noch ein Script geschrieben, welches ihr einsetzen könnt, um aus euren (in Unity) importierten 3D-Modelle automatisch in Prefabs umwandeln zu lassen ... ihr müsst da den Pfad etc. anpassen, da ich hardcoded und ohne Abfragen gearbeitet habe. Der Prefab-Generator sucht nach Objekten mit einem speziellen Tag (glaub CreatePrefab) ... diese werden dann generiert ... keine Ahnung, ob er bestehende Überschreibt. Probiert's aus.

Also:
Blender -> Export All UV Maps
Unity -> 3D-Modelle -> Generate Prefabs

Die Blender Python Scripte müssen in den Blender scripts/addons Ordner und dann kann man unter "Export" den UV-Map export auswählen.

In Unity muss das Script in Assets/Editor und dann bekommt ihr ein neues Menü in der Leiste.

Have fun with this shit. EDIT: Da anscheinend alle meine Anhänge gelöscht worden sind, könnt ihr nur noch den Blender-Exporter herunterladen. Das andere (Unity Prefab-Generator) könnt ihr sogar selbst coden, ist nicht schwer: Link. BlenderUVExporter.py

Mr. Clown

Mr. Clown

 

[Video-Tutorial Deutsch] Unity UI: Dynamische Selection List erstellen

Inspiriert von der Frage von [url="http://forum.unity-community.de/topic/8980-selectionlist/"]Felix zu SelectionList[/url] habe ich eben mal ein kleines Video-Tutorial zu eben diesem Thema erstellt und freue mich über Feedback (und natürlich, wenn es dem Einen oder Anderen nützt):

[media]https://vimeo.com/115799172[/media]

Und das Beispielprojekt dazu (ist ein Unity-Package, kann man in ein beliebiges Projekt importieren, entpackt sich ins Verzeichnis "Examples"):

[url="https://dl.dropboxusercontent.com/u/27308128/NarayanaGames/UnityExamples/SelectionListExample.unitypackage"]SelectionListExample[/url]

Forum-Link: [url="http://forum.unity-community.de/topic/8987-tutorial-deutsch-unity-ui-dynamische-selection-list-erstellen/page__view__findpost__p__68652"][Tutorial Deutsch] Unity UI: Dynamische Selection List erstellen[/url]

jashan

jashan

 

Tada: Unity 4.6 mit dem neuen Unity UI (früher uGUI) ist jetzt released

[color=#666666][font=tahoma, helvetica, arial, sans-serif][size=3]Wir hatten zwar schon die Beta, was cool war ... aber auf diesen Tag habe glaube nicht nur ich seit ein paar Jahren gewartet (nicht, dass man deswegen untätig war, aber so wie warten auf Weihnachten ;-) ).[/size][/font][/color]

[url="http://unity3d.com/unity/whats-new"]http://unity3d.com/unity/whats-new[/url]

[url="http://blogs.unity3d.com/2014/11/26/4-6-is-released-with-source-for-ui-system/"]http://blogs.unity3d...-for-ui-system/[/url]

[color=#666666][font=tahoma, helvetica, arial, sans-serif][size=3]Jetzt ist Zeit zum Feiern!!! ;-)[/size][/font][/color]

[color=#666666][font=tahoma, helvetica, arial, sans-serif][size=3]Am coolsten finde ich ja ehrlich gestanden, dass Unity 5.0 beta 14 endlich wieder auf einem recht aktuellen Stand des neuen Unity UI ist ... aber trotzdem ein toller Tag, heute ;-) [/size][/font][/color]

jashan

jashan

 

Skriptkommunikation in Unity

Immer, wenn Unity Tech ein neues Tutorial raus bringt, habe ich das Bedürfnis, es anzugucken... um festzustellen, ob Käse erzählt wird. In der Vergangenheit hat man z.B. in der Scripting Reference immer wieder Beispiele gesehen, die einem einen Schauer über den Rücken gejagt haben.
Du brauchst eine Referenz auf ein Objekt? GameObject.Find. Oder FindWithTag. Autsch.
Warum, habe ich schon öfter erklären müssen, und die Hemmschwelle, das zu ignorieren, was von offizieller Seite kommt, ist oft hoch.

Heute bin ich auf ein neues Videotutorial der offiziellen Learn-Serie gestoßen: [url="http://unity3d.com/learn/tutorials/modules/beginner/live-training-archive/communicating-between-components-gameobjects"]http://unity3d.com/l...nts-gameobjects[/url]

Da ist eine Menge wachgerüttelt worden, schon bevor ich darauf klickte. Kommunikation zwischen Komponenten ist ein sehr zentrales Thema in Unity, und so oft man es braucht, so oft wird es auch missverstanden oder suboptimal bis falsch vermittelt.

Also Augen [s]zu[/s] auf und durch.
Und was sehe ich? FindGameObjectsWithTag. Juuhuuu. In meinem Kopf setzen sich Formulierungen für einen neuen Blogeintrag zusammen.
[img]http://board.bytezero.de/let-me-tell-you-why-thats.jpg[/img]

Aber vielleicht, so dachte ich, lehne ich mich heute einfach mal nicht so weit aus dem Fenster, bevor ich ein paar Messungen gemacht habe. Dinge über Strings zu finden klingt auf den zweiten Blick und mit Hashtables im Hinterkopf gar nicht mal soo abwegig.

Über GameObject.Find und FindWithTag schreibe ich heute einmal nicht. Diese Funktionen fallen für mich völlig aus der Wertung, weil sie schon in der theoretischen Anwendung bescheuert sind.

Heute geht es um den Hauptteil des besagten Tutorials, der sich mit folgendem beschäftigt:
[size=5]Wie finde ich alle Komponenten vom Typ T in meiner Szene?[/size]

Dazu habe ich mir eine Szene mit 4000 gleichartigen GameObjects erstellt. Diese haben den gleichen Tag und außerdem alle ein Script vom Typ "Something".

Ich möchte in Start() oder Update() Referenzen auf alle diese GameObjects bzw. Komponenten vom Typ Something haben. Herangehensweisen dafür:[list=1]
[*]FindGameObjectsWithTag
[*]FindGameObjectsWithTag mit GetComponent<T> (um die Komponente direkt zu referenzieren)
[*]In Something.Awake eine List<T> befüllen
[*]FindObjectsOfType<T>
[*]FindObjectsOfType(typeof(T)) as T[]
[/list]
Da wir hier Variablen initialisieren, gehört der jeweilige Code im Zweifelsfall klassischerweise in Awake(). Allerdings gibt es erstaunliche Ergebnisse, wenn man ihn in Start() ausführt, aber lest selbst...

Die Werte, die gleich folgen, sind "Ticks". Die Messergebnisse waren auch bei 4000 Objekten (mehr wurde im Editor anstrengend) zu klein für Millisekunden-Angaben.
[b]In Klammern dahinter sind die Ergebnisse für das Gleiche mit nur 3 GameObjects.[/b]


[size=5]1. FindGameObjectsWithTag[/size]
Ich bin kein großer Fan von Tags, [s]da sie dazu verleiten, jegliche Identifikation darüber laufen zu lassen und sich dann zu wundern, wie man 33 verschiedene Arten von Objekten unterscheiden soll.[/s] Inzwischen gibt es offenbar beliebig viele Tags. Trotzdem sind Tags aus verschiedenen Gründen nicht ganz so toll. Wenn es dich interessiert, frag mich gerne

Für wirklich häufig vorkommende Objektsorten wie eben Player, Respawn oder Finish sind Tags aber zumindest von der Idee her vertretbar. Wie sieht es mit der Performance aus?

Der Code:
[CODE]
var sw = new Stopwatch();
sw.Start();
var gos = GameObject.FindGameObjectsWithTag("Respawn");
sw.Stop();
print(sw.Elapsed);
[/CODE]
Das Ergebnis:
[b]In Awake: 10533 (1360)[/b]
[b]In Start: 4065 (1703)[/b]

Zwischenfazit: Offenbar legt Unity zwischen Awake und Start Strukturen an, die FindGameObjectsWithTag bei vielen Objekten beschleunigen. Verrückt!


[size=5]2. FindGameObjectsWithTag mit GetComponent<T>[/size]
Wir wollen in den meisten Fällen direkt die Referenzen auf die Komponenten haben, da wir ja mit denen arbeiten und nicht mit dem GameObject. Diese sollten wir jetzt besorgen und speichern, sonst heißt es im Zweifelsfall in Update GetComponent<T>, und das muss ja nicht sein

Der Code:
[CODE]
var sw = new Stopwatch();
sw.Start();
var gos = GameObject.FindGameObjectsWithTag("Respawn");
var things = new Something[gos.Length];
for(int i = 0; i < gos.Length; ++i)
{
things[i] = gos[i].GetComponent<Something>();
}
sw.Stop();
print(sw.Elapsed);
[/CODE]
Das Ergebnis:
[b]In Awake: 73343 (3540)[/b]
[b]In Start: 69558 (3050)[/b]

Zwischenfazit: Mit GetComponent<T> legt diese Variante ordentlich zu. Je mehr Objekte man hat, desto öfter wird GetComponent<T> aufgerufen und das dauert.
Getestet habe ich auch mit LINQ. Das dauert länger, insbesondere bei wenigen Objekten (10849 in Awake für 3 GOs!), da ein Umwandeln durch ToList() und, will man am Ende wieder ein Array haben, danach ein Zurückwandeln mit ToArray() nötig ist. Und das kostet konstant eine Menge Zeit.


[size=5]3. Eine List<T> in T.Awake befüllen[/size]
So habe ich das bisher immer gemacht. Ich halte es für elegant, dass die Menge aller Komponenten T auch in der Klasse T angelegt und verwaltet wird. Aber wie sieht's mit der Performance aus?

Der Code:
[CODE]
private static Stopwatch sw = new Stopwatch();
public static List<Something> all = new List<Something>();

void Awake()
{
if(all.Count == 0) sw.Start();
all.Add(this);
if(all.Count == 4000)
{
Finder.sw.Stop();
print(sw.Elapsed);
}
}
[/CODE]
Das Ergebnis:
[b]29928 (975)[/b]

Zwischenfazit: Diese Variante ist offenbar durchaus schneller. Zumindest, wenn man Anspruch darauf hat, die Referenzen auf die Komponente zu haben, und nicht auf die GameObjects.
Bei wenigen GameObjects allerdings ist diese Methode soweit die beste.

[size=5]4. FindObjectsOfType<T>[/size]
Auf diese Idee bin ich erst durch das Tutorial gekommen. Einfach mal ausprobieren!

Der Code:
[CODE]
var sw = new Stopwatch();
sw.Start();
things = FindObjectsOfType<Something>();
sw.Stop();
print(sw.Elapsed);
[/CODE]
Das Ergebnis:
[b]In Awake: 49376 (5184)[/b]
[b]In Start: 62903 (4657)[/b]

Zwischenfazit: Gar nicht mal schlecht! Diese Variante ist etwas langsamer als Variante 3, besonders bei wenigen GameObjects. Sie hat allerdings noch einen dicken Haken, aber auf den gehe ich im nächsten Zwischenfazit ein.

[size=5]5. FindObjectsOfType(typeof(T)) as T[][/size]
Das Tutorial benutzt diese Variante der Methode... ich hätte zwar gedacht, dass die generische Variante schneller ist, aber trotzdem habe ich es einfach mal ausprobiert.

Der Code:
[CODE]
var sw = new Stopwatch();
sw.Start();
things = FindObjectsOfType(typeof(Something)) as Something[];
sw.Stop();
print(sw.Elapsed);
[/CODE]
Das Ergebnis:
[b]In Awake: 31080 (2536)[/b]
[b]In Start: 28986 (2226)[/b]

Zwischenfazit: Verrückt, diese Variante ist tatsächlich schneller als die generische.
Aber zu dem erwähnten Problem: FindObjectsOfType kommt für mich als Lösung nicht wirklich in Frage, da man es dort benutzen muss, wo man die Objekte braucht, nicht dort, wo die Objekte sind.
Braucht man die Liste aller Komponenten also an mehreren Stellen, muss man FindObjectsOfType auch mehrere Male aufrufen. Einzige Alternative ist ein "T-Manager", der alle Komponenten vom Typ T verwaltet und für andere zur Verfürgung stelle. Und das ist alles andere als lose Kopplung. Bäh.

[size=5]Endfazit[/size]
Die ganzen Messergebnisse sind hier so klein, dass sie kaum wichtig erscheinen. Und ja, auf einem guten Computer ist FindGameObjectsWithTag vielleicht gar nicht mal soo problematisch.
Jedoch soll vielleicht auch das Spiel auf Android exportiert werden, und die Zielgruppe dort ist nicht bekannt dafür, besonders geduldig zu sein
Außerdem gilt nach wie vor meine Kritik an Tags und, wer aufmerksam gelesen hat und sich ein wenig auskennt, mag bemerkt haben, dass meine Kritik an FindObjectsOfType auch für FindGameObjectsWithTag gelten muss: Haben mehrere Scripts Interesse an z.B. allen Spawns, wird's haarig.
Der einzige saubere Weg ist imo der, die Menge aller Komponenten T in der Klasse T selbst aufzubewahren. Und das geht mit Variante 3.

Ein schöner Umstand, dass diese Vorgehensweise auch gleichzeitig die performanteste zu sein scheint.

Sascha

Sascha

 

GUISystem Tagebuch #1

Hallo,

ich habe angefangen eigenes GUI System zu schreiben. Ich wollte vieles automatisieren und erleichtern. Kleines Beispiel. Ich möchte nicht jedes mal selbst rechnen, um alles zu zentrieren oder ich möchte nicht so viele if Bedingungen mit Buttons haben.

Darum habe ich ein Anlass gehabt um sowas zu machen um dann für meine Projekte das zu verwenden.

Ein Bespiel. Ich redete von Buttons.
So sieht das aus zur Zeit aus

[img]http://puu.sh/aUU8U/b74342c5d5.png[/img]
(Menü-Skripte)

[img]http://puu.sh/aURfV/7a1bc7cfe9.jpg[/img]

Kleines Beispiel mit einem Video
[url="http://garrysmod.zulu907.server4you.de/sharex/imgs/2014-08-16_15-57-01.mp4"]http://garrysmod.zul...16_15-57-01.mp4[/url]

Aufgebaut ist dieser Code nur so (Der Rest kommt vom GUISystem selbst):

[img]http://puu.sh/aURwB/c93243a057.png[/img]

[color=#0000ff]CreateVerticalButtons(bool center, float space, Rect r, params string[] buttons)[/color]

Wie man hier sieht erstelle ich hier automatisch Buttons durch eine Funktion. 3 Items Play, Option, Und Quit wurde erstellt.
Sie alle geben ein ID zurück wenn was geklickt wurde. Ansonsten ist es immer -1.

Außerdem lasse ich mit Open oder Close die Menüs anzeigen oder verstecken.

So wenn ich in Option Menü bin.


[img]http://puu.sh/aUTPg/037c4ed754.png[/img]

Schaut euch die markierte Zeile an. Ein Extension erlaubt mir die Rect-Klasse mit Methoden zu erweitern. Und das schöne ist halt, dass ich jedes mal mit einem "." eine weitere Methode dranhängen kann. Ich zentriere es vertical und lasse es dann nach unten Andocken. Da ich aber sage -10f hoch (man muss das als Ursprungspunkt beachten, darum - 10 hoch) wirds etwas nach oben verschoben.

Man kann es getrennt schreiben aber zur Zeit hab ich damit ein Bug. Lösung wird gesucht.

Ergebnis:

[img]http://puu.sh/aUTYr/15e3596847.jpg[/img]

Schön oder?

Schlusssatz. Ein bissel Zeit sollte man schon opfern, bevor man das eigentliche Anfängt

(Da das eine Anfangsphase ist, kann es natürlich in den nächsten Blogeinträgen zu Veränderungen kommen bzw. kann bereits in den Screenshots eine Abweichungen vorhanden sein..).

NACHTRAG: Besseres Video
[url="http://garrysmod.zulu907.server4you.de/sharex/imgs/2014-08-16_16-53-32.mp4"]http://garrysmod.zulu907.server4you.de/sharex/imgs/2014-08-16_16-53-32.mp4[/url]

MaZy

MaZy

 

Nervig! Der Nullpunkt ist nicht in der Mitte vom Model. Lösung!

Ich hatte mal lust ein "Demo" zu machen, wo man einfach mit ner Flugzeug rumfliegen kann. Ich habe dazu einen kostenlosen Flugzeugmodel runtergeladen.

Ich habe aber gemerkt, dass viele Nullpunkte nicht mittig sind. Sie sind sogar manchmal außerhalb. Zum Beispiel: Die Turbinen können nicht rotiert werden. Warum? Da der Nullpunkt nicht in der Mitte sind könnte sie falsch rotiert werden oder in einer Eierorbit oder so.

Jetzt könnte ich das Problem lösen, in dem ich neues GameObject nehme und sie dann in die Mitte schiebe. Und dann schiebe ich die Turbine in das GameObject. Sagen wir es heißt TurbinenRotierer. Jetzt sagen wir mal ich habe, aber 10-100 kleine Models die sowas benötigen. Man hätte kein bock darauf alles zu machen. Tatsächlich war es wirklich so, dass da jede Menge dinge waren die mich gestört haben. Also habe ich einen kleinen Script geschrieben.

[b]Collider [/b]und [b]Renderer [/b]haben eine coole Funktionen die sich [b]Bounds [/b]nennt. Dadurch kann man nämlich die Mitte herauskriegen in dem man [b]center [/b]benutzt. Und die habe ich genutzt.

[CODE]
void RotateCenter(GameObject rotatingObject, Vector3 eulerAngle) {
if(!rotatingObject.renderer) {
return;
}

GameObject theRotator = GameObject.Find("Center_" + rotatingObject.gameObject.name);

if(!theRotator) {
theRotator = new GameObject();
theRotator.name = "Center_" + rotatingObject.name;
theRotator.transform.position = rotatingObject.renderer.bounds.center;
theRotator.transform.parent = rotatingObject.transform.parent;
rotatingObject.transform.parent = theRotator.transform;
}

theRotator.transform.Rotate(eulerAngle);
}
[/CODE]

Hier rufe ich einfach die Methode [b]RotateCenter [/b]aufund gibt an welchen GameObject man rotieren will und dazu die eulerAngle , um die Turbinen zu rotieren. Also funktioniert eigentlich wie Rotate(). Der Script lässt einfach einen GameObject erstellen falls es noch nicht existiert und benennt sie um und parented das auch um.

[CODE]
RotateCenter(TurbineLeft,new Vector3(0,0,-throttle));
RotateCenter(TurbineRight,new Vector3(0,0,throttle));
[/CODE]

Joa das wars erst mal

[b]NACHTRAG (13.08.2014):[/b]
[b]NACHTRAG #2:[/b] Paar Fehler behoben.

Ein Hinweis von Sascha. Man kann das natürlich als Extension machen.
Ein Beispiel wie es es aussehen könnte[CODE]
using UnityEngine;
using System.Collections;
// Das hier sollte static sein.
public static class TransformExtensions {

/*
Was tut sie?
Wenn ein Model mal nicht mittig ist, kann man die Funktion verwenden.
Im Endeffekt wird ein Hilfsobjekt erstellt und zentriert. Das alte Objekt wird dann zu ihm parented.
Danach rotieren wir eigentlich nur den Hilfsobjekt. Je nach Situation kann das behilflich sein.
*/
public static void RotateCenter(this Transform t, Vector3 eulerAngle) {

// Hat as render (mesh?)
if(!t.renderer) {
// Wenn nicht, abbrechen.
return;
}

// Den "Hilfsobjekt" bzw. den "Drehobjekt" ermitteln
GameObject theRotator = GameObject.Find("Center_" + t.gameObject.name);

// Existiert dieses Hilfsobjekt?
if(!theRotator) {

// Wenn nein dann erstellen wir sie.
theRotator = new GameObject();
theRotator.name = "Center_" + t.name;

// Ermittle die Mitte
theRotator.transform.position = t.renderer.bounds.center;

// Diesen Objekt den gleichen Parent zuweisen
theRotator.transform.parent = t.transform.parent;

// Nun den alten Objekt parent durch "Hilfsobjekt" zuweisen.
t.transform.parent = theRotator.transform;

}

// schließlich den Rotor drehen.
theRotator.transform.Rotate(eulerAngle);
}

}
[/CODE]
Nun sollte man sie so verwenden können: transform.RotateCenter(new Vector3(0,0,1));
Hab leider jetzt nicht testen können, aber sollte eigentlich funktionieren.

MaZy

MaZy

 

Toleranz und Akzeptanz

Toleranz und Akzeptanz

Beides überzeugt mich nicht ganz. Ich möchte das an einem kleinen Beispiel demonstrieren.

Wir leben in einer Demokratie, in der es auch erlaubt ist eine andere Meinung zu haben. Somit sind unterschiedliche Gruppierungen vorprogrammiert. Als Beispiel nutze ich die Nazis und die Kommunisten hier im Land. Also die Neonazis und die Antifa. Beide behindert.

Mein Problem liegt darin: Ich toleriere beide Gruppierungen, weil wir eben jedem das Recht auf eigene Meinung geben. So wurde auch neulich vor einem Gericht entschieden, dass der Hitler-Gruß keine Hetze oder sowas ist, sondern die Bekundung zu der eigenen Gesinnung und somit nicht unter Strafe fällt. Mir egal ... wenn das den Leuten gefällt. Okay ... toleriere das. Aber ...

Wenn ich diese Gruppierungen toleriere mit all' den Rechten und Pflichten, die durch unsere Demokratur damit ermöglicht werden, so sollte ich mich doch nicht aufregen, wenn irgendwann ein Mal die Kommunisten oder die Nazis im Bundestag sitzen, oder?

Was bedeutet das denn, wenn sie in den Bundestag kommen? Naja ... Verfolgungen, Deskriminierung ... das Standardprogramm von Radikalen eben. Werde ich das akzeptieren? Wohl kaum. Aber da stellt sich doch dann die Frage, ob die Toleranz dann nicht auch Heuchelei ist.

Wenn ich die Gruppierungen toleriere und ihnen alle Rechte eingestehe, die auch die anderen erhalten ... und mich dann bei einem Wahlsieg einer solchen Gruppierung doch aufrege und diese nicht akzeptiere ... welchen Wert hat dann die Toleranz? Das ist so als ob ich sagen würde: Yo, geh' ruhig wählen, solange du mich wählst. Vor Gott sind wir alle gleich, aber der Papst ist etwas gleicher ... wichtiger. Für mich ist beides in Bezug auf handfeste Sachen nicht mit einander vertretbar. Für mich ist die Toleranz nur eine aufgeschobene Entscheidung über die Akzeptanz. (Das ist ein supergeiler Satz ... muss ich mir merken.)

Bei rein ideellen Sachen, die niemals bewiesen oder widerlegt werden können, kann man das ja noch nachvollziehen ... aber eben weil da nie eine Entscheidung anstehen wird. Z.B.: StarTrek vs. StarWars. Aber sobald es eine physikalische Manifestation geben kann ... so wird es auf einen Konflikt, auf eine Entscheidung hinauslaufen. Beispielhaft erwähne ich hier die Ziele der Bündnis90 damals Kindersex zu legalisieren ... niemals in meinem Leben werde ich das zulassen. Hier wird es auch nicht toleriert ... ihr seht ... diese aufgeschobene Entscheidung wurde sofort gefällt.

Was sagt ihr dazu? Ich werde alle Antworten tolerieren.

Ps, diese und andere Themen beschäftigen mich ... aber normalerweise schreibe ich nicht darüber, weil ich nicht weiß wie ... aber kommt demnächst öfters ... da mein MakeAGame momentan wegen der Abschlussarbeit arg vernachlässigt wird. Ich will unbedingt etwas zu dem Ukraine-Konflikt schreiben etc.. Die aktuelle Toleranzfrage hatte ich, als ich die GameChallenge#5 betrachtet hatte ... ich will versuchen ein Spiel auf dieser Thematik aufzubauen ... mal sehen ob das klappt. Wohl eher nicht.

Mr. Clown

Mr. Clown

 

Unbedingt lesen!: GUI positionieren, oder programmieren? Natürlich positionieren!

Hallo,

ihr kennt das bestimmt. Man hatte eine Vorstellung wohin dieser Button hin soll. Dann programmieren wir es und setzen die Werte ein. Doch dann passt es nicht. Oder man will es doch etwas verschieben. Jedoch kann es auf dauer nervig sein. Was tun wir da? Natürlich! Wir setzen alle Variablen Public damit wir nicht immer die Datei verändern brauchen.

Doch, was, wenn da eine bessere Methode gibt? Wo man überhaupt keine Zahlen eintragen muss? Genau! Du hast es erfasst. Wir nehmen einfach ein GameObject .

GameObjects liefern einige Informationen um so etwas zu realisieren. Wir können sie verschieben, skalieren und rotieren. Doch lass mal erst überlegen wie wir vor gehen wollen.
Bestimmt habt ihr schon mal gewollt, dass die Position des Mauses in Weltkoordination angegeben wird. Und das tut man in dem man mit Hilfe von Kamera sie berechnen lässt. Das können wir auch für die GUIs verwenden. Jedoch andersherum. Wir nehmen die Weltkoordinaten um dann daraus Screenkoordinaten zu machen. So da ich euch dies angedeutet habe nun ein bissel Code.

[CODE]
public class IngameElements : MonoBehaviour {
public Transform restartButton;
private Rect restartButtonRect;

void Start() {
if(restartButton != null) {
// Die Screenkoordinaten herauskriegen
Vector3 restartButtonWorld = Camera.main.WorldToScreenPoint (new Vector3(restartButton.position.x,
-restartButton.position.y,
restartButton.position.z));

// Die Screenkoordinaten verwenden um neuen Rect zu erstellen. Wir benutzen den localscale als breite und länge.
restartButtonRect = new Rect (restartButtonWorld.x,
restartButtonWorld.y,
restartButton.localScale.x,
restartButton.localScale.y);
}
}

// Nun "malen" wir es in OnGUI
void OnGUI () {
if (GUI.Button (restartButtonRect, "Restart Game")) {
RestartGame();
}
}
}
[/CODE]

Jetzt müsst ihr nur noch ein Gameobjects erstellen und zuweisen. Fertig.
Am Besten macht ihr es präziser.
--InGameMenu
---Panel(Bsp: Obenrechts)
----RestartButton
----SoundToggleButton

Damit könnt ihr die Gruppen besser an- und ausschalten oder verschieben usw.

Jetzt kann man dies noch mit einer Funktion erweitern, so dass er nicht immer alles schreiben musst. Oder am besten nen Library, aber ich belasse simpel bei dem selben Beispiel:
[CODE]
public class IngameElements : MonoBehaviour {
public Transform restartButton;
public Transform exitGameButton;

void OnGUI () {
if (DrawButton("Restart Game", restartButton) {
RestartGame();
}

if (DrawButton("Exit Game", exitGameButton) {
ExitGame();
}
}

bool DrawButton(string name, Transform t) {
return GUI.Button(transfomElementToScreen(t), name);
}

Rect transformElementToScreen(Transform t) {
Vector3 world = Camera.main.WorldToScreenPoint (new Vector3(t.position.x, -t.position.y, t.position.z));
return new Rect (restartButtonWorld.x, restartButtonWorld.y, restartButton.localScale.x, restartButton.localScale.y);
}
}
[/CODE]

Probiert es aus und liiiiiiiiiiiiiiiiken

MaZy

MaZy

 

#4 Tabl - Pure Stress

Hi [b]Tabl[/b],

sorry das ich dich nicht regelmäßig aufsuchen kann. Leider werde ich andauernd mit irgendwelchen Anfragen oder Aufträgen abgelenkt. Was man nicht alles für sein täglich Brot tut.[list]
[*]Webseiten bauen
[*]Webseiten aktualisieren
[*]Shop Plattformen konfigurieren
[*]Java Applikationen zur Steuerung und Auswertung von Produktionslinien
[*]Java Web Applikationen usw. usw.
[/list]
Tja, und dann muss ich auch noch an einem anderen Projekt schrauben, was das Zeug hält. So im Bereich e-commerce over all.
Natürlich versuche ich meine Zeit für Unity zu finden, aber leider verlangt auch mein Körper regelmäßig nach Erholung.

Bisher kam ich auch nicht dazu am u3dam weiterzumachen.

[b]Tja, wo sind denn die guten Neuigkeiten? [/b]

Mein Team wächst. Neben einer Grafikerin kam noch ein weiterer Programmierer dazu.
Vielleicht ist das der moment, wo ich das Projekt "dc" erwähnen sollte.

[b]Was das ist?[/b]

Die Erwähnung an dieser Stelle muss reichen. Mehr Informationen gibt es zu einem anderen Zeitpunkt.

Bis denn [b]Tabl[/b]

[i][font=courier new,courier,monospace]Post Rätsel: Welcher Fisch ist der höflichste[/font][/i]

Nax

Nax

 

#3 Tabl - The Riddler?

Hi [b]Tabl[/b],

mir ist aufgefallen das du ja eigentlich noch kein richtiges [b]Tabl [/b]für mich bist. Was aber eher daran liegt, das ich verdammt noch mal schwer beschäftigt bin.

[b]Wieso ich dir das sage?[/b]

Du Witzbold. Ich versuche mich dir zu öffnen...
Jedenfalls denke ich das wir einen guten Weg zusammen einschlagen. Mir ist ja besonders aufgefallen, das hier wirklich wenig los ist. Zu mindestens im Blog Bereich dieser Community.

[b]Hast du eigentlich in letzter Zeit mal in mein GitHub Profil geschaut?[/b]

Nicht? Ich bin ja in letzter Zeit dabei, fast alles was ich so nebenher mache, dort irgendwie zu hinterlegen. Sehr vieles auch unter MIT Lizenzen, damit das jedermann nutzen kann, ohne sich da Gedanken machen zu müssen, ob er es darf.

[center][img]http://www.inqbation.com/wp-content/uploads/2014/02/github-logo1.png[/img][/center]


[b]Was ich da so hinterlege?[/b]

Zum Beispiel meine Idee von einem Unity3D Assets Manager (u3dam). Nach dem ich die Möglichkeiten der Kommandozeilen Befehle von Unity geprüft habe, wäre ein solches Tool bestimmt sinnvoll.
Falls du es verfolgen möchtest. Schau hier: [url="https://github.com/Naxmeify/u3dam"]u3dam[/url]
Bisher sollte dieser aber noch nicht benutzt werden, da dieser noch voll in der Entwicklung steckt.

[b]Wieso der Titel vom Beitrag "The Riddler" heisst?[/b]

Ist es dir und den (evtl. vorhandenen) Lesern nicht aufgefallen, das Ende meiner Beiträge ein "Post Rätsel" dabei ist? Keine Ahnung...ich finde es witzig. Hast du versucht mal die Rätsel zu lösen [b]Tabl[/b]? Nicht? Also gut. Dann verrate ich dir mal die Lösung der letzten beiden Beiträge:

[i]Rätsel aus Beitrag #1 [b]Tabl [/b]war: "Wer reist ständig kostenlos um die Welt?"[/i]
[i]Die Antwortet lautet:[/i] "[i]Der Mond oder Objekte, welche im Orbit der Erde kreisen."[/i]

[i]Rätsel [/i][i]aus Beitrag #2 [b]Tabl [/b]war: "Loch an Loch und hält doch."[/i]
[i]Die Antwortet lautet: "Eine Kette."[/i]

War doch gar nicht so schwer oder?
Bis dann [b]Tabl[/b]

[font=courier new,courier,monospace][i]Post Rätsel: "Welche Brille trägt man nicht auf der Nase?"[/i][/font]

Nax

Nax

 

#2 Tabl - Where do I begin?

Hi [b]Tabl[/b],

ich hab gerade überlegt, mit was ich in diesem Blog anfangen soll bzw. ob ich mir einpaar kleine Ziele setzen sollte. Was würdest du davon halten, wenn ich einfach versuche ein bisschen was beizutragen?

[b]Was ich meine?[/b]

Zum Beispiel könnte kleine Geschichten entwerfen, welche genutzt werden dürfen für die Videospiele, welche die Leute hier entwickeln. Zum Beispiel so eine Science Fiction Geschichte oder eine Post Apokalyptische Begebenheit.

Oder ich erstelle eine Kategorie zu dem Thema "Erweitertes Unity Package Management", wo ich doch sowieso gerade heimlich an einem Package Manager arbeite der funktionieren soll, wie der "Node Package Manager".

Oder ich präsentiere meine Resultate zum Testen von Unity Projekten mittels Testing Tools, UnitTesting und Continuous Integration. Ich denke wenn ich eine Möglichkeit finde sehr einfach Travis, Jenkins oder TeamCity einzubinden, wäre das verdammt genial. Besonders dann, wenn man sogar damit deployen könnte.
Verstehst du wovon ich spreche?

[center][img]https://raw.githubusercontent.com/Naxmeify/unity-insider-resources/master/blog/tabl/testingworkflow.png[/img][/center]

[b]Natürlich kann man das ganze noch weiter denken Tabl![/b]

Aber ich selbst bin erst seit einpaar Wochen dabei und vieles was noch Unbekannt ist kommt erst nach und nach ans Licht.

Bis denn [b]Tabl[/b]

[font=courier new,courier,monospace][b][i]Post Rätsel: "Loch an Loch und hält doch?"[/i][/b][/font]

Nax

Nax

 

#1 Tabl - Who am I?

Hi [b]Tabl[/b],

schön dich zu sehen. Ich will dir ein bisschen was von mir erzählen.


[center][img]https://yt3.ggpht.com/-tftNEjUGBAU/AAAAAAAAAAI/AAAAAAAAAAA/GXZpt1smJQk/s100-c-k-no/photo.jpg[/img][/center]

Meine Name ist Matt auch bekannt als Nax. Für dich Nax. Ich bin 28 Jahre alt (seit gestern...damit sollte meine Geburtsdatum bekannt sein...) und habe diverse Schwierigkeiten damit dir einfach zu sagen was mein Beruf ist.
Ich könnte nun mehrere Berufsbezeichnungen aufzählen, aber ich glaube die beste Bezeichnung lautet: "Träumer".
Ich hoffe du nimmst mich nun ernst und amüsierst dich nicht heimlich auf meine Kosten, wobei mir das wohl dann ziemlich egal wär. Mir gefällt es ein Träumer zu sein!

Kommen wir zurück zu mir, bzw. was ich dir noch von mir erzählen möchte. Ich erwähnte mehrere Berufsbezeichnungen. Zum Beispiel bin ich Programmierer.
Ich habe es vor vielen Jahren gelernt. Damals als ich noch zur Schule ging. Ich glaube es begann in der 8. Klasse. Später dann auf einer Schule, wo man Informatik gelernt hat und noch viel später dann in einer Uni. Angewandte Informatik vor einpaar Jahren und aktuell Medieninformatik über ein Online Studium.

Ach ja, ich arbeite auch als Programmierer bei einer Firma, die primär Java Web Applikationen für die Automobil-Industrie erstellt. Da muss ich mich mit Sachen prügeln, die man GWT oder Spring nennt.
Ach ja, und ich bin auch selbstständig. Das ist sowas wie mein Hobby. Ich entwickle Mobile Applikationen und Web Applikationen mit Technologien, wie JavaScript, Ruby oder PHP. Primär eigentlich nur JavaScript. Mit so Anwendungen wie Node.js oder PhoneGap.
Ob ich auch native Applikationen entwickle? Natürlich. Ich kenne mich sehr gut mit iOS zum Beispiel aus. Oder mit der Entwicklung von Desktop Applikation mit C++ oder .Net (C# oder Basic). Ach ja und natürlich auch OSX via Objective-C ist kein Problem.

[b]Haha. Wieso ich dich nun voll stopfe? Weil du ein Tabl bei den Unity Insider bist?[/b]

Nun ja. Ich bin schon seit einer Weile dabei mich mit Unity zu beschäftigen. Als ich damals entschied Software zu Entwickeln wollte ich dies, weil ich fasziniert von Videospielen war. Ich wollte selbst Videospiele entwickeln. Spiele, wie Zelda oder Final Fantasy haben mein Leben sehr stark beeinflusst. Personen, wie Shigeru Miyamoto oder Hironobu Sakaguchi waren meine großen Vorbilder.

Du wirst dich bestimmt fragen, was das nun alles soll?

[size=5][b][font=comic sans ms,cursive]Einfach so![/font][/b][/size]

Bis später Tabl

[font=courier new,courier,monospace][b][i]Post Rätsel: "Wer reist ständig kostenlos um die Welt?"[/i][/b][/font]

Nax

Nax

 

AMT4 Update

Der AMT4 verfügt nun neben der Ionenkanone die mit am PlasmaImplusionsgenerator hängt auch über ein einzieh Fahrwerk...[img]http://ahteris.syrka.net/spacer/amt4-2.jpg[/img]
[img]http://ahteris.syrka.net/spacer/amt4-1.jpg[/img]

Ahteris

Ahteris

×