im having trouble with the hand IK of a -recoil shoot animation- that is on an override layer in the animator. I have it set up so that when I aim(left trigger), it allows me to shoot with another button(right trigger). I have it so the weight (hand IK) increases to 1 (in the rig layer) when I aim and decreases to 0 when I let go of the aim button.
The problem is that if I shoot the gun (uses recoil gun animation) and let go of the aim button immediately afterwards, the animation will continue to play but the IK will go to 0 and the hands will look all messed up.
I've tried setting the IK hand weight to 1 when he fires the gun, so he'll still hold onto it, but it doesn't work since shoot is only true if aim is being held down.
So overall I fire the gun, he does a recoil animation, and when you let go of aim too early, the animation looks all messed up like he's waving to you from behind his back. Like it aborts the animation or something.
private void HandleMovementInput()
{
horizontalMovementInput = movementInput.x;
verticalMovementInput = movementInput.y;
animatorManager.HandleAnimatorValues(horizontalMovementInput, verticalMovementInput, runInput);
if (verticalMovementInput != 0 || horizontalMovementInput !=0) //running
{
if (aimingInput)
{
if (animatorManager.isAimingGunn == false)
{
shootInput = false;
}
}
}
if (animatorManager.isAimingGunn)
{
animatorManager.leftHandIK.weight = 1; // IK weight
animatorManager.rightHandIK.weight = 1;
horizontalMovementInput = 0f; // joystick
verticalMovementInput = 0f;
}
else if(animatorManager.isAimingGunn == false)
{
if(verticalMovementInput != 0 || horizontalMovementInput !=0) //running
{
animatorManager.leftHandIK.weight = 0;
}
animatorManager.leftHandIK.weight = 0; // IK weight
animatorManager.rightHandIK.weight = 0;
}
}
private void HandleShoot()
{
if (aimingInput) // must aim otherwise shootInput(right trigger on controller) wont work
{
if (shootInput)
{
shootInput = false;
playerManager.UseCurrentWeapon();
}
}
}
I was able to fix it. I used this code to tell the character to keep aiming if still in the current animation.This allows for the animation to finish before you set the Hand IK to 0.
if(animator.GetCurrentAnimatorStateInfo(1).IsName("Pistol_Shoot"))
{
aimingInput = true;
}
Also Due to it getting overly complicated I changed the aim cancel button to the top left trigger on the controller ( while aim is on the bottom left trigger).
I'm a beginner on Unity3D and I decided to create a 3D Tetris to start learning. Everything was fine so far, but I have a problem with collision detection.
https://gyazo.com/49fbf5798dc67a546c5e187fde8f6096
As you can see on this screen, the blue tetromino is not at the good place. This is due to the fact that the orange tetromino position in X is not precise (-2.9999).
Each block that makes up a tetromino has the tag "Block". The ground has the tag "Ground".
This is how I detect collisions in my OnCollisionEnter method.
if (collision.collider.tag == "Block" && !detectedBefore)
{
for (int k = 0; k < collision.contacts.Length; k++)
{
if (Vector3.Angle(collision.contacts[k].normal, validDirection) <= contactThreshold)
{
GetComponent<TetrominoMovement>().Snap();
GetComponent<TetrominoMovement>().enabled = false;
FindObjectOfType<Tetromino>().GenTetromino();
detectedBefore = true;
break;
}
}
}
if (collision.collider.tag == "Ground" && !detectedBefore)
{
GetComponent<TetrominoMovement>().Snap();
GetComponent<TetrominoMovement>().enabled = false;
FindObjectOfType<Tetromino>().GenTetromino();
detectedBefore = true;
}
Do you know how to get around this problem? Thank you in advance.
I am trying to spawn a set number of cubes within an ever changing area (a plane, ARKit) and NOT have them overlap. Pretty simple I'd think, and I have this working in Unity editor like so:
My problem is deploy to device (iPhone) and everything is different. Several things aren't working, and I don't know why - it's a relatively simple script. First I thought CheckSphere wasn't working, something with scale being different - but this is how I try to get an empty space:
public Vector3 CheckForEmptySpace (Bounds bounds)
{
float sphereRadius = tierDist;
Vector3 startingPos = new Vector3 (UnityEngine.Random.Range(bounds.min.x, bounds.max.x), bounds.min.y, UnityEngine.Random.Range(bounds.min.z, bounds.max.z));
// Loop, until empty adjacent space is found
var spawnPos = startingPos;
while ( true )
{
if (!(Physics.CheckSphere(spawnPos, sphereRadius, 1 << 0)) ) // Check if area is empty
return spawnPos; // Return location
else
{
// Not empty, so gradually move position down. If we hit the boundary edge, move and start again from the opposite edge.
var shiftAmount = 0.5f;
spawnPos.z -= shiftAmount;
if ( spawnPos.z < bounds.min.z )
{
spawnPos.z = bounds.max.z;
spawnPos.x += shiftAmount;
if ( spawnPos.x > bounds.max.x )
spawnPos.x = bounds.min.x;
}
// If we reach back to a close radius of the starting point, then we didn't find any empty spots
var proximity = (spawnPos - startingPos).sqrMagnitude;
var range = shiftAmount-0.1; // Slight 0.1 buffer so it ignores our initial proximity to the start point
if ( proximity < range*range ) // Square the range
{
Debug.Log( "An empty location could not be found" );
return new Vector3 (200, 200, 200);
}
}
}
}
This again, works perfect in editor. This is the code Im running on my device (without check sphere)
public void spawnAllTiers(int maxNum)
{
if(GameController.trackingReady && !hasTriedSpawn)
{
hasTriedSpawn = true;
int numTimesTried = 0;
BoxCollider bounds = GetGrid ();
if (bounds != null) {
while (tiersSpawned.Length < maxNum && numTimesTried < 70) { //still has space
Tier t = getNextTier ();
Vector3 newPos = new Vector3 (UnityEngine.Random.Range(GetGrid ().bounds.min.x, GetGrid ().bounds.max.x), GetGrid ().bounds.min.y, UnityEngine.Random.Range(GetGrid ().bounds.min.z, GetGrid ().bounds.max.z));
//Vector3 newPos = CheckForEmptySpace (bounds.bounds);
if(GetGrid ().bounds.Contains(newPos)) //meaning not 200 so it is there
{
spawnTier (newPos, t);
}
numTimesTried++;
platformsSpawned = GameObject.FindObjectsOfType<Platform> ();
tiersSpawned = GameObject.FindObjectsOfType<Tier> ();
}
if(tiersSpawned.Length < maxNum)
{
print ("DIDNT REACH - maxed at "+tiersSpawned.Length);
}
}
}
//maybe check for num times trying, or if size of all spawned tiers is greater than area approx
}
//SPAWN NEXT TIER
public void spawnTier(Vector3 position, Tier t) //if run out of plats THEN we spawn up like tree house
{
print ("SUCCESS - spawn "+position+"SPHERE: "+Physics.CheckSphere(position, tierDist, 1 << 0));
// Vector3 pos = currentTier.transform.position; //LATER UNCOMMENT - would be the current tier spawning from
//TO TEST comment to this line ---------------------------------------------------------------------------
#if UNITY_EDITOR
Instantiate (t, position, Quaternion.identity);
anchorManager.AddAnchor(t.gameObject);
#else
//------------------------------------------------------------------------------------------
Instantiate (t, position, Quaternion.identity);
anchorManager.AddAnchor(t.gameObject);
#endif
}
This doesnt crash the device but spawns ALL in the same place. I cant understand why. If I do this, CHECKING for overlap:
public void spawnAllTiers(int maxNum)
{
if(GameController.trackingReady && !hasTriedSpawn)
{
hasTriedSpawn = true;
int numTimesTried = 0;
BoxCollider bounds = GetGrid ();
if (bounds != null) {
while (tiersSpawned.Length < maxNum && numTimesTried < 70) { //still has space
Tier t = getNextTier ();
//Vector3 newPos = new Vector3 (UnityEngine.Random.Range(GetGrid ().bounds.min.x, GetGrid ().bounds.max.x), GetGrid ().bounds.min.y, UnityEngine.Random.Range(GetGrid ().bounds.min.z, GetGrid ().bounds.max.z));
Vector3 newPos = CheckForEmptySpace (GetGrid ().bounds);
if(GetGrid ().bounds.Contains(newPos) && t) //meaning not 200 so it is there
{
spawnTier (newPos, t);
}
numTimesTried++;
platformsSpawned = GameObject.FindObjectsOfType<Platform> ();
tiersSpawned = GameObject.FindObjectsOfType<Tier> ();
}
if(tiersSpawned.Length < maxNum)
{
print ("DIDNT REACH - maxed at "+tiersSpawned.Length);
}
}
}
//maybe check for num times trying, or if size of all spawned tiers is greater than area approx
}
Works great in editor again, but completely freezes the device. Logs are not helpful, as I just get this every time, even though they aren't spawning in those positions:
SUCCESS - spawn (0.2, -0.9, -0.9)SPHERE: False
SUCCESS - spawn (-0.4, -0.9, 0.2)SPHERE: False
SUCCESS - spawn (0.8, -0.9, 0.2)SPHERE: False
SUCCESS - spawn (-0.4, -0.9, -0.8)SPHERE: False
SUCCESS - spawn (0.9, -0.9, -0.8)SPHERE: False
What the hell is happening - why would it freeze only on device like this?
Summary:
it sounds like you needed a short gap between each spawn.
(BTW a useful trick is, learn how to wait until the next frame - check out many articles on it.)
All-time classic answer for this
https://stackoverflow.com/a/35228592/294884
get in to "chunking" for random algorthims
observe the handy line of code at "How to get sets of unique random numbers."
Enjoy
Unrelated issue -
Could it be you need to basically wait a small moment between spawning each cube?
For a time in unity it's very simply Invoke - your code pattern would look something like this:
Currently ...
for 1 to 100 .. spawn a cube
To have a pause between each ...
In Start ...
Call Invoke("_spawn", 1f)
and then
func _spawn() {
if count > 70 .. break
spawn a cube
Invoke("_spawn", 1f)
}
Similar example code - https://stackoverflow.com/a/36736807/294884
Even simpler - https://stackoverflow.com/a/35807346/294884
Enjoy
So, I want to implement dodging which is something like a dash in a direction. It works pretty simple - if you move in a direction and press the button the character dodges there. The velocity should not matter for this, so that the dodging speed is always the same, no matter if you are running or standing and then pressing a direction + dodging. I've got something that seems to work but there are still problems left. It seems like that diagonal dodging is a bit too far in comparison to horizontal/vertical dodging and I tried to fix this. But I'm still not sure if it worked or not. In practice the character dodges and stuff but something still seems off, like it works pretty good with a controller but sometimes it's still wacky when using keyboard after standing still and then using dodge. The thing is - I'm not sure if the code I have is the best I could have or if there are still problems.
A good example of how it should work would be the dodging in Rune Factory 4.
Edit: If the problem lies in the Input Settings I could show them.
if (IsDodging == false)
{
Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
if (input.sqrMagnitude > 1) input.Normalize();
if (Input.GetButtonDown("Jump"))
{
// Jumping stuff I blended out
}
else if (Input.GetButtonDown("Block/Dodge") && input.x != 0 || Input.GetButtonDown("Block/Dodge") && input.z != 0) // To activate dodging
{
if (Time.time > Time_Start + DodgeCooldown) // Checks the cooldown
{
Time_Start = Time.time;
IsDodging = true;
dodge_direction = input;
if (dodge_direction.x > 0) { dodge_direction.x = 1; } // To fixate the distance traveled when dodging while ignoring how fast you are
if (dodge_direction.z > 0) { dodge_direction.z = 1; }
if (dodge_direction.x > 0 && dodge_direction.z > 0) { dodge_direction.Normalize(); } // To prevent diagonal dodging distance from becoming too big
}
}
else
{
// Walk.
transform.position += input * run_speed * Time.deltaTime;
}
}
else
{
transform.position += dodge_direction * dodge_distance;
distance_traveled += Vector3.Distance(transform.position, dodge_direction * dodge_distance) * Time.deltaTime;
if (distance_traveled > dodge_distance)
{
IsDodging = false;
dodge_direction = Vector3.zero;
distance_traveled = 0;
}
}
I'm trying to detect the movement (to the right or left) performed by users.
We assume that the user starts with his arm extended in front of him and then moves his arm to the right or to the left (about 90 degrees off center).
I've integrated CMMotionManager and want to understand detecting direction via startAccelerometerUpdatesToQueue and startDeviceMotionUpdatesToQueue methods.
Can anyone suggest how to implement this logic on an iPhone and then on an Apple Watch?
Apple provides watchOS 3 SwingWatch sample code demonstrating how to use CMMotionManager() and startDeviceMotionUpdates(to:) to count swings in a racquet sport.
Their code demonstrates how to detect the direction of a one-second interval of motion, although you may have to tweak the thresholds to account for the characteristics of the motion you want to track.
func processDeviceMotion(_ deviceMotion: CMDeviceMotion) {
let gravity = deviceMotion.gravity
let rotationRate = deviceMotion.rotationRate
let rateAlongGravity = rotationRate.x * gravity.x // r⃗ · ĝ
+ rotationRate.y * gravity.y
+ rotationRate.z * gravity.z
rateAlongGravityBuffer.addSample(rateAlongGravity)
if !rateAlongGravityBuffer.isFull() {
return
}
let accumulatedYawRot = rateAlongGravityBuffer.sum() * sampleInterval
let peakRate = accumulatedYawRot > 0 ?
rateAlongGravityBuffer.max() : rateAlongGravityBuffer.min()
if (accumulatedYawRot < -yawThreshold && peakRate < -rateThreshold) {
// Counter clockwise swing.
if (wristLocationIsLeft) {
incrementBackhandCountAndUpdateDelegate()
} else {
incrementForehandCountAndUpdateDelegate()
}
} else if (accumulatedYawRot > yawThreshold && peakRate > rateThreshold) {
// Clockwise swing.
if (wristLocationIsLeft) {
incrementForehandCountAndUpdateDelegate()
} else {
incrementBackhandCountAndUpdateDelegate()
}
}
// Reset after letting the rate settle to catch the return swing.
if (recentDetection && abs(rateAlongGravityBuffer.recentMean()) < resetThreshold) {
recentDetection = false
rateAlongGravityBuffer.reset()
}
}