Skip to content

Instantly share code, notes, and snippets.

@LordNed
Last active August 29, 2015 14:21
Show Gist options
  • Save LordNed/30e3322f4c9a61364e98 to your computer and use it in GitHub Desktop.
Save LordNed/30e3322f4c9a61364e98 to your computer and use it in GitHub Desktop.
using UnityEngine;
using System.Collections;
using DG.Tweening;
public class ArrowProjectile : AmmoPickup, IStatusAfflictionReciever
{
[SerializeField] private ParticleSystem m_fireTrailParticle;
[SerializeField] private int m_damageAmount = 2;
[SerializeField] private float m_antiGravDuration = 0.15f;
[SerializeField] private float m_gravityScale = 0.2f;
[SerializeField] private float m_dragAmount = 1.5f;
private Rigidbody2D m_rigidBody2D;
private Transform m_transformCache;
private GameObject m_arrowOwner;
private TriggeredStatusAffliction m_statusAffliction;
private Vector2 m_velocity;
private float m_currentGravityScale;
private float m_currentDrag;
private bool m_isAtRest;
private void Awake()
{
m_fireTrailParticle.Play();
m_fireTrailParticle.enableEmission = false;
m_fireTrailParticle.renderer.sortingLayerName = "Foreground";
m_rigidBody2D = GetComponent<Rigidbody2D>();
m_transformCache = transform;
m_statusAffliction = GetComponent<TriggeredStatusAffliction>();
m_statusAffliction.Affliction = StatusAfflictionType.None;
// Ramp on the gravity after a short delay.
DOTween.To(() => m_currentGravityScale, x => m_currentGravityScale = x, m_gravityScale, 0.1f).SetDelay(m_antiGravDuration).SetEase(Ease.InQuart);
PickupType = Type.None;
AmmoType = WeaponAmmoType.Arrow;
Amount = 1;
}
public void Setup(GameObject owner, Vector2 velocity)
{
m_arrowOwner = owner;
m_velocity = velocity;
}
private void Update()
{
if (m_isAtRest)
return;
// Apply gravity
m_velocity += Physics2D.gravity * m_currentGravityScale * Time.deltaTime;
// Apply drag - to horizontal and vertical y components.
// This should keep drag from slowing down gravity falls.
m_velocity.x -= m_velocity.x * m_currentDrag * Time.deltaTime;
if (m_velocity.y > 0)
{
m_velocity.y -= m_velocity.y * m_currentDrag * Time.deltaTime;
// Also always apply gravity to vertical y components.
m_velocity.y += Physics2D.gravity.y * m_gravityScale * Time.deltaTime;
}
// Fire a ray in the directon of our velocity to handle collisions ourselves since Unity fucking sucks at it.
Vector3 dir = m_velocity.normalized;
float dist = m_velocity.magnitude * Time.deltaTime;
Vector2 rayStart = m_transformCache.TransformPoint(0.35f, 0, 0);
RaycastHit2D raycastHit = Physics2D.Raycast(rayStart, dir, dist, LayerMask.GetMask("Platforms", "One Way Platforms"));
if(raycastHit)
{
// Check the impact angle and our current speed.
float dotResult = Vector2.Dot(raycastHit.normal, m_velocity.normalized);
float speed = m_velocity.magnitude;
Debug.Log("Speed: " + m_velocity.magnitude + " Dot: " + dotResult);
// Take reasonably straight on impacts at sufficiently high speeds as "stick into wall".
if(dotResult < -0.9f && speed >= 8f)
{
Debug.Log("Stuck into wall.");
m_isAtRest = true;
PickupType = Type.Ammo;
m_velocity = m_velocity.normalized;
// Step it 1 further forward so it's in the wall somewhat.
m_transformCache.position += new Vector3(m_velocity.x, m_velocity.y, 0) * 0.2f;
return;
}
m_currentDrag += m_dragAmount;
m_velocity = Vector3.Reflect(m_velocity, raycastHit.normal);
m_transformCache.position += new Vector3(m_velocity.x, m_velocity.y) * Time.deltaTime;
if(m_velocity.magnitude < 0.1f)
{
m_isAtRest = true;
PickupType = Type.Ammo;
m_velocity = Vector2.zero;
}
}
m_transformCache.position += dir * dist;
}
private void LateUpdate()
{
// Orient the arrow to face in the direction of the velocity.
transform.rotation = Quaternion.FromToRotation(Vector3.right, m_velocity);
}
private void OnTriggerEnter2D(Collider2D col)
{
if (m_isAtRest)
return;
// See if it's something that takes damage, if so we're going to kill the velocity and its ability to hurt.
IDamageable damageable = (IDamageable)col.gameObject.GetComponent(typeof(IDamageable));
if (damageable != null)
{
AttackerInfo attackInfo = new AttackerInfo(m_arrowOwner, m_statusAffliction.Affliction, KnockbackForceAmount.Low, m_damageAmount);
damageable.OnTakeDamage(attackInfo);
}
}
public void OnEnterStatusAffliction(StatusAfflictionType type, TriggeredStatusAffliction other)
{
switch (type)
{
case StatusAfflictionType.Fire:
OnIgnition();
break;
case StatusAfflictionType.Water:
OnExtinguish();
break;
}
}
public void OnExitStatusAffliction(StatusAfflictionType type, TriggeredStatusAffliction other)
{
}
public void OnIgnition()
{
m_statusAffliction.Affliction = StatusAfflictionType.Fire;
m_fireTrailParticle.enableEmission = true;
}
public void OnExtinguish()
{
m_fireTrailParticle.enableEmission = false;
m_statusAffliction.Affliction = StatusAfflictionType.None;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment