3
\$\begingroup\$

I'm trying to achieve the same effect that cards in Hearthstone and Eternal CCG does, for example, cards behave as they were a type of "crane", when the cards move, their body is tilted towards the direction they are moving, making it behave like a "crane".

Does anyone have any idea whatsoever on how I could achieve this? I'm trying to do everything manually, e.g., get the card position, detect if the card is moving left or right, change the card Y axis to achieve the tilt effect relative to the direction the card is moving, clamping the value so it doesn't over-rotate, etc., etc.

I would really appreciate and would LOVE to know how I could be doing this. Do I need to create an animation and play after giving it the direction? I don't know you help me out please!

\$\endgroup\$
3
  • \$\begingroup\$ It would be nice if you could find a video which demonstrates the effect you want to create. Most people here are far too busy with making games to play every game ever made. \$\endgroup\$
    – Philipp
    Commented Feb 12, 2017 at 16:07
  • \$\begingroup\$ This should be your example: youtube.com/watch?v=mQcSaLT_Zow&feature=youtu.be&t=1m4s just notice how the cards behaves when the player moves them around \$\endgroup\$
    – ULI-R0
    Commented Feb 12, 2017 at 22:28
  • \$\begingroup\$ Also I must add, this is the result I'm expecting, but I still feel there's gotta be some other ways to do it: puu.sh/u0xHi/7d70923581.mp4 \$\endgroup\$
    – ULI-R0
    Commented Feb 13, 2017 at 0:56

3 Answers 3

1
\$\begingroup\$

I've got the perfect solution, see the scripts at the end of the post.

These scripts are those actually used in Hearthstone client. You need to attach a DragRotator script to the object you want to rotate. In the Awake() function of DragRotator.cd I just added a Reset() that wasn't here, but you need to to a Reset() before using the script anyway. You need to adapt it to your game, in my case when the object move one the y axis, there is a rotation following the x axis, and when it move on the x axis, the rotation follows the y axis (it wasn't the same on the hearthstone script).

You also need a reference to a DragRotatorInfo script, made by the function SetInfo(DragRotatorInfo) info using the script. Personaly, I used a singleton to have one DragRotatorInfo script for all my DragRotator scripts. Thanks to that you can modify the values of the two DragRotatorAxisInfo of the DragRotatorInfos.

These infos are very simple and they control the two rotations (when you move up/down and left/right).

Force multiplier : the more it is, the less you have to move the object quickly to make it rotate. I use values of 10-15.

Min Degrees/Max Degrees : obviously the min & max values of the rotation in degress. I use values of 40-50.

Rest seconds : the time the object take to go back to its original position. I use values of 2-3.

Hope it helps someone!

DragRotator.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DragRotator : MonoBehaviour
{
    private const float EPSILON = 0.0001f;
    private const float SMOOTH_DAMP_SEC_FUDGE = 0.1f;
    private DragRotatorInfo m_info;
    private float m_pitchDeg;
    private float m_rollDeg;
    private float m_pitchVel;
    private float m_rollVel;
    private Vector3 m_prevPos;
    private Vector3 m_originalAngles;

    private void Awake()
    {
        Reset();
        this.m_prevPos = this.transform.position;
        this.m_originalAngles = this.transform.localRotation.eulerAngles;

    }

    private void Update()
    {
        Vector3 position = this.transform.position;
        Vector3 vector3 = position - this.m_prevPos;
        if ((double)vector3.sqrMagnitude > 9.99999974737875E-05)
        {
            this.m_pitchDeg += vector3.y * this.m_info.m_PitchInfo.m_ForceMultiplier;
            this.m_pitchDeg = Mathf.Clamp(this.m_pitchDeg, this.m_info.m_PitchInfo.m_MinDegrees, this.m_info.m_PitchInfo.m_MaxDegrees);
            this.m_rollDeg -= vector3.x * this.m_info.m_RollInfo.m_ForceMultiplier;
            this.m_rollDeg = Mathf.Clamp(this.m_rollDeg, this.m_info.m_RollInfo.m_MinDegrees, this.m_info.m_RollInfo.m_MaxDegrees);
        }
        this.m_pitchDeg = Mathf.SmoothDamp(this.m_pitchDeg, 0.0f, ref this.m_pitchVel, this.m_info.m_PitchInfo.m_RestSeconds * 0.1f);
        this.m_rollDeg = Mathf.SmoothDamp(this.m_rollDeg, 0.0f, ref this.m_rollVel, this.m_info.m_RollInfo.m_RestSeconds * 0.1f);
        this.transform.localRotation = Quaternion.Euler(this.m_originalAngles.x + this.m_pitchDeg, this.m_originalAngles.y + this.m_rollDeg, this.m_originalAngles.z);
        this.m_prevPos = position;
    }

    public DragRotatorInfo GetInfo()
    {
        return this.m_info;
    }

    public void SetInfo(DragRotatorInfo info)
    {
        this.m_info = info;
    }

    public void Reset()
    {
        this.m_prevPos = this.transform.position;
        this.transform.localRotation = Quaternion.Euler(this.m_originalAngles);
        this.m_rollDeg = 0.0f;
        this.m_rollVel = 0.0f;
        this.m_pitchDeg = 0.0f;
        this.m_pitchVel = 0.0f;
    }
}

DragRotatorInfo.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

using System;

[Serializable]
public class DragRotatorInfo
{
    public DragRotatorAxisInfo m_PitchInfo;
    public DragRotatorAxisInfo m_RollInfo;
}

DragRotatorAxisInfo.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

[Serializable]
public class DragRotatorAxisInfo
{
    public float m_ForceMultiplier;
    public float m_MinDegrees;
    public float m_MaxDegrees;
    public float m_RestSeconds;
}
\$\endgroup\$
2
  • \$\begingroup\$ It appears your linking to the script; you should include the script in formatted code, as part of the answer. If your answer depends on the script to be complete, and the script is only accessible via link, your answer may be deleted. \$\endgroup\$
    – Gnemlock
    Commented Aug 17, 2017 at 5:19
  • \$\begingroup\$ Amazing, I couldn't have asked for more! Definitely way more intricate the way they do it than the way I was doing it (visually) \$\endgroup\$
    – ULI-R0
    Commented Aug 19, 2018 at 2:42
2
\$\begingroup\$

You can use Unity's Physics. "Joints".

Which allows you to move your object like attached to a rope or spring.

Here is a video from Unity, about Physics Joint.

Here is the docs from Unity.

You need to make some adjustments to values in order to get the best effect you want.

I don't know how much Unity's Physics use your resource but this should be the easiest and fastest way.

Hope this helps! Cheers!

\$\endgroup\$
3
  • \$\begingroup\$ Truly amazing! this is what I was referring to! however will it be able to work? because in my case, I'm using the mouse cursor as the initial object that's moving the card, so in my case, the "invisible rope" would somehow has to be attached to my mouse? or how would it go? Also how I would be able to fix the problem of gravity? since things that are attached to joints are usually hanging down and my card is positioned vertically, I guess this is where you said I would need to make some adjustments indeed :D \$\endgroup\$
    – ULI-R0
    Commented Feb 13, 2017 at 22:57
  • \$\begingroup\$ I chose your answer as solution, you pointed me in the right direction, thankfully I have found this: gist.github.com/mstevenson/4552515 which proves to be a working solution to what I was originally looking for! I of course have to make some tweaks but thanks to you I can finally achieve my goal! \$\endgroup\$
    – ULI-R0
    Commented Feb 14, 2017 at 0:22
  • 1
    \$\begingroup\$ I am glad that is helpful. Also i could add few things to your previous comment. There could be an invisible object; which position is same as mouse. While you start dragging you will set a joint between that object and and your card, also in that time you will enable gravity to your card. After dragging you will disable the joint and disable the gravity on your card. Have a nice coding! @ULI-R0 \$\endgroup\$
    – Thalthanas
    Commented Feb 14, 2017 at 6:33
0
\$\begingroup\$

Use SmoothDamp to create a delay movement toward your mouse position, change the z to the same level of your card to avoid the card stick to the camera.

Create a virtual point by using mouse x,y and the card z - an offset. It is because you want the point in front of your card. Then use LookAt or LookRotation to make your card look at that virtual point.

Vector3 targetPos = new Vector3(point.x, point.y ,CardBaseNode.transform.position.z);
        CardBaseNode.transform.position = Vector3.SmoothDamp(CardBaseNode.transform.position, targetPos, ref velocity, 0.1f);
        CardBaseNode.transform.rotation = Quaternion.LookRotation(CardBaseNode.transform.position - point);

The point is a Vector3 with mouse x,y and the card position with z offset already.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .