Make an attack system for a card game ?

Hi, I’m making a card game and am trying to find the best way to implement an attack system for my cards.
What I basically want to do is :
-Click on the card which needs to attack
-Select the target by clicking on it(and check whether it is valid)
-Attack

I tried using the OnPointerClick interface that called a coroutine in which it waited for the user to click, capture what was clicked on with a raycast then do my magic with that information, the problem being that clicking on said card will also trigger the coroutine, creating an infinite chain.
Is there any elegant way to do this (maybe disabling the Clickable script for other cards beforehand so that they can’t receive mouse inputs ?) or should I use the OnBeginDrag and OnEndDrag as it seems way simpler to create what I want with ?

Thanks a lot for your help !

Grab a piece of paper and make yourself a little state diagram of what leads to what UI-wise. Keep it initially VERY simple, because these things turn into hairy beasts really quickly. Here’s an example based on what you said above, with each circle being a state, and each wire being a user input (text in red).

5192816--516092--cards.png

Now you can make variables that track the states (no coroutines until the attack actually sequences through), and input conditions that move you from state to state, and update your UI elements accordingly: show the card selected, show the available targets, highlight the target once chosen, etc.

I have a package called Datasacks which is useful for hooking up UI to code without lots of specific dragging. It does NOT specifically solve the problem above, but it is completely usable in the above problem.

Datasacks is presently hosted at these locations:

https://bitbucket.org/kurtdekker/datasacks

Oh thanks, that’s a good way to visualize it!

So if I’m following correctly, this is what I would need to implement :
1- Make sure the game is in the right state to enable said card attacking
2- When all the conditions are met, clicking on a valid card would call a method in another class that keeps track of the Attack state,changing the state to “Card selected”.
3- In that state, clicking on another (valid target) card would call the same method, which would then act differently as the game state is different. Clicking on the first card or an invalid target would bring us back out of the Card Selected state.

This seems like a solid way to implement it, but I’m not sure how I would go about coding it, maybe something like this ? (this is obviously not code)

Method called by OnPointerClick()
{
-Checks which AttackState we’re in
-Call the method that is associated with that attack state
}

Method CheckCard() // Called when AttackState is Idle
{
-Checks whether the selected Card is valid
-If so, puts the game in “Card Selected” state
}

Method CardSelected() // Called when AttackState is CardSelected
{
-Checks whether the 2nd clicked GameObject is valid
-If not, returns an error message but keeps the game in this state
-Checks if the card clicked is the same as the first card (= cancelling) or a certain key is pressed (key to cancel)
-If the card is a valid target, put the game into TargetSelectedState
}

Method TargetSelected() // Called when AttackState is TargetSelected
{
// As I don’t need further confirmation, I’m skipping the whole “tap attack” phase
-Execute the attack
}

I am also not sure what the best way to easily cycle through these phases could be. For my turn phases, I used a switch condition controller by a simple int variable that was incremented everytime the “Turn phase button” was pressed, calling the associated method within a different class. But maybe there is a way to cycle through a list of state, for example in an enum ?

Thanks again for your help !

That approach seems good… and yes, you should use an enum to capture each state. “ChooseTarget” is always easier to understand than “3”

However, you should NOT actually just increment it to change the state!

The reason is that the entire thing breaks if someone far in the future reorders the enums, or inserts another one.

It’s always better to have something like:

state = State.Idle;

Rather than just an increment. It also lets you search for all instances of State.Idle, for instance, and have confidence you found them all.

I would even go so far as to make your enum skip by 10s initially so that even if you increment it, you will end up with an invalid state, and you can either catch that with a switch statement than ensures you are in a known state, and if you are not it throws an error and you find it immediately before going too far ahead.

The debugger you save will be you. :slight_smile: