-

   rss_rss_hh_new

 - e-mail

 

 -

 LiveInternet.ru:
: 17.03.2011
:
:
: 51

:


, 21 2017 . 14:48 +

google play? , , - ?


, : - . . , devlog.




Level 1.1. .


 -
-.


? . , ( , ) . ? ? ? ? , , . !


, . . , , .
, . Crimsonland . gui . :


: , .
: (), .
. . :
1. ;
2. ;
3. .

. , .

:


  • :
    • ( );
    • ( , , ).
  • :
    • ( : );
    • ;
    • ( level design), .

. , .


Todo: , / .


Level 1.2. .


Unity3D, .
BoxCollider2D, RigidBody2D CircleCollider2D (, ). , , , RigidBody2D, CircleCollider2D TrailRenderer .


Clock, (, ) , Time.DeltaTime.


Clock.cs,
using UnityEngine;
using System.Collections;

public class Clock : MonoBehaviour {
    [SerializeField, Range(0, 2)] float stepDuration;
    [SerializeField] AnimationCurve stepCurve;

    float time = -1;
    float timeRatio = 0;
    float defaultFixedDeltaTime = 0;

    static Clock instance;

    public static Clock Instance { get { return instance; } }

    void Start() {
        instance = this;
        defaultFixedDeltaTime = Time.fixedDeltaTime;
    }

    void OnDestroy() {
        if (instance == this)
            instance = null;
    }

    public bool Paused {
        get { return time < 0; }
    }

    public float DeltaTime {
        get { return 
            timeRatio * Time.deltaTime; }
    }

    public float FixedDeltaTime {
        get { return 
            timeRatio * Time.fixedDeltaTime; }
    }

    public void Play() {
        if (!Paused)
            return;

        time = 0;
        timeRatio = Mathf.Max(0, stepCurve.Evaluate(0));
        UpdatePhysicSpeed();
    }

    public void Update() {
        if (Paused)
            return;

        time = Mathf.Min(time + Time.unscaledDeltaTime, stepDuration);

        if (time >= stepDuration) {
            timeRatio = 0;
            time = -1;
            UpdatePhysicSpeed();
            return;
        }

        timeRatio = Mathf.Max(0, stepCurve.Evaluate(time / stepDuration));
        UpdatePhysicSpeed();
    }

    void UpdatePhysicSpeed() {
        Time.timeScale = timeRatio;
        Time.fixedDeltaTime = defaultFixedDeltaTime * timeRatio;
    }

}

, :


  1. transform.position, velocity, , ;
  2. ( fixedDeltaTime), - ( ).

. , , :




:
:


  1. "" , ;
  2. ( );
  3. ( " ", ).

:


  1. velocity, transform.position;
  2. ( , , ).

Todo: .


Level 1.3. .


, :


  1. . , ;
  2. . , ;
  3. . , ;
  4. , , . , , ;
  5. , . , ( , );
  6. .

, . - :


, :


OnCollisionEnter2D
void OnCollisionEnter2D(Collision2D coll) {
    int layer = 1 << coll.gameObject.layer;

    if (layer == wall.value)
        Destroy(gameObject);
    else if (layer == human.value) {
        Destroy(gameObject);

        var humanBody = coll.gameObject.GetComponent();

        if (humanBody != null)
            humanBody.Kill();

        return;
    } else if (layer == wallMirror.value) {
        Vector2 normal = Vector2.zero;

        foreach (var contact in coll.contacts)
            normal += contact.normal;

        direction = Vector2.Reflect(direction, normal);
    }
}

, .
Clock: stepDuration , stepCurve. .
   Clock.cs
Clock.cs


, / ( 1). "" , (.. "" ). , /.


, .


, , . , , . playtest':


  1. . , ;
  2. . , ;
  3. . , , . .. , . ( );
  4. , . , ;
  5. : bullet storm;
  6. . ;

, !





Todo: , .


Level 1.boss [100hp]. .


"" , .
: , , .


. , , . , , .


. . , , .
360 , , . , " ", . - , , . : " !", Hotline miami ( !). : " !".
, : , .




(, !) , !


Todo: .


Level 1.boss [75hp]. 3D.


! Wildfire worlds, . , , :




, 3 , 3 . , . , , .


: . , .
: . . , , . , ...




Level 1.boss [15hp]. Procedural generation.


. , - , , . 3 ? , ! , , low poly. , , .


, . , , , . !


Todo: .


Level 2.1. 2D.


. 2, :


  • ( ) ;
  • , ( ).

!

, :




, "", , . , , , .
$1 - cos\frac{\pi}{edges}$ .
, :




, :




!
, ( - ).



.


: , , . , . , . : , ?



,


, . 3D.


Level 2.2. 3D.


, 3D . , 2D.


:


  1. height ;
  2. edges ;
  3. size Vector2D, ;
  4. isCircle ? , , , size.y size.x.

, :


  1. "";
  2. ;
  3. ;
  4. ;
  5. 1 .

. 3 :


  1. Body ;
  2. Border ;
  3. Side ;

, .. x y, .




:
, , .
AnglesCache :


namespace ObstacleGenerators {
    public class AnglesCache {
        public Vector3[] GetAngles(int sides);
    }
}

, 3 , ( , , ..). , , , .


: , , , :



, ..


. :




, ZTest On (LEqual) Less. . , :



ZTest'


, :


  1. uv . ;
  2. ;
  3. _fixed3 _LightPosition, - ( ). , , isCircle : , , . isCircle .




, , uv . ( )


PolygonCollider2D .
: lowpoly .


Todo: .


Level 3.1. .


, :



, ..


:




" ?" . " Unity3D !".
, . Shadow mapping. : , , , , - . , ( z-buffer' ). . , .
.. "pixel perfect", , , . , , . , , .


, . "Shadow volume" , .
, .


  1. ( , );
  2. "" ( 2 ).
  3. ( color buffer , z-buffer' , ):
    3.1. (front): ;
    3.1. (back): .

, 1 "" ( front ) "" ( back ) $inline$-1 + 1 = 0$inline$ . , (, front back - , z-buffer) .


, , , , , , . , !


Todo: .


Level 3.2. .


, - , GL . , .


32 . 4 , :
32 , 32 , 96 .
, 96*2 = 192 384 . .


, : , (front), (back). 2 , 4 (2 ), Cull Back Cull Front.


32 * 4 = 128 , 256 512 . .


, .
.


: , (, ). , :


  1. ;
  2. A, B, C , ;
  3. , ;
  4. , ;
  5. 1-4 ;
  6. ( ), ;
  7. , , ;
  8. , , (, 100 );

:
( ) , .


, !
, , :


  1. . , . 32 $16 * 4 = 64$ $(16 * 2 + 2) * 2 = 68$ . 256 512 .
  2. . ( ). , . ( ) .

.



, : 100-200 draw call' . , CPU. , , ? :)


Todo: CPU.


Level 3.2. cpu.


.


  1. :
    1.1. ;
    1.2. ;
    1.3. ;
    1.4. , , (lightToShadowIndex);
    1.5.1 , , (shadowToLightIndex);


  2. :
    2.1. lightToShadowIndex shadowToLightIndex 2 (, 4-, 2 , 2 , );


  3. :
    3.1 shadowToLightIndex lightToShadowIndex 2 ;


  4. :
    4.1 shadowToLightIndex lightToShadowIndex;

:
, ( ).
: , .

, . , 60fps 10 , 600 . ( 6 10 ).


Todo: , 60fps nexus 5.


Level 3.3. .


:
, . , .


:
. AnglesCache, . :


using UnityEngine;
using System.Collections.Generic;

namespace ObstacleGenerators {
    public class AnglesCache {
        List cache;
        const int MAX_CACHE_SIZE = 100;

        public AnglesCache () {
            cache = new List(MAX_CACHE_SIZE);

            for (int i = 0; i < MAX_CACHE_SIZE; ++i)
                cache.Add(null);
        }

        public Vector2[] GetAngles(int sides) {
            if (sides < 0)
                return null;

            if (sides > MAX_CACHE_SIZE)
                return GenerateAngles(sides);

            if (cache[sides] == null)
                cache[sides] = GenerateAngles(sides);

            return cache[sides];
        }

        public float AngleOffset {
            get { return Mathf.PI * 0.25f; }
        }

        Vector2[] GenerateAngles(int sides) {
            var result = new Vector2[sides];

            float deltaAngle = 360.0f / sides;
            float firstAngle = AngleOffset;

            var matrix = Matrix4x4.TRS(Vector2.zero, Quaternion.Euler(0, 0, deltaAngle), Vector2.one);
            var direction = new Vector2(Mathf.Cos(firstAngle), Mathf.Sin(firstAngle));

            for (int i = 0; i < sides; ++i) {
                result[i] = direction;
                direction = matrix.MultiplyPoint3x4(direction);
            }

            return result;
        }
    }
}

:
( ). , c .


:
Transform.TransformPoint transform.localToWorldMatrix MultiplyPoint3x4.
Vector3 Vector2 ( , ), , :


Vector2 v2;
Vector3 v3;

//    , 
v2.x = v3.x;
v2.y = v3.y;
//   
v2.Set(v3.x, v3.y);
//    ,   
v2 = v3;

, , , .

:
. , , :


  1. (size.x == size.y);
  2. .

, . .


:


  1. , : size.x == size.y ;
  2. :
    direction = lightPosition - obstacleCenter;
  3. LCT (L , C , T , L) LC, CT (). deltaAngle LC CT;
  4. directionAngle ( OX) LC;
  5. firstAngle, secondAngle LT:
    firstAngle = directionAngle - deltaAngle;
    secondAngle = directionAngle + deltaAngle;
  6. , 360 / edges, z:
    fromLightToShadow = Mathf.FloorToInt(firstAngle / pi2 * edges + edges) % edges;
    fromShadowToLight = Mathf.FloorToInt(secondAngle / pi2 * edges + edges) % edges;
  7. , . , firstAngle : , . , , (fromLightToShadow fromShadowToLight), :
    if (linesCache[fromLightToShadow].HalfPlainSign(lightPosition) < 0)
    fromLightToShadow = (fromLightToShadow + 1) % edges;
    if (linesCache[fromShadowToLight].HalfPlainSign(lightPosition) >= 0)
    fromShadowToLight = (fromShadowToLight + 1) % edges;

. (Acos, Atan2) . . , . , :





.


bool CanUseFastSilhouette(Vector2 lightPosition) {
    if (size.x != size.y || edgesList != null)
        return false;

    return (lightPosition - (Vector2)transform.position).sqrMagnitude > size.x * size.x;
}

bool FindSilhouetteEdges(Vector2 lightPosition, Vector3[] angles, out int fromLightToShadow, out int fromShadowToLight) {
    if (CanUseFastSilhouette(lightPosition))
        return FindSilhouetteEdgesFast(lightPosition, angles, out fromLightToShadow, out fromShadowToLight);

    return FindSilhouetteEdges(lightPosition, out fromLightToShadow, out fromShadowToLight);
}

bool FindSilhouetteEdgesFast(Vector2 lightPosition, Vector3[] angles, out int fromLightToShadow, out int fromShadowToLight) {
    Vector2 center = transform.position;
    float radius = size.x;

    Vector2 delta = center - lightPosition;
    float deltaMagnitude = delta.magnitude;

    float sin = radius / deltaMagnitude;
    Vector2 direction = delta / deltaMagnitude;

    float pi2 = Mathf.PI * 2.0f;
    float directionAngle = Mathf.Atan2(-direction.y, -direction.x) - anglesCache.AngleOffset - transform.rotation.eulerAngles.z * Mathf.Deg2Rad;
    float deltaAngle = Mathf.Acos(sin);
    float firstAngle = ((directionAngle - deltaAngle) % pi2 + pi2) % pi2;
    float secondAngle = ((directionAngle + deltaAngle) % pi2 + pi2) % pi2;

    fromLightToShadow = Mathf.RoundToInt(firstAngle / pi2 * edges - 1 + edges) % edges;
    fromShadowToLight = Mathf.RoundToInt(secondAngle / pi2 * edges - 1 + edges) % edges;

    return true;
}

:
cpu, . , , 32 , , 42 36 ( 512 256 gpu).


:
, . "" . , .


:
x y ( ) c , .


bounding box:
Mesh.RecalculateBounds . AABB .


:


  1. 4 : circleCenter lightPosition, ;
  2. 4 4-, z ( 8 , );
  3. .
  4. ( , z == 0)
  5. 16 , ;
  6. AABB .

, , .


( )



( )



Bounding box ( )


, , .



, , . :)


, , , . , , :


  1. ;
  2. ;
  3. .

:


  1. , , ;
  2. ;
  3. 3 , ;
  4. .
  5. (, Gizmos), .

, ! :)

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/322262/

:  

: [1] []
 

:
: 

: ( )

:

  URL