Skip to content
Snippets Groups Projects
UGameTransform_modded.qvto 13.2 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();
	types += self.components-> map Component2Class();
	
	// convert all types into files!
	files += types-> map Internal2File();	
}

mapping Unity::Component::Component2Class() : Prog::Class {	
	identifier := self.name.firstToUpper();

	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;
	
	log("Component " + self.name + " has movement? " + (self.movement->size() > 0).toString());
	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";
				body += 'this.isGrounded = true;';
				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.GetButtownDown("Jump") && ' + isGrounded.identifier + ') {
				' + rigidbody.identifier + '.AddForce(new Vector2(0,1) * ' + jumpIntensity.identifier + ');
				' + isGrounded.identifier + ' = false;'; 
			updateMethod.body += rigidbody.identifier + 'AddForce(new Vector2(' + horizontal.identifier + '* ' + speed.identifier + ', 0));';
			collisionMethod.body += 'if (collider.gameObject.tag == "Floor")
					{
						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");';
			updateMethod.body += 
			rigidbody.identifier + '.velocity = new Vector2(' + horizontal.identifier + ' * ' + speed.identifier + ', ' + vertical.identifier + ' * ' + speed.identifier + ');';
		};
	};
	
	var createCounter : Integer = 0;
		unity.objectsOfType(Unity::ObjectCreation)->forEach(e){
			var prefab: MemberDef;
			object prefab: MemberDef{
			accessability := AccessModifier::public;
			type := toType(gameObject);
			identifier := "createdObject"+createCounter.toString();
			createCounter := createCounter + 1;
			};
		};
		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) {
	triggermethod.body += 'if (colider.gameObject.tag == "PlayerFoot")
        {';
	self.execute->forEach(action){
		triggermethod.body += action.Action2Body(creationCounter);
	};
	triggermethod.body += '}';
}
helper Unity::GameAction::Action2Body(inout creationCounter: Integer) : String {
	if (self.oclIsTypeOf(Unity::Add)){
		var value =self.oclAsType(Unity::Add).value;
		return '(GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).setScore((GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).getScore()+'+value+');';
	};
	if (self.oclIsTypeOf(Unity::Subtract)){
		var value =self.oclAsType(Unity::Subtract).value;
		return '(GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).setScore((GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).getScore()-'+value+');';
	};
	if (self.oclIsTypeOf(Unity::Define)){
		var value =self.oclAsType(Unity::Define).value;
		return '(GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).setScore('+value+');';
	};
	if(self.oclIsTypeOf(Unity::SelfDestruction)){
		return 'Destroy(gameObject);'
	};
	if(self.oclIsTypeOf(Unity::ApplyForce)){
		log("Dirction size of " + self.oclAsType(Unity::ApplyForce).direction->size().toString());
		if (self.oclAsType(Unity::ApplyForce).isInstant){
			return 'body.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()+',ForceMode2D.Impulse);'
		}else{
			return 'body.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()+');'
		};
	};
	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);'
		
	};
	
}

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

	baseType := monoBehaviour;
	identifier := "TextDisplay"+self.data.name.firstToUpper();
	
	var update := object MethodDef {
		accessability := AccessModifier::none;
		returnType := toType(EPrimitiveType::void);
		identifier := "Update"
	};
	
	if (isTextual) {
		var value := object MemberDef {
			accessability := AccessModifier::public;
			type := toType(EPrimitiveType::string);
			identifier := 'text';
		};
		var prefix := object MemberDef {
			accessability := AccessModifier::public;
			type := toType(EPrimitiveType::string);
			identifier := 'prefix';
		}; 
		members += value;
		members += prefix;
		update.body += value.identifier + '.text = ' + prefix.identifier + ' + GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).Get'+self.data.name.firstToUpper()+"()";
		update.body += 'text.text = standardText + GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).Get'+self.data.name.firstToUpper()+"()";
	} else {
		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 =  GameObject.Find("DataManager").GetComponent("DataManager") as DataManager).Get'+self.data.name.firstToUpper()+"()/maxValue";
		members += max;
		members += bar;
	};
	
	methods += update;
}

mapping Unity::DataManager::DataManager2Class () : Prog::Class {
	identifier := self.name.firstToUpper();
	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;';
	};
	methods += awake;
	methods +=	self.controls-> map Data2Get();
	methods +=	self.controls-> map Data2Set();
}

mapping Unity::Data::Data2Member(): Prog::MemberDef{
	accessability := AccessModifier::private;	
	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;
	returnType := toType(self.type);
	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;
	}
}