Skip to content

Sword-Fighter-Double-Click/Photon-Server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Sword Fighter

2022 2학기 대소고 교내 18팀 TeamInterlink 해커톤 작품 리메이크 (웹툰 '더블클릭' IP를 활용한 2D 대전 격투 게임)


게임 시연

게임 시연 영상


시스템 구조

인 게임 이미지
- 타이틀
image

- 플레이
image
image
image
image
image
image
image
image

image


주요 코드

Fighter
    ● 캐릭터의 모체가 되는 추상화 클래스입니다.
    ● 이동, 공격, 피격, 가드, 그라운드 체크, 애니메이션 변경 등의 기능이 있습니다.
자세한 코드
using System;
using UnityEngine;
using UnityEngine.UI;
using MyConstants;

public abstract class Fighter : MonoBehaviour
{
  [Header("Caching")]
  [SerializeField] private Image HPBar;
  [SerializeField] private Image FPBar;
  [SerializeField] private GameObject lethalMoveScreen;
  [SerializeField] private AnimationClip lethalMove;
  [SerializeField] private BoxCollider2D[] motionColliders = new BoxCollider2D[4];

  // 기존 에셋에 있던 먼지 효과 프리팹 오브젝트
  [SerializeField] private GameObject m_RunStopDust;
  [SerializeField] private GameObject m_JumpDust;
  [SerializeField] private GameObject m_LandingDust;

  [Header("Action")]
  // Attack, None, Guard와 같이 플레이어의 상태를 지정하는 변수
  public FighterAction fighterAction;

  [Header("Value")]
  // 0번은 왼쪽 플레이어, 1번은 오른쪽 플레이어로 지정됨
  [Range(0, 1)] public int fighterNumber = 0;
  // 키 입력 여부를 정하는 변수
  public bool canInput = true;
  // 상대 캐릭터 클래스 저장 변수
  public Fighter enemyFighter;

  // 최대 속도, 점프 높이, 카운터 데미지 배율, 공격 데미지, 가드 시 데미지 감소율 등등 여러 스테이터스 값을 저장하는 변수들
  [Header("Stats")]
  public float HP = 100;
  public float FP = 0;
  [SerializeField] protected float maxSpeed = 4.5f;
  [SerializeField] protected float jumpForce = 7.5f;
  [SerializeField] protected float counterDamageRate = 1.2f;
  [SerializeField] protected float attackDamage = 6f;
  [SerializeField] protected float chargedAttackDamage = 12;
  [SerializeField] protected float jumpAttackDamage = 15;
  [SerializeField] protected float lethalMoveDamage = 35;
  [SerializeField] protected float attackAbsorptionRate = 0.95f;
  [SerializeField] protected float chargedAttackAbsorptionRate = 0.75f;
  [SerializeField] protected float jumpAttackAbsorptionRate = 0.7f;
  [SerializeField] protected float lethalMoveAbsorptionRate = 0.5f;
  [SerializeField] protected float chargedAttackFP = 3;
  [SerializeField] protected float jumpAttackCoolFP = 5;
  [SerializeField] protected float lethalMoveFP = 75;
  [SerializeField] protected float chargedAttackCoolDownTime = 1.2f;
  [SerializeField] protected float jumpAttackCoolDownTime = 1.5f;
  [SerializeField] protected float hitKnockBackPower = 10;
  [SerializeField] protected float guardKnockBackPower = 5;

  protected Animator animator;
  protected Rigidbody2D rigidbody2d;
  protected SpriteRenderer spriteRenderer;
  private Sensor groundSensor;
  private FighterAudio fighterAudio;

  // 그라운드 체크 변수
  protected bool isGround = false;
  // 이동 방향 변수 -1은 좌, 1은 우
  private int facingDirection = 0;

  // 강공격과 점프공격의 쿨타임을 계산하는 변수
  private float countChargedAttack;
  private float countJumpAttack;

  // 키 입력할 수 없는 시간을 정하는 변수
  protected float cantInputTime = 0;

  // 적이 궁극기에 맞았는지를 저장하는 변수
  protected bool hitLethalMove;

  private GameObject lethalMoveScreenClone;

  private void Awake()
  {
  	animator = GetComponent<Animator>();
  	rigidbody2d = GetComponent<Rigidbody2D>();
  	spriteRenderer = GetComponent<SpriteRenderer>();
  	fighterAudio = transform.Find("Audio").GetComponent<FighterAudio>();
  	groundSensor = transform.Find("GroundSensor").GetComponent<Sensor>();
  }

  // 자식 클래스에서도 쓸 수 있도록 추상화
  protected virtual void Start()
  {
  	SettingUI();
  }

  // 자식 클래스에서도 쓸 수 있도록 추상화
  protected virtual void Update()
  {
  	HandleCantInputTime(Time.deltaTime);

  	Death();

  	OnGround();

  	SetAirspeed();

  	CountCoolTime(Time.deltaTime);

  	HandleUI();

  	Jump();

  	Movement();

  	Guard();

  	Attack();

  	ChargedAttack();

  	JumpAttack();

  	LethalMove();

  	// 켜져 있는 Collider의 크기를 이용하여 공격판정을 생성하고 적이 맞았는지 확인하는 반복문
  	foreach (BoxCollider2D collider in motionColliders)
  	{
  		if (!collider.enabled) continue;

  		Fighter enemyFighter = SearchFighterWithinRange(collider);

  		if (enemyFighter == null) continue;

  		// 적이 맞았다면

  		if (fighterAction == FighterAction.LethalMove)
  		{
  			hitLethalMove = true;
  		}

  		collider.enabled = false;

  		// 데미지를 가함
  		GiveDamage(enemyFighter);
  	}
  }

  #region HandleValue

  // 현재 fighterNumber에 따라 UI 캐싱
  private void SettingUI()
  {
  	if (fighterNumber == 0)
  	{
  		GameObject player1UI = GameObject.FindGameObjectWithTag("Player1UI");
  		HPBar = player1UI.transform.Find("HPBar").GetComponent<Image>();
  		FPBar = player1UI.transform.Find("FPBar").GetComponent<Image>();
  		rigidbody2d.sharedMaterial = GameObject.Find("Fighter1PhysicsMaterial").GetComponent<Rigidbody2D>().sharedMaterial;
  	}
  	else if (fighterNumber == 1)
  	{
  		GameObject player2UI = GameObject.FindGameObjectWithTag("Player2UI");
  		HPBar = player2UI.transform.Find("HPBar").GetComponent<Image>();
  		FPBar = player2UI.transform.Find("FPBar").GetComponent<Image>();
  		rigidbody2d.sharedMaterial = GameObject.Find("Fighter2PhysicsMaterial").GetComponent<Rigidbody2D>().sharedMaterial;
  	}
  }

  // fighterNumber에 따라 태그 설정 및 스테이터스, 애니메이션, 공격판정 초기화
  public void ResetState()
  {
  	// 태그 설정
  	if (fighterNumber == 0)
  	{
  		tag = "Player1";
  		//spriteRenderer.flipX = false;
  	}
  	else if (fighterNumber == 1)
  	{
  		tag = "Player2";
  		//spriteRenderer.flipX = true;
  	}

  	// 애니메이션 및 스테이터스 초기화
  	animator.SetInteger("FacingDirection", 0);
  	HP = 100;
  	FP = 0;
  	SetAction(0);
  	animator.SetTrigger("RoundStart");

  	// 공격판정 초기화
  	foreach (BoxCollider2D boxCollider2D in motionColliders)
  	{
  		boxCollider2D.enabled = false;
  	}
  }

  // 그라운드 체크
  private void OnGround()
  {
  	if (fighterAction == FighterAction.JumpAttack) return;

  	if (!isGround && groundSensor.State())
  	{
  		// 마찰력 10으로 설정
  		rigidbody2d.sharedMaterial.friction = 10;
  		isGround = true;
  		fighterAction = FighterAction.None;
  		animator.SetBool("Grounded", isGround);
  		animator.SetBool("Jump", false);
  	}
  }

