Controller2D.cs
using UnityEngine;
using System.Collections;
public class Controller2D : RaycastController {
float maxClimbAngle = 80;
float maxDescendingAngle = 75;
public CollisionInfo collisions;
[HideInInspector]
public Vector2 playerInput;
public override void Start(){
base.Start ();
collisions.faceDir = 1;
}
public void Move(Vector3 velocity, bool standingOnPlatform){
Move (velocity, Vector2.zero, standingOnPlatform);
}
public void Move(Vector3 velocity, Vector2 input, bool standingOnPlatform = false){
UpdateRaycastOrigins ();
collisions.Reset ();
collisions.velocityOld = velocity;
playerInput = input;
if (velocity.x != 0) {
collisions.faceDir = (int)Mathf.Sign (velocity.x);
}
if(velocity.y < 0){
DescendSlope (ref velocity);
}
//좌우충돌체크를 한다음에 상하충돌체크를 해야한다.
//왜냐하면 VerticalCollisions함수에서 rayOrigin에 velocity.x를 더하기때문이다.
HorizontalCollisions (ref velocity);
if(velocity.y != 0){
VerticalCollisions (ref velocity);
}
transform.Translate (velocity);
if(standingOnPlatform){
collisions.below = true;
}
}
void HorizontalCollisions(ref Vector3 velocity){
float directionX = collisions.faceDir;
float rayLenth = Mathf.Abs (velocity.x) + skinWidth;
if (Mathf.Abs (velocity.x) < skinWidth) {
rayLenth = 2 * skinWidth;
}
for(int i = 0; i < horizontalRayCount; i++){
Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
rayOrigin += Vector2.up * (horizontalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, rayLenth, collisionMask);
Debug.DrawRay (rayOrigin, Vector2.right* directionX *rayLenth, Color.red);
if(hit){
if (hit.distance == 0) {
continue;
}
float slopeAngle = Vector2.Angle (hit.normal, Vector2.up);
if (i == 0 && slopeAngle <= maxClimbAngle) {
if(collisions.descendingSlope){
collisions.descendingSlope = false;
velocity = collisions.velocityOld;
}
float distanceToSlopeStart = 0;
if(slopeAngle != collisions.slopeAngleOld){
distanceToSlopeStart = hit.distance - skinWidth;
velocity.x -= distanceToSlopeStart * directionX;
}
ClimbSlope (ref velocity, slopeAngle);
velocity.x += distanceToSlopeStart * directionX;
}
if(!collisions.climbingSlope || slopeAngle > maxClimbAngle){
velocity.x = (hit.distance - skinWidth) * directionX;
rayLenth = hit.distance;
if (collisions.climbingSlope) {
velocity.y = Mathf.Tan (collisions.slopeAngle * Mathf.Deg2Rad)*Mathf.Abs(velocity.x);
}
collisions.left = directionX == -1;
collisions.right = directionX == 1;
}
}
}
}
void VerticalCollisions(ref Vector3 velocity){
float directionY = Mathf.Sign (velocity.y);
float rayLenth = Mathf.Abs (velocity.y) + skinWidth;
for(int i = 0; i < verticalRayCount; i++){
Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i + velocity.x);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up * directionY, rayLenth, collisionMask);
Debug.DrawRay (rayOrigin, Vector2.up* directionY *rayLenth, Color.red);
if(hit){
if(hit.collider.tag == "Through"){
if (directionY == 1 || hit.distance == 0) {
continue;
}
if(collisions.fallingThroughPlatform == true){
continue;
}
if(playerInput.y == -1){
collisions.fallingThroughPlatform = true;
Invoke ("ResetFallingthroughPlatform", .5f);
continue;
}
}
velocity.y = (hit.distance - skinWidth) * directionY;
rayLenth = hit.distance;
if (collisions.climbingSlope) {
velocity.x = velocity.y / Mathf.Tan(collisions.slopeAngle * Mathf.Deg2Rad) * Mathf.Sign(velocity.x);
}
collisions.below = directionY == -1;
collisions.above = directionY == 1;
}
}
if (collisions.climbingSlope) {
float directionX = Mathf.Sign (velocity.x);
rayLenth = Mathf.Abs (velocity.x) + skinWidth;
Vector2 rayOrigin = ((directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight) + Vector2.up * velocity.y;
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, rayLenth, collisionMask);
if(hit){
float slopeAngle = Vector2.Angle (hit.normal, Vector2.up);
if(slopeAngle != collisions.slopeAngle){
velocity.x = (hit.distance - skinWidth) * directionX;
collisions.slopeAngle = slopeAngle;
}
}
}
}
void ClimbSlope(ref Vector3 velocity, float slopeAngle){
float moveDistance = Mathf.Abs (velocity.x);
float climbVelocityY = Mathf.Sin (slopeAngle*Mathf.Deg2Rad) * moveDistance;
if (velocity.y <= climbVelocityY) {
velocity.y = climbVelocityY;
velocity.x = Mathf.Cos (slopeAngle*Mathf.Deg2Rad) * moveDistance * Mathf.Sign(velocity.x);
collisions.below = true;
collisions.climbingSlope = true;
collisions.slopeAngle = slopeAngle;
}
}
void DescendSlope(ref Vector3 velocity){
float directionX = Mathf.Sign (velocity.x);
Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomRight : raycastOrigins.bottomLeft;
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, - Vector2.up, Mathf.Infinity, collisionMask);
if (hit) {
float slopeAngle = Vector2.Angle (hit.normal, Vector2.up);
if(slopeAngle != 0 && slopeAngle <= maxDescendingAngle){
if (Mathf.Sign (hit.normal.x) == directionX) {
if (hit.distance - skinWidth <= Mathf.Tan (slopeAngle * Mathf.Deg2Rad) * Mathf.Abs (velocity.x)) {
float moveDistance = Mathf.Abs (velocity.x);
float descendVelocityY = Mathf.Sin (slopeAngle*Mathf.Deg2Rad) * moveDistance;
velocity.x = Mathf.Cos (slopeAngle*Mathf.Deg2Rad) * moveDistance * Mathf.Sign(velocity.x);
velocity.y -= descendVelocityY;
collisions.slopeAngle = slopeAngle;
collisions.descendingSlope = true;
collisions.below = true;
}
}
}
}
}
void ResetFallingthroughPlatform(){
collisions.fallingThroughPlatform = false;
}
public struct CollisionInfo{
public bool above, below;
public bool left, right;
public bool climbingSlope;
public bool descendingSlope;
public float slopeAngle, slopeAngleOld;
public int faceDir;
public bool fallingThroughPlatform;
public Vector3 velocityOld;
public void Reset(){
above = below = false;
left = right = false;
climbingSlope = false;
descendingSlope = false;
slopeAngleOld = slopeAngle;
slopeAngle = 0;
}
}
}
PlatFormController.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class PlatFormController : RaycastController {
public LayerMask passengerMask;
public Vector3[] localWayPoints;
Vector3[] globalWayPoints;
public float speed;
public bool cyclic;
public float waitTime;
[Range(0,2)]
public float easeAmount;
int fromWaypointIndex;
float percentBetweenWaypoints;
float nextMoveTime;
List<PassengerMovement> passengerMovement;
Dictionary<Transform, Controller2D> passengerDictionary = new Dictionary<Transform, Controller2D>();
// Use this for initialization
public override void Start () {
base.Start ();
globalWayPoints = new Vector3[localWayPoints.Length];
for (int i = 0; i < localWayPoints.Length; i++) {
globalWayPoints [i] = localWayPoints [i] + transform.position;
}
}
// Update is called once per frame
void Update () {
UpdateRaycastOrigins ();
Vector3 velocity = CalculatePlatformMovement();
CalculatePassengerMovement (velocity);
MovePassengers (true);
transform.Translate (velocity);
MovePassengers (false);
}
float Ease(float x){
float a = easeAmount + 1;
return Mathf.Pow (x, a) / (Mathf.Pow (x, a) + Mathf.Pow (1 - x, a));
}
Vector3 CalculatePlatformMovement(){
if (Time.time < nextMoveTime) {
return Vector3.zero;
}
fromWaypointIndex %= globalWayPoints.Length;
int toWaypointIndex = (fromWaypointIndex + 1) % globalWayPoints.Length;
float distanceBetweenWaypoints = Vector3.Distance (globalWayPoints[fromWaypointIndex], globalWayPoints[toWaypointIndex]);
percentBetweenWaypoints += Time.deltaTime * speed/distanceBetweenWaypoints;
percentBetweenWaypoints = Mathf.Clamp01 (percentBetweenWaypoints);
float easedPercentBetweenWaypoints = Ease (percentBetweenWaypoints);
Vector3 newPos = Vector3.Lerp (globalWayPoints [fromWaypointIndex], globalWayPoints [toWaypointIndex], easedPercentBetweenWaypoints);
if(percentBetweenWaypoints >= 1){
percentBetweenWaypoints = 0;
fromWaypointIndex++;
if(!cyclic){
if (fromWaypointIndex >= globalWayPoints.Length - 1) {
fromWaypointIndex = 0;
System.Array.Reverse (globalWayPoints);
}
}
nextMoveTime = Time.time + waitTime;
}
return newPos - transform.position;
}
void MovePassengers(bool beforeMovePlatform){
foreach(PassengerMovement passenger in passengerMovement){
if (!passengerDictionary.ContainsKey (passenger.transform)) {
passengerDictionary.Add (passenger.transform, passenger.transform.GetComponent<Controller2D>());
}
if(passenger.moveBeforePlatform == beforeMovePlatform){
passengerDictionary[passenger.transform].Move (passenger.velocity, passenger.standingOnPlatform);
}
}
}
void CalculatePassengerMovement(Vector3 velocity){
HashSet<Transform> movedPassengers = new HashSet<Transform> ();
passengerMovement = new List<PassengerMovement> ();
float directionX = Mathf.Sign (velocity.x);
float directionY = Mathf.Sign (velocity.y);
// Vertically moving
if (velocity.y != 0) {
float rayLenth = Mathf.Abs (velocity.y) + skinWidth;
for (int i = 0; i < verticalRayCount; i++) {
Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
rayOrigin += Vector2.right * (verticalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up * directionY, rayLenth, passengerMask);
if (hit && hit.distance != 0) {
if(!movedPassengers.Contains(hit.transform)){
movedPassengers.Add (hit.transform);
float pushX = (directionY == 1) ? velocity.x : 0f;
float pushY = velocity.y - (hit.distance - skinWidth) * directionY;
passengerMovement.Add (new PassengerMovement (hit.transform, new Vector3(pushX, pushY),
directionY == 1, true));
}
}
}
}
// horizontally moving
if(velocity.x != 0){
float rayLenth = Mathf.Abs (velocity.x) + skinWidth;
for (int i = 0; i < horizontalRayCount; i++) {
Vector2 rayOrigin = (directionX == -1) ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight;
rayOrigin += Vector2.up * (horizontalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.right * directionX, rayLenth, passengerMask);
if (hit && hit.distance != 0) {
if (!movedPassengers.Contains (hit.transform)) {
movedPassengers.Add (hit.transform);
float pushX = velocity.x - (hit.distance - skinWidth) * directionX;
float pushY = -skinWidth;
passengerMovement.Add (new PassengerMovement (hit.transform, new Vector3(pushX, pushY),
false, true));
}
}
}
}
//passenger on top of a horizontally or downward moving platform
if(directionY == -1 || velocity.y == 0 && velocity.x != 0){
float rayLenth = skinWidth *2;
for (int i = 0; i < verticalRayCount; i++) {
Vector2 rayOrigin = raycastOrigins.topLeft + Vector2.right * (verticalRaySpacing * i);
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.up, rayLenth, passengerMask);
if (hit && hit.distance != 0) {
if(!movedPassengers.Contains(hit.transform)){
movedPassengers.Add (hit.transform);
float pushX = velocity.x;
float pushY = velocity.y;
passengerMovement.Add (new PassengerMovement (hit.transform, new Vector3(pushX, pushY),
true, false));
}
}
}
}
}
struct PassengerMovement{
public Transform transform;
public Vector3 velocity;
public bool standingOnPlatform;
public bool moveBeforePlatform;
public PassengerMovement(Transform _transform, Vector3 _velocity, bool _standingOnPlatform, bool _moveBeforePlatform){
transform = _transform;
velocity = _velocity;
standingOnPlatform = _standingOnPlatform;
moveBeforePlatform = _moveBeforePlatform;
}
}
void OnDrawGizmos(){
if(localWayPoints != null){
Gizmos.color = Color.red;
float size = .3f;
for(int i = 0; i < localWayPoints.Length; i++){
Vector3 globalWayPointPos = (Application.isPlaying)?globalWayPoints[i] : localWayPoints [i] + transform.position;
Gizmos.DrawLine (globalWayPointPos - Vector3.up * size, globalWayPointPos + Vector3.up * size);
Gizmos.DrawLine (globalWayPointPos - Vector3.left * size, globalWayPointPos + Vector3.left * size);
}
}
}
}
CameraFallow.cs
using UnityEngine;
using System.Collections;
public class CameraFallow : MonoBehaviour {
public Controller2D target;
public float verticalOffset;
public float lookAheadDstX;
public float lookSmoothTimeX;
public float verticalSmoothTime;
public Vector2 focusAreaSize;
FocusArea focusArea;
float currentLookAheadX;
float targetLookAheadX;
float lookAheadDirX;
float smoothLookVelocityX;
float smoothVelocityY;
bool lookAheadStopped;
void Start(){
focusArea = new FocusArea (target.collider.bounds, focusAreaSize);
}
void LateUpdate(){
focusArea.Update (target.collider.bounds);
Vector2 focusPosition = focusArea.center + Vector2.up * verticalOffset;
if (focusArea.velocity.x != 0) {
lookAheadDirX = Mathf.Sign (focusArea.velocity.x);
if (Mathf.Sign (target.playerInput.x) == Mathf.Sign (focusArea.velocity.x) && target.playerInput.x != 0) {
lookAheadStopped = false;
targetLookAheadX = lookAheadDirX * lookAheadDstX;
} else {
if(!lookAheadStopped){
lookAheadStopped = true;
targetLookAheadX = currentLookAheadX + (lookAheadDirX * lookAheadDstX - currentLookAheadX)/4f;
}
}
}
currentLookAheadX = Mathf.SmoothDamp (currentLookAheadX, targetLookAheadX, ref smoothLookVelocityX, lookSmoothTimeX);
focusPosition.y = Mathf.SmoothDamp (transform.position.y, focusPosition.y, ref smoothVelocityY, verticalSmoothTime);
focusPosition += Vector2.right * currentLookAheadX;
transform.position = (Vector3)focusPosition + Vector3.forward * -10;
}
void OnDrawGizmos(){
Gizmos.color = new Color (1, 0, 0, .5f);
Gizmos.DrawCube (focusArea.center, focusAreaSize);
}
struct FocusArea{
public Vector2 center;
public Vector2 velocity;
float left, right;
float top, bottom;
public FocusArea(Bounds targetBounds, Vector2 size){
left = targetBounds.center.x - size.x/2;
right = targetBounds.center.x + size.x/2;
bottom = targetBounds.min.y;
top = targetBounds.min.y + size.y;
velocity = Vector2.zero;
center = new Vector2((left + right)/2, (top+bottom)/2);
}
public void Update(Bounds targetBounds){
float shiftX = 0;
if(targetBounds.min.x < left){
shiftX = targetBounds.min.x - left;
}else if(targetBounds.max.x > right){
shiftX = targetBounds.max.x - right;
}
left += shiftX;
right += shiftX;
float shiftY= 0;
if(targetBounds.min.y < bottom){
shiftY = targetBounds.min.y - bottom;
}else if(targetBounds.max.y > top){
shiftY = targetBounds.max.y - top;
}
top += shiftY;
bottom += shiftY;
center = new Vector2((left + right)/2, (top+bottom)/2);
velocity = new Vector2 (shiftX, shiftY);
}
}
}
'IT > 유니티' 카테고리의 다른 글
2016/8/24 개발노트 (0) | 2016.08.24 |
---|---|
2016/8/18 유니티 개발 노트 (0) | 2016.08.18 |
19. 유니티 교육 (Sebastian Lague 강의-2DRunner #1) (0) | 2016.08.08 |
18. 유니티 교육 (Sebastian Lague 강의-3DShooter #5) (0) | 2016.08.05 |
17. 유니티 교육 (Sebastian Lague 강의-3DShooter #4) (0) | 2016.08.04 |