- Home /
Simplest way to call c# code from Unity and hook events
I'm trying to create a game that does not rely on a specific game engine for rendering and logic such as range-checking, consider the following simplified example;
/// <summary>
/// All non-engine specific api methods/events etc.
/// </summary>
public interface IApiBase
{
void Start();
void PerformPlayerAttack();
event Action<IDamageableEntity> EntityCreated;
}
/// <summary>
/// Unity specific API Methods etc.
/// </summary>
public interface IUnityApi : IApiBase
{
void SetPlayerLocation(UnityEngine.Vector3 v);
}
static class Bootstrapper
{
/// <summary>
/// We'll somehow need to get Unity to call this so it can
/// hook the events and call 'Start()' and other methods
/// throughout the game.
/// </summary>
public static IUnityApi CreateApi()
{
return new UnityApi(new ServiceFactoryUnityImpl(), new Vector3SrvcUnityImpl());
}
}
//Relevant entity part for this question
public interface IDamageableEntity : IMovableEntity
{
event Action Damaged;
}
So bottom line;
I need to call Bootstrapper.CreateApi(); from within Unity
Hook the 'EntityCreated' event
Call Start()
Each time 'EntityCreated' fires, create a model for it in the gameworld and hook the Entity's 'Damaged' event
Each time that fires, execute the relevant model's 'takehit' animation or w/e it is we're doing
In addition to this, it'll need to call PerformPlayerAttack();
on left mouse button (or w/e) and SetPlayerLocation();
when the player model moved, passing the model's position as a parameter.
Preferrably, it'd be a two-way street so the c# application can correct the model's position after lag/possible hack attempts etc.
I'm running .NET 4.0 - any ideas?
Your reinventing the world, not a good idea.
$$anonymous$$ore moving parts = more chances for it to break.
If you want to separate your concerns, try mvvm.
Not enough code to really understand what your trying to do.
@Benproductions: Why not? $$anonymous$$eeping things seperate makes it easier to swap out certain parts. Anyway, I figured out that most of what I want to do can be done using mono on .NET 3.5 - what bugs me though is that even then some features of .NET35 aren't supported. As an example, I can't use Linfu for dynamic proxy creation because then Unity throws a typeloadexception.. is there any way around such restrictions? The only thing I can think of is creating a proxy over TCP so I can run a mono .NET 4.0 application seperately but considering all the serialization that would probably hurt performance quite a bit.
@spammenao252 Because I want to finish a project within a reasonable amount of time, ins$$anonymous$$d of writing an underlying system that I would hardly ever use... How many times are you really going to swap out an entire system in a game? (especially an entire game engine?) How much time would this actually save?
Anyway... thats just my opinion... you can obviously do whatever, and to be honest this does sound kind of cool XD
Answer by Tomer-Barkan · May 22, 2013 at 09:03 PM
Unlike what some others wrote, I agree that separating your logic from the engine that runs it, as much as possible, is good practice. For example, you wouldn't access a database directly from your code, you would use a class and methods that translate your database queries to specific queries for your chosen database. Then, if you would want to change database provider, you only have to change one level of your code, the one that translates high level queries to specific database implementation.
That said, take into account that development time will be much longer, since you will have to create a generic API for every action that you perform in unity, and then the unity specific implementation of this API. So if you change engine, you will only have to re-create the engine specific implementation of the API, but the API itself and the game logic will remain untouched.
My recommendation: 1. Create your own classes per game object that handle the actual game logic, decision making, etc. 2. Have a layer of intermediate classes, that translate high-level commands (for example, move object 10 meters right) to unity-specific commands (transform.translate() in the given example). 3. The intermediate classes will need to have reference to actual unity objects, and perform unity-specific operations. They will implement generic (non unity specific) interface, which will be the interface between your logic classes and these intermidiate classes 4. Your logic classes will have reference to the interfaces, and use them to perform the actions 5. Your actual unity scripts (attached to actual unity objects) will have very basic functionality, that will instantiate your logic classes, and pass them the relevant parameters and the unity-specific intermediate classes. The unity classes will also call the logic class methods Start(), Update(), etc.
Here's a simple example:
interface MovementHandler {
public void MoveObject(Vector3 moveVector); // this is a generic definition of what MoveObject() does - move the object from current position towards moveVector. Not unity specific.
}
class UnityMovementHandler : MovementHandler {
private GameObject object; // the unity specific implementation of movement handler needs an actual unity object to move
public UnityMovementHandler(GameObject object) {
this.object = object;
}
public void MovementHandler.MoveObject(Vector3 moveVector) {
object.transform.position = object.transform.position + moveVector; // this is the unity specific implementation for moving an object
}
}
class MyPlayer {
private MovementHandler movementHandler;
public MyPlayer(MovementHandler movementHandler) {
this.movementHandler = movementHandler;
}
public onFrameUpdate() {
movementHandler.MoveObject(new Vector3 (1, 0, 0)); // move object 1 meter to the right. Independent of engine since it uses the generic version - MovementHandler
}
}
// this is the unity script, which will be created and called by the unity engine. It needs to instantiate and use your unity-independent classes
class UnityPlayer : MonoBehavior {
private MyPlayer player;
void Start() {
MovementHandler moveHandler = new UnityMovementHandler(this.gameObject);
player = new MyPlayer(moveHandler);
}
void Update() {
player.onFrameUpdate();
}
}
$$anonymous$$udos for understanding what I'm getting at rather than simply nay-saying. I'm still having a couple of issues as described in my comment @ the question but this answers my original question so I'll pick it. Thanks for your time!
@spammenao252: I'm glad my answer helped. I read your comment, and would like to try to answer. Since unity is multi platform (it's code will be run on windows AND linux/$$anonymous$$AC/IOS machines, so it doesn't really use .NET language, it uses $$anonymous$$ONO which is an open source implementation of .NET. Unfortunately, not all of .NET's stuff exist in $$anonymous$$ONO, hence the error you're getting. I can't think of only using $$anonymous$$ONO classes... read here for some more info: http://stackoverflow.com/questions/15924850/unity3d-typeloadexception
Answer by Jamora · May 22, 2013 at 10:39 PM
Is the goal here to create a game engine that can combine features from other game engines or a game that uses only one engine, but is transferrable to another engine?
In case of the former, I don't think this forum is the right place to ask. The latter, however could (possibly) be accomplished by -creating a wrapper for all classes from Unity that you need
-creating a custom base class that extends MonoBehaviour, which is in turn extended by all your classes
-programming to interfaces instead of the implementation
-instantiating everything from code (apart from one of Unity's own GameObjects that starts the game)
If the game engine is changed, to let the new game engine do all the work, all that needs changing are the wrapper classes and what the base class extends.
Something like this:
public class BaseClass : MonoBehaviour {}
public class GameObjectWrapper {
private GameObject thisGameObject;
public GameObjectWrapper (GameObject newObject){ thisGameObject = newObject;}
}
public class GameObjectWrapperFactory{
public static GameObjectWrapper Create(){ return new GameObjectWrapper(new GameObject());}
}
I'd upvote this if I could because it answers a couple of questions but it would seem I need more rep to do so.. thanks for your time though! To answer your question, I'm not trying to mix multiple engines together but having a hot-swappable engine is nice but still, it's mostly just to keep things seperated and prevent spaghetti code.
Answer by tpainton · Feb 08, 2015 at 02:28 PM
Its amazing to me that so many unity programmers really don't understand encapsulation and true object oriented programming. Thanks for this question. It's going to make expansion of my game over time much faster.