  // AirSpeed 값 할당
  private void SetAirspeed()
  {
  	// airSpeedY가 0 이하가 되면 낙하 애니메이션 출력
  	animator.SetFloat("AirSpeedY", rigidbody2d.velocity.y);
  }

  // 강공격과 점프공격 쿨타임 계산
  private void CountCoolTime(float deltaTime)
  {
  	if (countChargedAttack > 0)
  	{
  		countChargedAttack -= deltaTime;
  	}
  	if (countJumpAttack > 0)
  	{
  		countJumpAttack -= deltaTime;
  	}
  }

  // 플레이어의 상태를 정수로 설정
  void SetAction(int value)
  {
  	if (value < (int)FighterAction.None && value > (int)FighterAction.LethalMove) return;

  	fighterAction = (FighterAction)value;
  }

  // 입력 불가 시간 계산
  private void HandleCantInputTime(float deltaTime)
  {
  	// 입력 불가 시간이 남아있으면 키 입력 불가
  	if (cantInputTime > 0)
  	{
  		cantInputTime -= deltaTime;

  		canInput = false;
  	}
  	else
  	{
  		canInput = true;
  	}
  }

  // 입력 불가 시간 설정
  void SetCantInputTime(float value)
  {
  	cantInputTime = value;
  }

  // 입력이 가능하게 설정
  public void OnInput()
  {
  	cantInputTime = 0;
  }

  // 입력이 불가능하게 설정
  public void OffInput()
  {
  	cantInputTime = float.MaxValue;
  }
  #endregion

  #region HandleHitBox
  // 인자 내 정수값에 해당하는 공격 판정 collider 활성화
  void OnHitBox(int number)
  {
  	motionColliders[number].enabled = true;
  }

  // 인자 내 정수값에 해당하는 공격 판정 collider 비활성화
  void OffHitBox(int number)
  {
  	motionColliders[number].enabled = false;
  }
  #endregion

  #region HandleUI
  // HP 및 스킬 게이지 UI에 표현
  private void HandleUI()
  {
  	HPBar.fillAmount = HP * 0.01f;
  	FPBar.fillAmount = FP * 0.01f;
  }
  #endregion

  #region Action
  // 이동 및 플레이어 방향 조정
  private void Movement()
  {
  	if (!canInput) return;
  	// IDLE과 점프일 때만 이동 함수 진입
  	if (!(fighterAction == FighterAction.None || fighterAction == FighterAction.Jump)) return;

  	// 키 입력 여부 저장
  	bool inputRight = Input.GetKey(KeySetting.keys[fighterNumber, 3]);
  	bool inputLeft = Input.GetKey(KeySetting.keys[fighterNumber, 1]);

  	// 방향 설정 및 저장
  	int direction = (inputLeft ? -1 : 0) + (inputRight ? 1 : 0);
  	facingDirection = direction;

  	// 이동 애니메이션 출력
  	animator.SetInteger("FacingDirection", facingDirection);

  	// 이동 방향에 따라 이미지 방향 설정
  	transform.eulerAngles = (enemyFighter.transform.position.x > transform.position.x ? Vector3.zero : Vector3.up * 180);
  	
  	// 이동
  	rigidbody2d.velocity = new Vector2(facingDirection * maxSpeed, rigidbody2d.velocity.y);
  }

  // 점프
  private void Jump()
  {
  	if (!canInput) return;
  	if (!isGround) return;
  	// IDLE 상태에만 함수 진입
  	if (fighterAction != FighterAction.None) return;

  	if (Input.GetKeyDown(KeySetting.keys[fighterNumber, 0]))
  	{
  		// 벽끼임 방지를 위해 마찰력 0으로 설정
  		rigidbody2d.sharedMaterial.friction = 0;
  		isGround = false;
  		fighterAction = FighterAction.Jump;
  		animator.SetBool("Grounded", isGround);
  		// 애니메이션 출력
  		animator.SetBool("Jump", true);
  		// 점프
  		rigidbody2d.velocity = new Vector2(rigidbody2d.velocity.x, jumpForce);
  		groundSensor.Disable(0.2f);
  	}
  }
  
  // 가드
  private void Guard()
  {
  	if (!canInput) return;
  	if (!isGround) return;
  	// IDLE 및 가드 상태에만 함수 진입
  	if (!(fighterAction == FighterAction.None || fighterAction == FighterAction.Guard)) return;

  	// 키를 누르고 있으면 가드 활성화, 떼면 가드 비활성화
  	if (Input.GetKey(KeySetting.keys[fighterNumber, 2]))
  	{
  		fighterAction = FighterAction.Guard;

  		animator.CrossFade("Guard", 0f);
  	}
  	else if (Input.GetKeyUp(KeySetting.keys[fighterNumber, 2]))
  	{
  		fighterAction = FighterAction.None;
  		animator.SetTrigger("UnGuard");
  	}
  }

  // 일반공격
  private void Attack()
  {
  	if (!canInput) return;
  	if (!isGround) return;
  	// IDLE 상태에만 함수 진입
  	if (fighterAction != FighterAction.None) return;

  	if (Input.GetKeyDown(KeySetting.keys[fighterNumber, 4]))
  	{
  		fighterAction = FighterAction.Attack;

  		animator.CrossFade("Attack", 0);
  	}
  }

  // 강공격
  private void ChargedAttack()
  {
  	if (!canInput) return;
  	if (!isGround) return;
  	// IDLE 상태에만 함수 진입
  	if (fighterAction != FighterAction.None) return;
  	if (countChargedAttack > 0) return;

  	if (Input.GetKeyDown(KeySetting.keys[fighterNumber, 5]))
  	{
  		fighterAction = FighterAction.ChargedAttack;

  		animator.CrossFade("ChargedAttack", 0);
  		
  		// 강공격 이후 쿨타임 설정
  		countChargedAttack = chargedAttackCoolDownTime;
  	}
  }

  // 점프공격
  private void JumpAttack()
  {
  	if (!canInput) return;
  	if (isGround) return;
  	// 점프 상태에서만 함수 진입
  	if (fighterAction != FighterAction.Jump) return;
  	if (countJumpAttack > 0) return;

  	if (Input.GetKeyDown(KeySetting.keys[fighterNumber, 4]))
  	{
  		fighterAction = FighterAction.JumpAttack;

  		animator.CrossFade("JumpAttack", 0);
  		
  		// 점프공격 이후 쿨타임 설정
  		countJumpAttack = jumpAttackCoolDownTime;
  	}
  }

  // 궁극기
  private void LethalMove()
  {
  	if (!canInput) return;
  	if (!isGround) return;
  	// IDLE 상태에서만 함수 진입
  	if (fighterAction != FighterAction.None) return;

  	if (Input.GetKeyDown(KeySetting.keys[fighterNumber, 6]))
  	{
  		fighterAction = FighterAction.LethalMove;

  		animator.CrossFade("LethalMove", 0);
  	}
  }

  // 피격
  private void Hit(bool isGuard, float enemyRotationY, float lethalMoveCantInputTime)
  {
  	Vector2 knockBackPath = enemyRotationY == 0 ? Vector2.right : Vector2.left;

  	// 가드 시 입력 불가와 넉백이 시간이 가드를 안했을 때보다 줄어듭니다.
  	// 궁극기는 시전시간이 끝날 때까지 고정적으로 입력을 못하게 만듭니다.
  	if (isGuard)
  	{
  		// 입력 불가 시간 설정
  		cantInputTime = lethalMoveCantInputTime > 0 ? lethalMoveCantInputTime : 0.1f;
  		// 넉백
  		rigidbody2d.AddForce(knockBackPath * guardKnockBackPower, ForceMode2D.Impulse);
  	}
  	else
  	{
  		// 현재 공격 중단
  		for (int count = 0; count < motionColliders.Length; count++)
  		{
  			OffHitBox(count);
  		}
  		SetAction(0);
  		// 입력 불가 시간 설정
  		cantInputTime = lethalMoveCantInputTime > 0 ? lethalMoveCantInputTime : 0.3f;
  		// 넉백
  		rigidbody2d.AddForce(knockBackPath * hitKnockBackPower, ForceMode2D.Impulse);
  	}
  }

