Jump to content
GreenSock

Search In
  • More options...
Find results that contain...
Find results in...
Giggioz

Animating a card game in React with GSAP

Recommended Posts

Hi folks,

 

i moved my first steps in the Green Sock world and i find it amazing :)

Thanks a lot for all the goodies.

 

I'm trying to develop a card game in react and i've read a lot of resources in the forum to know how match React+GSAP and i think i get it (in particular i love this

I don't really have a GSAP related question, it's more an abstract question on how to correctly implement the whole flow of my app because i'm getting stuck in the animation part.

I posted the question in stack overflow HERE but i would love to hear some impressions by the forum experts because typically they give wonderful hints :)


If you feel this post does not belong to this forum feel free to delete it, thanks anyway.

Link to comment
Share on other sites

Asking a question like that on StackOverflow probably won't get you very far as it might be considered too broad or opinionated. 

 

I don't mess with React that much, so I can't help you out with that part, but searching this forum for React related questions is probably the best place to start. Look for posts by @Rodrigo as he the resident React expert around here.

https://greensock.com/forums/profile/9252-rodrigo/

 

Just wondering if you did the tic-tac-toe tutorial?

https://reactjs.org/tutorial/tutorial.html

 

I would probably start with that, and add animations to it to get an idea of how to structure stuff.

 

  • Like 3
Link to comment
Share on other sites

Hey, thanks for the reply.

 

I think i'm ok with the React stuff, my main problem is to understand how React and GSAP connect together at the end of the animation.

 

The example of the board game is almost perfect, we need some pieces to animate from a square to another, so let’s go with checkers for example:

 

  • i think you’ll have a Board, Square and Piece components that display the status of the app when we need to render
  • when you have a new update in the status (a piece moved from a cell to another cell) you start an animation (with gsap of course)
  • this animation moves a div-Piece from a div-Square to another div-Square… but you did not change the DOM position of the Piece, you did just an animation (a translation indeed)
  • this is my concern… do you need to reconciliate the div-Piece with the DOM? With this question i mean to remove the div-Piece from his parent and attach it to the new parent 
Link to comment
Share on other sites

1 hour ago, Giggioz said:

The example of the board game is almost perfect, we need some pieces to animate from a square to another, so let’s go with checkers for example:

 

  • i think you’ll have a Board, Square and Piece components that display the status of the app when we need to render
  • when you have a new update in the status (a piece moved from a cell to another cell) you start an animation (with gsap of course)
  • this animation moves a div-Piece from a div-Square to another div-Square… but you did not change the DOM position of the Piece, you did just an animation (a translation indeed)
  • this is my concern… do you need to reconciliate the div-Piece with the DOM? With this question i mean to remove the div-Piece from his parent and attach it to the new parent 

 

 

Those are really good questions. For a DOM/React based game, the reconcillation of the div-piece might be a good option. You could do a FLIP animation.

https://aerotwist.com/blog/flip-your-animations/

 

Check out this demo using Vue. It's not a real game, but it uses the FLIP technique.

https://jsfiddle.net/chrisvfritz/sLrhk1bc/

 

So lets say the cells are 100 x 100, and you want to move a piece from cell 0,0 to cell 1,1. You might want to animate it directly like...

 

TweenLite.to(element, 1, {
  x: 100,
  y: 100,
  onComplete: function() {
    // reconcilliate???
  }
})

 

With the FLIP technique, you would change the DOM first, the reconcillation part, and then animate it from where it was to its new position.

TweenLite.fromTo(element, 1, {
  x: -100,
  y: -100
}, {
  x: 0,
  y: 0
});

 

 

  • Like 5
Link to comment
Share on other sites

Wow, thank you SO much.

 

I'll dig into these links and will report back!

 

Regards.

Link to comment
Share on other sites

@OSUblake has a great point regarding DOM reconciliation.

 

Keep in mind that in react DOM manipulation is normally considered a no-no, anti-pattern, no-op and all those fancy terms that exists to politely tell you: "DON'T DO THAT!!!;)

 

I'd try to avoid changing the elements from one parent to another, but it this is a must-do situation using an onComplete callback (you see how shamelessly I'm re-using Blake's ideas?? :mrgreen:) to update the state, perhaps the index position of each child to match the order in which each parent is added to the DOM, to place them in the corresponding parent, would be a good way to do it. Perhaps using redux or mobx to store everything and access throughout the app.

 

Happy Tweening!!

  • Like 4
Link to comment
Share on other sites

Hehe. I did say I wasn't a React expert, so I'm not sure about the best way to do the reconciliation/DOM manipulation. What I was describing is something I've done with games using vanilla JavaScript. I guess it would be similar to using redux or mobx.

Link to comment
Share on other sites

Yep, the principle remains the framework changes, that's all. Is just about the "right moment" to update the DOM in cases like this. How to do that is up to whatever framework is being used.

  • Like 2
Link to comment
Share on other sites

Hey, i really appreciate the help here.

I investigated the flip pattern and it sounds promising. The react-flip-move repo links to a interesting article to explore some details of this topic, if you are interested.

 

Anyway, it looks like the reconciliation strategy is a viable one and i started to mock a streamlined codesandbox (sorry for not using codepen) but pretty similar to my real project and i'm starting to get my hands dirty with some tweening :)

In this example i use Grid from Semantic-UI to layout a Card and a Deck component.

They live in two different columns and i was trying to animate the Card moving on top of the Deck

 

I succeeded in doing that using getBoundingClientRect and i have few questions for you guys:

 

https://codesandbox.io/s/m9jn02vpp9

 

1) first of all, are you liking this approach? What do you think in general? Would you do something different?

2) am i using the tweens correctly?

3) is this approach 'responsive proof'?

 

Edited by Giggioz
edited with new codesandbox more polished and jquery free
Link to comment
Share on other sites

What type of game are you making? I can't comment too much on the React part, but that article looks like a good approach. 

 

On 4/5/2018 at 3:56 PM, Giggioz said:

3) is this approach 'responsive proof'?

 

Oh yeah! That's where a FLIP animation really shines. Click away at this demo.

 

See the Pen e266184b436634919d933ac0a94b608c by osublake (@osublake) on CodePen

 

 

An important thing to remember is that there shouldn't be any inline styling that deals with position or size on your elements. Before calling getBoundingClientRect in that demo, I set the transform on each element to "none", otherwise the bounds might be incorrect. Later on, I add any transforms that were on the element into the invert calculations. A nice thing about GSAP is that the transform values are cached on the element. For example, to get the x and y translation value, you can do this.

 

var x = element._gsTransform.x;
var y = element._gsTransform.y;

 

 

  • Like 4
Link to comment
Share on other sites

Hey!

 

I greatly improved the demo, now it has a simple status and, i think, it performs the FLIP.

 

The important bits are in App.js at lines 55, when you click on the Deal button:

  • the status changes
  • then the DOM sync accordingly (this.forceUpdate)
  • when the update is done dealAnimation is called to perform the animation fromTo

https://codesandbox.io/s/nwy30q5xw4

 

I have one issue tough: as you can see the animation starts and finishes at the 'wrong' spots, this has something to do with what you say here ?

I'm not able to fix it.

 

38 minutes ago, OSUblake said:

An important thing to remember is that there shouldn't be any inline styling that deals with position or size on your elements. Before calling getBoundingClientRect in that demo, I set the transform on each element to "none", otherwise the bounds might be incorrect. Later on, I add any transforms that were on the element into the invert calculations. A nice thing about GSAP is that the transform values are cached on the element. For example, to get the x and y translation value, you can do this.

 


var x = element._gsTransform.x;
var y = element._gsTransform.y;

 

 

side note: i use jquery to get the node references for the animation, this is not an issue for me now

 

Link to comment
Share on other sites

Here's a simplified example of FLIP without React. It's really like an optical illusion.  When the DOM changes, the elements will actually be in their end position/state, but the inverted animation makes it appear like it's transitioning to its new position/state.

 

See the Pen GxYPOX by osublake (@osublake) on CodePen

 

  • Like 3
Link to comment
Share on other sites

I'm doing pretty much the same stuff but i have some problem because i use left and top property (%) and then something goes wrong.

 

I modified  the css .card, to display it in the center of a bigger deck, when you toggle back there is a mismatch, can you help me with this?

 

.

card {
    position: absolute;
    top:50%;
    left:50%;
    transform: translate(-50%,-50%);
  }

 

See the Pen EEdMjM?editors=0110 by anon (@anon) on CodePen

 

Link to comment
Share on other sites

Hehe. Welcome to crazy world of DOM coordinates. Look at the different values reported by getBoundingClientRect and offsetLeft/Top/Width/Height.

 

See the Pen d960fccd812eb2de06e2a05f7e2255df by osublake (@osublake) on CodePen

 

 

getBoundingClientRect takes transforms into account, which is what's throwing off your positioning.

 

card {
  transform: translate(-50%,-50%);
}

 

And there's no easy way to read that transform value from a CSS file because the browser will convert it into a matrix.

 

An easy way to center the card would be with flexbox.

 

See the Pen wmYOxm by osublake (@osublake) on CodePen

 

 

Actually, CSS Grid Layout has really good support now.

https://caniuse.com/#search=grid

 

That might be a better an option than using semantic-ui for a grid.

https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Grid_Layout/Basic_Concepts_of_Grid_Layout

 

 

  • Like 3
Link to comment
Share on other sites

Wow, thanks again! (can i assume i always thank you when i reply? It's getting obvious :-D)

You're giving me an accelerated course in DOM animations :)

I read tons of articles today (and as many codepens...), trying to figure out a lot of notions that were missing in my head.

I stopped to work on my demo because i was caught by a lot of subtle details you addressed (getBoundingClientRect sheganigans, flexbox/grid/semantic grid, and more) and now i'm pretty tired to continue.

Basically i agree that flexbox should do the job and i love the last codepen you've done.

I want to explore the semantic-ui grid possibilities tough, under the hood it's just a glorified flexbox system, and see where i can get.

 

Have a nice week end, see you next days with new exciting questions :)

 

 

Link to comment
Share on other sites

Hi,

 

the flip basic codepen has been very helpful: my demo is almost finished and is almost working with Grid from Semantic ui.

 

https://codesandbox.io/s/w7831r09kk

 

If you can take a look at it you will see:

 

1) At start 12 cards are in the deck (overlapped thanks to position: absolute)

2) When you press 'DEAL' 9 cards change dom parent (the green rectangle)

3) Soon after an animation starts and move the 9 cards to the new parent using FLIP and some math to make them fit in the green rect with some overlap

 

I'm pretty ahead so far but i'm missing a last bit: as you can see from the demo the cards do not start their animation from the deck because when they change dom parent they lose the 'position: absolute' attribute and the flex container spread them horizontally.

 

Do you have any advise on how i could modify the staggerTo (or the whole approach) to make it functioning?

Thanks a lot.

 

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×