How to Create a 2D Card Game in Unity - Part 2 (Canvas Cleanup and Advanced Interactivity)

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everybody em as far as on here and welcome to part 2 of building a 2d card game with unity in this video we're gonna clean up some of the things that we saw when we created the layout and the basic structure for our game in the first tutorial and we're gonna add a cool feature where when I hover over a card with my mouse I can get a preview of it that's twice the size of the card so that I can look at what the cards gonna do before I play it if you haven't already worked through part 1 of this tutorial or at least watched it I highly recommend that you do so as you'll get a sense of what kind of code we're using to create our the scripts in our game and also what the game structure looks like and how everything works together I'm gonna describe everything that we're doing moving forward but I'm not going to talk too much about what we've already done I'll also include a link to the entire repository on github if you'd like to look at the project yourself and all of the code yourself so let's get started by just playing our game and seeing where we're at right now when I hit play I get this really ugly screen which consists of the the top third being the enemy area or the opponent's area to play cards I've got the bottom area which is my area to play cards and in the middle I've got a drop zone where I can drag and drop cards into I don't expect you for you to love the cyberpunk like and really ugly theme of this playing field right now we're focusing on functionality and not design you can do anything that you want with this and make it look exactly like the card game that you want to play when I hit draw cards it's gonna randomly draw from a list of these two cards so that I get red and and green cards as you can see in my my project tab I have these two cards here and it's gonna draw them as flat images on the screen onto the canvas and I can drag a green card and drop it right in the middle where it gets dropped into the drop zone or I can drag a red card and you know do that to my heart's content great well one of the issues that we ran into which is a really good learning experience for us about the unity canvas is that when I drag a card from the player area over to the drop zone it looks just fine it looks naturally natural like I'm just you know drawing a card and dropping it there but if I drag it to the enemy area it goes underneath this enemy area or the opponent area and if I drag it over to the draw cards area it goes underneath the button and that doesn't look very good similarly when I drag something from the opponent area it is fine over the drop zone and actually it goes over the player area but it goes underneath the draw cards button which isn't ideal there's a there's a reason for this and that's because the way the canvas works in unity is that it is going to the unity the unity engine engine is going to render things within the canvas hierarchy in order of their appearance in the hierarchy from top to bottom meaning that the lower you get on the hierarchy the closer to the screen or to my eyeballs are is the object going to appear so as you can see here if I just close this close all the trees here so that we don't have to see anything that's nested I have the background closest to the canvas then the drop zone then the player area then the enemy area and then the button and the button is the closest thing to the screen whereas the background is the furthest furthest thing from the screen so if I were to for example move the button behind the player area under the drop zone not nested within the drop zone but under the drop zone now when I draw things from the player area it's going to go over the over the button it's still going to go underneath the enemy area because the enemy area as you see here is lower on the hierarchy than the player area so I could just move the player area below the enemy area well let's do that now and now when I do it it goes over the the enemy area and it goes over everything and that great but now I'm in this conundrum where if I try and draw something from the enemy area it goes over everything here but I have the reverse issue where it goes under the player area which is not ideal so we're gonna we're gonna deal with that issue first okay for that we need to go into our code so I'm gonna go into my scripts and I'm going to go into my drag-drop script that we created in the previous time just to in the previous tutorial just to give you a reminder up here at the top we've declared all of our variables that we need we have an update method which is checked every frame that everything every frame it unity checks to see if the directives that we have in that within the code block is true and if so it'll execute whatever it is that we want to do and we've said that if the card is being dragged we want to change the position of the transform or of the card that's being dragged to a new vector to where the vector 2 is equal to the mouse positions x-coordinate and the mouth positions y-coordinate that just means that it's going to move where the mouse moves and we did some work where if there's a there's a collision meaning a collision between our card and the drop zones colliders then we'll allow it to be dropped if it is if it's not over the drop zone then it'll be returned to its starting position and we've bound all this together with the start drag and the end drag functions which I'll remind you are located in the prefabs so if I go to the card one prefab I see this in this event trigger where when I begin dragging I use my start drag function and when I end dragging I use the end drag function if that's not clear to you please return to the first part of the tutorial and you can recreate this yourself and it'll make a lot more sense right now I got to deal with the canvas issue so what I'm going to start by doing is creating a public game object right here where I declare all my variables a public game object called canvas and I'm gonna add we in the previous time we deleted the start function I'm going to add the a private void awake function which essentially unity calls this function when the when the this particular script or object is instantiated basically when it becomes awake and I'm this say that canvas should be equal to a game object called main canvas so what I'm asking unity to do I'm saying when this script comes alive or awake assign this canvas variable to a game object within my scene called main canvas in parentheses I'm sorry in quotation marks meaning there's a string called main canvas that I want you to find and I'm gonna change the name of this canvas to main canvas you can call it whatever you like just make sure that the name of the object and the name of your variable are the same and what it's going to happen is going to search my my scene for this thing called the main canvas and then what I'm gonna do is during the update method that we have we've said if if the object is dragging we want the transform position to become equal to the mouse position so make sure that the card follows the mouse wherever the mouse goes and that basically means I'm drawing my card around the screen I'm an add a line here that says transform dot position I'm sorry transform dot set parent canvas transform comma troupe let's just hover over this so we see what's happening here when I'm when I'm saying that I want the well let's back up and just say what does it transform the transform means the literal transform of the object that I'm moving like the position of it and I'm saying that the the position of the transform I'm moving it based on the mouse position and I want to set the transforms parents parent to the canvas that I declared up here and the this particular declaration requires you to say whether or not the world position of the of the object should say true or false we're just going to say it's true right right now meaning that the transform should stay where it is rather than being moved in terms of the world position but there's a couple of things other things that I need to address before I can make this all work together the first one is that I need to figure out how what to what happens when I drop the card anywhere on the screen we saw before that if I don't drop it right in a drop zone it should just return to its original position in my hand but that's not going to be necessarily true if I if I assign it to if I assign the parent of the card to the canvas in the middle of the whole operation and then I drop it somewhere else it's going to stay with the parent so what I need to do here is also declare a private game object start parent just as I did with start position and I'm going to move down here to the to this part of the code where I say start drag start position is equal to transform dot position I'm going to add another line that says start parent is equal to the transform dot parent game object meaning when I start this dragging process I want to store whatever the parent is into this variable called start parent and then in the end drag function you see we've said that it the variable is is dragging or the Bullock boolean is dragging is equal to false and if it's over the drop zone well okay drop the the card make its make its parent transform the the drop zone and here we said false meaning that I don't want it to keep its world position I want you to move the card to the position of the drop zone if it isn't over a drop zone then I say that I want the transforms position to be to go back to its start position and I also want transform set parent to be the start parent transform and I don't want it to keep its world position I want it to move to the start point the start parent position okay so let's take a look at the the game now that we've added this code I'm gonna hit play and now everything loads up as normal when I draw cards the this card which is in the player area and as you can see in that hierarchy it is higher in the hierarchy I mean closer to the main care mean main canvas but it is further away from the screen than the button but when I move it over here or I move it over to the enemy area it's the the closest thing to the screen so that looks a lot more natural and by the same token when I pull this card from the enemy area it is it goes above everything else in the screen which is what we want and if I drag and I don't drop it over the drop zone it just goes back to where it should be if I drag it goes while I didn't drag it correctly if I drag it let's say over to the player area it goes back to where it started so that's all working properly all that does is that it all that it means is that I'm making the element a child of the main canvas at the very bottom or the closest to the screen while it's dragging and then I send it back to its original location and I make its transforms parent the original locations parent at the end of the drag process if it doesn't get dropped into the drop zone if it gets dropped in the drop zone it shares the drop zones transform position and also it makes the drop zone its parent there's another method that you might see when you or declaration that you might say see if you've been searching for this exact issue it's called set as first or set as last sibling that just means that if I want something to be set as the last sibling of the of a hierarchy then I just use that method if I want to be said it's the first sibling I can do that as well you don't need to do this and that do that in this case but there are two methods that are are worth knowing about as you might run into them as well okay so that's looking pretty good the other thing is that or I should say the second thing is that if I hover over this over this card let's say that you have a card with text on it and it's really tiny and you can't see it when you are playing the game well that can be problematic for your players so we're going to introduce a script that is going to create a new version of that card and project it or render it right above wherever the card is and allow you to see a more clear version of it because it's just simply bigger but when you move your mouse away from it it's going to destroy that game object so that you don't have to look at it anymore it doesn't clutter up your screen so let's take a look at how to do that the first thing I'm going to do is I'm going to create a new script and I'm going to call it card zoom very descriptive and I'm going to open this card card zoom script and there's not much going on it on in it but what I am gonna do is I'm gonna do a similar thing that we did before in that in fact I don't think I need any of these methods here I'm going to create a public game object called canvass and a private game object called zoom card that's the card that's going to be zoomed zoomed in on I should say and in this public void awake that is built into unity I'm going to do the same thing that I did before and say that the canvas variable is equal to a game object and I'm going to find it and it's going to be called the main canvas great so we found our canvas now I'm going to create a a public method that's called on hover enter you can call this whatever you want but this just helps me remember what the what the method does and this is the this is the script that I want to run or the code that I want to run when my mouse is enters the field where the card is located and I'm going to say that zoom card should be equal to the instantiation or the creation of a game object and when I say game object without you know any frills around it I just mean this game object that it's attached to I'm going to attach this to my prefab so when I say instantiate game object that means instantiate this very game object or this very prefab this card that this script is attached to and I want it to be at a new vector2 where the a vector2 is input mouse position dot X an input dot Mouse position dot Y and I don't want it to have any rotation so I'm going to say quaternion identity here at the end of this these parameters and okay let's see if this works just by itself I have a sense that it actually won't work but I want you to give a get like a progressive understanding of how this code works I sent essentially right now I'm saying on hover enter make this zoom card instantiate this zoom card with a new vector2 or a new position right where the mouse is and actually let's just play it right now so that you see that it won't work but it'll give you an idea of why we're doing things in the direction that we're doing them so when I go to this card I'm actually going to attach the script to both cards so I attach my card zoom here and where's my other prefab I go to card two and I attach my card zoom here and this is this is a great reason why you'll probably want to make a just one prefab that is your base prefab for everything before you start adding all these scripts and colors or whatever you need to do to them anything that's gonna be shared across all your prefabs make that prefab first so you don't have to add different components to them multiple times and do all this stuff multiple times it will just help so if I go back to my prefab and in fact just to make things a little bit easier on us I'm gonna I'm gonna go to my script of card zoom and I'm gonna add a public void on hover exit and I'm just I'm just gonna leave this empty for a net for now I just want to have it there so I can show you what's gonna happen so just like we did with our drag and drop script I'm gonna say I want to on each of my prefabs I'm gonna add a new event type and in this one I'm gonna say a pointer enter event meaning when the pointer or the mouse pointer enters the the field or the transform of the card I want to do something and when the pointer exits the field I want to do something and rather than it doing this drag drop and drag script I've already attached the the card one prefab to this little field here which is how I can access or expose the script that's attached to it now I'm going to choose the card zoom script and use on hover enter so when the pointer enters it's gonna call the uh never hover enter script and when the pointer exits it's going to call the card zoom on hover exit method so not is gonna happen but now it's all at least wired together and I'm gonna do the same here on card - we're on pointer enter I'm going to use card zoom on hover enter I guess I could call them the same thing and then on pointer exit I'm gonna call card zoom on hover exit great so it's all wired together but it's not gonna work check this out I hit play I hit draw cards and now when I hover over things you see that it's actually it's in the hierarchy things are happening it is drawing or creating new cards but I'm not really seeing anything that's going on and I'm not actually sure right now if it's just creating them on top of these other cards and we're not seeing them move but it doesn't really matter what what matters is that it's kind of working and what we need to do is clean this up and add a few few things so that it's actually going to work the first thing here is we're going to create the we're gonna add we're gonna set the parent of the zoom cards transform to the canvas just like we did before so that it is higher or closer to the screen than anything else in the game so here we're gonna say zoom card dot transform dot set parent canvas that's the canvas object that we declared earlier canvas transform and remember I'm gonna say false because I want the world position where the card already is to stay where it is I don't want to set it to true because true would mean I set it to the world position of the canvas I don't want that to happen here I wanted to stay where it is and then I'm gonna say well actually let's run that first so that you can see the difference here when I hit play now watch this side of the the screen I hit draw cards and then rather than the card being instantiated elsewhere like outside of the main canvas they're all being instantiated right below everything else in terms of the hierarchy which means that they're higher on the screen or closer to my eyeballs than everything else that's great that's working as intended I'm gonna add a line in on hover exit just to say okay when I exit the area just destroy the game object I don't need it anymore okay now the thing that we need to do here is make a larger version of the card so that I can see it and make it be bigger and that's relatively easy easy to store easy to do what I need to understand is how the object that this script is attached to actually works and this can be really helpful in your understanding of the canvas and just unity in general so if I look at this object right now I'm on card 2 I have many different components that are attached to it an empty game object will have none of these new components and we're actually going to start from the bottom so we look at things in reverse order and you can move these around as you like I've got a rigidbody 2d which is what we use for physics in unity our unity 2d physics I've got a box Collider which handles my collisions I've got these event triggers that are that are triggered when an event happens when right now it's when the pointer enters or exits or when I begin our end dragging I've got these two scripts that are attached to it I've got an image and a canvas renderer which is what we see when when the object is populated on screen on screen and I've got this rect transform the the transform has the position of the object it has the width and the height the height it has the pivot and the anchors of the image rotation and scale bunch of things that you'd want to do if you're messing with the transform of the of the image and that's the component that we need to access when we want to change the size of the object through code or the scale of it so I'm going to say I'm going to declare a private variable called rect transform just call it rect is equal to zoom card dot getcomponent I want to get the component in the zoom card and the component that I want to get is the rect transform and I need these parentheses because it is a a method and then so now I've got that I've got this component that we just looked at the rect transform and I'm going to change the size of it recked size Delta equals a new vector2 and well let's see what the size of it is right now it's 120 by 177 in unity units or pixels I think we're working in pixel perfect I'm not sure but let's just call them unity units of measurement and I'm gonna make it 240 by 344 what's great about just a plug for visual studio when I'm using visual studio with the unity toolset installed i when i hover over or when I'm writing it uses in what's called intellisense it's the it's Microsoft's version of autocomplete basically and when I hover over or M I'm writing my code it gives me an indication of what fields I should be using what methods are available to me and so right now I see that I'm using size Delta and it says with a new when I'm writing a new vector 2 I need to have a float X and a float Y and in this case I'm using 240 and 344 which are the when we looked at 120 and 177 that's just twice that so I'm singing I'm saying make this twice as big as it was before when I save that and I play our game and I hit draw cards they all draw and then look now when I hover over them I see a bigger version of the thing and when I when I leave when I mouse enter my mouse pointer leaves they the object gets destroyed you can see that in the left side of the hierarchy - when this happens but I'm seeing some some bugginess here I'm seeing that they're flashing back and forth and there's a reason for that and what I could do is just like put a bunch of debug logs in here so I could see in my console what what's happening where but I'm just gonna save you that time and I'm gonna let you know that there's a few things that are happening one is that there is because I'm instantiating a game object that is the identical it's the same thing as this original game object it comes with all of these different properties these components including the box Collider so when I instantiate one of these objects here and I hover over them it creates that object and there's a it's having collisions all the time and not only that I'm hovering over an original game object so the game doesn't quite know am i hovering over this original card or am i hovering over this new card and just it's just kind of out of whack so I'm gonna do a couple of things to correct that plus the the new card is just going off-screen and that's not really working for me you're gonna have to do some some work to make this fit your game exactly I'm just going to show you one example of how to do this but the first thing I'm gonna do is I'm going to change this variable this parameter here which is when I instantiate this new game object I'm just saying put it where the mouse is in this case I'm gonna say change that to input Mouse position dot y plus let's say 250 unity units immediately we'll see a difference when I instantiate the game object on my hover hover over it's now going to be over the the drop zone it's gonna be 50 game units above where I originally had it so cool that's a little bit more sensible if I do it up here that doesn't work so what I'll need to do is I I'll need to tag these game objects is either being enemy objects or player objects and I have to do that when I instantiate them from drawing cards I'm not going to do that right now that that's a story for another time so you you could work with that depending on what you want to do or perhaps these game objects up here they're face down so I don't want the ability to actually be able to to hover over them and have them display a new game object so we're not gonna deal with that right now what I just want you to see is that I've given the cards the ability to instantiate 50 units above where my mouse is when they enter when when the mouse pointer enters the the transform you could actually have this be in a static place like let's say you want them to always be previewed here on the left you could do that the same in the code instead of saying input Mouse position X&Y you could just choose an absolute value and put them in there but for now this works for me but one thing that we didn't see and we would see if we used our debug log is that when I'm hovering over that it is then going to that new object the the twice the size object its colliding with the drop zone because we have a Collider on the drop zone which allows us to draw things in the drop zone and I don't want that to happen so I need to do something here to make sure that it's a little bit more clean and so what I'm gonna do here is remember how we talked about how there are all these different components to this to this game object well this game object also has a layer and right now it's part of the UI layer oh I'm looking at the drop zone if I look at card one or card to the layer here is in the cards and so what I'm gonna do here in this same code is I'm gonna make the zoom card layer so that zoom card that transform dot and if I ever forget any of this if you're using intellisense and and visual studio you can just like scroll down and find it or just start entering what you think it is and I say zoom card dot layer zoom card I'm sorry I'd said that incorrectly I'm going to say zoom card layer equals layer mask dot name to layer zoom this is a little bit convoluted and actually took me a little bit while to figure out is that when you say zoom card layer if I hover over this it says well this is the layer the game object is in but that's not exactly accurate there's a number of integers that it can assign the the zoom card to but if you want to access actually the names the named layers here like I want to add it to the cards layer for example I have to say the zoom card layer is equal to the layer mask or here it says when I hover over specifies layers to use in a physics tray cast name to layer and then I name the layer zoom and here I'm going to add a layer here that's called zoom and you'll recall from our previous tutorial that if I go to my project settings and under physics 2d I have the layer collision mask which means which layers are gonna collide with others and I'm gonna say you know what I don't want the zoom cards to just I don't want them to mess with anything like don't let them collide with the UI or the cards we just leave them alone okay so this this card so you get an idea as a prefab it defaults to the cards layer but and that that is going to collide with the with the drop zone so when I go into my code and I say when I instantiate a new card and I make it twice the size that it originally was so that it makes it a zoomed-in card I want to change the layer to zoom so that it's not kind of collide with anything anymore there's another way of handling list though there's at least one other way of handling handling this which is to instantiate the card and make it so that you disable the collider on it or you could instantiate it without a Collider like instantiate a different prefab I just find this to be easier so so we'll work with that you might find a different solution for this but now when I save this and I play the game and I draw cards and hover over them that now it's not it's not colliding with anything anymore it's just you know it's it's basically just a blank image that's flat and doesn't do anything but but show like if I had text on here if it was an image with text on it it would be twice as big you could make it three times a big you can make it one and a half times as big it's up to you and then when I when I exit its its destroyed there's one outstanding piece of this that I think would clean this up even better and that will become evident when I try and drag this see how it just stays on screen until I kind of hover off of it and it's just kind of weird what I want to do is I want to make that not happen so what I'm gonna do is i go to my card prefab and here under the event triggers where I have when I begin drag I call drive drop the start drag method I'm going to add another method here and I'm going to say well I have to drag my card one object here so that I can access the scripted attach to it scripts I should say and I want to call the card zoom method on hover exit what does that do well if I look at on hover exit I say destroy the zoom card and that's exactly what I want to happen when I start dragging the card because I don't want to see that zoomed card anymore and that's what I'm doing when the the pointer exits the the zoom transfer the card transform I have to do that in my card too as well so I go to my begin drag and I add will I pull in the same game object so I can access the script called card zoom and I say call the on hover exit function now when I play the game I draw cards and I can hover over them when I begin dragging the the hover card disappears and it goes right into the right into this drop zone and the same thing happens with my other card up here with the opponent cards and a neat project would be and perhaps we'll look at this in a future video but I think it might be fun for for you to check this out is how do you differentiate this the cards down here with the cards up here meaning that right now all cards are considered the same so when I hover over this card down here in the player area I see this this nice hovered card this zoomed in card but when I hover over these it's populating on the 50 units above or 250 units above my my mouse pointer how do I get that to be 250 units below my mouse pointer or none at all which is going to require me to create some way of to meaning that these cards down here are different from these cards up here and that would be an interesting way to start working with your code and differentiating which cards are which I have a sense that the way that I would begin to approach it is to go into my draw card my draw card script and in this on click method that is called when you press the button I'm calling this a player card and an enemy card so I'm already differentiating them between the two maybe I can add a tag of some sort like up here where I have tags right now this is untag untagged maybe I can create a tag for it and and set each card with that tag or make them part of a layer for example and do that programmatically through my code and then when this card zoom function is called I can either I'm changing if I'm changing the layer that might not work or I might say that if I might make create an if-else statement and say that if it's a player card do one thing with it and if it's or if or else if it's an enemy card do another thing with it and I'll play with my tags in my layers that way I'm not sure there are many ways to do it but that's that would be one way that I would start trying it out I've also received at least one question about the original tutorial about how do I handle if I have like 52 cards should I create 52 prefabs for them and that's definitely one way to do do it let's say I'm creating a card game that has 52 cards in it what I would do is I would create the the base structure and behavior for every card with just one prefab so I would say right now I just have card 1 and I'm doing everything that I can possibly imagine that all cards will need to do they'll need to be able to be dragged in drops they'll need to be able to be zoom then you'll need to be able to be destroyed they need to be tagged or whatever they need to do everything that they share in common just make one prefab and then duplicate that prefab fifty-two times and keep them in a prefab cards folder each of which and and each of the prefab should have the specific logic or images or scripts or whatever that are particular to that prefab but they all share the same or they all share the the derive the same behavior from the original card prefab that's gonna make your life easier on you so you don't have to change like a bunch of stuff across 52 prefabs that you've created from the get-go I would just say create one prefab that has all of the shared behavior and then create a prefab for each of the different cards that you're you're using in your game and then it's gonna depend on how you use how you instantiate those cards right now we're instantiated them on the button just if I look at my button script again my draw card script I have these public game objects card one card two and I create a list that has all my cards and I add those cards to that list and these cards correspond as you'll recall to these exposed objects in the in the draw cards component here on my on the actual button what I would do is I would create I would literally create 52 cards here in my prefabs and then I would expose them in the code here so instead of card 1 and cartoon it would be card 1 through card 54 I would add all of them programmatically to this list so that I can draw from them and then I would drag their prefabs onto this this these exposed fields on the on the button object it within this component so that they're all available and then possibly I'll delete them from that list as I as I draw from them and then when the the deck is has been completely drawn then I'll replenish the the deck and reshuffle them and do all that kind of fun stuff maybe we can do another video on that but in any case that's how I would do it so that's it for part 2 of building a 2d card game with unity I hope you've enjoyed this video and please do check out the github repository that I'll share in the description of this video as well if you'd like to take a look at the code yourself please be sure to like this video and subscribe to my channel for more and I look forward to seeing you soon [Music]
Info
Channel: M. S. Farzan
Views: 23,174
Rating: undefined out of 5
Keywords: coding, programming, learn to code, javascript, python, c#, c++, game development, html, css, 2d games, 3d games, learn programming, beginner coding, coding tutorial, entromancy, m s farzan, 2d game engine, react, unity, godot engine, game maker 2, construct 3, phaser 3, 2d game framework, what 2d game engine should I use, unity 2d, unity 3d, card game, tcg, ccg, trading card game, collectible card game
Id: eo6-FIT3G0M
Channel Id: undefined
Length: 42min 39sec (2559 seconds)
Published: Thu Mar 05 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.