Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice
  4. Dismiss Notice

Swordplay mechanics

Discussion in 'Game Design' started by bobadi, Dec 7, 2020.

  1. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    this is new 180 animations
    made in mecanim (root transform rotation +-offset)
    from Frank Climax's katana pack
    sRslash90A.gif sRslash180A.gif sRslash180E.gif
    and this blending LStance slashes
    frankskatanablend.gif

    not planning to use any combos, but separate action moves
    though I should set stop-start on input for every action (attack > guard / attack)
    and attack direction on input

    haven't seen any swordplay discussions so any technical discussion goes
     

    Attached Files:

    Last edited: Dec 7, 2020
    tylerguitar75 likes this.
  2. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    playin with blend values add up some guard motions (though might be a bit lower)
    sRslashblends.gif
    and its mirrored couterpart
    sRslashblendsM.gif

    blend to stance
    blendtostance.gif
     
    Last edited: Dec 8, 2020
  3. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    so I created R stances similar to Frank Climax base pose
    which can be forward and backward attack starter
    stancesR.gif

    can be crossfaded between if clip is swapped on the other state w override controller
    these different hand poses are significant because slash is initiated based on hand position (L/R)
    but might want to start slashL instead of slashR which need hand position switch (not slash>slash, but slash>handswitch>slash) or not if the hand is close to center


    the stances will be tracked by events (the calculated errs)

    first test
    prototest.gif

    have to watch out for that gimp angle
    baked root rotation is a must
    so have to care for the transitions how they relate

    blend to stance
    switchLR.gif blendtostance2.gif
     
    Last edited: Dec 9, 2020
  4. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    here is an issue
    hand position drifts into left zone when body is at 135
    handPissue135.jpg

    and this happens (plays r-stance l-slash)
    handPissue135.gif

    but other times (when not doing 180 attack) it works
    handP_overshoot.gif

    update: usin hip bone and handP center range now
     
    Last edited: Dec 10, 2020
  5. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    stance switch tests
    switchtest1.gif

    R stance step backs
    RStanceStepB.gif

    R slash w stance switch
    RStanceSw.gif

    direction variant
    slashdirU.gif
     
    Last edited: Dec 9, 2020
  6. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    guard poses and managed to find a possible blend

    Rguards endin in LUp and LDwn
    guardsR.gif
     

    Attached Files:

    Last edited: Jan 9, 2021
  7. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    Interesting.
     
  8. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    as you probably noticed, the right stance fwd animations are the same as left stance back (RF = L180. LF= R180), just the orientation is different

    guards cont.
    LG20.jpg LG21.jpg
    guardF (right stance)
    left and right, which blend between them
    rgfl.gif
     
    BrandyStarbrite likes this.
  9. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    How come you removed the gifs and jpg's?
     
  10. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    the pictures should be okay, dl might stop if bad connection

    modified frank's walkF
    had to correct hold for my model (used animFixer fixerANM.cs see settings attached)
    walkF.gif
    and recorded one dif speed and put 0.4 speed and 1 on blend tree
    walkFblend.gif
    note: don't record man animation w onAnimIK.cs on it, because then SceneMotionCapture captures only in-place.

     

    Attached Files:

    Last edited: Jan 9, 2021
  11. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    Nice walk animation.
     
  12. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    yeah, its the basic. attackin move, root45R used with handgun, sword or fightmode move ahead.
    there's then stepF, which is like startWalk, different from continuous walkF.

    +also have to note that from stance can only start with speed 1 version,
    have to be a delay of half second for speed input


    now will have to find a meaningful mix, which probably will be blend tree with blendtree...
    between 3 guard sequences (the dif here that the second presumes attack from left / attacker ahead)
    maybe the 180 will remain just this one and 2 will be forward
    guardR1.gif guardR2x.gif
    +the RguardF right n left above #8


    the animator for sword state machine looks like this now
    animator1218.jpg
     
    Last edited: Dec 18, 2020
  13. YBtheS

    YBtheS

    Joined:
    Feb 22, 2016
    Posts:
    239
    This is looking pretty good so far.
     
  14. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    Wow! That is looking cool.
     
  15. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    Are there any big horizontal attacks, or big vertical slice attacks?
     
  16. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    not yet

    could be separate state or used in blend tree something like this
    vertangle.gif

    and setting blend parameter based on gamepad stick angle or button press
     
  17. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    changing stance idle using override controller
    (this way can transition to any idle in the 1D blend tree)
     

    Attached Files:

    Last edited: Jan 9, 2021
  18. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    so I managed to merge the 3 guard blend trees
    but can be more integrated (only need to change the motion to blendtree)
    mecanim blend trees are very good for blend mixings
    guardcontr.jpg

    I think the best approach is to have one full guard sequence for one stance
    seems there's no problem with transitioning directly to any of the guard poses
    changetest.gif

    there's three variables
    up : hand position height
    rgt : guard side (left 0 > right 1)
    wdwn : weapon direction (up 0 > down 1)

    there's two input buttons for guardFwd* and guardBck* for right and left stance;
    there's quick buttons for unHold, switchSide, and weaponDwn

    the default is guard stays up, on unHold button press turns back to stance idle.

    * I think these will hardcoded, so everytime guardR pressd will be same pose.(or modified values stay on**)
    when in guard mode, then can use input to lerp blend values of guard blend tree.

    ** for side, for up, for wdwn ...I think should work but I think need a another button to switch back to default, so defGuard on double press(?)
     
    Last edited: Dec 29, 2020
  19. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    Very cool, is this part of a game or a just standalone thing atm?
     
  20. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    it is part of the Renegade system, but planning to release it as a separate asset too
     
  21. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    YBtheS likes this.
  22. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
  23. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    come to the conclusion that

    there's
    3 types of attacksF (stayin, stepSwitch, stepF)
    staynmove3.gif
    - for stanceR and stanceL
    - 3 attack angles for each side
    slashes.gif
    and also one hand and both hand holding
     
    Last edited: Jan 9, 2021
    BrandyStarbrite, SparrowGS and YBtheS like this.
  24. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    the slash can end in regular stance (like above) or in freeze pose
    probably best to script crossfades, since anim clips can have diff lengths

    the two hold poses in blend
    holdsides.gif
    and slash endin in hold
    tohold.gif
     
    BrandyStarbrite and SparrowGS like this.
  25. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    What you're doing is really cool but I think you need to make a thread in the WIP section, this isn't really the right place.
     
    Antypodish likes this.
  26. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    opened up the thread to discuss implementation of (realistic) swordplay in unity.

    looks like was bogged down with the animations,
    though next I wanted to deal with input and hit detection

    if there's not much discussion on design, it's just demo, I get it
     
    Last edited: Jan 12, 2021
  27. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    That is some really cool nice stuff you are doing there.

    Question: Any parries or moves that deflect attacks?
    They do stuff like that in real sword fighting too.
     
    Last edited: Jan 12, 2021
  28. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    no actual parry moves, but
    the guard anims are made to do that. if you transition from slash or stance to guard.
    (when attack ends, can move/attack/guard and is defined by animation event.)

    guard seq, what you see in #12 and #18
    if you know which side the slash ends, you can know what parameter of the guard sequence will transition to the closest guard pose to deflect attack.
    I presume the player should select guard move to defend himself from slash (then later can be calculated based on attacker move)

    the actual deflection (stopping attack) is done by IK / animation stop.
     
    Last edited: Jan 12, 2021
    BrandyStarbrite likes this.
  29. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    did some test on stringcompare and objID compare performances
    in one on one, objID is faster by 1/3, but

    must compare at least 4 things (kinematic obj, rigidbody obj, sword, untagged obj)
    and can rule out selfhit by objIDCompare (for man and for sword)

    but turned out there's a little difference if using
    1 layer with all mixed layers (for stringC +2objIDC) or 4 layers and 2 or 3 objC

    1 layer: all [1x raycast] tag>> body ragd weapon id>> bodyself weaponself
    4 layer: default kinem ragdoll weapon [4x raycast] id>>> bodyself weaponself (else opponent)

    the biggest factor on performance is the number of raycast loops
     
    Last edited: Jan 23, 2021
  30. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    about the input

    using just one press for slashF [and setting blend px for slash direction, fwd and rgt]
    could have only one RSlash state but L and R variant is better if want to adjust transition time to stances
    sslash.jpg
    one press for guardF
    sguard.jpg

    not much, but proof of prototype workin
    swordtestR1a.gif
    there's a blend parameter mixup (mistyped guard.rgt for slash.rgt)

    mixing slash and guard rgt parameter not a good idea

    feels a bit better
    swordtestR2a.gif
     
    Last edited: Jan 23, 2021
  31. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,582
    You should be avoiding strings comparison, whenever possible. If not for speed, you can also generate potentially GC with strings. Just to be aware.
     
    SparrowGS likes this.
  32. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    I know, I don't use even enums anymore.

    that's why I did the test. do you know any other way to identify/filter a object hit by a raycast (than layermask + tag)?
     
  33. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,582
    There is number ways of doing such thing.
    Personally I don't use Unit tag system. Is too unreliable in my experience.

    You could for example create GO component, and andentify raycaste GO by that.
    I would probably store GOs in a dictionary as a key, and have custom tagging enum, as value.
    So if you raycast multiple GOs, you just iterate them, check GO hash against dictionary key and ckeck corresponding value (tag).

    You can have even multiple tag assigned to same GOs.
     
    SparrowGS likes this.
  34. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
    What? enums are not strings, they are ints* and use their string name only for convenience.

    *by default, you can change the backing type.
     
    Antypodish likes this.
  35. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    I've read that they are like strings
     
  36. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    yes but that is cumbersome to cache all the objects in the scene at start.
    since (if want to stop slash at hitting a wall/vehicle etc) would need to know if raycast hit anything/that.

    that is how would use with only gameobjectID comparing.

    though maybe caching just the players and swords (and maybe cuttable, hitable objects like glass, trees etc) could work
     
    Last edited: Jan 24, 2021
  37. SparrowGS

    SparrowGS

    Joined:
    Apr 6, 2017
    Posts:
    2,536
  38. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,582
    No more than setting different tags for all GOs. With tags, moving to different project, may cause you nightmares.
    You can add component with a script and enum input field as tag(s), which cashes GOs automatically at initialisation.

    As mentioned post above, enums are ints. But can be represented as string. However, you can not change name at runtime. In fact, in normal cases you can not alter enums itself at runtime. While you can do that with strings, unless is hardcoded.

    Similarly as with layers, you can access them by a name, or by int layer mask. But in case of layer mask, name is a string. So layer mask should be used instead. Each enum name and int should be unique. However, in case of layers, you are limited to 32 elements. Not the case for an enums.
    If enum value is not unique, otherwise you wił be prompted with an error, if trying otherwise.
    For each name you can set ints manually, or let them be set by default.
    Setting manually may have sense for convenience, debugging and config use.
    So in the case of comparing enums, even you can use enum name, you are actually compare an int. Not the string.
     
  39. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    oh crap. I might have mistaken it with parse.enum...
    can go back and add enums back

    can not alter enums itself at runtime
    yeah, it might have been the other reason stopped using it in some cases.

    can add component with a script and enum input field as tag(s)
    and getComponent() 's performance? using it on every raycast?
     
    Last edited: Jan 24, 2021
  40. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,582
    You should be cashing GOs, to avoid using GetComponent at runtime.
    But on other hand, ask yourself a question, how many GOs you will hit at once really, to be that even concerned about performance. 2, 5, 10 GOs per frame? That is nothing for modern CPU these days.

    Profile you performance.
     
  41. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    there's like 15 raycasts just for the sword. there are raycasts for obj detections for other features like jump, ai path etc
    these don't happen on every frame but multiplied with the number of characters there;s easily hundreds of raycasts and using getcomponent on each of them would be too much I guess*

    2. this script should go on every collider, not just GO...

    I think I go with a list of objects and using instanceID will try to filter them out on raycasthit

    *since hits can happen any time. can rule out selfhit if raycast starts inside the collider, but other collider can move in
     
  42. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    was thinking a bit more about it

    since I want the swords to be interchangeable (weapon pickup), need to check selfhit on sword itself not on other list (if for whatever reason want to start raycast outside of collider)

    and can avoid tag compare
    doing 1 raycast with a mixed layermask, then compare which layer is the hit object on
    hit.transform.gameObject.layer == layerX (which is a int compare)

    and this way can pretty much determine if ray hit player or enemy, or some other obj - by its layer (I guess max 10 layers is enough)
    and a list on the actor can get exacly which bodypart is hit
     
  43. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    so need layers:
    kinem, (*ragd), smashable, default

    *selectable

    other thing
    one exception is for slashes: LRslash can change while attack, can end in guard pose (by wrist rotation, arm cannot change rotation mid-slash)

    probly will use anim event for this exception

    probly will use event ranges only for animation input not for hit detection
     
  44. BrandyStarbrite

    BrandyStarbrite

    Joined:
    Aug 4, 2013
    Posts:
    2,068
    Nice work so far.

    Question: Are you using triggers for hit confirmation, or are you doing that by code only?
     
  45. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    it's raycasts
    swordtrace1.gif

    or you mean damage animation? that's probably code
     
    Last edited: Jan 25, 2021
  46. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,582
    You really should have a hotbox. (collided). First, it should detect, if there is collision at all with anything. Then you may cast a rays, if collision happens. But maybe multiple hitboxes would be sufficient in the first place?
     
  47. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    I don't think so.

    1. collision detection will miss mid-frames collisions (okay there are ways, but default behavior is that)
    2. performance. (raycasts are better, but more needed. but might need more colliders, if weapon has other shape) + contact point (if raycast)
    3. bodyparts have kinematic colliders (and no collision is detected between two isTrigger colliders)
     
  48. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    so input is
    adapted for gamepad controller

    there's 3 types of attack: slash in-place, slash moving, slash move with stance switch

    front buttons
    right1 : SLASH
    right2 : GUARD
    left1 : SLASH180
    left2 : TURN MOVE

    left stick :
    if no slash/guard : MOVE
    if slash : SLASH MOVE
    if guard : V : guard weapon dwn H : guard up
    if turn move : V : angle of turn

    right stick :
    if slash : V : slash angle H : slash direction
    if guard: V : guard fwd H : guard rgt



    also made a test with 52 actors
    sword50.gif
     
    Last edited: Jan 28, 2021
    BrandyStarbrite likes this.
  49. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    prototype

    swordPT1a.gif swordPT1b.gif
     
  50. bobadi

    bobadi

    Joined:
    Jan 3, 2019
    Posts:
    594
    there's (at least) two type of attacks to add

    vertical slash : stick input only gives 3 variants (-1, 0, 1) which can be use diagonal up slash, horizontal slash, diagonal down slash.
    so straight vertical top-to-bottom or bottom-to-top slash needs
    ....

    update:
    since h==0 is not not used for slash direction (-1: slash left, 1: slash right)
    0 can be slash down/up (v: -1:slash down, 1:slash up)

    stab : also needs separate input and animator state
     
    Last edited: Jan 30, 2021