Archive

Archive for the ‘Uncategorized’ Category

Unity3d :: UML :: Transform visualization cheat sheet

May 22nd, 2011 Michael Schmalle No comments

Hi,

Here is a detailed UML class diagram of the Transform API for Unity 3D.

Coming from an ActionScript – Flash background, this class stumped me for a bit until I really started looking into the api docs and realizing that GameObject is just a container for composite instances such as the Transform class. The Transform instance is accessed through the GameObject.transform instance property as well as a couple other ways with methods like GameObject.GetComponent().

In ActionScript, the UIComponent owns, measures, lays out and renders the display object children (although UIComponent is abstract for measurement and layout). In a sense, the UIComponent is the Transform as well as a million other things. Have you seen how many lines of code UIComponent has in Flex 4? :)

What Unity3D does is composite all the features such as transform into the class. Adobe should take note, this is a much cleaner design since having the composite instances create any easy interface for each section the GameObject contains. There are clear boundaries between functionality.

As we can see in the UML, the Transform class deals with it’s own position, scale and rotation and also has the duty of containing other Transform children. In the whole design pattern area this is called the composite pattern. The composite is a tree of instances that share the same api (interface).

Basically the action duties of the Transform class include;

  • Addition and removal of children
  • Child queries
  • Translation (position) transform
  • Rotational (rotation) transform

The Transform class makes heavy use of the following;

  • Vector3 (position)
  • Quaternion (rotation)
  • Matrix4x4 (transform)

The parent

In a lot of graphical languages you will have a method called addChild() or addElement(). In Unity3D, there is no method for adding a child to a Transform. Setting the parent property of the parent Transform will automatically add the child Transform to the parent.

The root

The root property returns the top level Transform that is attached to the Scene. This could also be achieved by creating a while() loop and looping through the Transform.parent until null is reached.

UnityEngine.Transform Class Diagram

Categories: Uncategorized Tags:

Unity3d :: UML :: Animation visualization cheat sheet

May 19th, 2011 Michael Schmalle No comments

Hi,

Here is a detailed UML class diagram of the Animation API for Unity 3D.

The Animation component is composed in the GameObject as the animation property. Each GameObject uses this instance to control it’s registered AnimationState instances.

There is a subtle composite hierarchy found within Animation that is worth noting.

  • Animation
    • AnimationState
      • AnimationClip
        • AnimationCurve
          • Keyframe

Mike

PS There will be more detailed adventures in these classes found in the Unity3D section of the site down the road. I’m just publishing the UML for now so others can see the system and api as a whole.

UnityEngine.Animation Class Diagram

Categories: Uncategorized Tags:

Unity3d :: UML :: GameObject cheat sheet

May 17th, 2011 Michael Schmalle No comments

Hi,

I am putting together a series of Unity3D class tutorials and UML class designs. My programming background comes from years of pretty regimented design pattern applications using Java, PHP and ActionScript. Mainly object oriented components and projects that relied heavily on forward and reverse engineering. The UML diagram below is an example of reverse engineering, to document and map an existing software system.

When it comes to this programming stuff, I need a map (my previous career in the 90′s was a Land Surveyor :) . To become an efficient programmer and master of a language it is really important to grasp something graphically as well as textually.

This is going to be my contribution to the Unity3D community. I hope you budding programmers/artists see the value in what I offer here and make some really well architected Unity3d games as well as something that hasn’t been thought of (non-game).

Another area that I see Unity3D growing in is how to actually architect the application with javascript or C#. It’s sad to say that some of the Unity3D code I have seen lately looks like my code did back in Flash 5 circa 2001. What does this all amount to? Spaghetti code that is touched by everything and contained by nothing. If I were to make a bet, I would bet in 5 years you will see a real software approach coming to Unity3D. An example of this is how Flash turned into Flex with a Flash site becoming a now coined buzz word "RIA" Rich Internet Application.

Will we see the same thing happen to Unity3D? Yes we will because the engine is much more than a game engine. That is what I am here to expose. :)

In some of my later blog posts I will explain more of these diagrams, also will be adding to the Unity3D section of the site which is a developing book.

Mike

UnityEngine.GameObject Class Diagram

Categories: Uncategorized Tags:

Unity3d :: Editor vs EditorWindow

May 15th, 2011 Michael Schmalle No comments

Hi,

When getting into writing custom editors or extending the functionality of the Unity 3D user interface, looking at the API for the first time (Editor API) might have you scratching your head. Reading a bit into the docs, you start to see a very subtle difference between the two classes Editor and EditorWindow.