  // 사망
  private void Death()
  {
  	// HP가 0이 되면 애니메이션을 출력
  	if (HP <= 0)
  	{
  		if (!animator.GetCurrentAnimatorStateInfo(0).IsName("Death"))
  		{
  			animator.CrossFade("Death", 0);
  		}
  	}
  }
  #endregion

  #region Action Effect
  // 에셋 먼지 효과 함수
  private void SpawnDustEffect(GameObject dust, float dustXOffset = 0)
  {
  	if (dust != null)
  	{
  		Vector3 dustSpawnPosition = transform.position + new Vector3(dustXOffset * facingDirection, 0f, 0f);
  		GameObject newDust = Instantiate(dust, dustSpawnPosition, Quaternion.identity);
  		newDust.transform.localScale = newDust.transform.localScale.x * new Vector3(facingDirection, 1, 1);
  	}
  }

  void AE_runStop()
  {
  	fighterAudio.PlaySound("RunStop");
  	float dustXOffset = 0.6f;
  	SpawnDustEffect(m_RunStopDust, dustXOffset);
  }

  void AE_footstep()
  {
  	fighterAudio.PlaySound("Footstep");
  }

  void AE_Jump()
  {
  	fighterAudio.PlaySound("Jump");
  	SpawnDustEffect(m_JumpDust);
  }

  void AE_Landing()
  {
  	fighterAudio.PlaySound("Landing");
  	SpawnDustEffect(m_LandingDust);
  }

  // 궁극기 배경화면 활성화
  protected void OnLethalMoveScreen()
  {
  	lethalMoveScreenClone = Instantiate(lethalMoveScreen);

  	lethalMoveScreenClone.SetActive(true);
  }

  // 궁극기 배경화면 비활성화
  protected void OffLethalMoveScreen()
  {
  	Destroy(lethalMoveScreenClone);
  }
  #endregion

  #region HandleHitDetection
  // 공격판정 생성 및 공격판정에 인식된 적 플레이어 데이터 반환
  private Fighter SearchFighterWithinRange(Collider2D searchRange)
  {
  	// BoxCast로 공격판정 생성
  	RaycastHit2D[] raycastHits = Physics2D.BoxCastAll(searchRange.bounds.center, searchRange.bounds.size, 0f, transform.rotation.y == 0 ? Vector2.right : Vector2.left, 0.01f, LayerMask.GetMask("Player"));

  	foreach (RaycastHit2D raycastHit in raycastHits)
  	{
  		// 태그가 같으면, 즉 나 자신이면 다음 코드를 실행하지 않음
  		if (CompareTag(raycastHit.collider.tag)) continue;

  		// 공격판정에 들어온 적 플레이어 데이터 반환
  		return raycastHit.collider.GetComponent<Fighter>();
  	}

  	// 찾지 못하면 null 반환
  	return null;
  }

  // 적 플레이어에게 데미지를 가하는 함수
  private void GiveDamage(Fighter enemyFighter)
  {
  	bool isGuard = false;

  	// 공격 별 데미지 배열에 저장
  	float[] damages = { attackDamage, chargedAttackDamage, jumpAttackDamage, lethalMoveDamage };

  	// 공격 별 가드 시 데미지 감소율 배열에 저장
  	float[] absorptionRates = { attackAbsorptionRate, chargedAttackAbsorptionRate, jumpAttackAbsorptionRate, lethalMoveAbsorptionRate };

  	float damage = 0;

  	// 피격 당해 입력 불가 시간이 있다면 아래 코드를 실행하지 않음
  	if (cantInputTime > 0) return;

  	// 현재 공격의 데미지 저장
  	damage += damages[(int)fighterAction - 4];

  	// 가드 시 데미지 감소
  	if (enemyFighter.fighterAction == FighterAction.Guard)
  	{
  		damage = damages[(int)fighterAction - 4] - damages[(int)fighterAction - 4] * absorptionRates[(int)fighterAction - 4];

  		isGuard = true;

  		cantInputTime = 0.5f;

  		SetAction(0);
  	}
  	// 적 플레이어가 공격 애니메이션일 시, 카운데 배율을 곱하여 데미지 증가
  	else if (!(enemyFighter.fighterAction == FighterAction.None || enemyFighter.fighterAction == FighterAction.Hit))
  	{
  		damage *= counterDamageRate;
  	}

  	// 현재 공격이 궁극기일 시, 시전시간+0.5초의 입력 불가 시간을 적에게 적용한다.
  	float lethalMoveCantInputTime = 0;
  	if (fighterAction == FighterAction.LethalMove)
  	{
  		lethalMoveCantInputTime = lethalMove.length + 0.5f;
  	}

  	enemyFighter.HP -= damage;
  	enemyFighter.Hit(isGuard, transform.rotation.y, lethalMoveCantInputTime);
  }
  #endregion
}

Speero
    ● Fighter 클래스를 상속하여 만든 캐릭터 스피로의 클래스입니다.
    ● 점프공격 위치 이동, 궁극기 사용 시의 애니메이션 오브젝트 생성 및 삭제 등의 기능이 있습니다.

자세한 코드
using UnityEngine;

// 캐릭터 추상화 클래스 상속으로 스피로 설계
public class Speero : Fighter
{
  [Header("Speero Object")]
  [SerializeField] GameObject lethalMoveAnimation;

  // 점프 공격 시 얼마나 이동하는지를 정하는 변수
  [Header("Speero Value")]
  [SerializeField] private float jumpAttackRushPower = 30;
  [SerializeField] private float jumpAttackDownPower = 100;

  private CapsuleCollider2D playerHitBox;

  // 생성된 궁극기 애니메이션 오브젝트의 데이터를 저장하는 변수
  private GameObject lethalMoveAnimationClone = null;

  private bool usingLethalMoveAnimation;

  protected override void Start()
  {
  	base.Start();

  	playerHitBox = GetComponent<CapsuleCollider2D>();
  }

  protected override void Update()
  {
  	base.Update();

  	// 궁극기를 사용
  	if (usingLethalMoveAnimation)
  	{
  		// 애니메이션이 출력되고 삭제되었다면
  		if (lethalMoveAnimationClone == null)
  		{
  			lethalMoveAnimationClone = null;
  			
  			usingLethalMoveAnimation = false;
  			
  			SetPlayerVisible(1);
  			
  			OffLethalMoveScreen();
  			
  			// IDLE 상태로 초기화
  			fighterAction = MyConstants.FighterAction.None;
  		}
  	}
  }

  // 캐릭터 히트박스 활성화(1), 비활성화(0)
  void SetPlayerHitBox(int value)
  {
  	if (value == 0)
  	{
  		playerHitBox.enabled = false;
  		cantInputTime = float.MaxValue;
  	}
  	else if (value == 1)
  	{
  		playerHitBox.enabled = true;
  		cantInputTime = 0;
  	}
  }

  // 캐릭터 이미지 활성화(1), 비활성화(0)
  void SetPlayerVisible(int value)
  {
  	if (value == 0)
  	{
  		spriteRenderer.enabled = false;

  	}
  	else if (value == 1)
  	{
  		spriteRenderer.enabled = true;
  	}
  }

  // 점프공격 시 위치 이동
  void MoveDuringJumpAttack()
  {
  	rigidbody2d.AddForce(Vector2.down * jumpAttackDownPower + (transform.rotation.y == 0 ? 1 : -1) * jumpAttackRushPower * Vector2.right, ForceMode2D.Impulse);
  }

  // 카운터 데미지 배율 설정
  void SetCounterDamageRate(float value)
  {
  	counterDamageRate = value;
  }

  // 적의 궁극기 피격 여부에 따라 애니메이션 출력
  void HandleLethalMoveAnimation()
  {
  	// 맞았다면
  	if (hitLethalMove)
  	{
  		usingLethalMoveAnimation = true;

  		// 애니메이션 오브젝트 생성
  		lethalMoveAnimationClone = Instantiate(lethalMoveAnimation);
  		
  		// 캐릭터 이미지 비활성화
  		SetPlayerVisible(0);
  		
  		OnLethalMoveScreen();

  		hitLethalMove = false;
  	}
  	// 맞지 않았다면
  	else
  	{
  		// IDLE 상태로 초기화
  		fighterAction = MyConstants.FighterAction.None;
  	}
  }
}

ArkSha
    ● Fighter 클래스를 상속하여 만든 캐릭터 아크샤의 클래스입니다.
    ● 점프공격 이동, 점프공격 키를 누른 만큼 데미지 증가, 궁극기 배경화면 연출 등의 기능이 있습니다.

자세한 코드
using UnityEngine;

// 캐릭터 추상화 클래스 상속으로 아크샤 설계
public class ArkSha : Fighter
{
  [Header("Arksha Value")]
  // 점프공격 시 얼마나 이동하는지를 정하는 변수
  [SerializeField] private float jumpAttackUpPower = 5;
  [SerializeField] private float jumpAttackDownPower = 100;
  // 점프공격 시 최소한 공중에 떠있는 시간을 정하는 변수
  [SerializeField] private float stayJumpAttack = 0.85f;

  private float originalJumpAttackDamage;

  /// 점프공격 대기 중인지 확인하는 변수
  private bool isStayJumpAttack;

  // 점프공격 시 공중에 떠있는 시간을 저장하는 변수
  private float countStayJumpAttack;

  private bool isLethalMove;

  protected override void Start()
  {
  	base.Start();

  	originalJumpAttackDamage = jumpAttackDamage;
  }

  protected override void Update()
  {
  	base.Update();

  	if (!isStayJumpAttack) return;

  	countStayJumpAttack -= Time.deltaTime;

  	if (countStayJumpAttack > 0)
  	{
  		if (Input.GetKeyUp(MyConstants.KeySetting.keys[fighterNumber, 4]))
  		{
  			TryJumpAttack();
  		}
  	}
  	else
  	{
  		countStayJumpAttack = 0;
  		TryJumpAttack();
  	}
  }

  // 점프 공격 대기. 공중에 떠있는 시간 카운트
  void StayJumpAttack()
  {
  	isStayJumpAttack = true;
  	countStayJumpAttack = stayJumpAttack;
  }

  // 공중에 떠있는 시간에 비례하여 점프공격 데미지 설정
  void SetJumpAttackDamage()
  {
  	jumpAttackDamage *= (stayJumpAttack - countStayJumpAttack) / stayJumpAttack;
  }

  // 점프공격 데미지 초기화
  void InitializeJumpAttackDamage()
  {
  	jumpAttackDamage = originalJumpAttackDamage;
  }

  // 점프공격 실행
  private void TryJumpAttack()
  {
  	isStayJumpAttack = false;

  	animator.CrossFade("TryJumpAttack", 0);

  	// 아래로 이동
  	MoveDuringJumpAttack(-1);
  }

  // 위로 이동(1), 아래로 이동(0)
  void MoveDuringJumpAttack(int path)
  {
  	rigidbody2d.AddForce(path > 0 ? Vector2.up * jumpAttackUpPower : Vector2.down * jumpAttackDownPower, ForceMode2D.Impulse);
  }

  // 궁극기 효과 출력
  void HandleLethalMoveAnimation()
  {
  // 맞았다면
      if (hitLethalMove)
      {
  	// 추가타 발생
  	animator.CrossFade("HitLethalMove", 0);

  	// 궁극기 배경화면 활성화
          OnLethalMoveScreen();

          hitLethalMove = false;
      }
      else
      {
  	// 궁극기 종료 애니메이션 출력
  	animator.CrossFade("MissLethalMove", 0);
      }
  }
}

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages