일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- MAC
- 메카님
- polymorphism
- STCF
- stride
- 배경 그림
- Unity #Indie Game
- 컴퓨터 네트워크
- DP
- frequency-domain spectrum analysis
- Trap
- 유스케이스
- SJF
- AINCAA
- OSI 7계층
- link layer
- DSP
- FIFO
- OWASP
- Security
- 게임 개발
- Waterfall
- protection
- unity
- MLFQ
- information hiding
- 유니티
- 운영체제
- SDLC
- 게임개발
- Today
- Total
다양한 기록
Parrying Sword #8 : [기획][프로그래밍] 와이어 액션 구현 본문
벽 잡기를 만들고 나서도 y축을 활용하는 액션이 부족하다는 생각이 들어
와이어 액션을 구현하였습니다
마법을 쓴다는 이미지로 구상을 했고, 그 결과 위 이미지처럼 제작하게 되었습니다.
// 와이어 액션 **************************************
if ( Input.GetKey(KeyCode.S) && playerCtrl.actionActive && wire != 0 )
{
prevWire = wire;
wire = playerCtrl.ActionWireJump();
if( prevWire != -1 && wire == 0 || (prevWire == 1 && wire == -1) )
{
playerCtrl.ActionWireInertia();
}
}
if( Input.GetKeyUp(KeyCode.S) )
{
if( wire > 0 )
{
wire = -1;
playerCtrl.ActionWireInertia();
}
else if( wire == 0 )
{
wire = -1;
}
}
if (wire > 0) return;
// ************************************************
PlayerMain 클래스에서의 와이어 액션 코드입니다.
여기서 wire 변수가 1이면 잡기 성공, 0이면 너무 가까워서 실패, -1이면 잡을 벽이 없음 판정입니다.
잡을 벽이 가까이에 없으면 아예 실패하고
중간에 키 입력을 놓거나, 너무 가까워지면 와이어가 끊기도록 설정합니다.
가능하면 리턴을 bool 변수로 다루고 싶었으나, 각각의 상황을 전부 제대로 다루어 놓지 않으면 의도대로 작동하지 않습니다.
다른 클래스와 너무 깊게 엮이는 것 같아 그렇게 마음에 들지는 않지만, 그래도 버그가 나는 대로 내버려 둘 수는 없습니다.
// 와이어액션
public int ActionWireJump()
{
int success = wireAction.ActionWireJump();
if( success > 0 )
{
usingWire = true;
animator.SetTrigger("WireAction");
}
return success;
}
public void ActionWireInertia()
{
usingWire = false;
wireAction.inactiveWire();
rb.velocity = new Vector2(rb.velocity.x * 1.3f, 40.0f);
}
위에서 언급된 wire 변수의 값을 위 함수에서 제공합니다.
WireAction 클래스에서 값을 받아오고, 애니메이션 상태를 변경 해 줍니다.
중요한 것은, 와이어가 끊어졌을 때 반동으로 가해지는 힘을 억지로 바꿔주어야 합니다.
그렇지 않으면 와이어액션 중 가해지는 힘에 의해 저 멀리 날아가는 문제가 생깁니다.
그렇다고 아예 없으면 안되니 velocity를 바꾸어 반동을 조절합니다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WireAction : MonoBehaviour
{
private PlayerController playerCtrl;
private GameObject player;
private Transform wire;
private Transform wireHook;
private SpriteRenderer[] sprites;
private Transform wirePosition;
private float distance = 0;
private void Awake()
{
player = GameObject.Find("Player");
playerCtrl = player.GetComponent<PlayerController>();
sprites = GetComponentsInChildren<SpriteRenderer>();
wire = transform.Find("Wire");
wireHook = transform.Find("WireHook");
wirePosition = player.transform.Find("WirePosition");
}
// 템플릿 메소드 *********************************************************
// -1 탐색 실패, 0 너무 가까움 1 가능
public int ActionWireJump()
{
moveAtPlayer();
int check = checkDistance();
if (check < 1) return check;
modifyTransform();
activeWire();
addForce();
return check;
}
// ********************************************************************
private void moveAtPlayer()
{
transform.position = wirePosition.position;
}
// -1 탐색 실패, 0 너무 가까움 1 가능
private int checkDistance()
{
Collider2D[] colliders;
for( int i = 0; i < 2; i++ )
{
colliders = Physics2D.OverlapPointAll(new Vector2(transform.position.x + i * playerCtrl.dir,
transform.position.y + i));
// Debug.Log(i);
foreach (Collider2D collider in colliders)
{
if (collider.tag == "Road")
{
return 0;
}
}
}
for( int i = 1; i < 26; i++ )
{
colliders = Physics2D.OverlapPointAll(new Vector2(transform.position.x + i * playerCtrl.dir,
transform.position.y + i));
// Debug.Log(i);
foreach( Collider2D collider in colliders )
{
if( collider.tag == "Road" )
{
distance = i;
return 1;
}
}
}
return -1;
}
private void modifyTransform()
{
wire.localScale = new Vector3(distance * 1.4f, wire.localScale.y,
wire.localScale.z);
transform.localScale = new Vector3( Mathf.Abs( transform.localScale.x ),
transform.localScale.y,
transform.localScale.z);
wireHook.transform.position = new Vector3(transform.position.x + ( distance + 1 ) * playerCtrl.dir,
transform.position.y + distance,
transform.position.z);
}
private void activeWire()
{
foreach( SpriteRenderer sprite in sprites )
{
sprite.enabled = true;
}
}
private void addForce()
{
player.GetComponent<Rigidbody2D>().velocity = new Vector2(70.0f * playerCtrl.dir, 60.0f);
}
// 스프라이트 끄기
public void inactiveWire()
{
foreach (SpriteRenderer sprite in sprites)
{
sprite.enabled = false;
}
}
}
WireAction 클래스입니다.
순서가 중요한 관계로 템플릿 메소드 패턴을 적용하였습니다.
시작 지점을 기준으로 x, y축을 대각선으로 1만큼 이동하며 잡을 벽이 있나를 체크하고, 있으면 벽을 잡고 쭉 진행합니다.
추가로 와이어를 끊기 위해 스프라이트를 꺼주는 함수를 하나 더 만들어 줍니다.
'유니티 엔진 > Parrying Sowrd' 카테고리의 다른 글
Parrying Sword #10 : [아트][기획] 벽 잡기, 와이어 액션, 폭탄 스프라이트 / 플레이어 애니메이션 현황 (0) | 2023.02.17 |
---|---|
Parrying Sword #9 : [기획][프로그래밍] 폭탄 구현 중 (0) | 2023.02.17 |
Parrying Sword #7 : [기획][프로그래밍] 벽 잡기 (등반) 구현 (0) | 2023.02.17 |
Parrying Sword #6 : [기획] 플레이어 액션 구현 (0) | 2022.11.21 |
Parrying Sword #5 : [프로그래밍] 맵의 가장자리를 벽으로 둘러 싸기 (0) | 2022.11.13 |