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.
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());}
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:
Create your own classes per game object that handle the actual game logic, decision making, etc.
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).
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
Your logic classes will have reference to the interfaces, and use them to perform the actions
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();
}
}
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.