public bool IsGrounded() { if (groundInfos == null) groundInfos = new GroundInfo (); groundInfos.isGrounded = false; groundInfos.ground = null; RaycastHit2D hit = Physics2D.Raycast (CachedRigidbody.position, Vector3.down, 0.8f, groundLayers.value); if(hit.transform != null) { groundInfos.ground = hit.transform; groundInfos.isGrounded = true; } return groundInfos.isGrounded; }
public void SetPos(Vector3 pos) { //清空已有资源 for (int i = 0; i < m_rendererList.Count; i++) { GameObjectManager.DestroyGameObjectByPool(m_rendererList[i].gameObject); } m_rendererList.Clear(); //计算出应该是哪几个资源 //计算出对应的位置 //加载并摆放 m_offset = pos * scrollSpeed; //限制区域 int index = 0; bool isBreak = false; bool isShow = false; while (!isBreak) { GroundInfo info = GetGroundInfo(index); if (m_root.ViewBound.Overlaps(info.rect)) { isShow = true; //加载对应资源并摆放 CreateSprite(info); } else { //已经显示过,后面的不在显示区域中终止循环 if (isShow) { isBreak = true; } } index++; } }
public GoundMaker(GroundInfo info, IFactory <SceneContext> scFactory, IFactory <SceneContext, UnityEngine.Object, Player> playerFactory, IFactory <Canvas> uiFactory, [Inject(Id = "start")] IFactory <int, int, GameObject> startFactory, [Inject(Id = "exit")] IFactory <int, int, GameObject> exitFactory, [Inject(Id = "floor")] IFactory <int, int, UnityEngine.Object, IEnumerable <GameObject> > floorFactory, [Inject(Id = "wall")] IFactory <int, int, UnityEngine.Object, IEnumerable <GameObject> > wallFactory) { _info = info; _scFactory = scFactory; _playerFactory = playerFactory; _uiFactory = uiFactory; _startFactory = startFactory; _exitFactory = exitFactory; _floorFactory = floorFactory; _wallFactory = wallFactory; }
void StickToGround(GroundInfo info) { float angle = info.angle * Mathf.Rad2Deg; characterAngle = angle; Vector3 pos = transform.position; switch (groundMode) { case GroundMode.Floor: if (angle < 315f && angle > 225f) { groundMode = GroundMode.LeftWall; } else if (angle > 45f && angle < 180f) { groundMode = GroundMode.RightWall; } pos.y = info.point.y + heightHalf; break; case GroundMode.RightWall: if (angle < 45f && angle > 0f) { groundMode = GroundMode.Floor; } else if (angle > 135f && angle < 270f) { groundMode = GroundMode.Ceiling; } pos.x = info.point.x - heightHalf; break; case GroundMode.Ceiling: if (angle < 135f && angle > 45f) { groundMode = GroundMode.RightWall; } else if (angle > 225f && angle < 360f) { groundMode = GroundMode.LeftWall; } pos.y = info.point.y - heightHalf; break; case GroundMode.LeftWall: if (angle < 225f && angle > 45f) { groundMode = GroundMode.Ceiling; } else if (angle > 315f) { groundMode = GroundMode.Floor; } pos.x = info.point.x + heightHalf; break; default: break; } transform.position = pos; }
GroundInfo GroundedCheck(float distance, GroundMode groundMode, out bool groundedLeft, out bool groundedRight) { Quaternion rot = Quaternion.Euler(0f, 0f, (90f * (int)groundMode)); Vector2 dir = rot * Vector2.down; Vector2 leftCastPos = rot * leftRaycastPos; Vector2 rightCastPos = rot * rightRaycastPos; Vector2 pos = new Vector2(transform.position.x, transform.position.y); RaycastHit2D leftHit = Physics2D.Raycast(pos + leftCastPos, dir, distance); groundedLeft = leftHit.collider != null; RaycastHit2D rightHit = Physics2D.Raycast(pos + rightCastPos, dir, distance); groundedRight = rightHit.collider != null; Debug.DrawLine(pos + leftCastPos, pos + leftCastPos + (dir * distance), Color.magenta); Debug.DrawLine(pos + rightCastPos, pos + rightCastPos + (dir * distance), Color.red); GroundInfo found = null; if (groundedLeft && groundedRight) { float leftCompare = 0f; float rightCompare = 0f; switch (groundMode) { case GroundMode.Floor: leftCompare = leftHit.point.y; rightCompare = rightHit.point.y; break; case GroundMode.RightWall: leftCompare = -leftHit.point.x; rightCompare = -rightHit.point.x; break; case GroundMode.Ceiling: leftCompare = -leftHit.point.y; rightCompare = -rightHit.point.y; break; case GroundMode.LeftWall: leftCompare = leftHit.point.x; rightCompare = rightHit.point.x; break; default: break; } if (leftCompare >= rightCompare) { found = GetGroundInfo(leftHit); } else { found = GetGroundInfo(rightHit); } } else if (groundedLeft) { found = GetGroundInfo(leftHit); } else if (groundedRight) { found = GetGroundInfo(rightHit); } else { found = new GroundInfo(); } return(found); }
void FixedUpdate() { if (Input.GetKeyDown(KeyCode.Tab)) { debug = !debug; } Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical")); float accelSpeedCap = underwater ? uwGroundTopSpeed : groundTopSpeed; if (grounded) { if (!rolling && input.y < -0.005f && Mathf.Abs(groundVelocity) >= rollingMinSpeed) { rolling = true; transform.position -= new Vector3(0f, 5f); } float slope = 0f; if (rolling) { float sin = Mathf.Sin(currentGroundInfo.angle); bool uphill = (sin >= 0f && groundVelocity >= 0f) || (sin <= 0f && groundVelocity <= 0); slope = uphill ? rollUphillSlope : rollDownhillSlope; } else { slope = slopeFactor; } groundVelocity += (slope * -Mathf.Sin(currentGroundInfo.angle)) * Time.fixedDeltaTime; bool lostFooting = false; if (groundMode != GroundMode.Floor && Mathf.Abs(groundVelocity) < fallVelocityThreshold) { groundMode = GroundMode.Floor; grounded = false; hControlLock = true; hControlLockTime = 0.5f; lostFooting = true; } if (Input.GetButtonDown("Jump") && !lowCeiling) { float jumpVel = underwater ? uwJumpVelocity : jumpVelocity; velocity.x -= jumpVel * (Mathf.Sin(currentGroundInfo.angle)); velocity.y += jumpVel * (Mathf.Cos(currentGroundInfo.angle)); grounded = false; jumped = true; } else { if (hControlLock) { hControlLockTime -= Time.fixedDeltaTime; if (hControlLockTime <= 0f) { hControlLock = false; } } if (rolling || Mathf.Abs(input.x) < 0.005f) { // Mostly because I don't like chaining ternaries float fric = underwater ? uwFriction : friction; float rollFric = underwater ? uwRollingFriction : rollingFriction; float frc = rolling ? rollFric : fric; if (groundVelocity > 0f) { groundVelocity -= frc * Time.fixedDeltaTime; if (groundVelocity < 0f) { groundVelocity = 0f; } } else if (groundVelocity < 0f) { groundVelocity += frc * Time.fixedDeltaTime; if (groundVelocity > 0f) { groundVelocity = 0f; } } } if (!hControlLock && Mathf.Abs(input.x) >= 0.005f) { float accel = underwater ? uwAcceleration : groundAcceleration; float decel = underwater ? uwDeceleration : deceleration; if (input.x < 0f) { if (groundVelocity < 0f) { // TODO: Set a direction variable instead Vector3 scale = Vector3.one; scale.x *= Mathf.Sign(groundVelocity); transform.localScale = scale; } float acceleration = 0f; if (rolling && groundVelocity > 0f) { acceleration = rollingDeceleration; } else if (!rolling && groundVelocity > 0f) { acceleration = decel; } else if (!rolling && groundVelocity <= 0f) { acceleration = accel; } if (groundVelocity > -accelSpeedCap) { groundVelocity = Mathf.Max(-accelSpeedCap, groundVelocity + (input.x * acceleration) * Time.deltaTime); } } else { if (groundVelocity > 0f) { Vector3 scale = Vector3.one; transform.localScale = scale; } float acceleration = 0f; if (rolling && groundVelocity < 0f) { acceleration = rollingDeceleration; } else if (!rolling && groundVelocity < 0f) { acceleration = decel; } else if (!rolling && groundVelocity >= 0f) { acceleration = accel; } if (groundVelocity < accelSpeedCap) { groundVelocity = Mathf.Min(accelSpeedCap, groundVelocity + (input.x * acceleration) * Time.deltaTime); } } } if (groundVelocity > speedLimit) { groundVelocity = speedLimit; } else if (groundVelocity < -speedLimit) { groundVelocity = -speedLimit; } if (rolling && Mathf.Abs(groundVelocity) < unrollThreshold) { rolling = false; transform.position += new Vector3(0f, 5f); } Vector2 angledSpeed = new Vector2(groundVelocity * Mathf.Cos(currentGroundInfo.angle), groundVelocity * Mathf.Sin(currentGroundInfo.angle)); velocity = angledSpeed; if (lostFooting) { groundVelocity = 0f; } } } else { float jumpRelThreshold = underwater ? uwJumpReleaseThreshold : jumpReleaseThreshold; if (jumped && velocity.y > jumpRelThreshold && Input.GetButtonUp("Jump")) { velocity.y = jumpRelThreshold; } else { // Air drag effect if (velocity.y > 0f && velocity.y < 4f && Mathf.Abs(velocity.x) > 7.5f) { velocity.x *= airDrag; } float grv = underwater ? uwGravity : gravity; velocity.y = Mathf.Max(velocity.y + (grv * Time.fixedDeltaTime), -terminalVelocity); } if (!(rolling && jumped) && Mathf.Abs(input.x) >= 0.005f) { if ((input.x < 0f && velocity.x > -accelSpeedCap) || (input.x > 0f && velocity.x < accelSpeedCap)) { float airAcc = underwater ? uwAirAcceleration : airAcceleration; velocity.x = Mathf.Clamp(velocity.x + (input.x * airAcc * Time.fixedDeltaTime), -accelSpeedCap, accelSpeedCap); } } } // Clamp velocity to global speed limit; going any faster could result in passing through things velocity.x = Mathf.Clamp(velocity.x, -speedLimit, speedLimit); velocity.y = Mathf.Clamp(velocity.y, -speedLimit, speedLimit); // Apply movement transform.position += new Vector3(velocity.x, velocity.y, 0f) * Time.fixedDeltaTime; // Now do collision testing RaycastHit2D leftHit; RaycastHit2D rightHit; WallCheck(sideRaycastDist, grounded ? sideRaycastOffset : 0f, out leftHit, out rightHit); if (leftHit.collider != null && rightHit.collider != null) { // Got squashed Debug.Log("GOT SQUASHED"); } else if (leftHit.collider != null) { transform.position = new Vector2(leftHit.point.x + sideRaycastDist, transform.position.y); if (velocity.x < 0f) { velocity.x = 0f; groundVelocity = 0f; } } else if (rightHit.collider != null) { transform.position = new Vector2(rightHit.point.x - sideRaycastDist, transform.position.y); if (velocity.x > 0f) { velocity.x = 0f; groundVelocity = 0f; } } bool ceilingLeft = false; bool ceilingRight = false; int ceilDir = (int)groundMode + 2; if (ceilDir > 3) { ceilDir -= 4; } GroundInfo ceil = GroundedCheck(groundRaycastDist, (GroundMode)ceilDir, out ceilingLeft, out ceilingRight); bool groundedLeft = false; bool groundedRight = false; if (grounded) { currentGroundInfo = GroundedCheck(groundRaycastDist, groundMode, out groundedLeft, out groundedRight); grounded = groundedLeft || groundedRight; } else { if (ceil.valid && velocity.y > 0f) { bool hitCeiling = transform.position.y >= (ceil.point.y - heightHalf); float angleDeg = ceil.angle * Mathf.Rad2Deg; // Check for attaching to ceiling if (hitCeiling && ((angleDeg >= 225f && angleDeg <= 270f) || (angleDeg >= 90f && angleDeg <= 135f))) { grounded = true; jumped = false; rolling = false; currentGroundInfo = ceil; groundMode = GroundMode.Ceiling; groundVelocity = velocity.y * Mathf.Sign(Mathf.Sin(currentGroundInfo.angle)); velocity.y = 0f; } else if (hitCeiling) { if (transform.position.y > ceil.point.y - heightHalf) { transform.position = new Vector2(transform.position.x, ceil.point.y - heightHalf); velocity.y = 0f; } } } else { GroundInfo info = GroundedCheck(groundRaycastDist, GroundMode.Floor, out groundedLeft, out groundedRight); grounded = (groundedLeft || groundedRight) && velocity.y <= 0f && transform.position.y <= (info.height + heightHalf); // Re-calculate ground velocity based on previous air velocity if (grounded) { // If in a roll jump, add 5 to position upon landing if (jumped) { transform.position += new Vector3(0f, 5f); } jumped = false; rolling = false; currentGroundInfo = info; groundMode = GroundMode.Floor; float angleDeg = currentGroundInfo.angle * Mathf.Rad2Deg; // If angle is close to level with ground, just use x velocity as ground velocity if (angleDeg < 22.5f || (angleDeg > 337.5 && angleDeg <= 360f)) { groundVelocity = velocity.x; } else if ((angleDeg >= 22.5f && angleDeg < 45f) || (angleDeg >= 315f && angleDeg < 337.5f)) { if (Mathf.Abs(velocity.x) > Mathf.Abs(velocity.y)) { groundVelocity = velocity.x; } else { groundVelocity = velocity.y * 0.5f * Mathf.Sign(Mathf.Sin(currentGroundInfo.angle)); } } else if ((angleDeg >= 45f && angleDeg < 90f) || (angleDeg >= 270f && angleDeg < 315f)) { if (Mathf.Abs(velocity.x) > Mathf.Abs(velocity.y)) { groundVelocity = velocity.x; } else { groundVelocity = velocity.y * Mathf.Sign(Mathf.Sin(currentGroundInfo.angle)); } } velocity.y = 0f; } } } if (grounded) { StickToGround(currentGroundInfo); animator.SetFloat(speedHash, Mathf.Abs(groundVelocity)); lowCeiling = ceil.valid && transform.position.y > ceil.point.y - 25f; } else { currentGroundInfo = null; groundMode = GroundMode.Floor; lowCeiling = false; if (Mathf.Abs(input.x) > 0.005f && !(rolling && jumped)) { Vector3 scale = Vector3.one; scale.x *= Mathf.Sign(input.x); transform.localScale = scale; } if (characterAngle > 0f && characterAngle <= 180f) { characterAngle -= Time.deltaTime * 180f; if (characterAngle < 0f) { characterAngle = 0f; } } else if (characterAngle < 360f && characterAngle > 180f) { characterAngle += Time.deltaTime * 180f; if (characterAngle >= 360f) { characterAngle = 0f; } } } animator.SetBool(spinHash, rolling || jumped); if (!underwater && transform.position.y <= waterLevel.position.y) { EnterWater(); } else if (underwater && transform.position.y > waterLevel.position.y) { ExitWater(); } transform.localRotation = Quaternion.Euler(0f, 0f, SnapAngle(characterAngle)); }
/* Try and guess ground positions across an image */ public List <GroundInfo> GuessGroundPositions(Image sphere, int acc, bool straight, StraightLineBias bias) { //Work out the classifier between ground and sky float skyClassifier = TakeAverageBrightness(sphere.Height / 6, (Bitmap)sphere); float groundClassifier = TakeAverageBrightness(sphere.Height - (sphere.Height / 6), (Bitmap)sphere); float diffClassifier = skyClassifier - groundClassifier; //First pass of ground position guess, check every column List <GroundInfo> positions = new List <GroundInfo>(); int posOffset = 0; for (int i = 0; i < sphere.Width; i++) { GroundInfo thisGround = new GroundInfo(); thisGround.position = GuessGroundPositionForX(posOffset, (Bitmap)sphere, diffClassifier); thisGround.block_width = 1; positions.Add(thisGround); posOffset += thisGround.block_width; } positions = positions.OrderBy(o => o.position.x).ToList(); //Discredit any outliers on first pass List <GroundInfo> positions_new = new List <GroundInfo>(); int prevDiscredit = 0; int checkRadius = 1; for (int i = checkRadius; i < positions.Count - checkRadius; i++) { if (positions_new.Count != 0) { float prevDif = positions[i].position.y - positions[i - checkRadius].position.y; if (prevDif < 0) { prevDif *= -1; } float nextDif = positions[i].position.y - positions[i + checkRadius].position.y; if (nextDif < 0) { nextDif *= -1; } if (prevDif >= 50 || nextDif >= 50) //todo dont use a set value here, do it by sphere height { prevDiscredit++; continue; } positions_new[positions_new.Count - 1].block_width += prevDiscredit; } positions_new.Add(positions[i]); prevDiscredit = 0; } positions = positions_new; //Second/third pass, get average of blocks from first pass, remove any outliers again, recalculate average positions_new = new List <GroundInfo>(); for (int i = 1; i < positions.Count / acc; i++) { int startPos = acc * (i - 1); int endPos = acc * (i); List <float> yPos = new List <float>(); float avgY = 0.0f; float avgX = 0.0f; for (int x = startPos; x < endPos; x++) { yPos.Add(positions[x].position.y); avgY += positions[x].position.y; avgX += positions[x].position.x; } avgY /= acc; avgX /= acc; float avgY2 = 0.0f; int avgCount = 0; for (int x = 0; x < yPos.Count; x++) { if (yPos[x] >= avgY) { avgY2 += yPos[x]; avgCount++; } } avgY2 /= avgCount; GroundInfo newGndInf = new GroundInfo(); newGndInf.block_width = acc; newGndInf.position = new Vector2(avgX, avgY2); positions_new.Add(newGndInf); } positions = positions_new; //If requested to trim as a straight line, take an average of all points, or pick top/bottom if (straight) { float avgY = 0.0f; switch (bias) { case StraightLineBias.TOP: avgY = float.MaxValue; for (int i = 0; i < positions.Count; i++) { if (avgY >= positions[i].position.y) { avgY = positions[i].position.y; } } break; case StraightLineBias.MIDDLE: for (int i = 0; i < positions.Count; i++) { avgY += positions[i].position.y; } avgY /= positions.Count; break; case StraightLineBias.BOTTOM: for (int i = 0; i < positions.Count; i++) { if (avgY <= positions[i].position.y) { avgY = positions[i].position.y; } } break; } positions.Clear(); GroundInfo avgPos = new GroundInfo(); avgPos.block_width = sphere.Width / 2; avgPos.position = new Vector2(0.0f, avgY); positions.Add(avgPos); avgPos.position = new Vector2(sphere.Width / 2, avgY); positions.Add(avgPos); } return(positions); }
GroundInfo groundInfo; //地面端の位置クラス private void Start() { groundInfo = GetComponentInParent <GroundInfo>(); }