Делаю игру по англоязычному туториалу, все "скопировал" правильно, но что-то не работает. https://pixelnest.io/tutorials/2d-game-unity/animations-2/ это тот самый туториал. Ну вот всё скопировал как надо, но не работает. Единственное отличие от туториала что в окне Аниматора у меня ещё есть "прямоугольники" Entry и Exit вообще хз для чего они.
И ещё, в коде, который я скопировал с туториала, у меня показало ошибки в строках 45, 118 и 139. Ниже это код из туториала.
using UnityEngine;
public class BossScript : MonoBehaviour
{
private bool hasSpawn;
// Component references
private MoveScript moveScript;
private WeaponScript[] weapons;
private Animator animator;
private SpriteRenderer[] renderers;
// Boss pattern (not really an AI)
public float minAttackCooldown = 0.5f;
public float maxAttackCooldown = 2f;
private float aiCooldown;
private bool isAttacking;
private Vector2 positionTarget;
void Awake()
{
// Retrieve the weapon only once
weapons = GetComponentsInChildren<WeaponScript>();
// Retrieve scripts to disable when not spawned
moveScript = GetComponent<MoveScript>();
// Get the animator
animator = GetComponent<Animator>();
// Get the renderers in children
renderers = GetComponentsInChildren<SpriteRenderer>();
}
void Start()
{
hasSpawn = false;
// Disable everything
// -- Collider
collider2D.enabled = false; /////////////////45 строка
// -- Moving
moveScript.enabled = false;
// -- Shooting
foreach (WeaponScript weapon in weapons)
{
weapon.enabled = false;
}
// Default behavior
isAttacking = false;
aiCooldown = maxAttackCooldown;
}
void Update()
{
// Check if the enemy has spawned
if (hasSpawn == false)
{
// We check only the first renderer for simplicity.
// But we don't know if it's the body, and eye or the mouth...
if (renderers[0].IsVisibleFrom(Camera.main))
{
Spawn();
}
}
else
{
// AI
//------------------------------------
// Move or attack. permute. Repeat.
aiCooldown -= Time.deltaTime;
if (aiCooldown <= 0f)
{
isAttacking = !isAttacking;
aiCooldown = Random.Range(minAttackCooldown, maxAttackCooldown);
positionTarget = Vector2.zero;
// Set or unset the attack animation
animator.SetBool("Attack", isAttacking);
}
// Attack
//----------
if (isAttacking)
{
// Stop any movement
moveScript.direction = Vector2.zero;
foreach (WeaponScript weapon in weapons)
{
if (weapon != null && weapon.enabled && weapon.CanAttack)
{
weapon.Attack(true);
SoundEffectsHelper.Instance.MakeEnemyShotSound();
}
}
}
// Move
//----------
else
{
// Define a target?
if (positionTarget == Vector2.zero)
{
// Get a point on the screen, convert to world
Vector2 randomPoint = new Vector2(Random.Range(0f, 1f), Random.Range(0f, 1f));
positionTarget = Camera.main.ViewportToWorldPoint(randomPoint);
}
// Are we at the target? If so, find a new one
if (collider2D.OverlapPoint(positionTarget)) ////////////////////118 строка
{
// Reset, will be set at the next frame
positionTarget = Vector2.zero;
}
// Go to the point
Vector3 direction = ((Vector3)positionTarget - this.transform.position);
// Remember to use the move script
moveScript.direction = Vector3.Normalize(direction);
}
}
}
private void Spawn()
{
hasSpawn = true;
// Enable everything
// -- Collider
collider2D.enabled = true; ////////////////////////139 строка
// -- Moving
moveScript.enabled = true;
// -- Shooting
foreach (WeaponScript weapon in weapons)
{
weapon.enabled = true;
}
// Stop the main scrolling
foreach (ScrollingScript scrolling in FindObjectsOfType<ScrollingScript>())
{
if (scrolling.isLinkedToCamera)
{
scrolling.speed = Vector2.zero;
}
}
}
void OnTriggerEnter2D(Collider2D otherCollider2D)
{
// Taking damage? Change animation
ShotScript shot = otherCollider2D.gameObject.GetComponent<ShotScript>();
if (shot != null)
{
if (shot.isEnemyShot == false)
{
// Stop attacks and start moving awya
aiCooldown = Random.Range(minAttackCooldown, maxAttackCooldown);
isAttacking = false;
// Change animation
animator.SetTrigger("Hit");
}
}
}
void OnDrawGizmos()
{
// A little tip: you can display debug information in your scene with Gizmos
if (hasSpawn && isAttacking == false)
{
Gizmos.DrawSphere(positionTarget, 0.25f);
}
}
}
Но немного погуглив, я изменил код вот так. Изменения в строках 45, 118 и 139.
using UnityEngine;
public class BossScript : MonoBehaviour
{
private bool hasSpawn;
// Component references
private MoveScript moveScript;
private WeaponScript[] weapons;
private Animator animator;
private SpriteRenderer[] renderers;
// Boss pattern (not really an AI)
public float minAttackCooldown = 0.5f;
public float maxAttackCooldown = 2f;
private float aiCooldown;
private bool isAttacking;
private Vector2 positionTarget;
void Awake()
{
// Retrieve the weapon only once
weapons = GetComponentsInChildren<WeaponScript>();
// Retrieve scripts to disable when not spawned
moveScript = GetComponent<MoveScript>();
// Get the animator
animator = GetComponent<Animator>();
// Get the renderers in children
renderers = GetComponentsInChildren<SpriteRenderer>();
}
void Start()
{
hasSpawn = false;
// Disable everything
// -- Collider
GetComponent<Collider2D>().enabled = false; //////////////////45 строка
// -- Moving
moveScript.enabled = false;
// -- Shooting
foreach (WeaponScript weapon in weapons)
{
weapon.enabled = false;
}
// Default behavior
isAttacking = false;
aiCooldown = maxAttackCooldown;
}
void Update()
{
// Check if the enemy has spawned
if (hasSpawn == false)
{
// We check only the first renderer for simplicity.
// But we don't know if it's the body, and eye or the mouth...
if (renderers[0].IsVisibleFrom(Camera.main))
{
Spawn();
}
}
else
{
// AI
//------------------------------------
// Move or attack. permute. Repeat.
aiCooldown -= Time.deltaTime;
if (aiCooldown <= 0f)
{
isAttacking = !isAttacking;
aiCooldown = Random.Range(minAttackCooldown, maxAttackCooldown);
positionTarget = Vector2.zero;
// Set or unset the attack animation
animator.SetBool("Attack", isAttacking);
}
// Attack
//----------
if (isAttacking)
{
// Stop any movement
moveScript.direction = Vector2.zero;
foreach (WeaponScript weapon in weapons)
{
if (weapon != null && weapon.enabled && weapon.CanAttack)
{
weapon.Attack(true);
SoundEffectsHelper.Instance.MakeEnemyShotSound();
}
}
}
// Move
//----------
else
{
// Define a target?
if (positionTarget == Vector2.zero)
{
// Get a point on the screen, convert to world
Vector2 randomPoint = new Vector2(Random.Range(0f, 1f), Random.Range(0f, 1f));
positionTarget = Camera.main.ViewportToWorldPoint(randomPoint);
}
// Are we at the target? If so, find a new one
if (GetComponent<Collider2D>().OverlapPoint(positionTarget)) /////////////////////////118 строка
{
// Reset, will be set at the next frame
positionTarget = Vector2.zero;
}
// Go to the point
Vector3 direction = ((Vector3)positionTarget - this.transform.position);
// Remember to use the move script
moveScript.direction = Vector3.Normalize(direction);
}
}
}
private void Spawn()
{
hasSpawn = true;
// Enable everything
// -- Collider
GetComponent<Collider2D>().enabled = true; /////////////139 строка
// -- Moving
moveScript.enabled = true;
// -- Shooting
foreach (WeaponScript weapon in weapons)
{
weapon.enabled = true;
}
// Stop the main scrolling
foreach (ScrollingScript scrolling in FindObjectsOfType<ScrollingScript>())
{
if (scrolling.isLinkedToCamera)
{
scrolling.speed = Vector2.zero;
}
}
}
void OnTriggerEnter2D(Collider2D otherCollider2D)
{
// Taking damage? Change animation
ShotScript shot = otherCollider2D.gameObject.GetComponent<ShotScript>();
if (shot != null)
{
if (shot.isEnemyShot == false)
{
// Stop attacks and start moving awya
aiCooldown = Random.Range(minAttackCooldown, maxAttackCooldown);
isAttacking = false;
// Change animation
animator.SetTrigger("Hit");
}
}
}
void OnDrawGizmos()
{
// A little tip: you can display debug information in your scene with Gizmos
if (hasSpawn && isAttacking == false)
{
Gizmos.DrawSphere(positionTarget, 0.25f);
}
}
}
Помогите, пожалуйста, буду очень сильно благодарен
Ошибки вам выдало т.к. collider2d
в старых версиях было свойством, которое делало то, что вы написали в "исправленном" варианте.
Более оптимально будет сделать так, же как в методе Awake()
- создайте поле Collider2D _collider2d
и в этом методе назначьте в него результат GetComponent<Collider2D>()
. Т.е. "закешируйте" результат поиска компонента, как это сделано, например, с Animator
Это то, что касается вашего кода.
Что касается "прямоугольников" Entry
и Exit
- первый это точка из которой начинается анимирование. Т.е. базовое состояние из которого начинается движение логики анимации - в вашем случае это переход в анимацию "Idle". Состояние Exit
- это состояние, в которое можно сделать "переход" из любого другого и тогда перейдя в него анимация снова начнётся из состояния Entry
Это то, что касается состояния аниматора.
Всё остальное у вас, скорее всего, правильно. Поэтому уточняйте, что именно значит "не работает". Судя по тому, что я вижу, как минимум анимация Idle должна воспроизводиться.
Если у вас не работают переходы из анимации Idle, то вы либо забыли настроить в аниматоре переменные "Hit" и "Attack", либо не настроили их использование в самих переходах
переходы из анимации AnyState->Hit забыли добавит(Hit) Conditions >Add to list> Hit
Решение вопроса оказалось настолько легким, что я даже не думал что одна галочка может "сломать" анимацию. Нужно было снять галочку из префаба Босса в Инспекторе в окне Аниматор с Apply root motion
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Использую WPF, MVVM паттернНа ряду с использованием метода Webclient
Например есть поле и 2 кнопки, одна добавляет, каждый раз, после нажатия в поле число, а другая кнопка- убирает
Описание эмулятора здесьНо это какая-то волшебная страница
Подскажите как правильно сгенерировать приватный и закрытый ключ именно для RSA-2048