View difference between Paste ID: UV7i32S8 and nXirLCK3
SHOW: | | - or go back to the newest paste.
1
using UnityEngine;
2
using System.Collections;
3
4
public class CharacterController2D : MonoBehaviour
5
{
6
	private const float SkinWidth = .02f;
7
	private const int TotalHorizontalRays = 8;
8
	private const int TotalVerticalRays = 4;
9
10
	private static readonly float SlopeLimitTangant = Mathf.Tan (75f* Mathf.Deg2Rad);
11
12
	public LayerMask PlatformMask;
13
	public ControllerParameters2D DefaultParameters;
14
15
	public ControllerState2D State { get; private set; }
16
	public Vector2 Velocity { get { return _velocity; } }
17
    public bool HandleCollisions { get; set; }
18
    public ControllerParameters2D Parameters { get { return _overrideParameters ?? DefaultParameters; } }
19
    public GameObject StandingOn { get; private set; }
20
	public bool CanJump
21
    {
22
        get
23
        {
24
            if (Parameters.JumpRestrictions == ControllerParameters2D.JumpBehavior.CanJumpAnywhere)
25
                return _jumpIn <= 0;
26
27
            if (Parameters.JumpRestrictions == ControllerParameters2D.JumpBehavior.CanJumpOnGround)
28
                return State.IsGrounded;
29
30
            return false;
31
        } 
32
    }
33
34
	private Vector2 _velocity;
35
	private Transform _transform;
36
	private Vector3 _localScale;
37
	private BoxCollider2D _boxCollider;
38
    private ControllerParameters2D _overrideParameters;
39
    private float _jumpIn;
40
41
    private Vector3
42
        _raycastTopLeft,
43
        _raycastBottomRight,
44
        _raycastBottomLeft;
45
46
	private float 
47
		_verticalDistanceBetweenRays,
48
		_horizontalDistanceBetweenRays;
49
50
	public void Awake()
51
	{
52
        HandleCollisions = true;
53
		State = new ControllerState2D();
54
		_transform = transform;
55
		_localScale = transform.localScale;
56
		_boxCollider = GetComponent<BoxCollider2D>();
57
58
		var colliderWidth = _boxCollider.size.x * Mathf.Abs (transform.localScale.x) - (2 * SkinWidth);
59
		_horizontalDistanceBetweenRays  = colliderWidth / (TotalVerticalRays - 1);
60
61
		var ColliderHeight = _boxCollider.size.y * Mathf.Abs(transform.localScale.y) - (2 * SkinWidth);
62
		_verticalDistanceBetweenRays = ColliderHeight / (TotalHorizontalRays - 1);
63
	}
64
65
	public void AddForce(Vector2 force)
66
	{
67
		_velocity += force;
68
	}
69
70
	public void SetForce(Vector2 force)
71
	{
72
		_velocity = force;
73
	}
74
75
	public void SetHorizontalForce(float x)
76
	{
77
		_velocity.x = x;
78
	}
79
80
	public void SetVerticalForce (float y)
81
	{
82
		_velocity.y = y;
83
	}
84
85
	public void Jump()
86
	{
87
        // TODO: Moving platform Support
88
        AddForce(new Vector2(0, Parameters.JumpMagnitude));
89
        _jumpIn = Parameters.JumpFrequency;
90
	}
91
92
	public void LateUpdate()
93
	{
94
        _jumpIn -= Time.deltaTime;
95
        _velocity.y += Parameters.Gravity * Time.deltaTime;
96
		Move(Velocity * Time.deltaTime);
97
98
	}
99
100
    private void Move(Vector2 deltaMovement)
101
	{
102
		var wasGrounded = State.IsCollidingBelow;
103
		State.Reset();
104
105
		if (HandleCollisions)
106
		{
107
			HandlePlatforms();
108
			CalculateRayOrigins();
109
110
			if (deltaMovement.y < 0 && wasGrounded)
111
                HandleVerticalSlope(ref deltaMovement);
112
113
			if (Mathf.Abs(deltaMovement.x) > .001f)
114
				MoveHorizontally(ref deltaMovement);
115
116
			MoveVertically(ref deltaMovement);
117
		}
118
119
		_transform.Translate(deltaMovement, Space.World);
120
121
        // TODO: Additional moving platform code
122
123
        if (Time.deltaTime > 0)
124
            _velocity = deltaMovement / Time.deltaTime;
125
126
        _velocity.x = Mathf.Min(_velocity.x, Parameters.MaxVelocity.x);
127
        _velocity.y = Mathf.Min(_velocity.y, Parameters.MaxVelocity.y);
128
129
        if (State.IsMovingUpSlope)
130
            _velocity.y = 0;
131
	}
132
133
	private void HandlePlatforms()
134
	{
135
136
	}
137
138
	private void CalculateRayOrigins()
139
	{
140
        var size = new Vector2(_boxCollider.size.x * Mathf.Abs(_localScale.x), _boxCollider.size.y * Mathf.Abs(_localScale.y)) / 2;
141
        var center = new Vector2(_boxCollider.center.x * _localScale.x, _boxCollider.center.y * _localScale.y);
142
143
        _raycastTopLeft = _transform.position + new Vector3(center.x - size.x + SkinWidth, center.y + size.y - SkinWidth);
144
        _raycastBottomRight = _transform.position + new Vector3(center.x + size.x - SkinWidth, center.y - size.y + SkinWidth);
145
        _raycastBottomLeft = _transform.position + new Vector3(center.x - size.x + SkinWidth, center.y - size.y + SkinWidth);
146
	}
147
148
	private void MoveHorizontally(ref Vector2 deltaMovement)
149
	{
150
        var isGoingRight = deltaMovement.x > 0;
151
        var rayDistance = Mathf.Abs(deltaMovement.x) + SkinWidth;
152
        var rayDirection = isGoingRight ? Vector2.right : -Vector2.right;
153
        var rayOrigin = isGoingRight ? _raycastBottomRight : _raycastBottomLeft;
154
        
155
        for (var i = 0; i < TotalHorizontalRays; i++)
156
        {
157
            var rayVector = new Vector2(rayOrigin.x, rayOrigin.y + (i * _verticalDistanceBetweenRays));
158
            Debug.DrawRay(rayVector, rayDirection * rayDistance, Color.red);
159
160
            var rayCastHit = Physics2D.Raycast(rayVector, rayDirection, rayDistance, PlatformMask);
161
            if (!rayCastHit)
162
                continue;
163
            
164
165
            if (i == 0 && HandleHorizontalSlope(ref deltaMovement, Vector2.Angle(rayCastHit.normal, Vector2.up), isGoingRight))
166
                break;
167
168
            deltaMovement.x = rayCastHit.point.x - rayVector.x;
169
            rayDistance = Mathf.Abs(deltaMovement.x);
170
171
            if (isGoingRight)
172
            {
173
                deltaMovement.x -= SkinWidth;
174
                State.IsCollidingRight = true;
175
            }
176
            else
177
            {
178
                deltaMovement.x += SkinWidth;
179
                State.IsCollidingLeft = true;
180
            }
181
182
            if (rayDistance < SkinWidth + .0001f)
183
                break;
184
        }
185
	}
186
187
	private void MoveVertically(ref Vector2 deltaMovement)
188
	{
189
        var isGoingUp = deltaMovement.y > 0;
190
        var rayDistance = Mathf.Abs(deltaMovement.y) + SkinWidth;
191
        var rayDirection = isGoingUp ? Vector2.up : -Vector2.up;
192
        var rayOrigin = isGoingUp ? _raycastTopLeft : _raycastBottomLeft;
193
194
        rayOrigin.x += deltaMovement.x;
195
196
        var standingOnDistance = float.MaxValue;
197
        for (var i = 0; i < TotalVerticalRays; i++)
198
        {
199
            var rayVector = new Vector2(rayOrigin.x + (i * _horizontalDistanceBetweenRays), rayOrigin.y);
200
            Debug.DrawRay(rayVector, rayDirection * rayDistance, Color.red);
201
202
            var raycastHit = Physics2D.Raycast(rayVector, rayDirection, rayDistance, PlatformMask);
203
            if (!raycastHit)
204
                continue;           
205
206
            if (!isGoingUp)
207
            {
208
                var verticalDistanceToHit = _transform.position.y - raycastHit.point.y;
209
                if (verticalDistanceToHit < standingOnDistance)
210
                {
211
                    standingOnDistance = verticalDistanceToHit;
212
                    StandingOn = raycastHit.collider.gameObject;
213
                }
214
            }
215
216
            deltaMovement.y = raycastHit.point.y - rayVector.y;
217
            rayDistance = Mathf.Abs(deltaMovement.y);
218
219
            if (isGoingUp)
220
            {
221
                deltaMovement.y -= SkinWidth;
222
                State.IsCollidingAbove = true;
223
            }
224
            else
225
            {
226
                deltaMovement.y += SkinWidth;
227
                State.IsCollidingBelow = true;
228
             }
229
230
            if (!isGoingUp && deltaMovement.y > .0001f)
231
            {
232
                State.IsMovingUpSlope = true;
233
            }
234
235
            if (rayDistance < SkinWidth + .0001f)
236
                break;
237
238
        }
239
240
	}
241
242
	private void HandleVerticalSlope(ref Vector2 deltaMovement)
243
	{
244
        var center = (_raycastBottomLeft.x + _raycastBottomRight.x) / 2;
245
        var direction = -Vector2.up;
246-
        var slopeRayVector = new Vector2(center, _raycastBottomLeft.x);
246+
247
        var slopeDistance = SlopeLimitTangant * (_raycastBottomRight.x - center);
248
        var slopeRayVector = new Vector2(center, _raycastBottomLeft.y);
249
250
        Debug.DrawRay(slopeRayVector, direction * slopeDistance, Color.yellow);
251
252
        var raycastHit = Physics2D.Raycast(slopeRayVector, direction, slopeDistance, PlatformMask);
253-
        return false;
253+
        if (!raycastHit)
254
            return;
255
256
        // Resharper disable CompareOfFloatsByEqualityOperator
257
258
        var isMovingDownSlope = Mathf.Sign(raycastHit.normal.x) == Mathf.Sign(deltaMovement.x);
259
        if (!isMovingDownSlope)
260
            return;
261
262
        var angle = Vector2.Angle(raycastHit.normal, Vector2.up);
263
        if (Mathf.Abs(angle) < .0001f)
264
            return;
265
266
        State.IsMovingDownSlope = true;
267
        State.SlopeAngle = angle;
268
        deltaMovement.y = raycastHit.point.y - slopeRayVector.y;
269
270
    }
271
272
	private bool HandleHorizontalSlope(ref Vector2 deltaMovement, float angle, bool isGoingRight)
273
	{
274
        if (Mathf.RoundToInt(angle) == 90)
275
            return false;
276
277
        if (angle > Parameters.SlopeLimit)
278
        {
279
            deltaMovement.x = 0;
280
            return true;
281
        }
282
283
        if (deltaMovement.y > .07f)
284
            return true;
285
286
        deltaMovement.x += isGoingRight ? -SkinWidth : SkinWidth;
287
        deltaMovement.y = Mathf.Abs(Mathf.Tan(angle * Mathf.Deg2Rad) * deltaMovement.x);
288
        State.IsMovingUpSlope = true;
289
        State.IsCollidingBelow = true;
290
        return true;
291
	}
292
293
	public void OnTriggerEnter2D(Collider2D other)
294
	{
295
	
296
	}
297
298
	public void OnTriggerExit2D(Collider2D other)
299
	{
300
301
	}
302
}