Skip to content

Instantly share code, notes, and snippets.

@rdavisau
Last active August 29, 2015 14:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rdavisau/96e9dba98fc0e2484fc5 to your computer and use it in GitHub Desktop.
Save rdavisau/96e9dba98fc0e2484fc5 to your computer and use it in GitHub Desktop.
CocosSharp Extension Methods - Helpers for actions, layout, sizing, drawing
/*
Snippet Name: CocosSharp Extension Methods
Platform: All
Function: CocosSharp helpers for actions, layout, sizing, drawing
Includes:
- Awaitable CCNode.RunActionsWithTask - allows you to await the running of a set of actions (for example, in order to not proceed with subsequent code till an animation completes), without having to explicitly calculate the duration of the actions or use a callback.
- Easy relative positioning with CCNode.PlaceAt - allows you to position a CCNode relative to the boundaries of a parent CCNode. Fluent style, so can be used at initialisation time.
- Easy filled colours with CCDrawNode.FillWith and quick sprite initialisation with CCNode.WithSprite, also fluent.
- Quick insetting or outsetting with CCSize.MultiplyBy.
- A few others - just take a look - they are all documented :)
You can paste this whole gist into LINQPad with the CocosSharp package installed and it will run the sample.
Snippet:
*/
public static class CocosExtensions
{
/// <summary>
/// Returns a task that will complete after the provided actions complete.
/// Will not complete if the action list contains a CCRepeatForever.
/// </summary>
/// <param name="node"></param>
/// <param name="actions">The actions to perform</param>
/// <returns></returns>
public static Task<bool> RunActionsWithTask(this CCNode node, params CCFiniteTimeAction[] actions)
{
var t = new TaskCompletionSource<bool>();
node.RunAction(new CCSequence(actions.Concat(new[] { new CCCallFunc(() => t.SetResult(true)) }).ToArray()));
return t.Task;
}
/// <summary>
/// Centers label text vertically and horizontally
/// </summary>
/// <typeparam name="TLabel"></typeparam>
/// <param name="label"></param>
/// <returns></returns>
public static TLabel WithTextCentered<TLabel>(this TLabel label) where TLabel : CCLabel
{
label.HorizontalAlignment = CCTextAlignment.Center;
label.VerticalAlignment = CCVerticalTextAlignment.Center;
return label;
}
/// <summary>
/// Applies the specified horizontal text aligment
/// </summary>
/// <typeparam name="TLabel"></typeparam>
/// <param name="label"></param>
/// <param name="alignment"></param>
/// <returns></returns>
public static TLabel WithTextAlignment<TLabel>(this TLabel label, CCTextAlignment alignment) where TLabel : CCLabel
{
label.HorizontalAlignment = alignment;
return label;
}
/// <summary>
/// Draws a rectangle the size of the provided node's BoundingBox in the provided colour
/// </summary>
/// <typeparam name="TNode"></typeparam>
/// <param name="node"></param>
/// <param name="colour"></param>
/// <returns></returns>
public static TNode FillWith<TNode>(this TNode node, CCColor3B colour) where TNode : CCDrawNode
{
node.Color = colour;
node.DrawRect(node.BoundingBox);
return node;
}
/// <summary>
/// Loads a sprite into the provided CCnode
/// </summary>
/// <typeparam name="TNode"></typeparam>
/// <param name="node"></param>
/// <param name="fileName"></param>
/// <returns></returns>
public static TNode WithSprite<TNode>(this TNode node, string fileName)
where TNode : CCNode
{
node.AddChild(new CCSprite(new CCTexture2D(fileName)));
return node;
}
/// <summary>
/// Places the target node within the provided parent node (or its existing node) according to the xPct and yPct factors
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="node"></param>
/// <param name="xPct">A value from 0f to 1f (left to right) indicating how far along the x-axis the node should sit within the parent.</param>
/// <param name="yPct">A value from 0f to 1f (top to bottom) indicating how far along the y-axis the node should sit within the parent.</param>
/// <param name="parent">The parent node within which the target should sit. If null, the target must already have a parent.</param>
/// <returns></returns>
public static T PlaceAt<T>(this T node, double xPct, double yPct, CCNode parent = null) where T : CCNode
{
if (parent == null)
parent = node.Parent.AssertNotNull("No parent container for node requiring PlaceAt");
else
{
// check whether target already has a parent, if it does we need to remove it before placing in new parent
if (node.Parent != null)
node.RemoveFromParent(false);
parent.AddChild(node);
}
var parentSize = parent.BoundingBox.Size;
var targetX = (float)(parentSize.Width * xPct);
var targetY = (float)(parentSize.Height - (parentSize.Height * yPct));
node.AnchorPoint = CCPoint.AnchorMiddle;
node.Position = new CCPoint(targetX, targetY);
return node;
}
/// <summary>
/// Returns the target node with the provided actions set to repeat indefinitely
/// </summary>
/// <typeparam name="TNode"></typeparam>
/// <param name="node"></param>
/// <param name="actions"></param>
/// <returns></returns>
public static TNode WithOngoingActions<TNode>(this TNode node, params CCFiniteTimeAction[] actions) where TNode : CCNode
{
var repeat = new CCRepeatForever (actions);
node.RunAction (repeat);
return node;
}
/// <summary>
/// Return a new CCSize with the dimensions of factor * the target CCSize
/// </summary>
/// <param name="size"></param>
/// <param name="factor"></param>
/// <returns></returns>
public static CCSize MultiplyBy(this CCSize size, float factor)
{
return new CCSize(size.Width * factor, size.Height * factor);
}
/// <summary>
/// Return a new CCSize with the dimensions of xFactor * the target CCSize width, yFactor * the target CCSize height
/// </summary>
/// <param name="size"></param>
/// <param name="factor"></param>
/// <returns></returns>
public static CCSize MultiplyBy(this CCSize size, float xFactor = 1, float yFactor = 1)
{
return new CCSize(size.Width * xFactor, size.Height * yFactor);
}
/// <summary>
/// Returns target after asserting not null
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="obj"></param>
/// <param name="msg"></param>
/// <returns></returns>
public static T AssertNotNull<T>(this T obj, string msg = null)
{
Debug.Assert(obj != null, msg ?? "AssertNotNull failed");
return obj;
}
/// <summary>
/// Clamps the provided value to within the provided range
/// </summary>
/// <param name="f"></param>
/// <param name="min"></param>
/// <param name="max"></param>
/// <returns></returns>
public static float Between(this float f, float min, float max)
{
return Math.Max(Math.Min(max, f), min);
}
/// <summary>
/// Returns true if the provided value is positive
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static bool IsPositive(this float f)
{
return f >= 0;
}
/// <summary>
/// Returns true if the provided value is negative
/// </summary>
/// <param name="f"></param>
/// <returns></returns>
public static bool IsNegative(this float f)
{
return !IsPositive(f);
}
/// <summary>
/// Returns true if the provided values have different signs
/// </summary>
/// <param name="f1"></param>
/// <param name="f2"></param>
/// <returns></returns>
public static bool HasDifferentSignTo(this float f1, float f2)
{
return !f1.HasSameSignAs(f2);
}
/// <summary>
/// Returns true if the provided values have the same sign (both positive, both negative)
/// </summary>
/// <param name="f1"></param>
/// <param name="f2"></param>
/// <returns></returns>
public static bool HasSameSignAs(this float f1, float f2)
{
return (f1.IsPositive() && f2.IsPositive()) || (f1.IsNegative() && f2.IsNegative());
}
}
/*
Example Use - Label Utils, PlaceAt, FillWith, RunActionsWithTask:
*/
public static class Example
{
public static async void DoExample(this CCLayer @this)
{
var container = new CCNode()
{
ContentSize = new CCSize(@this.VisibleBoundsWorldspace.MaxX*.75f, @this.VisibleBoundsWorldspace.MaxY*.1f),
Scale = 5f,
Rotation = -22.5f,
}.PlaceAt(.5f, .35f, @this);
var filledBanner = new CCDrawNode() {ContentSize = container.ContentSize}
.FillWith(CCColor3B.Red)
.PlaceAt(.5f, .5f, container);
var newLabel = new CCLabel("LABEL!", "consolas", 48f)
.WithTextCentered()
.PlaceAt(.5f, .5f, container);
await container.RunActionsWithTask(new CCEaseBounceOut(new CCScaleTo(1f, 1f)));
filledBanner.FillWith(CCColor3B.Green);
newLabel.Text = "The animation is done!!";
}
}
/* below is just scaffolding */
void Main()
{
var app = new CCApplication { ApplicationDelegate = new AppDelegate() };
app.StartGame();
}
public class AppDelegate : CCApplicationDelegate
{
public override void ApplicationDidFinishLaunching(CCApplication app, CCWindow window)
{
var scene = new CCScene(window);
var layer = new MyLayer();
scene.AddChild(layer);
window.RunWithScene(scene);
}
}
public class MyLayer : CCLayer
{
protected override void AddedToScene()
{
base.AddedToScene();
this.DoExample();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment