#include "private.h"
#include "group.h"
#include "world.h"
struct _Group {
HeliArray sprites;
};
Group createGroup() {
if (!heliInitialized) return NULL;
Group g = calloc(1, sizeof(*g));
heliObjectRegister(g, (HeliFreeCallback)&groupDestroy);
return g;
}
Group createEdgesGroupEx(double x1, double y1, double x2, double y2, double borderWidth) {
if (!heliInitialized) return NULL;
if (x2 < x1) { double x = x2; x2 = x1; x1 = x; }
if (y2 < y1) { double y = y2; y2 = y1; y1 = y; }
if (borderWidth < 0.1) borderWidth = 0.1;
double b = borderWidth;
double w = x2 - x1 + b*2;
double h = y2 - y1 + b*2;
x1 -= b;
y1 -= b;
Group g = createGroup();
groupAdd(g, createSpriteEx(x1 + w/2, y1 + b/2, w, b));
groupAdd(g, createSpriteEx(x1 + w/2, y2 + b/2, w, b));
groupAdd(g, createSpriteEx(x1 + b/2, y1 + h/2, b, h));
groupAdd(g, createSpriteEx(x2 + b/2, y1 + h/2, b, h));
return g;
}
Group createEdgesGroup()
{ return createEdgesGroupEx(0, 0, worldGetWidth(), worldGetHeight(), worldGetHeight()); }
void groupDestroy(Group group) {
groupClear(group);
heliArrayDestroy(&group->sprites);
heliObjectUnregister(group);
free(group);
}
void groupDestroyEx(Group group, int destroySprites) {
groupClearEx(group, destroySprites);
groupDestroy(group);
}
void groupAdd(Group group, Sprite sprite) {
if (!sprite) return;
if (groupContains(group, sprite)) return;
heliArrayInsert(&group->sprites, -1, sprite, NULL);
heliArrayInsert(heliSpriteGetGroups(sprite), -1, group, NULL);
}
void groupRemove(Group group, Sprite sprite) {
for(int i = group->sprites.count-1; i >= 0; --i)
if (group->sprites.items[i].value == sprite)
heliArrayRemove(&group->sprites, i);
HeliArray *groups = heliSpriteGetGroups(sprite);
for(int i = groups->count-1; i >= 0; --i)
if (groups->items[i].value == group)
heliArrayRemove(groups, i);
}
void groupClearEx(Group group, int destroySprites) {
while(groupGetCount(group) > 0) {
Sprite s = groupGet(group, 0);
groupRemove(group, s);
if (destroySprites) spriteDestroy(s);
}
}
void groupClear(Group group)
{ groupClearEx(group, FALSE); }
void groupDestroyEach(Group group)
{ groupClearEx(group, TRUE); }
int groupContains(Group group, Sprite sprite) {
for(int i = group->sprites.count-1; i >= 0; --i)
if (group->sprites.items[i].value == sprite)
return TRUE;
return FALSE;
}
int groupGetCount(Group group)
{ return group->sprites.count; }
Sprite groupGet(Group group, int i)
{ return (Sprite)heliArrayGetValue(&group->sprites, i); }
int groupOverlap(Group group, Sprite sprite)
{ return groupCollideEx(group, sprite, TRUE, TRUE, 0); }
int groupCollide(Group group, Sprite sprite, double bounciness)
{ return groupCollideEx(group, sprite, FALSE, FALSE, bounciness); }
int groupBounceOff(Group group, Sprite sprite, double bounciness)
{ return groupCollideEx(group, sprite, FALSE, TRUE, bounciness); }
int groupPush(Group group, Sprite sprite, double bounciness)
{ return groupCollideEx(group, sprite, TRUE, FALSE, bounciness); }
int groupCollideEx(Group group, Sprite sprite, int keepVelocityGroup, int keepVelocitySprite, double bounciness) {
int result = FALSE;
for(int i = 0; i < groupGetCount(group); ++i)
if (spriteCollideEx(groupGet(group, i), sprite, keepVelocityGroup, keepVelocitySprite, bounciness))
result = TRUE;
return result;
}
int groupOverlapGroup(Group a, Group b)
{ return groupCollideGroupEx(a, b, TRUE, TRUE, 0); }
int groupCollideGroup(Group a, Group b, double bounciness)
{ return groupCollideGroupEx(a, b, FALSE, FALSE, bounciness); }
int groupBounceOffGroup(Group group, Group other, double bounciness)
{ return groupCollideGroupEx(group, other, FALSE, TRUE, bounciness); }
int groupPushGroup(Group group, Group other, double bounciness)
{ return groupCollideGroupEx(group, other, TRUE, FALSE, bounciness); }
int groupCollideGroupEx(Group a, Group b, int keepVelocityA, int keepVelocityB, double bounciness) {
int result = FALSE;
for(int i = 0; i < groupGetCount(b); ++i)
if (groupCollideEx(a, groupGet(b, i), keepVelocityA, keepVelocityB, bounciness))
result = TRUE;
return result;
}
int groupOverlapBetween(Group group)
{ return groupCollideBetweenEx(group, TRUE, 0); }
int groupCollideBetween(Group group, double bounciness)
{ return groupCollideBetweenEx(group, FALSE, bounciness); }
int groupCollideBetweenEx(Group group, int keepVelocity, double bounciness) {
int result = FALSE;
for(int i = 0; i < groupGetCount(group); ++i)
for(int j = i+1; j < groupGetCount(group); ++j)
if (spriteCollideEx(groupGet(group, i), groupGet(group, j), keepVelocity, keepVelocity, bounciness))
result = TRUE;
return result;
}
double groupGetMinDepth(Group group) {
if (groupGetCount(group) <= 0) return 0;
double md = spriteGetDepth(groupGet(group, 0));
for(int i = 1; i < groupGetCount(group); ++i) {
double d = spriteGetDepth(groupGet(group, i));
if (d < md) md = d;
}
return md;
}
double groupGetMaxDepth(Group group) {
if (groupGetCount(group) <= 0) return 0;
double md = spriteGetDepth(groupGet(group, 0));
for(int i = 1; i < groupGetCount(group); ++i) {
double d = spriteGetDepth(groupGet(group, i));
if (d > md) md = d;
}
return md;
}
static void foreachInt(Group group, int value, HeliSpriteEashInt func)
{ for(int i = 0; i < groupGetCount(group); ++i) func(groupGet(group, i), value); }
static void foreachDouble(Group group, double value, HeliSpriteEashDouble func)
{ for(int i = 0; i < groupGetCount(group); ++i) func(groupGet(group, i), value); }
static void foreachString(Group group, const char *value, HeliSpriteEashString func)
{ for(int i = 0; i < groupGetCount(group); ++i) func(groupGet(group, i), value); }
void groupDestroyTimerEach(Group group, double lifetime)
{ for(int i = groupGetCount(group) - 1; i >= 0; --i) spriteDestroyTimer(groupGet(group, i), lifetime); }
void groupSetVisibleEach(Group group, int visible)
{ foreachInt(group, visible, &spriteSetVisible); }
void groupSetWidthEach(Group group, double width)
{ foreachDouble(group, width, &spriteSetWidth); }
void groupSetHeightEach(Group group, double height)
{ foreachDouble(group, height, &spriteSetHeight); }
void groupSetDepthEach(Group group, double depth)
{ foreachDouble(group, depth, &spriteSetDepth); }
void groupSetVelocityXEach(Group group, double x)
{ foreachDouble(group, x, &spriteSetVelocityX); }
void groupSetVelocityYEach(Group group, double y)
{ foreachDouble(group, y, &spriteSetVelocityY); }
void groupSetRotateToDirectionEach(Group group, int rotateToDirection)
{ foreachInt(group, rotateToDirection, &spriteSetRotateToDirection); }
void groupSetRotationEach(Group group, double rotation)
{ foreachDouble(group, rotation, &spriteSetRotation); }
void groupSetRotationSpeedEach(Group group, double rotationSpeed)
{ foreachDouble(group, rotationSpeed, &spriteSetRotationSpeed); }
void groupSetScaleEach(Group group, double scale)
{ foreachDouble(group, scale, &spriteSetScale); }
void groupSetMirrorXEach(Group group, int mirrorX)
{ foreachInt(group, mirrorX, &spriteSetMirrorX); }
void groupSetMirrorYEach(Group group, int mirrorY)
{ foreachInt(group, mirrorY, &spriteSetMirrorY); }
void groupSetTagEach(Group group, int tag)
{ foreachInt(group, tag, &spriteSetTag); }
void groupSetAnimationEach(Group group, const char *path)
{ foreachString(group, path, &spriteSetAnimation); }
void groupSetShapeColorEach(Group group, const char *color)
{ foreachString(group, color, &spriteSetShapeColor); }
void groupSetTintColorEach(Group group, const char *color)
{ foreachString(group, color, &spriteSetTintColor); }
void groupSetNoAnimationEach(Group group) {
for(int i = 0; i < groupGetCount(group); ++i)
spriteSetNoAnimation(groupGet(group, i));
}
void groupPointToEach(Group group, double x, double y) {
for(int i = 0; i < groupGetCount(group); ++i)
spritePointTo(groupGet(group, i), x, y);
}
void groupSetSpeedAndDirectionEach(Group group, double speed, double angle) {
for(int i = 0; i < groupGetCount(group); ++i)
spriteSetSpeedAndDirection(groupGet(group, i), speed, angle);
}
void groupSetVelocityEach(Group group, double x, double y) {
for(int i = 0; i < groupGetCount(group); ++i)
spriteSetVelocityXY(groupGet(group, i), x, y);
}
void groupSetColliderEach(Group group, Collider type, double xOffset, double yOffset, double rotationOffset)
{ groupSetColliderEachEx(group, type, xOffset, yOffset, rotationOffset, -1, -1, -1); }
void groupSetColliderCircleEach(Group group, double xOffset, double yOffset, double radius)
{ groupSetColliderEachEx(group, COLLIDER_CIRCLE, xOffset, yOffset, 0, 0, 0, radius); }
void groupSetColliderRectangleEach(
Group group, double xOffset, double yOffset, double rotationOffset,
double width, double height, double cornersRadius )
{
groupSetColliderEachEx(
group, COLLIDER_RECTANGLE,
xOffset, yOffset, rotationOffset,
width, height, cornersRadius);
}
void groupSetColliderEachEx(
Group group, Collider type,
double xOffset, double yOffset, double rotationOffset,
double width, double height, double radius)
{
for(int i = 0; i < groupGetCount(group); ++i)
spriteSetColliderEx(
groupGet(group, i), type,
xOffset, yOffset, rotationOffset,
width, height, radius );
}