Skip to content

Instantly share code, notes, and snippets.

@mfep
Last active July 13, 2017 20:25
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mfep/fab2d5c7d4230a1395eabb7f650cf6fa to your computer and use it in GitHub Desktop.
Save mfep/fab2d5c7d4230a1395eabb7f650cf6fa to your computer and use it in GitHub Desktop.
using System;
using Duality;
using Duality.Components.Physics;
using Duality.Components.Renderers;
using Duality.Drawing;
using Duality.Editor;
namespace mfep.Duality.Snippets
{
[RequiredComponent (typeof(SpriteRenderer))]
public class CharacterController : Component
{
[Flags]
public enum Sides
{
None = 0b0000,
Top = 0b0001,
Right = 0b0010,
Bottom = 0b0100,
Left = 0b1000,
TopRight = 0b0011,
BottomRight = 0b0110,
TopLeft = 0b1001,
BottomLeft = 0b1100
}
public int RayCount { get; set; } = 3;
public float Skin { get; set; } = 1f;
public bool Visualize { get; set; } = false;
[EditorHintFlags(MemberFlags.ReadOnly)]
public Sides Collision { get; private set; } = Sides.None;
public void Move (Vector2 deltaPos)
{
Collision = Sides.None;
MoveX (deltaPos);
MoveY (deltaPos);
}
private void MoveX (Vector2 deltaPos)
{
if (!(MathF.Abs (deltaPos.X) > 0.0f)) return;
var bounds = GameObj.GetComponent<SpriteRenderer> ().Rect.WithOffset(GameObj.Transform.Pos.Xy);
var dx = Vector2.UnitX * deltaPos.X;
var dirX = deltaPos.X > 0.0f ? 1.0f : -1.0f;
var skinV = Vector2.UnitX * dirX * this.Skin;
var topCenter = bounds.Center - Vector2.UnitY * (bounds.H * 0.5f - this.Skin);
var height = bounds.H - 2.0f * this.Skin;
var rayDivision = Vector2.UnitY * height / (this.RayCount - 1.0f);
var offs = Vector2.UnitX * (bounds.W * 0.5f * dirX) - skinV;
var minFraction = 1.0f;
var hit = false;
var frac = 1.0f;
for (int i = 0; i < RayCount; i++)
{
var origin = topCenter + i * rayDivision + offs;
if (RigidBody.RayCast(origin, origin + dx + skinV, data => 1.0f, out RayCastData firstHit))
{
hit = true;
frac = firstHit.Fraction;
minFraction = MathF.Min(minFraction, firstHit.Fraction);
}
if (this.Visualize)
{
VisualLog.Default.BaseColor = hit ? ColorRgba.Red : ColorRgba.White;
VisualLog.Default.DrawVector (new Vector3 (origin), (dx + skinV) * frac);
}
}
var xMove = (dx + skinV) * minFraction - skinV;
GameObj.Transform.MoveByAbs(xMove);
if (hit) {
var side = dirX > 0.0f ? Sides.Right : Sides.Left;
Collision |= side;
}
}
private void MoveY (Vector2 deltaPos)
{
if (!(MathF.Abs(deltaPos.Y) > 0.0f)) return;
var bounds = GameObj.GetComponent<SpriteRenderer>().Rect.WithOffset(GameObj.Transform.Pos.Xy);
var dy = Vector2.UnitY * deltaPos.Y;
var dirY = deltaPos.Y > 0.0f ? 1.0f : -1.0f;
var skinV = Vector2.UnitY * dirY * this.Skin;
var leftCenter = bounds.Center - Vector2.UnitX * (bounds.W * 0.5f - this.Skin);
var width = bounds.W - 2.0f * this.Skin;
var rayDivision = Vector2.UnitX * width / (this.RayCount - 1.0f);
var offs = Vector2.UnitY * (bounds.H * 0.5f * dirY) - skinV;
var minFraction = 1.0f;
var hit = false;
var frac = 1.0f;
for (int i = 0; i < RayCount; i++)
{
var origin = leftCenter + i * rayDivision + offs;
if (RigidBody.RayCast(origin, origin + dy + skinV, data => 1.0f, out RayCastData firstHit))
{
hit = true;
frac = firstHit.Fraction;
minFraction = MathF.Min(minFraction, firstHit.Fraction);
}
if (this.Visualize)
{
VisualLog.Default.BaseColor = hit ? ColorRgba.Red : ColorRgba.White;
VisualLog.Default.DrawVector (new Vector3 (origin), (dy + skinV) * frac);
}
}
var yMove = (dy + skinV) * minFraction - skinV;
GameObj.Transform.MoveByAbs(yMove);
if (hit) {
var side = dirY > 0.0f ? Sides.Bottom : Sides.Top;
Collision |= side;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment