0
\$\begingroup\$

I am trying to wrap my head around the concept of the Canvas in Unity and its many uses especially outside of user interfaces. However, I cannot really find a good tutorial that digs deep enough into it; so, I was hoping that I can find some help here.

The concept of a user interface needing to have a separate wrapper layer to position elements overlaying the game window does, kinda-sorta, make sense, and I have created one that works fine at the moment. What does not make sense is how everything that contains text also needs to be inside a canvas object to even be visible. I don't understand how a canvas makes sense when I want to display non-UI game elements that contain text, such as damage counters or, as in the case of the game I started working on, playing cards.

Furthering the concept of playing cards, it gets even more complicated. If I understand it correctly, I would not only need a canvas to place my cards on (preferably separate from the one that contains my UI elements) but if I want to put text on my cards and make them come from a reusable Prefab, the Prefab itself needs to be a canvas (or somehow contain one), otherwise text elements would not show up on it (at least based on my trials).

Now, I have read about and actually tried the Text Mesh Pro framework, but honestly I don't need that bloated functionality; a simple text would be perfectly fine for my needs, if only I could make it work.

My question is, can someone briefly illustrate how to work with canvases and text-based game objects (preferably in the context of a card game). My cards need to contain an image and several text fields to display various information. What would be the best way to create a Prefab to initialize these cards? Then, what would be the most optimal way to display these cards on the scene (they should not be part of the UI but the game itself).

My game is 2D and uses a pixel art aesthetic if it is relevant.

Many thanks for your answers!

\$\endgroup\$
1
\$\begingroup\$
  1. I don't understand how a canvas makes sense when I want to display non-UI game elements that contain text, such as damage counters or, as in the case of the game I started working on, playing cards.

A: All these things are graphical user interface design elements, so by definition they belong on the presentation layer, in this case a Canvas! Even if your cards exists physically in the scene, the best way to display icons, text etc everything you need for a card based game will be mostly done on canvases.

2: If I understand it correctly, I would not only need a canvas to place my cards on (preferably separate from the one that contains my UI elements) but if I want to put text on my cards and make them come from a reusable Prefab, the Prefab itself needs to be a canvas (or somehow contain one), otherwise text elements would not show up on it (at least based on my trials).

You can also use TextMeshPro Unity Package which has a Component TextMeshPro (not TextMeshProUGUI) which can be used to display text in world space without a canvas.

A: Incorrect, if the object you are spawning is going to be placed onto a canvas, then the object itself doesn't need its own canvas, in fact due to how Unity Canvases update I would think it would be even worse than giving every single item its own canvas, since a canvas only updates when something changes, but if something changes the ENTIRE canvas is refreshed and if you have a canvas within a canvas, it will be checking two canvases each time one of them changes.

I would have thought having all cards on their own canvas, then the dynamic UI on one canvas and static on another would be a good starting point, but really I wouldn't prematurely optimize this.

As to a tutorial there are actually plenty around, though I usually don't like linking Youtube tutorials on GameDevSE https://www.youtube.com/watch?v=aPXvoWVabPY by Brackeys would help you best, this covers using ScriptableObjects as Data containers for cards, it shows you how to set up a prefab, which along with the ScriptableObject data container can display any card you have, it generally explains the concept of using ScriptableObject as data containers for cards well without eating up too much time.

Hope some of this helps!

\$\endgroup\$
1
  • \$\begingroup\$ Thank you for the very thorough answer! \$\endgroup\$ May 18 at 17:53
1
\$\begingroup\$

everything that contains text also needs to be inside a canvas object to even be visible.

You actually can have text outside of the canvas by adding the TextMesh component or the (IMO superior) TextMeshPro Text Mesh component to a gameObject. These components allow you to create a regular game object represented by a piece of text floating in 3d space.

One possible use-case for that are damage numbers flying around when something gets hit.

But for text on cards in a card game, this is probably not the best approach. I would really recommend to use canvas instead. This makes it far easier to get the layouting of the cards correct and consistent.

if I want to put text on my cards and make them come from a reusable Prefab, the Prefab itself needs to be a canvas (or somehow contain one), otherwise text elements would not show up on it (at least based on my trials).

No, you misunderstood that. It is perfectly possible to turn a gameObject which is a child of a canvas into a prefab. That prefab will then "remember" that it belongs onto a canvas. When you edit such a prefab, it will even be presented to you within a dummy canvas. I am using that a lot. In fact one of the first things I do in most projects is to create prefabs based on each of the UI elements like Button or Text and then only use instances of those prefabs when building my UI. The reason is that I can then easily change the look of my game UI by editing those prefabs, and the changes then get applied automatically to all the UIs in the game.

So having the playing field as one canvas with each card being a separate gameObject on that canvas instantiated from prefabs is perfectly possible. I would recommend the approach of prefab variants here. Create one template card to define the basic layout all cards are going to have in common. Then create each individual card as a prefab variant inheriting from the basic template card. This has the advantage that any changes to the template card will also be respected in the variants. For example, when you decide to move the points cost from the upper right to the upper left corner, or change the font of the card name from Arial to Helvetica, you don't need to edit 100 cards, you only need to edit one, and all others will inherit those changes automatically.

However, the approach to keep each card as a separate canvas can also have benefits. For example, when you want to do some eye-candy effects like in Hearthstone with cards flying around in 3d space. In that case you can use a World Space Canvas for each card. A world space canvas is a canvas which is not glued to the screen, but instead acts as a game object in 3d space which you can move, scale and rotate as you want. But the drawback is of course that you are now responsible for managing the layout of the playing field yourself and can no longer rely on the auto layouting components for the canvas to do that for you.

\$\endgroup\$
1
  • \$\begingroup\$ Thank you! Interestingly enough, what you described in the last two paragraph is exactly what I ended up doing. My only problem is that my game being pixel-based, the world canvas and the one containing my UI does not scale the same way to resolution changes; so their pixels are slightly different in size. \$\endgroup\$ May 18 at 17:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.