// Use this for initialization void Start() { m_creature = GetComponent <Creature>(); m_creatureFeet = new List <Foot>(); m_feetCountPerHip = new Dictionary <BoneJoint, int>(); m_movingFeetPerHip = new Dictionary <BoneJoint, int>(); for (int i = 0; i < m_creature.m_feet.Count; i++) { Foot foot = new Foot(m_creature.m_feet[i].m_boneJoint); m_creatureFeet.Add(foot); if (m_feetCountPerHip.ContainsKey(foot.joint.closestBodyJoint)) { m_feetCountPerHip[foot.joint.closestBodyJoint]++; } else { m_feetCountPerHip.Add(foot.joint.closestBodyJoint, 1); m_movingFeetPerHip.Add(foot.joint.closestBodyJoint, 0); } } m_debugJoint = m_creature.m_head; headHeight = 0; BoneJoint current = m_creature.m_head.m_boneJoint; while (current.nextJoints.Count > 0) { current = current.nextJoints[0]; headHeight += current.distanceFromLastBone; } }
Sprite GetCorrectSprite(BoneJoint joint) { if (joint.isPartOfBody()) { if (joint.previousJoint == null) { return(m_headSprite); } else { return(m_bodySprite); } } else { if (joint.nextJoints == null || joint.nextJoints.Count == 0) { return(m_feetSprite); } else { return(m_legSprite); } } }
void MoveBodyJointTo(Vector2 finalPosition, Joint leadingJoint) { Vector2 constrainedPosition = finalPosition; float headBob = AddBobbing(leadingJoint.transform.position.x); headBob *= Mathf.Clamp01(Vector2.Distance(finalPosition, leadingJoint.transform.position) - m_headBobbingFadeOut); constrainedPosition.y += headBob; float distFromTarget = Vector2.Distance(leadingJoint.transform.position, finalPosition); for (int i = 0; i < m_creature.m_feet.Count; i++) { Joint currentFoot = m_creature.m_feet[i]; Transform currentFootTransform = currentFoot.transform; BoneJoint closestBodyJoint = currentFoot.m_boneJoint.closestBodyJoint; //Ignore this foot if it's closer to the target than the leading joint. if (Vector2.Distance(currentFoot.transform.position, finalPosition) < distFromTarget) { continue; } Vector2 constrainedToBodyJoint = GetPosLocked(currentFootTransform.position, closestBodyJoint.transform.position, currentFoot.m_boneJoint.maxDistanceFromBodyJoint); float distance = closestBodyJoint.maxDistanceFromHead; distance += currentFoot.m_boneJoint.maxDistanceFromBodyJoint - Vector2.Distance(currentFootTransform.position, closestBodyJoint.transform.position); //add any remaining distance constrainedPosition = GetPosLocked(constrainedToBodyJoint, constrainedPosition, distance); } Debug.DrawLine(leadingJoint.transform.position, constrainedPosition); float feetMovingRatio = m_creatureFeet.Count > 0 ? (m_currentMovingFeetCount / (1f * m_creatureFeet.Count)) : 1; float speed = m_movementSpeed * Mathf.Lerp(m_nonMovingFeetSpeedFactor.x, m_nonMovingFeetSpeedFactor.y, 1f - feetMovingRatio); leadingJoint.transform.position = Vector2.MoveTowards(leadingJoint.transform.position, constrainedPosition, speed * Time.deltaTime); UpdatePosToNeighbours(leadingJoint); }
public GameObject CreateSkeletonGameObject(Skeleton s, System.Random random) { GameObject creature = Instantiate(m_creaturePrefab); creature.GetComponent <Creature>().m_skeleton = s; List <BoneJoint> jointsToVisit = new List <BoneJoint>(); jointsToVisit.Add(s.head); GameObject lastJointGO = creature; float bodyLineRendererScale = Mathf.Lerp(m_bodyLineRendererScaleMinMax.x, m_bodyLineRendererScaleMinMax.y, (float)random.NextDouble()); float legsLineRendererScale = Mathf.Lerp(m_legsLineRendererScaleMinMax.x, m_legsLineRendererScaleMinMax.y, (float)random.NextDouble()); while (jointsToVisit.Count > 0) { BoneJoint currentJoint = jointsToVisit[0]; if (currentJoint.previousJoint != null) { lastJointGO = currentJoint.previousJoint.gameObject; } GameObject currentJointGO = Instantiate(m_jointPrefab); currentJointGO.transform.parent = creature.transform;// lastJointGO.transform; currentJointGO.transform.localScale = currentJoint.scale; currentJointGO.transform.position = lastJointGO.transform.position; Vector2 pos = Utility.PolarToCartesian(currentJoint.distanceFromLastBone, currentJoint.angleFromLastBone); currentJointGO.transform.position += new Vector3(pos.x, pos.y, 0); currentJointGO.GetComponent <SpriteRenderer>().material.color = currentJoint.color; if (m_useSprites) { Sprite correctSprite = GetCorrectSprite(currentJoint); if (correctSprite != null) { currentJointGO.GetComponent <SpriteRenderer>().sprite = correctSprite; } } Joint joint = currentJointGO.AddComponent <Joint>(); joint.m_boneJoint = currentJoint; LineRenderer lr = currentJointGO.GetComponent <LineRenderer>(); lr.SetPosition(0, currentJointGO.transform.position); lr.startColor = currentJoint.color; lr.startWidth = currentJoint.scale.x * (currentJoint.isPartOfBody() ? bodyLineRendererScale : legsLineRendererScale); lr.SetPosition(1, lastJointGO.transform.position); if (currentJoint.previousJoint != null) { lr.endWidth = currentJoint.previousJoint.scale.x * (currentJoint.previousJoint.isPartOfBody() ? bodyLineRendererScale : legsLineRendererScale); lr.endColor = currentJoint.previousJoint.color; } currentJoint.gameObject = currentJointGO; currentJoint.transform = currentJointGO.transform; jointsToVisit.RemoveAt(0); if (currentJoint.nextJoints != null) { jointsToVisit.AddRange(currentJoint.nextJoints); } } return(creature); }
public void StepForward(Foot foot, Vector2 targetDestination) { BoneJoint footJoint = foot.joint; if (foot.stepTargetDefined == false) // if this is the first frame in this step, figure out where the foot is going { bool foundSuitableNextStep = DefineNextStep(foot, targetDestination); if (foundSuitableNextStep == false) { return; } m_movingFeetPerHip[foot.joint.closestBodyJoint]++; } Vector2 footToTarget = (foot.currentTarget - ((Vector2)footJoint.transform.position)); footToTarget = footToTarget.normalized; Vector2 pathToTarget; float speed = m_feetSpeed * Mathf.Lerp(m_nonMovingFeetSpeedFactor.x, m_nonMovingFeetSpeedFactor.y, 1f - (m_currentMovingFeetCount / (1f * m_creatureFeet.Count))); float diffFromLastFrame = (speed * Time.deltaTime); pathToTarget.y = footJoint.transform.position.y + (diffFromLastFrame * footToTarget.y); // targetIsAbove); pathToTarget.x = footJoint.transform.position.x + (diffFromLastFrame * footToTarget.x); // targetIsToTheRight); if (Vector2.Distance(footJoint.transform.position, pathToTarget) > Vector2.Distance(footJoint.transform.position, foot.currentTarget)) { pathToTarget = foot.currentTarget; } else { // float xToYRatio = 1; // if (foot.currentTarget.y - foot.startStepPos.y != 0) // xToYRatio = Mathf.Abs((foot.currentTarget.x - foot.startStepPos.x) / (foot.currentTarget.y - foot.startStepPos.y)); float xDist = Mathf.Clamp01(Mathf.Abs((footJoint.transform.position.x - foot.currentTarget.x) / (foot.startStepPos.x - foot.currentTarget.x))); foot.stepCompleteness = completeness = 1f - xDist; Vector2 animationCurve = Vector2.zero; // animationCurve.x = (m_legHeightCurve.Evaluate(foot.stepCompleteness) * foot.currentStepHeight);// * (1 - xToYRatio)); animationCurve.y = (m_legHeightCurve.Evaluate(foot.stepCompleteness) * foot.currentStepHeight) * (speed * Time.deltaTime);// * xToYRatio); pathToTarget += animationCurve; } m_targetVec = pathToTarget; footJoint.transform.position = Vector2.MoveTowards(footJoint.transform.position, pathToTarget, m_feetSpeed * Time.deltaTime); if (((Vector2)footJoint.transform.position) == foot.currentTarget) { foot.isGrounded = true; foot.stepTargetDefined = false; m_movingFeetPerHip[foot.joint.closestBodyJoint]--; } else { foot.isGrounded = false; } }
public BoneJoint GenerateRandomBoneJoint(BoneJoint previousJoint, float minJointScale, float maxJointScale, float minDist, float maxDist, float minAngleDiff, float maxAngleDiff, float perlinNoiseX, float perlinNoiseY, List <Color> ColorPalette, bool isLegJoint) { float dist = minDist + (Mathf.PerlinNoise(perlinNoiseX, perlinNoiseY) * (maxDist - minDist)); float angle = minAngleDiff + (Mathf.PerlinNoise(perlinNoiseX, (perlinNoiseY + 0.1f)) * (maxAngleDiff - minAngleDiff)); float xScale = minJointScale + (Mathf.PerlinNoise(perlinNoiseX, perlinNoiseY) * (maxJointScale - minJointScale)); float yScale = xScale; Color color = ColorPalette[(int)(Mathf.PerlinNoise(perlinNoiseX, perlinNoiseY) * ColorPalette.Count)]; return(new BoneJoint(previousJoint, dist, angle, xScale, yScale, color, isLegJoint)); }
public void GenerateLeg(int jointCount, BoneJoint previousLegJoint, float perlinNoiseSeed, float perlinOffset, List <Color> palette) { float legScale = m_minLegJointScale + (Mathf.PerlinNoise(perlinNoiseSeed, perlinNoiseSeed + 0.15f) * (m_maxLegJointScale - m_minLegJointScale)); float legPerlinNoiseX = 0f; for (int k = 0; k < jointCount; k++) { BoneJoint newLegJoint = GenerateRandomBoneJoint(previousLegJoint, legScale, legScale, m_minLegDist, m_maxLegDist, m_minLegAngleDiff, m_maxLegAngleDiff, perlinNoiseSeed + perlinOffset + legPerlinNoiseX, perlinNoiseSeed + perlinOffset, palette, true); previousLegJoint.nextJoints.Add(newLegJoint); previousLegJoint = newLegJoint; legPerlinNoiseX = (k * 1f) / jointCount; } }
public BoneJoint GenerateRandomSkeletonJoints(int jointCount, int legCount, int legJointCount, List <Color> palette) { float perlinNoiseSeed = RandomFloat(); //without this we would get the same result every time float perlinNoiseXOffset = RandomFloat() * 10f; //for nicer results we get a random subsection of the perlin noise float perlinNoiseX = 0f; BoneJoint firstJoint = GenerateRandomBoneJoint(null, m_minJointScale, m_maxJointScale, 0, 0, 0, 0, perlinNoiseSeed + perlinNoiseX + perlinNoiseXOffset, perlinNoiseSeed + 0f, palette, false); if (jointCount == 1) {//if only a head and no other body joints, attach legs to head, otherwise never have head to leg connection for (int i = 0; i < legCount; i++) { GenerateLeg(legJointCount, firstJoint, perlinNoiseSeed, ((i * 1f) / legCount), palette); } } BoneJoint previousFrameJoint = firstJoint; int leg = 0; int[] legIndexes = RandomIntArray(legCount, 1, jointCount - 1); for (int i = 1; i < jointCount; i++) { perlinNoiseX = (i * 1f + 1f) / jointCount; BoneJoint newJoint = GenerateRandomBoneJoint(previousFrameJoint, m_minJointScale, m_maxJointScale, m_minDist, m_maxDist, m_minAngleDiff, m_maxAngleDiff, perlinNoiseSeed + perlinNoiseX, perlinNoiseSeed + 0f, palette, false); previousFrameJoint.nextJoints.Add(newJoint); previousFrameJoint = newJoint; if (leg < legIndexes.Length) { for (int j = 0; j < legCount; j++) { if (legIndexes[j] == i) { GenerateLeg(legJointCount, newJoint, perlinNoiseSeed, ((leg * 1f) / legCount), palette); leg++; } } } } return(firstJoint); }
public float maxDistanceFromBodyJoint; //Only populated and used for feet public BoneJoint(BoneJoint previous, float distLastBone, float angLastBone, float xScale, float yScale, Color col, bool isPartOfLeg) { previousJoint = previous; scale = new Vector2(xScale, yScale); distanceFromLastBone = distLastBone; angleFromLastBone = angLastBone; nextJoints = new List <BoneJoint>(); color = col; if (isPartOfLeg) { type = BoneJointType.Leg; } else { type = BoneJointType.Body; } // isLegJoint = isPartOfLeg; closestBodyJoint = null; attachedFoot = null; maxDistanceFromBodyJoint = 0; maxDistanceFromHead = 0; distanceFromFoot = 0; }
private bool DefineNextStep(Foot foot, Vector2 targetDestination) { BoneJoint footJoint = foot.joint; foot.stepTargetDefined = true; Vector3 stepTarget = footJoint.closestBodyJoint.transform.position; float xDistTargetToFoot = targetDestination.x - footJoint.transform.position.x; float stepWidth = Random.Range(m_minFootStepWidth, m_maxFootStepWidth); stepTarget.x += ((xDistTargetToFoot > 0) ? 1 : -1) * (stepWidth * footJoint.maxDistanceFromBodyJoint); stepTarget.y = m_floorY; //DEBUG until I implement raycasts foot.currentStepHeight = m_footStepHeight * footJoint.maxDistanceFromBodyJoint; // Random.Range(minRand, maxRand); foot.currentTarget = GetPosLocked(footJoint.closestBodyJoint.transform.position, stepTarget, footJoint.maxDistanceFromBodyJoint * 0.8f); foot.currentTarget.y = m_floorY; m_target = foot.currentTarget; m_vector2Gizmos = foot.currentTarget; foot.stepCompleteness = 0; foot.startStepPos = footJoint.transform.position; if (foot.startStepPos == foot.currentTarget) // if we are already here { Debug.LogError("oddly we are already here"); foot.isGrounded = true; foot.stepTargetDefined = false; return(false); } if (Vector3.Distance(foot.currentTarget, targetDestination) > Vector3.Distance(footJoint.transform.position, targetDestination)) { //Debug.Log("the next step would be worse or equal"); foot.isGrounded = true; foot.stepTargetDefined = false; return(false); } return(true); }
public void SetupFromHead() { feet = new List <BoneJoint>(); List <BoneJoint> bodyJointsToVisit = new List <BoneJoint>(); bodyJointsToVisit.Add(head); boneCount = 0; float maxDistFromBodyJoint = 0f; float maxDistFromHead = 0f; BoneJoint latestBodyJoint = null; while (bodyJointsToVisit.Count > 0) { BoneJoint currentJoint = bodyJointsToVisit[0]; boneCount++; maxDistFromHead += currentJoint.distanceFromLastBone; currentJoint.maxDistanceFromHead = maxDistFromHead; latestBodyJoint = currentJoint; maxDistFromBodyJoint = 0f; if (baseOfNeck == null) { if (currentJoint.nextJoints != null && currentJoint.nextJoints.Count >= 2) { baseOfNeck = currentJoint; } } else if (currentJoint.nextJoints != null) { baseOfTail = currentJoint; } if (baseOfTail == null) { baseOfTail = currentJoint; } endOfTail = currentJoint; for (int i = 0; i < currentJoint.nextJoints.Count; i++) { BoneJoint nextJoint = currentJoint.nextJoints[i]; if (nextJoint.isPartOfLeg()) { while (nextJoint != null) { boneCount++; maxDistFromBodyJoint += nextJoint.distanceFromLastBone; nextJoint.maxDistanceFromHead = maxDistFromHead + maxDistFromBodyJoint; nextJoint.maxDistanceFromBodyJoint = maxDistFromBodyJoint; nextJoint.closestBodyJoint = latestBodyJoint; if (nextJoint.nextJoints == null || nextJoint.nextJoints.Count == 0) { nextJoint.type = BoneJoint.BoneJointType.Foot; feet.Add(nextJoint); maxDistFromBodyJoint = 0f; nextJoint = null; } else { nextJoint = nextJoint.nextJoints[0];// No need to worry about other next joints as only a body joint can have multiple next joints } } } else { bodyJointsToVisit.Add(nextJoint); } } bodyJointsToVisit.RemoveAt(0); } if (baseOfNeck == null) { baseOfNeck = head; } for (int i = 0; i < feet.Count; i++) { BoneJoint currentBonejoint = feet[i]; float dist = 0; while (currentBonejoint.previousJoint != null && currentBonejoint.isPartOfLeg()) { currentBonejoint.attachedFoot = feet[i]; currentBonejoint.distanceFromFoot = dist; currentBonejoint = currentBonejoint.previousJoint; dist += currentBonejoint.distanceFromLastBone; } if (currentBonejoint != null && currentBonejoint.isPartOfBody()) { currentBonejoint.type = BoneJoint.BoneJointType.Hip; } } }
public Foot(BoneJoint footJoint) { joint = footJoint; }
void FeedForward(Joint previous, Joint currentJoint) { if (previous.m_boneJoint == null || currentJoint.m_boneJoint == null) { return; } Vector2 previousJointPos = previous.transform.position; Vector2 currentJointPos = currentJoint.transform.position; Vector2 targetPos = GetPosLocked(previousJointPos, currentJointPos, currentJoint.m_boneJoint.distanceFromLastBone, false); if (currentJoint.m_boneJoint.isPartOfLeg()) //is either a legjoint { if (currentJoint.m_boneJoint.nextJoints != null) { Vector3 footPos = currentJoint.m_boneJoint.attachedFoot.transform.position; float maxDistFromFoot = currentJoint.m_boneJoint.distanceFromFoot; float maxDist = currentJoint.m_boneJoint.maxDistanceFromBodyJoint + maxDistFromFoot; float rotationToAddCurve = m_legCurve.Evaluate(maxDistFromFoot / maxDist); float footToBodyAngle = Vector2.Angle(Vector2.right, (Vector2)(currentJoint.m_boneJoint.closestBodyJoint.transform.position - footPos)); Vector2 toAdd = new Vector2(0, maxDistFromFoot / maxDist); Vector2 curved = (Quaternion.Euler(0, 0, footToBodyAngle * rotationToAddCurve) * toAdd) * m_legCurveStrength; curved += currentJointPos; Vector3 lockedPos = GetPosLocked(previousJointPos, curved, currentJoint.m_boneJoint.distanceFromLastBone, false); targetPos = GetPosLocked(footPos, lockedPos, currentJoint.m_boneJoint.distanceFromFoot, true); } else //if is a foot { targetPos = currentJointPos; } } else { if (currentJoint.m_boneJoint.type == BoneJoint.BoneJointType.Hip) { for (int i = 0; i < currentJoint.m_boneJoint.nextJoints.Count; i++) { BoneJoint nextJoint = currentJoint.m_boneJoint.nextJoints[i]; if (nextJoint.isPartOfLeg()) { Vector2 lockedTo = nextJoint.attachedFoot.transform.position; Vector2 jointMaxPos = GetPosLocked(lockedTo, nextJoint.transform.position, nextJoint.distanceFromFoot, true); jointMaxPos = GetPosLocked(jointMaxPos, currentJointPos, nextJoint.distanceFromLastBone, false); //where the joint should be targetPos = GetPosLocked(previousJointPos, jointMaxPos, currentJoint.m_boneJoint.distanceFromLastBone, false); targetPos = GetPosLocked(lockedTo, targetPos, nextJoint.distanceFromFoot + nextJoint.distanceFromLastBone, true); break; } } } else { BoneJoint nextHip = currentJoint.m_boneJoint; float distFromHip = 0; int i = 0; while (nextHip.type != BoneJoint.BoneJointType.Hip && nextHip.nextJoints.Count > 0) { nextHip = nextHip.nextJoints[0]; distFromHip += nextHip.distanceFromLastBone; } Vector2 jointMaxPos = GetPosLocked(nextHip.transform.position, currentJointPos, distFromHip, true); targetPos = GetPosLocked(previousJointPos, jointMaxPos, currentJoint.m_boneJoint.distanceFromLastBone, false); } } currentJoint.transform.position = targetPos;//Vector2.MoveTowards(currentJoint.transform.position, targetPos, m_boneJointsLerpSpeed * Time.deltaTime); UpdatePosToNeighbours(currentJoint, previous); }