My first instinct was that Editor was the base abstract class of EditorWindow, not the case.

The Editor decorates an existing Inspector, the EditorWindow is an entirely new Inspector with your custom editor contained within with custom controls to capture user information.

Editor

The Editor class allows you to “attach” user interface controls onto an existing Inspector. The Editor class contains a public variable target that holds the reference to the current selection in the scene. The UnityEngine knew that the Component selected in the scene was of the type CustomEditor defined in the editors class attribute.

Looking at the example below, MyBehaviorScript would be a javascript or C#(extending MonoBehaviour) script that contained behaviors to add onto a GameObject instance in the scene. Using the CustomEditor attribute, the UnityEngine knows to call OnInspectorGUI() on this class when an instance of MyBehaviorScript is found in the GameObject‘s component collection.

So in laymans terms, the Editor class dynamically adds controls to the Inspector when a selection occurs in the Scene Editor.

using UnityEngine;
using UnityEditor;
using System.Collections;
 
[CustomEditor(typeof(MyBehaviorScript))]
 
public class MyEditor : Editor 
{
	override public void OnInspectorGUI()
	{
		Debug.Log("OnInspectorGUI()");
	}
}

EditorWindow

The EditorWindow class allows you to create new Inspector windows that can float free or be docked as a tab, just like the native windows in the Unity 3D interface. The EditorWindow usually have menu items assigned within the declaring class.

Using;

[MenuItem ("Window/My EditorWindow")]

will create a menu item in the Window main menu. When a user selects this menu item, the new Inspector window will be created and if the Inspector exists will get focus.

using UnityEngine;
using UnityEditor;
using System.Collections;
 
public class MyEditorWindow : EditorWindow 
{
 
	[MenuItem ("Window/My EditorWindow")]
	static void Init ()
	{
		// Get existing open window or if none, create it
 
		MyEditorWindow window = (MyEditorWindow)EditorWindow.GetWindow(typeof(MyEditorWindow));
	}
 
	void OnGUI ()
	{
		// Called when the user interface is created
		GUILayout.Label ("Hellow World", EditorStyles.boldLabel);
	}
}

Remember that the Editor class is populated with it’s target as the current selection in the scene? You may ask, well since this class has nothing to do with Editor and the target property, how do you know what is selected in the scene.

Answer; The EditorWindow class receives OnSelectionChange() messages any time the selection changes in the scene editor. You can action the selection, save the selection or load a selection you saved. You will access the current selections in the scene with Selection.instanceIDs;.

	int[] selectionIDs;
 
	void OnSelectionChange()
	{
		selectionIDs = Selection.instanceIDs;
	}

The integers point to scene object instance ids. You could simply load the int array back into the Selection.instanceIDs array.

Selection.instanceIDs = ids;

Mike

Categories: Uncategorized Tags:

Fantasy Cottage 5 – 3D Model Released

We have just released a 3d medieval fantasy cottage model for purchase download. You must be a registered user to purchase the product zip.

A weathered stone cottage 3d model, stone foundation, slate roofing, stone chimney.

The Product Page with more images;

http://teotigraphix.com/3dmodels/fantasy/fantasycottage5

This model can be used with Unity 3D.

Mike

Categories: Uncategorized Tags:

asblocks :: Comming back into reality

January 2nd, 2011 Michael Schmalle No comments

For those that are following the asblocks (as3 parser AST read-write code generation library) development and have seen no commits or progress for three months, home disaster was the answer. I have managed to put my self/family and home back together and there will be a lot more from me coming up.

I have partnered with as3commons and plan on developing some Spring ActionScript applications with the library. I am sure Roland will be happy to hear this new news. :)

ASDoc, here we come to give you hell.

Mike

Categories: Uncategorized Tags:

asblocks & asbuilder update :: as3 code creation impl complete

September 16th, 2010 Michael Schmalle 3 comments

Hi,

Just thought I would pass along the example below to show where this project is at. I have worked really hard the last week to implement most of the actionscript 3 code creation.

I have also refactored the asdoc parser to use a linked list. This allows complete control over the ast after it is created and during creation with ast utilities.

I’m working on a little turnkey project that will show devs how to implement the libraries. The below code is included in this project;

GIT Repos

  • asblocks – AST and bloc read-write
  • asbuilder – AIR specific implementations (requires asblocks)

Code:

private var factory:ASFactory; 
 
protected function createProject():void
{
	factory = new ASBuilderFactory();
 
	var project:IASProject = factory.newEmptyASProject(
		File.desktopDirectory.resolvePath("test_src").nativePath);
 
	var classA:ICompilationUnit = project.newClass("my.domain.ClassA");
	var interfaceA:ICompilationUnit = project.newInterface("my.domain.IInterfaceA");
 
	var doc:IDocComment;
	var tag0:IDocTag;
	var tag1:IDocTag;
 
	var ctype:IClassType = IClassType(classA.typeNode);
	ctype.superClass = "ClassB";
	ctype.addImplementedInterface("IInterfaceA");
	ctype.addImplementedInterface("IInterfaceB");
 
	ctype.description = "A class documentation comment\nwith multiple lines.";
	doc = ctype.documentation;
	tag0 = doc.newDocTag("see", "my.other.Class");
	tag1 = doc.newDocTag("author", "Mike Schmalle <mschmalle@teotigraphix.com>");
 
	// add metadata
	var event:IMetaData = ctype.newMetaData("Event");
	event.description = "A class documentation comment\nwith multiple lines.";
 
	tag0 = event.documentation.newDocTag("see", "ClassB#event:myOtherEvent");
 
	event.addNamedStringParameter("name", "myEvent");
	event.addNamedStringParameter("type", "flash.events.Event");
 
	var defaultProperty:IMetaData = ctype.newMetaData("DefaultProperty");
	defaultProperty.addNamedStringParameter("defaultValue", "dataProvider");
 
	ctype.newMetaData("Bindable");
 
	createField(ctype);
	createStaticField(ctype);
	createStaticConstant(ctype);
 
	createMethod(ctype);
	createFinalMethod(ctype);
	createStaticMethod(ctype);
	createGetMethod(ctype);
	createSetMethod(ctype);
	createComplexMethod(ctype);
 
	walkUnit(classA);
 
	project.writeAll();
}
 
protected function walkUnit(unit:ICompilationUnit):void
{
	var visitor:IASVisitor = new TestVisitor();
	var walker:IASWalker = new ASWalker(visitor);
	walker.walkCompilationUnit(unit);
}
 
protected function createField(type:IClassType):void
{
	var f:IField = type.newField("field", Visibility.PUBLIC, "int");
	f.description = "An integer field.";
	var tag0:IDocTag = f.documentation.newDocTag("productversion", "1.0");
}
 
protected function createStaticField(type:IClassType):void
{
	var f:IField = type.newField("STATIC_FIELD", Visibility.PUBLIC, "int");
	f.isStatic = true;
	f.initializer = exp("42");
}
 
protected function createStaticConstant(type:IClassType):void
{
	var f:IField = type.newField("CONSTANT_FIELD", Visibility.PROTECTED, "int");
	// change field to static
	f.isStatic = true;
	// change field to a constant
	f.isConstant = true;
	// set the initializer
	f.initializer = exp("42");
}
 
protected function createMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("method", Visibility.PUBLIC, "void");
 
	// add parameters
	m.addParameter("arg0", "int");
	m.addParameter("arg1", "int", "42");
	m.addRestParam("rest");
 
	// change type 
	m.type = "String";
	m.addComment("TODO implement method");
	// add a return
	m.newReturn(factory.newExpression("null"));
}
 
protected function createFinalMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("methodFinal", Visibility.PUBLIC, "void");
}
 
protected function createStaticMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("methodStatic", Visibility.PUBLIC, "void");
	m.isStatic = true;
}
 
protected function createGetMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("property", Visibility.PUBLIC, "int");
	m.accessorRole = AccessorRole.GETTER;
	m.newReturn(factory.newNumberLiteral(-1));
}
 
protected function createSetMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("property", Visibility.PUBLIC, "void");
	m.addParameter("value", "int");
	m.accessorRole = AccessorRole.SETTER;
}
 
protected function createComplexMethod(type:IClassType):void
{
	var m:IMethod = type.newMethod("complex", Visibility.PRIVATE, "void");
	// add an if() statement
	var ifstmt:IIfStatement = m.newIf(exp("i < len && hasNext()"));
	// add a var declaration
	var dc:IDeclarationStatement = ifstmt.parseNewDeclaration("len:int = 2");
	// make it a constant
	dc.isConstant = true;
	// add a for() statement
	var forstmt:IForStatement = ifstmt.parseNewFor("var i:int = 0", "i < len", "i++");
	// add a switch() statement
	var swstmt:ISwitchStatement = forstmt.newSwitch(exp("name"));
	// add a case to the switch
	var cs1:ISwitchCase = swstmt.newCase("\"one\"");
	cs1.newBreak();
	// add a case to the switch
	var cs2:ISwitchCase = swstmt.newCase("\"two\"");
	var ifstmt2:IIfStatement = cs2.newIf(exp("i == 2"));
	// add a single lin comment
	ifstmt2.addComment("Trace the result");
	ifstmt2.addStatement("trace('Hello Two')");
	cs2.newBreak();
	// add a default to the switch
	var dfstmt:ISwitchDefault = swstmt.newDefault();
	dfstmt.newThrow(exp("new Error('Error here')"));
}
 
private function exp(expression:String):IExpression
{
	return factory.newExpression(expression);
}

Output:

package my.domain {
	/**
	 * A class documentation comment
	 * with multiple lines.
	 * @see ClassB#event:myOtherEvent
	 */
	[Event(name="myEvent",type="flash.events.Event")]
	[DefaultProperty(defaultValue="dataProvider")]
	[Bindable]
	/**
	 * A class documentation comment
	 * with multiple lines.
	 * @see my.other.Class
	 * @author Mike Schmalle <mschmalle@teotigraphix.com>
	 */
	public class ClassA extends ClassB implements IInterfaceA, IInterfaceB {
		/**
		 * An integer field.
		 * @productversion 1.0
		 */
		public var field:int;
		public static var STATIC_FIELD:int = 42;
		protected static const CONSTANT_FIELD:int = 42;
		public function method(arg0:int, arg1:int = 42):String {
			//TODO implement method
			return null;
		}
		public function methodFinal():void {
		}
		public static function methodStatic():void {
		}
		public get function property():int {
			return -1;
		}
		public set function property(value:int):void {
		}
		private function complex():void {
			if (i < len && hasNext()) {
				const len:int = 2;
				for (var i:int = 0; i < len; i++) {
					switch (name) {
						case "one":
							break;
						case "two":
							if (i == 2) {
								//Trace the result
								trace('Hello Two');
							}
							break;
						default:
							throw new Error('Error here');
					}
				}
			}
		}
	}
}

Mike

Categories: Uncategorized Tags:

as3parser-framework :: Facelift – asblocks & asbuilder

September 6th, 2010 Michael Schmalle No comments

Hi,

Well the last 2 weeks have been very productive. The as3nodes framework is retired, with the metaas DOM implemented. I talked with David Holroyd and have his very encouraging consent to use his API. The metaas Java framework was designed to parse and create AS3 code using antlr and a Document Object Model designed by David.

Davids quote to me;

“There is a lovely symmetry to being able to manipulate the source code of a language within the language itself!”

There have been significant changes in the project within the last 2 weeks;

  • The as3parser and DOM has their repository changed to asblocks
  • The as3builder-framework was changed to asbuilder and now lives at asbuilder
  • The majority of the parser and actionscript read/write DOM implementation is located in the asblocks repository.
  • The asbuilder repository will hold all classes key to the AIR desktop implementation of the IASProject.

For now, the asbook package is missing, that will be reimplemented using the new DOM.

As it stands the asblocks code right now can almost create any type, method, member, expression or statement in ActionScript3! :)

Check it out; This wiki got deprecated, that will be updated as well with a new sub domain asblocks.

The focus has shifted to read-write actionscript instead of the “parser”.

In the spirit of metaas, the following API;

Code:

var factory:ASFactory = new ASFactory();
var project:ASProject = factory.newEmptyASProject(".") as ASProject;
var unit:ICompilationUnit = project.newClass("Test");
var clazz:IClassType = unit.typeNode as IClassType;
var method:IMethod = clazz.newMethod("test", Visibility.PUBLIC, "void");
method.addStatement("trace('Hello world')");
project.writeAll();

Output:

package {
	public class Test {
		public function test():void {
			trace('Hello world');
		}
	}
}

Oh yeah here is another fun one;

Code:

var statement:IBlock = factory.newBlock();
var ifst:IIfStatement = statement.newIf(factory.newExpression("test()"));
ifst.addStatement("trace('test succeeded')");
ifst.elseBlock.addStatement("trace('test failed')");
var ifstSub:IIfStatement = ifst.newIf(factory.newExpression("test2()"));
ifstSub.addStatement("trace('sub test succeeded')");
ifstSub.elseBlock.addStatement("trace('sub test failed')");

Output:

{
	if (test()) {
		trace('test succeeded');
		if (test2()) {
			trace('sub test succeeded');
		} else {
			trace('sub test failed');
		}
	} else {
		trace('test failed');
	}
}

Mike

PS There is a lot more to come now, the was a BIG hurdle, but it’s implemented now!

Categories: Uncategorized Tags:

as3parser :: Expression building, sneak peak

August 25th, 2010 Michael Schmalle No comments

Hi,

I have been working the last 2 days completely refactoring, actually rewriting the AS3Parser, all 2500 lines.

The old parser implementation used recursive decent but it had no idea about token stream. I have re-written the parser to use a LinkedListToken token implementation with next and previous, start and stop tokens.

This is all possible since the metaas Java DOM was so awesome, thanks David, I learned a lot! Well, I am using his DOM api to about 80%, it’s really intuitive and tight, check the example below.

Yes, we are at the lowest level, every aspect of actionscript3 will be able to be created now. Not to mention code formatters can be easily written in an AIR application.

The below three tests are just some eye candy right now, this dev is on the as3block branch, I havn’t committed this yet

[Test]
public function testAssignmentExpressionNode():void
{
	var left:IExpressionNode = factory.newExpression("myAnswer");
	var right:IExpressionNode = factory.newExpression("4");
 
	var expression:IAssignmentExpressionNode = 
		factory.newAssignmentExpression(left, right);
 
	assertPrintExpression("myAnswer = 4", expression);
 
	// change right expression
	expression.rightExpression = factory.newExpression("otherAnswer = 4");
 
	assertPrintExpression("myAnswer = otherAnswer = 4", expression);
 
	// change left expression to an array access
	var target:IExpressionNode = factory.newExpression("myObject[42]");
	var subscript:IExpressionNode = factory.newExpression("2");
 
	var arrayAccessExpression:IArrayAccessExpressionNode = 
		factory.newArrayAccessExpression(target, subscript);
 
	expression.leftExpression = arrayAccessExpression;
 
	assertPrintExpression("myObject[42][2] = otherAnswer = 4", expression);
}
 
[Test]
public function testArrayLiteralNode():void
{
	var expression:IArrayLiteralNode = factory.newArrayLiteral();
 
	expression.add(factory.newSimpleNameExpressionNode("a"));
	expression.add(factory.newSimpleNameExpressionNode("b"));
	expression.add(factory.newSimpleNameExpressionNode("c"));
 
	assertPrintExpression("[a, b, c]", expression);
 
	expression.remove(2);
 
	var expression2:IArrayLiteralNode = factory.newArrayLiteral();
 
	expression2.add(factory.newNullLiteral());
	expression2.add(factory.newSimpleNameExpressionNode("foo"));
	expression2.add(factory.newStringLiteral("Hello World"));
	expression2.add(factory.newBooleanLiteral(true));
 
	expression.add(factory.newArrayAccessExpression(
		factory.newSimpleNameExpressionNode("abc"),
		factory.newNumberLiteral(0)));
 
	expression.add(expression2);
 
	assertPrintExpression("[a, b, abc[0], [null, foo, \"Hello World\", true]]", expression);
}
 
[Test]
public function testArrayAccessExpressionNode():void
{
	var target:IExpressionNode = factory.newExpression("myObject[42]");
	var subscript:IExpressionNode = factory.newExpression("0");
 
	var expression:IArrayAccessExpressionNode = 
		factory.newArrayAccessExpression(target, subscript);
 
	assertPrintExpression("myObject[42][0]", expression);
 
	// test changing the 'target'
	target = factory.newExpression("myObject");
	expression.target = target;
 
	assertPrintExpression("myObject[0]", expression);
 
	// test changing the 'subscript'
	subscript = factory.newExpression("42");
	expression.subscript = subscript;
 
	assertPrintExpression("myObject[42]", expression);
 
	// test changing the 'subscript' to a string literal
	subscript = factory.newExpression("'myProp'");
	// or you could use
	// subscript = factory.newStringLiteral("'myProp'");
	expression.subscript = subscript;
 
	assertPrintExpression("myObject['myProp']", expression);
}

Mike

Categories: Uncategorized Tags:

as3parser-framework :: Download first alpha SWC – parse and build!

August 23rd, 2010 Michael Schmalle No comments

Hi,

I just put together the first alpha swcs for use. You can get this zip here;

as3parser-framework_0.1_alpha.zip

The zip file contains 2 SWC libraries;

  • as3parser-framework_0.1_alpha.swc
  • as3builder-framework_0.1_alpha.swc

This is very alpha, but now you can experiment without the source. These are right out of the Library project so they contain the unit tests as well. This won’t be the case in the future.

Have fun,
Mike

Categories: Uncategorized Tags: