Skip to content
Snippets Groups Projects
UGameTransform_modded.qvto 14.6 KiB
Newer Older
modeltype Unity uses 'http://www.example.org/unityGameDSL_modded';
modeltype Prog uses 'http://www.example.org/examples/example.ecore';

transformation UgameTransform(in unity: Unity, out Prog);

property monoBehaviour : Prog::ExternalType;
property vector2 : Prog::ExternalType;
property rigidbody : Prog::ExternalType;
property text : Prog::ExternalType;
property collider : Prog::ExternalType;
property collision : Prog::ExternalType;
property gameObject : Prog::ExternalType;
property image : Prog::ExternalType;
property FIXED_NAMESPACE : String = 'DSL';

main() {
	monoBehaviour := object Prog::ExternalType {
		importedFrom := 'UnityEngine';
		identifier := 'MonoBehaviour';
		type := EType::_class;
	};
	vector2 := object Prog::ExternalType {
		importedFrom := 'UnityEngine';
		identifier := 'Vector2';
		type := EType::struct;
	};
	rigidbody := object Prog::ExternalType {
		importedFrom := 'UnityEngine';
		identifier := 'Rigidbody2D';
		type := EType::_class;
	};
	text := object Prog::ExternalType {
		importedFrom := 'UnityEngine.UI';
		identifier := 'Text';
		type := EType::_class;
	};
	image := object Prog::ExternalType {
		importedFrom := 'UnityEngine.UI';
		identifier := 'Image';
		type := EType::_class;
	};
	collider := object Prog::ExternalType {
		importedFrom := 'UnityEngine';
		identifier := 'Collider2D';
		type := EType::_class;
	};
	collision := object Prog::ExternalType {
		importedFrom := 'UnityEngine';
		identifier := 'Collision2D';
		type := EType::_class;
	};
	gameObject := object Prog::ExternalType {
		importedFrom := 'UnityEngine';
		identifier := 'GameObject';
		type := EType::_class;
	};


	unity.rootObjects()[Unity::Game]->asOrderedSet()->first()-> map Unity2Prog()
}

mapping Unity::Game::Unity2Prog () : Prog::Program {
	externalTypes += monoBehaviour;
	externalTypes += vector2;
	externalTypes += rigidbody;
	externalTypes += text;
	externalTypes += image;
	externalTypes += collider;
	externalTypes += collision;
	externalTypes += gameObject;
	
	var types : Set(InternalType);
	types += self.dataManager->map DataManager2Class();
	types += self.guiElements->map GUIElement2Class();
mcder's avatar
mcder committed
	types += self.gameobjects-> map GameObj2Class();
	// convert all types into separate files!
	files += types-> map Internal2File();	
}

mcder's avatar
mcder committed
mapping Unity::GameObject::GameObj2Class() : Prog::Class {	
	identifier := self.name.firstToUpper();
	log('GameObject to class: ' + identifier);

	var startMethod := object Prog::MethodDef {
			accessability := AccessModifier::none;
			returnType := toType(EPrimitiveType::void);
			identifier := 'Start'
			
	};
	var updateMethod := object Prog::MethodDef {
			accessability := AccessModifier::none;
			returnType := toType(EPrimitiveType::void);
			identifier := 'Update'
	};
	
	var triggerMethod := object MethodDef {
		identifier := "OnTriggerEnter2D";
		parameters += object Parameter {
			identifier := 'collider';
			type := toType(collider);
		};
		returnType := toType(EPrimitiveType::void);
	};
	
	methods += updateMethod;
	methods += startMethod;
	methods += triggerMethod;
	
	baseType := monoBehaviour;
	
	var speed : MemberDef;
	var horizontal : MemberDef;
	
	if (self.movement->size() > 0) {
		speed := object MemberDef {
			identifier := 'speed';
			type := toType(EPrimitiveType::float);
		};
		horizontal:= object MemberDef {
			identifier := 'horizontal';
			type := toType(EPrimitiveType::float);
			accessability := AccessModifier::private;
		};
		members += speed;
		members += horizontal;
	};
	
	var rigidbody : MemberDef;
	if (self.colision->select(c | c.oclIsTypeOf(RigidBody))->size() > 0) {
		// you can ignore this warning
		rigidbody := object MemberDef {
			identifier := 'rigidbody';
			type := toType(this.rigidbody);
		};
		members += rigidbody;
	};
	
	
	// sideways only: isGrounded, jumpIntensity, collisionmethod, triggermethod
	// topdown only: vertical
	// both: start, update, rigidbody, horizontal, speed
	
	if (self.movement->size() = 1) {
		if (self.movement->asOrderedSet()->first().oclIsTypeOf(Sideways)) {
			var isGrounded := object MemberDef {
				identifier := 'isGrounded';
				type := toType(EPrimitiveType::bool);
				accessability := AccessModifier::private;
			};
			var jumpIntensity:= object MemberDef {
				identifier := 'jumpIntensity';
				type := toType(EPrimitiveType::float);
			};
			var collisionMethod := object MethodDef {
				identifier := "OnCollisionEnter2D";
				parameters += object Parameter {
					identifier := 'collision';
					type := toType(collision);
				};
			returnType := toType(EPrimitiveType::void);
			};
			
			members += isGrounded;
			members += jumpIntensity;
			methods += collisionMethod;
			
			updateMethod.body += horizontal.identifier + ' = Input.GetAxisRaw("Horizontal");';
			updateMethod.body += 
			'if (Input.GetButtonDown("Jump") && ' + isGrounded.identifier + ') {
				' + rigidbody.identifier + '.AddForce(new Vector2(0,1) * ' + jumpIntensity.identifier + ');
mcder's avatar
mcder committed
				' + isGrounded.identifier + ' = false;
				}'; 
			updateMethod.body += rigidbody.identifier + '.AddForce(new Vector2(' + horizontal.identifier + '* ' + speed.identifier + ', 0));';
			collisionMethod.body += 'if (collision.collider.gameObject.tag == "Floor"){
mcder's avatar
mcder committed
						isGrounded = true;
					}';
		} else {
			var vertical := object MemberDef {
				identifier := 'vertical';
				type := toType(EPrimitiveType::float);
				accessability := AccessModifier::private;
			};
			
			members += vertical;
			
			updateMethod.body += horizontal.identifier + ' = Input.GetAxisRaw("Horizontal");';
			updateMethod.body += vertical.identifier + ' = Input.GetAxisRaw("Vertical");';
mcder's avatar
mcder committed
			updateMethod.body += rigidbody.identifier + '.velocity = new Vector2(' + horizontal.identifier + ' * ' + speed.identifier + ', ' + vertical.identifier + ' * ' + speed.identifier + ');';
	--childrens with object creation.
		self.start->forEach(e){
			if (e.oclIsKindOf(Unity::ObjectCreation)){
				var prefab: MemberDef;
			object prefab: MemberDef{
			accessability := AccessModifier::public;
			type := toType(gameObject);
			identifier := "createdObject"+createCounter.toString();
			createCounter := createCounter + 1;
			};
mcder's avatar
mcder committed
			members+=prefab;
			};
		};
		self.update->forEach(e){
			if (e.oclIsKindOf(Unity::ObjectCreation)){
				var prefab: MemberDef;
			object prefab: MemberDef{
			accessability := AccessModifier::public;
			type := toType(gameObject);
			identifier := "createdObject"+createCounter.toString();
			createCounter := createCounter + 1;
			};
			members+=prefab;
			};
		};
		self.interaction.execute->forEach(e){
			if (e.oclIsKindOf(Unity::ObjectCreation)){
				var prefab: MemberDef;
			object prefab: MemberDef{
			accessability := AccessModifier::public;
			type := toType(gameObject);
			identifier := "createdObject"+createCounter.toString();
			createCounter := createCounter + 1;
			};
			members+=prefab;
			};
		};
		self.colision->forEach(c | c.oclIsKindOf(Unity::Trigger)){
			c.oclAsType(Unity::Trigger).execute->forEach(e){
			if (e.oclIsKindOf(Unity::ObjectCreation)){
				var prefab: MemberDef;
			object prefab: MemberDef{
			accessability := AccessModifier::public;
			type := toType(gameObject);
			identifier := "createdObject"+createCounter.toString();
			createCounter := createCounter + 1;
			};
			members+=prefab;
			};
			};
		};
		createCounter := 0;
	
	-- triggers
	self.colision->forEach(e | e.oclIsTypeOf(Unity::Trigger)){
		e.oclAsType(Unity::Trigger)->SetTriggerBody(triggerMethod, createCounter);
	};
	-- start
	self.start->forEach(action){
		startMethod.body += action.Action2Body(createCounter);
	};
	-- update
	self.update->forEach(action){
		updateMethod.body += action.Action2Body(createCounter);
	};
	-- KeyPress
	self.interaction->forEach(keypress | keypress.oclIsTypeOf(Unity::Trigger)){
		keypress.oclAsType(Unity::Actionkey)->SetActionKeyBody(updateMethod, createCounter);
	};
}

helper Unity::Actionkey::SetActionKeyBody(inout updatemethod:Prog::MethodDef,inout creationCounter:Integer){
	if (self.pressType = KeyType::Instant) then {
		updatemethod.body +='if (Input.GetKeyDown(KeyCode.'+self.key+')) {';
    }
    else if (self.pressType = KeyType::Repeated) then {
    	updatemethod.body +='if (Input.GetKey(KeyCode.'+self.key+')) {'
    }
    endif endif;
    
    self.execute->forEach(action){
		updatemethod.body += action.Action2Body(creationCounter);
	};
	updatemethod.body+='}'
	
}

helper Unity::Trigger::SetTriggerBody(inout triggermethod:Prog::MethodDef,inout creationCounter: Integer) {
	log('INTERMEDIATE RESULT ' + self.collisionTAg);
	triggermethod.body->forEach(s) {
		log(s);
	};
	log('');
	
	triggermethod.body += 'if (collider.gameObject.tag == "'+self.collisionTAg+'") {';
	self.execute->forEach(action){
		var res := action.Action2Body(creationCounter);
		log(res);
		triggermethod.body += res;
	
	log('FINAL RESULT ' + self.collisionTAg);
	triggermethod.body->forEach(s) {
		log(s);
	};
	log('');
}
helper Unity::GameAction::Action2Body(inout creationCounter: Integer) : String {
	//log('action to body type: ' + self.toString());
	if (self.oclIsTypeOf(Unity::Add)){
		var value =self.oclAsType(Unity::Add).value;
		return 'DataManager.instance.Set'+self.oclAsType(Unity::DataChange).data.name.firstToUpper()+'(DataManager.instance.Get'+self.oclAsType(Unity::DataChange).data.name.firstToUpper()+'()+'+value+');';
	};
	if (self.oclIsTypeOf(Unity::Subtract)){
		var value =self.oclAsType(Unity::Subtract).value;
		return 'DataManager.instance.Set'+self.oclAsType(Unity::DataChange).data.name.firstToUpper()+'(DataManager.instance.Get'+self.oclAsType(Unity::DataChange).data.name.firstToUpper()+'()-'+value+');';
	};
	if (self.oclIsTypeOf(Unity::Define)){
		var value =self.oclAsType(Unity::Define).value;
		return 'DataManager.instance.Set'+self.oclAsType(Unity::DataChange).data.name.firstToUpper()+'('+value+');';
	};
	if(self.oclIsTypeOf(Unity::SelfDestruction)){
		return 'Destroy(gameObject);'
	};
	if(self.oclIsTypeOf(Unity::ApplyForce)){
		if (self.oclAsType(Unity::ApplyForce).isInstant){
			return 'rigidbody.AddForce(new Vector2('+self.oclAsType(Unity::ApplyForce).direction->at(2).toString()+','+self.oclAsType(Unity::ApplyForce).direction->at(2).toString()+')*'+self.oclAsType(Unity::ApplyForce).intensity.toString()+'f, ForceMode2D.Impulse);'
			return 'rigidbody.AddForce(new Vector2('+self.oclAsType(Unity::ApplyForce).direction->at(2).toString()+','+self.oclAsType(Unity::ApplyForce).direction->at(2).toString()+')*'+self.oclAsType(Unity::ApplyForce).intensity.toString()+'f);'
		};
	};
	if(self.oclIsTypeOf(Unity::ObjectCreation)){
		var currentCounter: Integer = creationCounter;
		creationCounter := creationCounter + 1;
		return 'Instantiate(createdObject'+creationCounter.toString()+', transform.position + new Vector3('+self.oclAsType(Unity::ObjectCreation).position->at(2).toString()+','+self.oclAsType(Unity::ObjectCreation).position->at(2).toString()+',0), transform.rotation);'
		
	};
	log('failed to convert action ' + self.toString());
	
}

// creates a class from GUIElement, possibly TextDisplay or BarDisplay
mapping Unity::GUIElement::GUIElement2Class() : Prog::Class {
	var isTextual := self.oclIsTypeOf(Unity::TextDisplay);

	baseType := monoBehaviour;
mcder's avatar
mcder committed
	
	
	var update := object MethodDef {
		accessability := AccessModifier::none;
		returnType := toType(EPrimitiveType::void);
		identifier := "Update"
	};
	
	if (isTextual) {
mcder's avatar
mcder committed
		identifier := "TextDisplay"+self.data.name.firstToUpper();
		var value := object MemberDef {
			accessability := AccessModifier::public;
mcder's avatar
mcder committed
			type := toType(text);
			identifier := 'text';
		};
		var prefix := object MemberDef {
			accessability := AccessModifier::public;
			type := toType(EPrimitiveType::string);
			identifier := 'prefix';
		};
		var postfix := object MemberDef {
			accessability := AccessModifier::public;
			type := toType(EPrimitiveType::string);
			identifier := 'postfix';
		};
		members += value;
		members += prefix;
		members += postfix;
		update.body += value.identifier + '.text = ' + prefix.identifier + ' + DataManager.instance.Get'+self.data.name.firstToUpper()+ '() +' + postfix.identifier + ';';
mcder's avatar
mcder committed
		identifier := "BarDisplay"+self.data.name.firstToUpper();
		var max := object MemberDef {
			accessability := AccessModifier::public;
			type := toType(EPrimitiveType::float);
			identifier := 'maxValue';
		};
		var bar := object MemberDef {
			accessability := AccessModifier::public;
			type := toType(image);
			identifier := 'barImage';
		};
		update.body += 'barImage.fillAmount =  DataManager.instance.Get'+self.data.name.firstToUpper()+"()/maxValue;";
		members += max;
		members += bar;
	};
	
	methods += update;
}

mapping Unity::DataManager::DataManager2Class () : Prog::Class {
mcder's avatar
mcder committed
	baseType := monoBehaviour;
	var instance := object MemberDef {
		specifier := Specifier::_static;
		identifier := 'instance';
		type := toType(result);
	}; 
	members += instance;
	members += self.controls -> map Data2Member();
	var awake := object MethodDef {
		identifier := 'Awake';
		accessability := AccessModifier::private;
		body += instance.identifier + '??= this;';
		returnType := toType(EPrimitiveType::void);
	};
	methods += awake;
	methods +=	self.controls-> map Data2Get();
	methods +=	self.controls-> map Data2Set();
}

mapping Unity::Data::Data2Member(): Prog::MemberDef{
mcder's avatar
mcder committed
	accessability := AccessModifier::public;	
	type := toType(self.type);
	identifier := self.name;
}
mapping Unity::Data::Data2Get(): Prog::MethodDef{
	accessability := AccessModifier::public;
	returnType := toType(self.type);
	identifier := "Get"+self.name.firstToUpper();
	body += "return this."+self.name + ';';
}
mapping Unity::Data::Data2Set(): Prog::MethodDef{
	init{
		var parameter := object Prog::Parameter{
			type:= toType(self.type);
			identifier := "value"
		}
	}
	accessability := AccessModifier::public;
mcder's avatar
mcder committed
	returnType := toType(EPrimitiveType::void);
	identifier := "Set"+self.name.firstToUpper();
	parameters += parameter;
	body += 'this.' + self.name + ' = value;';
}

// converts unity data type to primitive types
query toType(in type : DataTypes) : Prog::PrimitiveType {
	return if type = DataTypes::Integer then toType(EPrimitiveType::int)
	else if type = DataTypes::Decimal then toType(EPrimitiveType::float)
	else toType(EPrimitiveType::string) endif endif;
}

// converts InternalType to file
mapping InternalType::Internal2File() : Prog::File {
	filename:= self.identifier.firstToUpper();
	namespaces += object Namespace {
		namespace := FIXED_NAMESPACE;
		using += 'UnityEngine';
		using += 'System';
		typedefs += self;
	};
}

// converts a primitive type to a Type
query toType(in _type: EPrimitiveType) : Prog::PrimitiveType {
	return object Prog::PrimitiveType {
		type := _type;
	};
}

// converts a TypeDef to a Type through reference
query toType(in _type: TypeDef) : Prog::CompoundType {
	return object Prog::CompoundType {
		referencedType := _type;
	}
}