[by 27-45 / LostMoon Games]
- Player
- Ground Checker
- Hearts Controller
- Panoramic Background
- Checkpoints System
- Random ground generating
uses rigidbody and adds force to move player smoothly
uses GroundChecker
throws laser and calculates player distance to ground and changes field of view ;
Camera follows user as smoothly
uses GroundChecker
with unity api,we can detect collisions between objects.
we added CircleCollider to player 's head and used "OnCollisionEnter2D" method to detect collisions
playerHead might collide with player's body so we must check the collided object is ground layer
the speed boost for player , uses "E" key to activate dash for limited seconds
coroutines used for refill dash bar
if (Input.GetKey(KeyCode.D)){
rb.AddForce(this.transform.right * moveSpeed);}
if (Input.GetKey(KeyCode.S)){
//backflip
transform.Rotate(Vector3.forward * rotationForce * Time.deltaTime);
flipTime += 1;
}
if (Input.GetKey(KeyCode.W)){
//front flip
transform.Rotate(-Vector3.forward * rotationForce * Time.deltaTime);
flipTime += 1;}
throws laser and calculates player distance to ground and changes field of view ;
calcFov.orthographicSize = Mathf.Lerp(calcFov.orthographicSize,
Mathf.Clamp(gc.distanceToGround, 5f, MaxCameraFov),
Time.deltaTime * 5f);
transform.position = Vector3.Lerp(transform.position,
new Vector3(target.position.x + CenterDistance,
target.position.y, transform.position.z),
smoothDelay);
transform.rotation = Quaternion.Lerp(transform.rotation,
Quaternion.FromToRotation(Vector3.up * Time.deltaTime, gc.rotater.normal),
3f * Time.deltaTime);
we added CircleCollider to player 's head and used "OnCollisionEnter2D" method to detect collisions
playerHead might collide with player's body so we must check the collided object is ground layer
public bool hit { get; set; } // notify other objects
void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.layer == LayerMask.NameToLayer("ground"))// check the layer is "ground"
{
hit = true;
}
}
if (CanDash)
{
StartCoroutine("UseDash");
CanDash = false;
for (int i = 0; i < 100; i++)
{
rb.AddForce(player.right * dashPower);
}
StartCoroutine("CountDown");
}
the basic timer,increases time value(miliseconds) and converts to normal time for user interface
IEnumerator timerCounter()
{
if (player.CanMove)
{
time += 1;
label.text = GetAsUiTimeFormat();
}
yield return new WaitForSeconds(0.01f);
StartCoroutine(timerCounter());
}
public string GetAsUiTimeFormat(){
return FillZero((time / (60 * 60)) % 60) + ":" +
FillZero((time / (60)) % 60) + ":" +
FillZero(time % 100);
}
private string FillZero(int num){
return num < 10 ? "0" + num : num + "";
}
throws an laser from specified point to distance then returns objects by layer
displays distance as meter
displays distance as meter
RaycastHit2D hit = Physics2D.Raycast(
transform.position, // raycast start point
Vector2.down, // the direction
Mathf.Infinity, // max distance
layer); // layer (in this case : "ground")
gets heart objects from user interface
in every start,refreshes hearts
responsible with GameOver Screen
plays animations and sounds for gameover screen
Player uses hearthsController
in every start,refreshes hearts
responsible with GameOver Screen
plays animations and sounds for gameover screen
Player uses hearthsController
public void RemoveHeart()
{
if (getActiveHearts() <= 0)
{
player.CanMove = false;
gameOverScreen.SetActive(true);
}
else
{
hitSfx.Stop();
hitSfx.Play();
Animation anim = getNextActiveHeart().GetComponent<Animation>();
anim.Play();
StartCoroutine(
waitToanimate(anim, () =>
{
getNextActiveHeart().gameObject.SetActive(false);
}));
}
}
panoramic view that adds more depth to game
made with 3 layer,moves with opposite velocity of player
the parent object holds instances of layers in horizontal direction
layers moves by distance scale to player
according to this formule : PlayerVelocity/DistanceScale
uses Player to get player speed
made with 3 layer,moves with opposite velocity of player
the parent object holds instances of layers in horizontal direction
layers moves by distance scale to player
according to this formule : PlayerVelocity/DistanceScale
uses Player to get player speed
foreach (Transform item in this.transform)
{
item.Translate(-(velocity.velocity.x * Time.deltaTime / layerDistance), 0, 0);
}
requires : instance of UI Checkpoint and InGame Checkpoints(Array)
uses start and end point to calculate total distance
calculates every ingame checkpoint object's distance to finish line
then converts to UI values
uses start and end point to calculate total distance
calculates every ingame checkpoint object's distance to finish line
then converts to UI values
foreach (var item in CheckPoints)
{
float InWorldPercent = 100 * Vector2.Distance(item.transform.position, StartPoint.position) / finishDistance;
Transform NewUiCheckPoint = Instantiate(UiCheckpointInstance, UiCheckpointHolder);
float inUiPointX = UiDistanceSlider.rect.width * (InWorldPercent / 100);
NewUiCheckPoint.localPosition = new Vector2(inUiPointX, UiCheckpointInstance.position.y);
}
gets variables : width (points count) , points distance , points curve
and converts to path for sprite renderer
then sprite renderer fills the shape that created with points
and converts to path for sprite renderer
then sprite renderer fills the shape that created with points
public void ReStart(bool recheckpoint = false)
{
// clear previous objects
ssc = this.GetComponent<SpriteShapeController>();
ssc.spline.Clear();
foreach (Transform item in CheckpointsHolder)
{
Destroy(item.gameObject);
}
UiController.CheckPoints.Clear();
// add flat starting position for better landing
ssc.spline.InsertPointAt(0, Vector3.zero);
ssc.spline.InsertPointAt(1, new Vector3(HorizontalDistance, 0, 0));
AddCheckpoint(HorizontalDistance / 2, 0);
float l = HorizontalDistance * 2;
float minY = ssc.spline.GetPosition(0).y;
for (int i = 2; i <= Width; i++)
{
// calculate new Y point with previous Y point
float preY = ssc.spline.GetPosition(i - 1).y;
float t = Random.Range(preY - VerticalDistance, preY + VerticalDistance);
minY = (t < minY) ? t : minY;
ssc.spline.InsertPointAt(i, new Vector2(l, t));
l += HorizontalDistance;
if (i % perDistance == 0)
{
AddCheckpoint(ssc.spline.GetPosition(i).x, ssc.spline.GetPosition(i).y);
}
}
// turn back to first point with fill
Vector2 firstpoint = ssc.spline.GetPosition(0);
Vector2 lastpoint = ssc.spline.GetPosition(ssc.spline.GetPointCount() - 1);
ssc.spline.InsertPointAt(ssc.spline.GetPointCount(), new Vector2(lastpoint.x, minY - GroundFillDistance));
ssc.spline.InsertPointAt(0, new Vector2(firstpoint.x, minY - GroundFillDistance));
ssc.spline.InsertPointAt(ssc.spline.GetPointCount() - 1, new Vector2(finishLine.position.x - transform.position.x, finishLine.position.y - transform.position.y));
ssc.spline.InsertPointAt(ssc.spline.GetPointCount() - 1, new Vector2(finishLine.position.x - transform.position.x - HorizontalDistance * 2, finishLine.position.y - transform.position.y));
// adds curve between to points for better hill view
for (int i = 0; i < ssc.spline.GetPointCount(); i++)
{
ssc.spline.SetTangentMode(i, ShapeTangentMode.Continuous);
ssc.spline.SetLeftTangent(i, new Vector3(-PointCurve, 0, 0));
ssc.spline.SetRightTangent(i, new Vector3(PointCurve, 0, 0));
}
// update user interface checkpoints
if (recheckpoint)
{
UiController.ReplaceCheckpoints();
}
}