I have some existing C++ 2D game code that draws using immediate mode (i.e., each frame is drawn bottom-up one sprite at a time by my game code -- not using a scene graph or other retained mode concepts). I'm wondering if I can port this code to Unity without having to rework the game code to operate in terms of retained mode (adding objects to a scene, removing objects, etc.). I have read that Unity has an immediate mode GUI option. But in my case I want to use this for the game sprites themselves, not just the UI elements. I realize that for a 2D game there isn't a big difference between UI elements and game sprites. But I need to be able to do things like rotation and render-to-texture, so I wasn't sure if I'd run into trouble "misusing" the immediate mode GUI mechanism to handle the whole game. Alternatively, does Unity have a more general immediate mode option? (I did search for it and didn't see anything aside from the immediate mode GUI stuff.)
-
1\$\begingroup\$ So in essence you want to use Unity without actually using any of the features Unity provides? Why would you do that? What do you hope to gain from this? \$\endgroup\$– PhilippMay 15, 2020 at 10:59
-
1\$\begingroup\$ I’m not familiar enough with Unity to answer the question, but I will point out that it would be possible to create an immediate mode style API over a retained mode base system. For example the React JavaScript framework does a form of this where the JS objects returned from render methods are like a series of immediate mode calls, and the browser’s DOM is the retained mode base being built on top of. \$\endgroup\$– Ryan1729May 15, 2020 at 11:05
-
\$\begingroup\$ @Philipp, the reason is that I have a bunch of existing game code that was written in immediate mode style. I obviously wouldn't start a new game in Unity this way. It would be quite time consuming, and more importantly error-prone, to go through and make objects out of each thing I draw on the screen in immediate mode. \$\endgroup\$– M KatzMay 15, 2020 at 18:10
-
\$\begingroup\$ @Ryan1729, I don't know React, but I guess the question is how many retained mode objects I need to manage. If it's just one object called "the screen" and I can draw whatever I want on it, then that's great. If it has to effectively be one object per sprite drawn, then it's the same work (in terms of modifications to game code) as just rewriting the game code to use retained mode? \$\endgroup\$– M KatzMay 15, 2020 at 18:12
-
1\$\begingroup\$ It may be possible to write your own object called “the screen” that accepts your existing immediate mode calls, and behind the scenes manages a Unity scene graph. I suppose it would depend on things like how much API surface the existing calls use, and how easy it Is to translate things to the API the scene graph provides. You also might need to add something like a beginFrame and endFrame call pair to provide necessary information to the scene graph. Depending on how much code you have in the immediate mode API it may or may not be easier to rewrite the guts instead of all the calls. \$\endgroup\$– Ryan1729May 15, 2020 at 21:59
1 Answer
First of all, you should not be doing this.
The Unity scene graph exists for a reason. It's the very core concept which the engine architecture is built around. By rolling your own you are locking yourself out of approximately 99% of the features Unity provides to you. You won't really gain much over just keeping your codebase in C++. If this is just about portability, there are ways to make a C++ codebase portable to multiple platforms (but that's out of the scope of this question).
When you switch to a different technology to do the same thing you were already doing, then your first instinct is often to try to find a way to do everything in exactly the same way you used to do. But that's usually a bad approach, because you won't be using the tool in the way it was intended to be used. It's a bit like a carpenter switching from hammer and nails to screwdriver and screws, trying to drive the screws into the wood by repeatedly hitting them with the screwdriver, having a bad time and awful results and then wondering why everyone claims that screws are a viable alternative to nails.
A far better way to learn a new tool is to approach it with no preconception about how it is supposed to be used, familiarize yourself with its design choices and philosophies and embrace the differences rather than the similarities.
Still wanting to do it that way?
If you really want to manually draw sprites directly to the screen, then Unity can do that with the method Graphics.DrawTexture
(the rest of the Graphics
class might also come in handy for you).
It will draw a specific texture directly to specific screen coordinates, completely ignoring the camera position and settings, transform of the gameObject, z-buffering, post processing, UI-layout, and all the other nice features you pay for with your Unity license.
Create a Monobehaviour and implement the OnGui method to draw your sprites with Graphics.DrawTexture in the order you want. Here is the example which draws a sprite 2000 times per frame to random points in a 400x400 rectangle. Regarding performance: It runs at over 200 FPS on my machine:
using UnityEngine;
public class TextureRenderer : MonoBehaviour
{
public Texture sprite;
public int numOfSprites = 2000;
void OnGUI() {
if (Event.current.type.Equals(EventType.Repaint)) {
for (var i = 0; i < numOfSprites; i++) {
Graphics.DrawTexture(new Rect(
Random.Range(1f, 400f), // x-position
Random.Range(1f, 400f), // y-position
64f, // width
64f // height
),
sprite);
}
}
}
}
-
\$\begingroup\$ @Philipp, thanks for the information. I am not trying circumvent the normal Unity scene graph just for the sake of sticking to what I know. I'm doing it because I have a big pile of existing game code written in immediate mode. I know there are other libraries. I already have some stuff working in bgfx, which is an excelling cross-platform C++ rendering library. So then why am I thinking of Unity? Well, because there is more than just rendering: sound, resource management, in app purchase, and for all of that the ability to have a single cross-platform project/codebase (iOS/Android/PC). \$\endgroup\$– M KatzMay 15, 2020 at 18:23
-
\$\begingroup\$ Philipp, @Ed Marty, thanks for the pointers. So now my question is whether the method of preparing each frame using a single texture I've drawn to will be efficient enough. The games I have typically draw anywhere from 200 to 2000 sprites per frame. I can do the experiment to see how it works in Unity, and report back. But do you have a sense offhand if that would be a problem to create the screen scene with that many sprite draws to a single texture (e.g., because it's doing too much of the work on the CPU instead of GPU if you do it that way)? \$\endgroup\$– M KatzMay 15, 2020 at 18:30
-
1\$\begingroup\$ @EdMarty You are right about that - Graphics.Blit can indeed not be used to draw multiple sprites. But you are wrong about requiring to copy pixel blocks, because there is actually a better method which is even closer to what OP wanted: Using Graphics.DrawTexture. \$\endgroup\$– PhilippMay 15, 2020 at 23:46
-
1\$\begingroup\$ @MKatz The previous version of this answer recommended Graphics.Blit which isn't actually an appropriate solution. The new version uses Graphics.DrawTexture instead which is closer to what you want and even a lot simpler. \$\endgroup\$– PhilippMay 15, 2020 at 23:47