Learning Unity 2D

by re-creating Mega Man

To shoot backwards, there really only seems to be three things I have to do:

  1. Add another action to the player input controls.
  2. Flip the Mega Man game object.
  3. Adjust which direction the bullet is traveling.

I thought I might have to adjust the position of the gun object, but since that’s a child of Mega Man, so long as we flip him, the gun flips as well. Nice. After some searching, I discovered the lovely localScale property on the Transform that I can use. So, after adding a “Direction” key to the player input, I can just flip Mega Man.

However, one minor complexity here: I don’t currently have a script on Mega Man! So far, there’s just a movement script on the “Player” game object (which comprises of both Mega Man and Rush), and one for the “Gun” object (for spawning bullets). Now was a good time to clean up that ugly transform.parent.parent that I was using on the gun to reference the player input on the grandparent player object. So, the plan was:

  1. Add a Player Input component to both Mega Man and the child Gun.
  2. Move the animation-relevant stuff from the Gun’s script to a new script for Mega Man. The Gun’s responsibility now is solely to spawn bullets, not control Mega Man’s animation.
  3. Add a new performed event for the new Direction input which flips Mega Man’s localScale.

And so, our new Mega Man script is born, whose current responsibility is solely Mega Man’s animations:

void Awake()
{
    _animator = transform.GetComponent<Animator>();
    var playerInput = transform.GetComponent<PlayerInput>();
    
    _shootAction = playerInput.actions["Shoot"];
    _flipDirection = playerInput.actions["Direction"];
    
    _shootAction.started += Shoot;
    _shootAction.canceled += Shoot;
    _flipDirection.performed += FlipDirection;
}

private void OnDestroy()
{
    _shootAction.started -= Shoot;
    _shootAction.canceled -= Shoot;
    _flipDirection.performed -= FlipDirection;
}

private void Shoot(InputAction.CallbackContext context)
{
    _animator.SetBool(_shootAnimId, _shootAction.inProgress);
}

private void FlipDirection(InputAction.CallbackContext context)
{
    var scale = transform.localScale;
    transform.localScale = new Vector3(scale.x * -1, scale.y, 1);
}

Cool. Now he flips whenever I press the Direction key! Bullets are all still traveling right though, so I need to make the bullets direction non-static (the Vector2 for the direction was a readonly property), and then set that direction whenever I spawn a new bullet if it deviates from the default (to the right).

So, a direction flipping method on the projectile’s script:

private Vector2 _direction = new Vector2(1, 0);

public void FlipDirection()
{
    _direction.x *= -1;
}

And a modification to the method that spawns the bullets:

private InputAction _flipDirection;
private bool _isReverseDirection;

private void Awake()
{
    var playerInput = transform.GetComponent<PlayerInput>();
    _flipDirection = playerInput.actions["Direction"];
    _flipDirection.performed += FlipDirection;
}

private void OnDestroy()
{
    _flipDirection.performed -= FlipDirection;
}

private void FlipDirection(InputAction.CallbackContext context)
{
    _isReverseDirection = !_isReverseDirection;
}

private void CreateBullet()
{
    var bullet = Instantiate(weapon, transform.position, Quaternion.identity);
    if (_isReverseDirection)
    {
        bullet.FlipDirection();
    }
}

Nice. Every time I flip him, bullets travel in the opposite direction. Now I can script encounters that can spawn enemies on both sides and the player can feasibly attack either side.

Next Up

Now it gets harder. Basic movement and shooting is there… but there’s still nothing to shoot at. It’s time to make some targets. Perhaps they don’t shoot back or move yet, but something to shoot at. I think the steps here are:

  1. Put some objects to shoot at that get destroyed when a bullet hits them.
  2. Add destruction animation to those enemies.
  3. Make enemies shoot at the player.
  4. Detect player getting hit (not tracking damage/death yet).
  5. Add enemy movement.
  6. Add “encounter” scripts to spawn them off screen.

Quite a lot to do, likely not in one session. Ideally, enemy spawns are scripted encounters that I can pick randomly and are easy to script individually. We have a ways to go to get there, though! Start simple.

Posted in

Leave a comment