Skip to content

Instantly share code, notes, and snippets.

@sherjilozair
Created January 28, 2019 09:30
Show Gist options
  • Save sherjilozair/8a4901687c8cef0967452213c904b52f to your computer and use it in GitHub Desktop.
Save sherjilozair/8a4901687c8cef0967452213c904b52f to your computer and use it in GitHub Desktop.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerController : MonoBehaviour
{
public int m_playerID;
public float m_shootCooldown;
// Audio data
public AudioData m_dashSound;
public AudioData m_deflectSound;
public AudioData m_jumpSound;
public AudioData m_landSound;
public AudioData m_shootSound;
public Animator m_animator;
bool was_jump_pressed = false;
bool was_dash_pressed = false;
bool was_shoot_pressed = false;
float jump_speed = 4.3f;
float wall_jump_speed = 3f;
int jump_buffer = 0;
public int jump_buffer_size = 4;
int coyote_buffer = 0;
public int coyote_buffer_size = 6;
public int max_dashes = 1;
int dashes_available = 0;
public float maxspeed = 1;
public float ground_accel = 0.6f;
public float ground_deccel = 0.15f;
public float air_accel = 0.2f;
Vector2 speed;
public Vector2Int position;
Vector2 remainder;
SpriteRenderer spriteRenderer;
public Level level;
public GameObject ballPrefab;
public float ballSpawnSpeed;
int width = 12;
int height = 16;
int dash_effect_time = 0;
int dash_effect_time_max = 12;
float dash_full = 11f;
float dash_target_value = 2f;
float dash_accel_value = 2f;
Vector2 dash_target;
float epsilon = 0.01f;
float lastShootTime = 0f;
void Start()
{
spriteRenderer = gameObject.GetComponent<SpriteRenderer>();
Application.targetFrameRate = 60;
}
float Sign(float x)
{
if (Mathf.Abs(x) < epsilon) return 0f;
if (x > 0) return 1f;
return -1f;
}
bool Intersects(RectInt a, RectInt b)
{
return (b.xMin < a.xMax &&
a.xMin < b.xMax &&
b.yMin < a.yMax &&
a.yMin < b.yMax);
}
bool IsSolid(int dx, int dy)
{
List<RectInt> solids = level.GetAllSolids();
RectInt player = new RectInt(position.x-width/2+dx, position.y-height/2+dy, width, height);
foreach(RectInt solid in solids)
{
if(Intersects(player, solid))
{
return true;
}
}
return false;
}
bool OnPlatform(int dy)
{
List<RectInt> solids = level.GetAllPlatforms();
RectInt player = new RectInt(position.x - width / 2, position.y - height / 2 + dy, width, height);
foreach (RectInt solid in solids)
{
if (Intersects(player, solid))
{
return true;
}
}
return false;
}
float Approach(float value, float target, float amount)
{
if(value > target)
{
return Mathf.Max(value - amount, target);
}
else if(value < target)
{
return Mathf.Min(value + amount, target);
}
return target;
}
void Update()
{
if (Level.Get().m_paused)
return;
bool left_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_leftStick.x < 0f;
bool right_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_leftStick.x > 0f;
int x_input = 0;
if (left_pressed) {
x_input--;
}
if (right_pressed)
{
x_input++;
}
bool up_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_leftStick.y > 0f;
bool down_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_leftStick.y < 0f;
int y_input = 0;
if (up_pressed)
{
y_input++;
}
if (down_pressed)
{
y_input--;
}
Vector2 input_direction = new Vector2(x_input, y_input);
input_direction.Normalize();
bool jump_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_aButtonDown;
bool jump = jump_pressed && !was_jump_pressed;
was_jump_pressed = jump_pressed;
if (jump)
{
jump_buffer = jump_buffer_size;
}
else if(jump_buffer > 0)
{
jump_buffer--;
}
bool dash_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_xButtonDown;
bool dash = dash_pressed && !was_dash_pressed;
was_dash_pressed = dash_pressed;
bool on_ground = IsSolid(0, -1) || (!OnPlatform(0) && OnPlatform(-1));
if (on_ground)
{
coyote_buffer = coyote_buffer_size;
if(dashes_available < max_dashes)
{
dashes_available = max_dashes;
}
}
else if(coyote_buffer > 0)
{
coyote_buffer--;
}
// Dashing
Vector2 dash_accel;
dash_accel.x = dash_accel_value;
dash_accel.y = dash_accel_value;
if (dash_effect_time > 0)
{
dash_effect_time--;
speed.x = Approach(speed.x, dash_target.x, dash_accel.x);
speed.y = Approach(speed.y, dash_target.y, dash_accel.y);
}
else
{
// Moving
float accel = ground_accel;
if (!on_ground)
{
accel = air_accel;
}
if (Mathf.Abs(speed.x) > maxspeed)
{
speed.x = Approach(speed.x, Sign(speed.x) * maxspeed, ground_deccel);
}
else if (!InputSystem.Get().m_playerControllerStates[m_playerID].m_leftBumper && !InputSystem.Get().m_playerControllerStates[m_playerID].m_rightBumper)
{
speed.x = Approach(speed.x, x_input * maxspeed, accel);
}
else
speed.x = 0;
// gravity
float maxfall = -3f;
float gravity = 0.21f;
if (Mathf.Abs(speed.y) <= 0.15f)
{
gravity *= 0.5f;
}
// wall slide
if (x_input != 0 && IsSolid(x_input, 0))
{
maxfall = -2f;
}
if (!on_ground)
{
speed.y = Approach(speed.y, maxfall, gravity);
}
// jump
if (jump_buffer > 0)
{
if (coyote_buffer > 0)
{
jump_buffer = 0;
coyote_buffer = 0;
speed.y = jump_speed;
AudioEngine.Play(m_jumpSound);
m_animator.SetTrigger("jump");
}
else
{
int wall_dir = 0;
if (IsSolid(-3, 0))
{
wall_dir = -1;
}
if (IsSolid(3, 0))
{
wall_dir = 1;
}
if (wall_dir != 0)
{
jump_buffer = 0;
speed.y = jump_speed;
speed.x = -wall_dir * (wall_jump_speed);
}
}
}
// dash
if (dashes_available > 0 && dash)
{
dashes_available--;
dash_effect_time = dash_effect_time_max;
Vector2 dash_direction = input_direction;
if (dash_direction.magnitude < epsilon)
{
dash_direction.x = spriteRenderer.flipX ? -1.0f : 1.0f;
}
speed = dash_direction * dash_full;
dash_target.x = Sign(speed.x);
dash_target.y = Sign(speed.y);
dash_target.Normalize();
dash_target *= dash_target_value;
AudioEngine.Play(m_dashSound);
m_animator.SetTrigger("jump");
}
}
// shoot
bool shoot_pressed = InputSystem.Get().m_playerControllerStates[m_playerID].m_bButtonDown;
bool shoot = shoot_pressed && !was_shoot_pressed;
was_shoot_pressed = shoot_pressed;
if (shoot && Time.time > lastShootTime + m_shootCooldown)
{
lastShootTime = Time.time;
Vector2 shoot_direction = InputSystem.Get().m_playerControllerStates[m_playerID].m_leftStick;
if(shoot_direction.magnitude < epsilon)
{
shoot_direction.x = spriteRenderer.flipX ? -1.0f : 1.0f;
}
GameObject spawned_ball = Instantiate(ballPrefab);
spawned_ball.transform.position = transform.position;
Ball ball = spawned_ball.GetComponent<Ball>();
ball.m_owner = m_playerID;
Rigidbody2D rb2d = spawned_ball.GetComponent<Rigidbody2D>();
rb2d.velocity = shoot_direction * ballSpawnSpeed + 10f * speed;
AudioEngine.Play(m_shootSound);
m_animator.SetTrigger("shoot");
}
// update
Move(speed.x, speed.y);
// facing
if (Mathf.Abs(speed.x) > epsilon)
{
spriteRenderer.flipX = speed.x < 0;
}
// animation
}
void Move(float x, float y)
{
int amount;
remainder.x += x;
amount = Mathf.FloorToInt(remainder.x);
remainder.x -= amount;
MoveX(amount);
remainder.y += y;
amount = Mathf.FloorToInt(remainder.y);
remainder.y -= amount;
MoveY(amount);
if (m_playerID == 0)
position.x = Mathf.Min(position.x, 0);
else
position.x = Mathf.Max(position.x, 0);
transform.position = new Vector3(position.x, position.y, 0);
}
void MoveX(int amount)
{
int step = Mathf.RoundToInt(Sign(amount));
while (amount != 0)
{
if (IsSolid(step, 0))
{
speed.x = 0;
remainder.x = 0;
break;
}
else
{
position.x += step;
amount -= step;
}
}
}
void MoveY(int amount)
{
int step = Mathf.RoundToInt(Sign(amount));
while (amount != 0)
{
if (IsSolid(0, step) || (step < 0 && !OnPlatform(0) && OnPlatform(step)))
{
speed.y = 0;
remainder.y = 0;
AudioEngine.Play(m_landSound);
break;
}
else
{
position.y += step;
amount -= step;
}
}
}
//--------------------------------------------------------------------------------------------------
void OnTriggerEnter2D (Collider2D col)
{
// Only run this code when colliding with balls
if (col.gameObject.layer != LayerMask.NameToLayer("Ball"))
return;
// See if we can collide with the ball
Ball ball = col.GetComponent<Ball>();
// Seems like this will cause a 'feature' where the ball will eventually go through a player if it bounces back and
// forth between players a lot
if (m_playerID == ball.m_owner && !ball.m_canCollideWithPlayer)
return;
// Reflect the ball
Rigidbody2D ballRigid = col.GetComponent<Rigidbody2D>();
Vector2 normal = (col.transform.position - transform.position).normalized;
ballRigid.velocity = Mathf.Max(ballRigid.velocity.magnitude, ballSpawnSpeed) * normal;
AudioEngine.Play(m_deflectSound);
ball.m_canCollideWithPlayer = false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment