451

(69 replies, posted in UFE 1 (Deprecated))

Fantastic!  Throws are the main thing my game is missing, so I'm VERY excited for this.

My guess is Opponent Override is for their throw reactions?  I assume we're able to set multiple types of throws, where each could require a different reaction from the opponent.

Loving that this update also includes input viewer, rect hitboxes and AI.

Mistermind: firstly, thanks heaps for this awesome update.  I can't wait to get my hands on it.

How are rect hitboxes incorporated?  Are they available both as passive and hurtboxes?  Are we able to align to body parts, or are they positioned in another way?

Initially, I was just going to post the code for Blender Rigify rigs, but since this addition was actually quite easy, I thought it was a good idea to make a tutorial so others can implement it for their own skeleton systems.  This should work for any rig created from any package, you just need to know the names of your bones.

This will work in all versions as I think the CharacterEditorWindow.cs script is included in all versions.

Firstly, in Unity/UFE, manually create the hitboxes for one character that has the rig you want to use.  Make sure you assign hitboxes the correct bone types (deformation bones typically in a heirachy, not IK bones).  If you already have a character ready with this requirement, then you can use it.

Open the character in UFE's Character Editor, expand Hit Box Setup and press Open Character.  Expand the Hit Boxes, we'll need to refer back to it soon.

Then in your text editor, open CharacterEditorWindow.cs, and find this chunk of code:

                                    EditorGUI.BeginDisabledGroup(FindTransform("Head") == null);{
                                        if (StyledButton("Auto-Setup for Mixamo Auto-rigger")){
                                            if (EditorUtility.DisplayDialog("Replace Hitboxes?", 
                                                                            "This action will delete your current hitbox setup. Are you sure you want to replace it?",
                                                                            "Yes", "No")){
                                                hitBoxesScript.hitBoxes = new HitBox[0];
                                                for(int i = 0; i <= 14; i ++){
                                                    HitBox newHitBox = new HitBox();
                                                    if (i == 0){
                                                        newHitBox.bodyPart = BodyPart.head;
                                                        newHitBox.collisionType = CollisionType.bodyCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .7f;
                                                        newHitBox.position = FindTransform("Head");
                                                    /*}else if (i == 1){
                                                        newHitBox.bodyPart = BodyPart.neck;
                                                        newHitBox.collisionType = CollisionType.noCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .2f;
                                                        newHitBox.position = FindTransform("Neck");*/
                                                    }else if (i == 1){
                                                        newHitBox.bodyPart = BodyPart.upperTorso;
                                                        newHitBox.collisionType = CollisionType.bodyCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .9f;
                                                        newHitBox.position = FindTransform("Spine2");
                                                    }else if (i == 2){
                                                        newHitBox.bodyPart = BodyPart.lowerTorso;
                                                        newHitBox.collisionType = CollisionType.bodyCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .9f;
                                                        newHitBox.position = FindTransform("Spine");
                                                    }else if (i == 3){
                                                        newHitBox.bodyPart = BodyPart.leftUpperArm;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("LeftArm");
                                                    }else if (i == 4){
                                                        newHitBox.bodyPart = BodyPart.rightUpperArm;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("RightArm");
                                                    }else if (i == 5){
                                                        newHitBox.bodyPart = BodyPart.leftForearm;
                                                        newHitBox.collisionType = CollisionType.noCollider;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("LeftForeArm");
                                                    }else if (i == 6){
                                                        newHitBox.bodyPart = BodyPart.rightForearm;
                                                        newHitBox.collisionType = CollisionType.noCollider;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("RightForeArm");
                                                    }else if (i == 7){
                                                        newHitBox.bodyPart = BodyPart.leftHand;
                                                        newHitBox.collisionType = CollisionType.noCollider;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("LeftHand");
                                                    }else if (i == 8){
                                                        newHitBox.bodyPart = BodyPart.rightHand;
                                                        newHitBox.collisionType = CollisionType.noCollider;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("RightHand");
                                                    }else if (i == 9){
                                                        newHitBox.bodyPart = BodyPart.leftThigh;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("LeftUpLeg");
                                                    }else if (i == 10){
                                                        newHitBox.bodyPart = BodyPart.rightThigh;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("RightUpLeg");
                                                    }else if (i == 11){
                                                        newHitBox.bodyPart = BodyPart.leftCalf;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("LeftLeg");
                                                    }else if (i == 12){
                                                        newHitBox.bodyPart = BodyPart.rightCalf;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("RightLeg");
                                                    }else if (i == 13){
                                                        newHitBox.bodyPart = BodyPart.leftFoot;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("LeftFoot");
                                                    }else if (i == 14){
                                                        newHitBox.bodyPart = BodyPart.rightFoot;
                                                        newHitBox.collisionType = CollisionType.hitCollider;
                                                        newHitBox.type = HitBoxType.low;
                                                        newHitBox.radius = .5f;
                                                        newHitBox.position = FindTransform("RightFoot");
                                                    }
                                                    hitBoxesScript.hitBoxes = AddElement<HitBox>(hitBoxesScript.hitBoxes, newHitBox);
                                                }
                                            }
                                        }
                                    }EditorGUI.EndDisabledGroup();

and copy it and paste it just below.  You've just created a second button that does the same thing as Mixamo Auto-Rig Setup.  We're going to edit this copy.  I recommend adding a comment just before your pasted statement so you know which button is which.

From here on, you'll be editing the pasted block of text, NOT the original you copied from.  MAKE SURE YOU ARE WORKING ON A COPY OF THE TEXT, otherwise you'll lose the Mixamo AutoRig button!


Where is says:

if (StyledButton("Auto-Setup for Mixamo Auto-rigger")){

change the button name to suit.  I used "Auto setup for Blender Rigify".


The Mixamo auto rigger button is inactive if a certain bone is missing.  You can do the same by looking for a bone that's specific to your rig.  In the line just above the button name, you'll see:

EditorGUI.BeginDisabledGroup(FindTransform("Head") == null);{

Change it from Head to something specific to your rig.  In my case with Blender Rigify, I went with ORG-hips.


Then just a few lines down, you'll see a for loop with this chunk of code near the top:

                                                    if (i == 0){
                                                        newHitBox.bodyPart = BodyPart.head;
                                                        newHitBox.collisionType = CollisionType.bodyCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .7f;
                                                        newHitBox.position = FindTransform("Head");

The Mixamo AutoRig setup simply looks for named transforms and assigns hitboxes appropriately.  All you need to do here is in each if statement, change the transform you're looking for to the appropriate one in your rig.  Here's what the above one looks like in mine:

                                                    if (i == 0){
                                                        newHitBox.bodyPart = BodyPart.head;
                                                        newHitBox.collisionType = CollisionType.bodyCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .7f;
                                                        newHitBox.position = FindTransform("ORG-head");

Note that with Blender Rigify, for the upperTorso hitbox I had to offset the chest bone since it was too low.  See the below snippet for how that's handled.  Note that the offset has to be after the transform search, else it won't work.

                                                    }else if (i == 1){
                                                        newHitBox.bodyPart = BodyPart.upperTorso;
                                                        newHitBox.collisionType = CollisionType.bodyCollider;
                                                        newHitBox.type = HitBoxType.high;
                                                        newHitBox.radius = .9f;
                                                        newHitBox.position = FindTransform("ORG-chest");
                                                        newHitBox.offSet = new Vector2(0f, .5f);

Once you have done all hitboxes, save the script.  Then in UFE open a new character with the same rig.  You should see the Mixamo button disabled but your new one is active.  Test the button and you should find the new button auto set ups the hitboxes.  If there are missing hitboxes, check the spelling of the transform names you entered.

If you want to take this further, try creating buttons that do specific set ups.  Like auto set up with weapons, if you were making a soul calibur type fighter; or auto set up with wings/tails if your game has some characters with those components.  There are 9 custom bones that could easily be used for such things.

453

(2 replies, posted in UFE 1 (Deprecated))

In Hit06, you have a y force of 1.  That could be propping up your enemy.

In Nikova_02, it's a High Knockdown type, which will also prop up the enemy.  And if your knockdown has hitboxes, then you could still be hitting them after this too.

Hit 03 is a Knockback type, so that could also be propping up your enemy a bit.

If you want the hit to never knock the opponent up, then always give it a y force of 0 and make sure it's type is not one of the knockdown types.  That's usually all that's required.  But since you have modded UFE to be a beat em up, not sure if anything you've done there might also be a factor.

Game looks good though.  Keen to know how you incorporated UFE into a beat em up.

Whelp!  Just realised I wasn't correctly checking for charge attacks.  It's a simple enough fix.  After doing all of the above, go back into GUIScript.cs and look for:

moveCommand += p1Moves[h].attackMoves[g].buttonSequence[i] + " ";

and replace with:

                        if (p1Moves[h].attackMoves[g].chargeMove && i==0) {
                            moveCommand += p1Moves[h].attackMoves[g].buttonSequence[i] + " (hold) ";
                        } else {
                            moveCommand += p1Moves[h].attackMoves[g].buttonSequence[i] + " ";
                        }

… then look for:

moveCommand += p2Moves[k].attackMoves[l].buttonSequence[m] + " ";

and replace with:

                        if (p2Moves[k].attackMoves[l].chargeMove && m==0) {
                            moveCommand += p2Moves[k].attackMoves[l].buttonSequence[m] + " (hold) ";
                        } else {
                            moveCommand += p2Moves[k].attackMoves[l].buttonSequence[m] + " ";
                        }

Also you'll need to fix up 4 lines of string replacements (commandListP1.Replace and commandListP2.Replace) to suit.

If it still doesn't work, let me know and I'll post corrections.

* EDIT: forgot to check only first sequence button has charge

455

(3 replies, posted in UFE 1 (Deprecated))

Ah, sorry I didn't realise you're modifying the Stage Options.  I think in theory what you have should work.  I assume you've tested, how does it feel?

Also, answering question from first post:  Round Options has the initial spawn locations for p1 and p2.

456

(3 replies, posted in UFE 1 (Deprecated))

I think it depends the stage (http://www.ufe3d.com/doku.php/global:stages).

You can set different left/right boundaries, so the centre could be considered different if you have different left/right boundaries.

At least, that's my understanding.  This also doesn't take into consideration 3D movement.

BTW, will you have walls or ring outs in your game?

I've recently enabled a basic dynamic special command display which gets all non-normal attacks of both players and puts them into a string.  While making this, I also decided to create options for my own names for the buttons should I need them elsewhere (like a button config).  This way, Button1 appears as Light Punch.  You can edit the button names in Global Input Options.

My method below only covers charge attacks and quarter circle commands, but it should be simple enough to add support for other command types if you have them. 

Something else that might be worth adding is a way to minimise multiple commands for different strengths (so you only have one Flash Kick command instead of one for each button strength).  One way I can think of is creating a bool in the Move's General section, where if checked it won't come up in command lists.  Then just check for that bool in the GUIScript loops.

You'll need to modify 3 scripts: GlobalInfo.cs, GlobalEditorWindow.cs and GUIScript.cs (or your own GUI script).

In GlobalInfo.cs, find:

[System.Serializable]
public class InputOptions {

at the end of the class, add:

public InputNaming[] inputNaming;


then right below the class, create a new class:

[System.Serializable]
public class InputNaming {
    public ButtonPress UFEButton;
    public string displayName;
}


In GlobalEditorWindow.cs, find:

private bool player2InputOptions;

below, add:

private bool inputDisplayNames;


then find:

globalInfo.inputOptions.cancelButton = (ButtonPress) EditorGUILayout.EnumPopup("Cancel Button:", globalInfo.inputOptions.cancelButton, enumStyle);

below it, add:

// Button In-game Names
                        EditorGUILayout.Space();
                        //EditorGUIUtility.labelWidth = 180;

                        inputDisplayNames = EditorGUILayout.Foldout(inputDisplayNames, "Input Display Names", foldStyle);

                        if (inputDisplayNames) {
                            EditorGUIUtility.labelWidth = 180;
                            EditorGUILayout.BeginVertical(subGroupStyle);{
                                for (int i = 0; i < globalInfo.inputOptions.inputNaming.Length; i ++){
                                    EditorGUILayout.BeginVertical(arrayElementStyle);{    
                                        EditorGUILayout.Space();
                                        EditorGUILayout.BeginHorizontal();{
                                            globalInfo.inputOptions.inputNaming[i].UFEButton = (ButtonPress) EditorGUILayout.EnumPopup("UFE Input:", globalInfo.inputOptions.inputNaming[i].UFEButton, enumStyle);
                                            globalInfo.inputOptions.inputNaming[i].displayName = EditorGUILayout.TextField("Display Name:", globalInfo.inputOptions.inputNaming[i].displayName);    
                                            if (GUILayout.Button("", removeButtonStyle)){
                                                globalInfo.inputOptions.inputNaming = RemoveElement<InputNaming>(globalInfo.inputOptions.inputNaming, globalInfo.inputOptions.inputNaming[i]);
                                                return;
                                            }
                                        }EditorGUILayout.EndHorizontal();
                                    }EditorGUILayout.EndVertical();
                                    EditorGUILayout.Space();
                                }

                                if (StyledButton("New Display Name")) {
                                    globalInfo.inputOptions.inputNaming = AddElement<InputNaming>(globalInfo.inputOptions.inputNaming, new InputNaming());
                                }

                            }EditorGUILayout.EndVertical();
                        }


In GUIScript.cs, above the Awake() add:

    // Command List stuff
    private string commandListP1;
    private string commandListP2;


then find:

isRunning = true;

and above it, add:

        // Command List GET!

        MoveSetData[] p1Moves = UFE.config.player1Character.moves;
        MoveSetData[] p2Moves = UFE.config.player2Character.moves;

        // P1
        for (var h=0;h<p1Moves.Length;h++) {
            for (var g=0;g<p1Moves[h].attackMoves.Length;g++) {
                if (p1Moves[h].attackMoves[g].attackType != AttackType.Regular) {
                    string moveCommand = "";
                    for (var i=0;i<p1Moves[h].attackMoves[g].buttonSequence.Length;i++) {
                        moveCommand += p1Moves[h].attackMoves[g].buttonSequence[i] + " ";
                    }

                    for (var j=0;j<p1Moves[h].attackMoves[g].buttonExecution.Length;j++) {
                        if (j<p1Moves[h].attackMoves[g].buttonExecution.Length-1) {
                            moveCommand += p1Moves[h].attackMoves[g].buttonExecution[j] + "+";
                        } else {
                            moveCommand += p1Moves[h].attackMoves[g].buttonExecution[j];
                        }
                    }

                    commandListP1 += p1Moves[h].attackMoves[g].moveName + ": " + moveCommand + "\n";

                }
            }
        }

        commandListP1 = commandListP1.Replace("Back Foward ", "b (hold), f+");
        commandListP1 = commandListP1.Replace("Down Up ", "d (hold), u+");
        commandListP1 = commandListP1.Replace("Down Foward ", "qcf+");
        commandListP1 = commandListP1.Replace("Down Back ", "qcb+");

        foreach (InputNaming inputName in UFE.config.inputOptions.inputNaming) {
            commandListP1 = commandListP1.Replace(inputName.UFEButton.ToString(), inputName.displayName);
        }

        // P2
        for (var k=0;k<p2Moves.Length;k++) {
            for (var l=0;l<p2Moves[k].attackMoves.Length;l++) {
                if (p2Moves[k].attackMoves[l].attackType != AttackType.Regular) {
                    string moveCommand = "";
                    for (var m=0;m<p2Moves[k].attackMoves[l].buttonSequence.Length;m++) {
                        moveCommand += p2Moves[k].attackMoves[l].buttonSequence[m] + " ";
                    }

                    for (var n=0;n<p2Moves[k].attackMoves[l].buttonExecution.Length;n++) {
                        if (n<p2Moves[k].attackMoves[l].buttonExecution.Length-1) {
                            moveCommand += p2Moves[k].attackMoves[l].buttonExecution[n] + "+";
                        } else {
                            moveCommand += p2Moves[k].attackMoves[l].buttonExecution[n];
                        }
                    }
                    
                    commandListP2 += p2Moves[k].attackMoves[l].moveName + ": " + moveCommand + "\n";
                    
                }
            }
        }
        
        commandListP2 = commandListP2.Replace("Back Foward ", "b (hold), f+");
        commandListP2 = commandListP2.Replace("Down Up ", "d (hold), u+");
        commandListP2 = commandListP2.Replace("Down Foward ", "qcf+");
        commandListP2 = commandListP2.Replace("Down Back ", "qcb+");
        
        foreach (InputNaming inputName in UFE.config.inputOptions.inputNaming) {
            commandListP2 = commandListP2.Replace(inputName.UFEButton.ToString(), inputName.displayName);
        }

        // end Command List GET!


then, find the 2nd instance of:

if (showSpecials){

Inside here, you can remove everything before the else statement, or comment it out.  Then add:

                        GUILayout.BeginHorizontal();{
                            GUILayout.Label(player1.characterName);
                            GUILayout.FlexibleSpace();
                            GUILayout.Label(player2.characterName);
                        }GUILayout.EndHorizontal();

                        GUILayout.BeginHorizontal();{
                            GUILayout.Label(commandListP1);
                            GUILayout.FlexibleSpace();
                            GUILayout.Label(commandListP2);
                        }GUILayout.EndHorizontal();

I think that's all of it.  If I missed anything, or if you get errors let me know and I'll fix it up.

458

(2 replies, posted in UFE 1 (Deprecated))

Maybe I'm misunderstanding the question, but I think what johndman is proposing is possible.

ie: I have a generic Standing Heavy Punch move that two characters will use: Ryu and Guile.  In the sHP Move data, I have links to both Ryu's Fireball (QCF+P) and Guile's Sonic Boom (Charge b, f+P).  So when Ryu is using the sHP, he can cancel into his fireball but not the Sonic Boom because he doesn't have that move in his list, even if he performs the Sonic Boom command (which won't come out because it's not in his move set).  And vice-versa for Guile.

This is how it works for me so far, and I haven't had any issues regarding missing moves for characters (like Ryu missing Guile's Sonic Boom from above example).

459

(180 replies, posted in UFE 1 Source (Deprecated))

Have you looked at the camera scripts from Unity tutorials?  They're very smooth, and would easily be doable for UFE.

I'm curious, what was the solution to the campointer issue?

Sorry, yeah I forgot to say that even with what I mentioned it doesn't explain why in your case A->B works but B->A doesn't.

Long story short, I can confirm that creating moves with your desired functionality isn't possible.  In fact, the only way I could get results was when I made the Button Execution be Button 1 and Button 2 (any order).  This way, Hold 1 then pressing 2 allows the attack, but holding 2 than pressing 1 doesn't.  So, I can confirm your results in-game (which you already knew tongue).

Have you looked in AbstractInputController?  It seems to be where all the inputs are logged before ControlScript looks for it.  I was looking in that script, but my programming knowledge isn't up to understanding most in there.  I'm suspecting that either the inputs are always in the same order in a list, rather than in order of oldest->youngest (if it's even polled that way).

Hopefully, you'll have more luck than me.  Short of MisterMind chiming in on this...

You know GetButton and GetButtonDown are reporting on two different things right?  GetButtonDown will only provide a positive on the frame the button is pressed, while GetButton is true while the button is still pressed.  And of course, GetButtonUp will be true the frame the button is released.

I brought up the functionality aspect, as I've never had any problems with inputs not registering in the game.  And the Input Leniency feature is generally what you need to play with to achieve desired functionality.

How long are you holding the first button before pressing the next one?  If more than a frame, than the first button should always be true with GetButton and the 2nd button true on the frame for GetButtonDown...

Do you still not get the functionality you want when you set Allow Input Leniency for the move?

463

(180 replies, posted in UFE 1 Source (Deprecated))

Not even with something like:

CustomScript customScript = Player.gameObject.GetComponent<CustomScript>();

If that's not even working, than I have no idea…

So I understand clearly, what would accessing these empties in each player allow you to do?  Hopefully there's another way to achieve what you want without needing to access children of player prefabs.

464

(180 replies, posted in UFE 1 Source (Deprecated))

OK, it's a bit of a hack, but what I'd do is just manually assign the empty on the prefab.

So, in a script on the prefab create a variable

public Transform childEmpty

.  Then in Unity, drag the prefab to the scene, drag the empty child into the childEmpty variable on the parent script, then re-save the prefab.  When you want to access the empty, get to it via the parent's script public variable.

It does mean you'll need to do this for each character, but without seeing why you're not able to search for the empty I can't think of another way to get it working.

465

(180 replies, posted in UFE 1 Source (Deprecated))

How have you put the cam pointer empty in each player prefab?  After instantiation, or is it in the prefab already?
And while running the game, can you confirm the empty is actually a child of the player transform?

EDIT: just read your other post about it wink.

OK, so it's attached (a child?) of the head transform.

It's probably not the best method, but have you tried a direct path like in this example?

http://docs.unity3d.com/ScriptReference … .Find.html

466

(180 replies, posted in UFE 1 Source (Deprecated))

Can you confirm that both P1Trans and P2Trans are assigning correctly in Start()?  I'd put a quick check after the last foreach loop.  Something like:

if (P1Trans == null || P2Trans == null) Debug.Log("Player Transform(s) not assigned!");

I'm suspecting you're looking for them before they're created, but that's just a hunch looking at your code without testing...

467

(3 replies, posted in Animation)

I haven't touched Max in over a decade, but I believe Character Studio and biped (or whatever is in it now) should work OK.

Are you sure it's working fine in Mecanim (i.e., test the model/animations in a basic scene without any UFE stuff)?

You're probably aware, but mecanim requires a standard FK hierarchy in order to map the bones correctly.  I've had to rejig a lot of my custom skeletons in order to use mecanim features.  Personally, it's worth it, as it adds a lot of useful functionality in Unity.  UFE, being one of the biggest with requirements of flipping animations for player 2 side.

Anyway, if you like, you can post the fbx/max for someone to look at.  Another thing worth trying, is looking at the free models on Unity Asset Store or Mixamo and see how they work.  They're a good baseline for how your rig should look.

468

(3 replies, posted in Animation)

Are you using mecanim?

469

(5 replies, posted in Suggestions)

Personally, for this sort of thing I'm hesitant to modify stuff pertaining to idle/crouch/jump etc, as those states are determined by the game engine and the player doesn't really get direct control over them.  I would imagine if you did do that, you could end up with Roll Cancel like mechanics, where a property of one state is inherited by another state (i.e. you're in knockdown state but actually standing so you can't be hit by anything).

Can you describe the type of wave dashing you are wanting to do (like from which game, or how it behaves)?  Let's see if we can work something out smile

470

(5 replies, posted in Suggestions)

One of the default characters (Robot Kyle) has an auto jump after launching the opponent.  There's a move called Super Jump, which is the jump used for this chain.

Basically, it's as MrPonton says - you can make an attack that behaves like a jump.  Have a look at Robot Kyle's set up and you'll get the idea.  Notice there's no active frames, and the self applied forces is what makes him jump (and casting frame is set to match character's jump delay).

For crouch, try a 1-2 frame crouch move, which shares the same animation as your character's crouch (so it looks the same and players can't tell it's a new move).  Set the execution to Down, reset X forces, no active frames and that might work.

Also, have you tried playing around with the friction stuff in physics?

Since the next UFE update is a few months away, thought I'd post this in case anyone else was wanting to get their training modes a little more fleshed out.

This is just a simple implementation of refilling health, with the time delay exposed under the Training Mode checkbox.  I recommend testing what delay works best for your game as each game will feel different, especially when considering wake up times.

In GlobalInfo.cs, after line:

public bool trainingMode; // NOT COMPLETE

add:

public float updateHealthInSeconds = 3;

In GlobalEditorWindow.cs, after line:

globalInfo.trainingMode = EditorGUILayout.Toggle("Training Mode", globalInfo.trainingMode);

add:

                    if (globalInfo.trainingMode) {
                        globalInfo.updateHealthInSeconds = EditorGUILayout.FloatField("Update Health Time:", globalInfo.updateHealthInSeconds);
                    }

Then in ControlsScript.cs
above:

    void Start () {

add:

    private float trainingTimeToHealthFull;
    private bool trainingCanUpdateHealth = false;

… then, just under:

    void Update() {

add:

        if (UFE.config.trainingMode) {
            if (trainingCanUpdateHealth && Time.timeSinceLevelLoad >= trainingTimeToHealthFull) {
                myInfo.currentLifePoints = myInfo.lifePoints;
                trainingCanUpdateHealth = false;
            }
        }

… and finally replace the whole private bool DamageMe(float damage) method with:

    private bool DamageMe(float damage){
        if (UFE.config.trainingMode) {
            trainingTimeToHealthFull = Time.timeSinceLevelLoad + UFE.config.updateHealthInSeconds;
            trainingCanUpdateHealth = true;
        } else {
            if (myInfo.currentLifePoints <= 0 || opInfo.currentLifePoints <= 0) return true;
        }
        if (UFE.GetTimer() <= 0 && UFE.config.roundOptions.hasTimer) return true;
        myInfo.currentLifePoints -= damage;
        UFE.SetLifePoints(myInfo.currentLifePoints, myInfo);
        if (myInfo.currentLifePoints <= 0 && !UFE.config.trainingMode){
            UFE.PlaySound(myInfo.deathSound);
            UFE.PauseTimer();
            if (UFE.config.roundOptions.slowMotionKO){
                Time.timeScale = Time.timeScale * .2f;
                Invoke("ReturnTimeScale", .4f); // Low timer to account for the slowmotion
            }else{
                Invoke("EndRound", 3);
            }
            return true;
        }
        return false;
    }

Careful with that last one, there are two DamageMe methods, make sure you replace DamageMe(float damage) and not DamageMe(float damage, bool doesntKill)!!

472

(5 replies, posted in UFE 1 Source (Deprecated))

Not sure if this was missed or is already fixed for next update, but the Sticky and Bodypart variables on Particle Effects don't work (I kept getting a null exception error when the particles were cast, but non-sticky works fine).  I was in the process of doing a convoluted hack to access the character's bone transforms, when I eventually noticed you have a HitBoxesScript.getTransform.  This works GREAT!  We can now create simple particle effects to simulate slashes and attack lines without need of baking into FBX (which I have no idea how to do anyway tongue).

So here's the single line of code that needs to be changed to make it work properly (the particle to stick to the body part):

In ControlScript.cs, change:

if (particleEffect.particleEffect.stick) pTemp.transform.parent = transform;

to:

if (particleEffect.particleEffect.stick) pTemp.transform.parent = myHitBoxesScript.getTransform(particleEffect.particleEffect.bodyPart);

Oh, actually that captcha isn't there now.  Looks like it's there for the first 5 posts to prevent bots?  It's all good now, so don't worry about it wink.

474

(6 replies, posted in Character Design)

The Unity docs say less than 30 bones per character with 300 - 1500 polygon count per mesh.

http://docs.unity3d.com/Manual/Modeling … cters.html

I think if you're doing a fighting game, you can get away with more of each as long as your backgrounds don't have any bones (or very minimal).  Also, I think those figures are a few years old now so current gen can probably run a bit more.

I thought I read once that for Unity Mobile there was an actual max limit of bones per mesh (something like 55 I think), but I could just be remembering something else entirely so don't quote me on that.

Anyway, the best thing you can do is just test it yourself.  I know I've gotten more than 30 bones on a mesh with a simple rag doll test for mobile before, so you should be right.

I thought I'd have a quick look to see if this was easy enough to add, and it was! big_smile

Here's my edits to get this working:

In MoveInfo.cs, add:

public bool onPress = true;

to the line above:

public bool onRelease;

In MoveEditorWindow.cs, add:

moveInfo.onPress = EditorGUILayout.Toggle("On Button Press", moveInfo.onPress, toggleStyle);

to the line above:

moveInfo.onRelease = EditorGUILayout.Toggle("On Button Release", moveInfo.onRelease, toggleStyle);

Then in MoveSetScript.cs, add:

if (!inputUp && !move.onPress) return null;

on the line below:

if (inputUp && !move.onRelease) return null;

Note sure if there's a better way to do that last one (maybe combine both in single if statement?) or if the order matters, but with my quick testing it seems to work fine.

Please feel free to move this into the Code forum too.

BTW, thanks for making this easy to extend.  I don't consider myself a very coder, but even I've found it quite easy to add in additional functionality.