Skip to content

REFUPANKER/The_2D_Ski_Game

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

17 Commits
 
 
 
 
 
 

Repository files navigation

Ski Game

[by 27-45 / LostMoon Games]

Gameplay
Documentation

Gameplay

Menu : Start

Menu : Settings

Menu : Level Completed

Menu : Game Over

In Game : First Step

In Game : Landing after jump

In Game : Checkpoints

Back to top

Documentation

Player

Movement

uses rigidbody and adds force to move player smoothly
if (Input.GetKey(KeyCode.D)){
rb.AddForce(this.transform.right * moveSpeed);}

Back & Front Flip

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;}

Camera Scale

uses GroundChecker
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);

Align Camera

Camera follows user as smoothly
transform.position = Vector3.Lerp(transform.position, 
new Vector3(target.position.x + CenterDistance, 
target.position.y, transform.position.z), 
smoothDelay);

Align player to ground

uses GroundChecker
transform.rotation = Quaternion.Lerp(transform.rotation,
Quaternion.FromToRotation(Vector3.up * Time.deltaTime, gc.rotater.normal), 
3f * Time.deltaTime);

Head Controller

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
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;
    }
}

Dash Controller

the speed boost for player , uses "E" key to activate dash for limited seconds coroutines used for refill dash bar
    if (CanDash)
    {
        StartCoroutine("UseDash");
        CanDash = false;
        for (int i = 0; i < 100; i++)
        {
            rb.AddForce(player.right * dashPower);
        }
        StartCoroutine("CountDown");
    }

Back to top

Timer

How it works

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 + "";
}

Back to top

Ground Checker

How it works

throws an laser from specified point to distance then returns objects by layer
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")

Back to top

Hearths Controller

How it works

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
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);
        }));
    }
}

Back to top

Panorama

How it works

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
 foreach (Transform item in this.transform)
 {
     item.Translate(-(velocity.velocity.x * Time.deltaTime / layerDistance), 0, 0);
 }

Back to top

Checkpoints Controller

How it works

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
    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);
    }

Back to top

Ground Generater

How it works

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
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();
    }
}

Back to top