diff --git a/demo/src/phisics.c b/demo/src/phisics.c index fb3f013..dde503b 100644 --- a/demo/src/phisics.c +++ b/demo/src/phisics.c @@ -13,7 +13,7 @@ static Sound beep; void phisicsInit() { - ball = createSpriteEx(200, 200, 64, 64); + ball = createSpriteEx(200+1, 200+1, 64-2, 64-2); spriteSetAnimation(ball, createAnimation("data/sprite/breadball.png")); spriteSetColliderCircle(ball, 0, 0, -1); spriteSetRotateToDirection(ball, TRUE); @@ -23,9 +23,9 @@ void phisicsInit() { spriteSetTintColor(brick1, colorByRGB(0, 0, 1)); spriteSetColliderRectangle(brick1, 0, 0, 0, -1, -1, 20); spriteSetBounciness(brick1, 0.5); - spriteSetWeightLevel(brick1, 1); + spriteSetMassLevel(brick1, 1); - brick2 = createSpriteEx(200+32, 200+64, 64, 64); + brick2 = createSpriteEx(200+32+1, 200+64+1, 64-2, 64-2); spriteSetAnimation(brick2, createAnimation("data/sprite/bricks.png")); spriteSetColliderRectangle(brick2, 0, 0, 0, -1, -1, 20); @@ -34,7 +34,7 @@ void phisicsInit() { spriteSetTintColor(brick3, colorByRGBA(1, 0, 1, 0.5)); spriteSetColliderRectangle(brick3, 0, 0, 0, -1, -1, 20); spriteSetBounciness(brick3, 2); - spriteSetWeightLevel(brick3, 1); + spriteSetMassLevel(brick3, 1); movement = createGroup(); groupAdd(movement, ball); @@ -60,8 +60,8 @@ void phisicsDraw() { if (keyDown("down")) spriteSetVelocityY(ball, vy + accel*dt); int collision = FALSE; - if (groupCollideBetween(movement, 0)) collision = TRUE; - if (groupCollideGroup(edges, movement, 0)) collision = TRUE; + if (groupCollideBetween(movement)) collision = TRUE; + if (groupCollideGroup(edges, movement)) collision = TRUE; if (collision) soundPlay(beep, FALSE); } diff --git a/src/collider.c b/src/collider.c index 1ee2af2..88fcc86 100644 --- a/src/collider.c +++ b/src/collider.c @@ -128,11 +128,12 @@ static void collisionCorners(HeliCollisionData *data, double *corners, double x, int heliCheckCollision( - HeliCollider *a, HeliCollider *b, - double *dx, double *dy, - double *vx, double *vy, - double extra ) + HeliCollider *a, + HeliCollider *b, + HeliCollisionInfo *info, + double distance ) { + distance = fabs(distance); HeliCollisionData data = {}; // calc "moving" direction @@ -150,7 +151,7 @@ int heliCheckCollision( // check collision if (a->type == COLLIDER_CIRCLE && b->type == COLLIDER_CIRCLE) { - data.radius = fabs(a->radius) + fabs(b->radius) + fabs(extra); + data.radius = fabs(a->radius) + fabs(b->radius) + distance; data.x1 = data.x2 = b->x - a->x; data.y1 = data.y2 = b->y - a->y; collision(&data); @@ -158,21 +159,21 @@ int heliCheckCollision( if (a->type == COLLIDER_CIRCLE && b->type == COLLIDER_RECTANGLE) { double corners[8]; calcCorners(b, corners); - data.radius = fabs(a->radius) + fabs(b->radius) + fabs(extra); + data.radius = fabs(a->radius) + fabs(b->radius) + distance; if (data.radius > HELI_PRECISION) collisionCorners(&data, corners, a->x, a->y); } else if (a->type == COLLIDER_RECTANGLE && b->type == COLLIDER_CIRCLE) { double corners[8]; calcCorners(a, corners); data.flip = TRUE; - data.radius = fabs(a->radius) + fabs(b->radius) + fabs(extra); + data.radius = fabs(a->radius) + fabs(b->radius) + distance; if (data.radius > HELI_PRECISION) collisionCorners(&data, corners, b->x, b->y); } else if (a->type == COLLIDER_RECTANGLE && b->type == COLLIDER_RECTANGLE) { double cornersA[8], cornersB[8]; calcCorners(a, cornersA); calcCorners(b, cornersB); - data.radius = fabs(a->radius) + fabs(b->radius) + fabs(extra); + data.radius = fabs(a->radius) + fabs(b->radius) + distance; for(int i = 0; i < 4; ++i) collisionCorners(&data, cornersB, cornersA[2*i+0], cornersA[2*i+1]); data.flip = TRUE; @@ -181,10 +182,16 @@ int heliCheckCollision( } // is collision found? + info->actualCollision = FALSE; + info->distance = 0; + info->dx = info->dy = 0; if ( !data.found || data.lmin >= -HELI_PRECISION || data.lmax <= HELI_PRECISION ) + { + info->ax = info->ay = 0; return FALSE; + } // calc normal double l, nx, ny; @@ -198,49 +205,49 @@ int heliCheckCollision( ny = data.nyMax; } - // check angle - //double a0x = cos(angle0); - //double a0y = sin(angle0); - //double a1x = cos(angle1); - //double a1y = sin(angle1); - //double dax = a1x - a0x; - //double day = a1y - a0y; - //double ka = day*nx - dax*ny; - //if (ka < -HELI_PRECISION) return FALSE; - // calc displacement - *dx = 0; *dy = 0; + info->actualCollision = TRUE; double kd = (nx*data.dirx + ny*data.diry)*l; - *dx = nx*kd; - *dy = ny*kd; + info->distance = kd; + if (kd > distance + HELI_PRECISION) kd -= distance - HELI_PRECISION; else + if (kd < -distance - HELI_PRECISION) kd += distance - HELI_PRECISION; else + { kd = 0; info->actualCollision = FALSE; } + + if (info->actualCollision) { + info->dx = nx*kd; + info->dy = ny*kd; + } // calc velocity double bounciness = fabs(a->bounciness * b->bounciness); double bouncinessThreshold = fabs(a->bouncinessThreshold) + fabs(b->bouncinessThreshold); if (bounciness < HELI_PRECISION) bounciness = 0; - double sliding = a->sliding * b->sliding; - double slidingThreshold = fabs(a->slidingThreshold) + fabs(b->slidingThreshold); - if (!(slidingThreshold > HELI_PRECISION)) slidingThreshold = HELI_PRECISION; - if (sliding < HELI_PRECISION) sliding = 0; + double vb = -info->vx*nx - info->vy*ny; + double vs = info->vy*nx - info->vx*ny; - double vb = -(*vx*nx + *vy*ny); - double vs = *vy*nx - *vx*ny; + if (vb > -0.5*HELI_PRECISION) { + vb -= bouncinessThreshold; + if (vb < HELI_PRECISION) vb = 0; + vb *= bounciness; - vb -= bouncinessThreshold; - if (vb < HELI_PRECISION) vb = 0; - vb *= bounciness; - - if (vs > slidingThreshold) vs -= slidingThreshold; else - if (vs < slidingThreshold) vs += slidingThreshold; else vs = 0; - vs *= sliding; + if (info->actualCollision || vb > HELI_PRECISION) { + info->vx = nx*vb - ny*vs; + info->vy = ny*vb + nx*vs; + } + } - *vx = nx*vb - ny*vs; - *vy = ny*vb + nx*vs; + // calc weight + double w = -info->ax*nx - info->ay*ny; + if (w < HELI_PRECISION) w = 0; + if (fabs(vb) > 0.4*HELI_PRECISION) w = 0; + info->ax = nx*w; + info->ay = ny*w; return TRUE; } + int heliPointCollision(HeliCollider *c, double x, double y) { x -= c->x; y -= c->y; diff --git a/src/group.c b/src/group.c index db0bc64..0600235 100644 --- a/src/group.c +++ b/src/group.c @@ -33,7 +33,7 @@ Group createEdgesGroupEx(double x1, double y1, double x2, double y2, double bord 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)); - groupSetWeightLevel(g, weightLevel); + groupSetMassLevel(g, weightLevel); return g; } @@ -110,53 +110,76 @@ Sprite groupSpriteByPoint(Group group, double x, double y, int onlyVisible) { return NULL; } -int groupOverlap(Group group, Sprite sprite, double distance) { + +int groupOverlap(Group group, Sprite sprite) { for(int i = 0; i < groupGetCount(group); ++i) - if (spriteOverlap(groupGet(group, i), sprite, distance)) + if (spriteOverlap(groupGet(group, i), sprite)) return TRUE; return FALSE; } -int groupCollide(Group group, Sprite sprite, double distance) { +int groupCollide(Group group, Sprite sprite) { int result = FALSE; - for(int i = 0; i < groupGetCount(group); ++i) - if (spriteCollide(groupGet(group, i), sprite, distance)) - result = TRUE; + for(int j = 0; j < 10; ++j) { + int actualCollision = FALSE; + Sprite bestSprite = NULL; + HeliCollisionInfo bestInfo = {}; + for(int i = 0; i < groupGetCount(group); ++i) { + Sprite s = groupGet(group, i); + HeliCollisionInfo info = {}; + if (heliSpriteCollisionCheck(s, sprite, &info)) { + if (info.actualCollision) actualCollision = TRUE; + if (!bestSprite || bestInfo.distance <= info.distance) { + bestSprite = s; + memcpy(&bestInfo, &info, sizeof(bestInfo)); + } + } + } + if (!bestSprite) break; + heliSpriteCollisionApply(bestSprite, sprite, &bestInfo); + if (!actualCollision) break; + result = TRUE; + } return result; } -int groupOverlapGroup(Group a, Group b, double distance) { +int groupOverlapGroup(Group a, Group b) { for(int i = 0; i < groupGetCount(b); ++i) - if (groupCollide(a, groupGet(b, i), distance)) + if (groupOverlap(a, groupGet(b, i))) return TRUE; return FALSE; } -int groupCollideGroup(Group a, Group b, double distance) { +int groupCollideGroup(Group a, Group b) { int result = FALSE; for(int i = 0; i < groupGetCount(b); ++i) - if (groupCollide(a, groupGet(b, i), distance)) + if (groupCollide(a, groupGet(b, i))) result = TRUE; return result; } -int groupOverlapBetween(Group group, double distance) { +int groupOverlapBetween(Group group) { for(int i = 0; i < groupGetCount(group); ++i) for(int j = i+1; j < groupGetCount(group); ++j) - if (spriteCollide(groupGet(group, i), groupGet(group, j), distance)) + if (spriteOverlap(groupGet(group, i), groupGet(group, j))) return TRUE; return FALSE; } -int groupCollideBetween(Group group, double distance) { +int groupCollideBetween(Group group) { int result = FALSE; for(int i = 0; i < groupGetCount(group); ++i) for(int j = i+1; j < groupGetCount(group); ++j) - if (spriteCollide(groupGet(group, i), groupGet(group, j), distance)) + if (spriteCollide(groupGet(group, i), groupGet(group, j))) result = TRUE; return result; } +void groupResetTouch(Group group) { + for(int i = 0; i < groupGetCount(group); ++i) + spriteResetTouch(groupGet(group, i)); +} + double groupGetMinDepth(Group group) { if (groupGetCount(group) <= 0) return 0; @@ -198,10 +221,18 @@ void groupSetHeightEach(Group group, double height) { foreachDouble(group, height, &spriteSetHeight); } void groupSetDepthEach(Group group, double depth) { foreachDouble(group, depth, &spriteSetDepth); } +void groupSetXEach(Group group, double x) + { foreachDouble(group, x, &spriteSetX); } +void groupSetYEach(Group group, double y) + { foreachDouble(group, y, &spriteSetY); } void groupSetVelocityXEach(Group group, double x) { foreachDouble(group, x, &spriteSetVelocityX); } void groupSetVelocityYEach(Group group, double y) { foreachDouble(group, y, &spriteSetVelocityY); } +void groupSetAccelerationXEach(Group group, double x) + { foreachDouble(group, x, &spriteSetAccelerationX); } +void groupSetAccelerationYEach(Group group, double y) + { foreachDouble(group, y, &spriteSetAccelerationY); } void groupSetRotateToDirectionEach(Group group, int rotateToDirection) { foreachInt(group, rotateToDirection, &spriteSetRotateToDirection); } void groupSetRotationEach(Group group, double rotation) @@ -225,12 +256,14 @@ void groupSetBounciness(Group group, double bounciness) { foreachDouble(group, bounciness, &spriteSetBounciness); } void groupSetBouncinessThreshold(Group group, double bouncinessThreshold) { foreachDouble(group, bouncinessThreshold, &spriteSetBouncinessThreshold); } -void groupSetSliding(Group group, double sliding) - { foreachDouble(group, sliding, &spriteSetSliding); } -void groupSetSlidingThreshold(Group group, double slidingThreshold) - { foreachDouble(group, slidingThreshold, &spriteSetSlidingThreshold); } -void groupSetWeightLevel(Group group, int weightLevel) - { foreachInt(group, weightLevel, &spriteSetWeightLevel); } +void groupSetFriction(Group group, double friction) + { foreachDouble(group, friction, &spriteSetFriction); } +void groupSetAirFriction(Group group, double friction) + { foreachDouble(group, friction, &spriteSetAirFriction); } +void groupSetMassLevel(Group group, int massLevel) + { foreachInt(group, massLevel, &spriteSetMassLevel); } +void groupSetColliderSensitiveDistance(Group group, double distance) + { foreachDouble(group, distance, &spriteSetColliderSensitiveDistance); } void groupSetAnimationEach(Group group, Animation animation) { @@ -253,10 +286,18 @@ void groupSetSpeedAndDirectionEach(Group group, double speed, double angle) { spriteSetSpeedAndDirection(groupGet(group, i), speed, angle); } +void groupSetXYEach(Group group, double x, double y) { + for(int i = 0; i < groupGetCount(group); ++i) + spriteSetXY(groupGet(group, i), x, y); +} void groupSetVelocityEach(Group group, double x, double y) { for(int i = 0; i < groupGetCount(group); ++i) spriteSetVelocityXY(groupGet(group, i), x, y); } +void groupSetAccelerationEach(Group group, double x, double y) { + for(int i = 0; i < groupGetCount(group); ++i) + spriteSetAccelerationXY(groupGet(group, i), x, y); +} void groupSetUserTextEach(Group group, const char *text) { diff --git a/src/group.h b/src/group.h index 7efb37b..a66d53e 100644 --- a/src/group.h +++ b/src/group.h @@ -23,34 +23,41 @@ int groupContains(Group group, Sprite sprite); int groupGetCount(Group group); Sprite groupGet(Group group, int i); -Sprite groupSpriteByPoint(Group group, double x, double y, int onlyVisible); - -int groupOverlap(Group group, Sprite sprite, double distance); -int groupCollide(Group group, Sprite sprite, double distance); -int groupOverlapGroup(Group a, Group b, double distance); -int groupCollideGroup(Group a, Group b, double distance); -int groupOverlapBetween(Group group, double distance); -int groupCollideBetween(Group group, double distance); - double groupGetMinDepth(Group group); double groupGetMaxDepth(Group group); void groupDestroyEach(Group group); void groupDestroyTimerEach(Group group, double lifetime); +Sprite groupSpriteByPoint(Group group, double x, double y, int onlyVisible); + +int groupOverlap(Group group, Sprite sprite); +int groupCollide(Group group, Sprite sprite); +int groupOverlapGroup(Group a, Group b); +int groupCollideGroup(Group a, Group b); +int groupOverlapBetween(Group group); +int groupCollideBetween(Group group); +void groupResetTouch(Group group); + void groupSetBounciness(Group group, double bounciness); void groupSetBouncinessThreshold(Group group, double bouncinessThreshold); -void groupSetSliding(Group group, double sliding); -void groupSetSlidingThreshold(Group group, double slidingThreshold); -void groupSetWeightLevel(Group group, int weightLevel); +void groupSetFriction(Group group, double friction); +void groupSetAirFriction(Group group, double friction); +void groupSetMassLevel(Group group, int massLevel); void groupSetVisibleEach(Group group, int visible); void groupSetWidthEach(Group group, double width); void groupSetHeightEach(Group group, double height); void groupSetDepthEach(Group group, double depth); +void groupSetXEach(Group group, double x); +void groupSetYEach(Group group, double y); +void groupSetXYEach(Group group, double x, double y); void groupSetVelocityXEach(Group group, double x); void groupSetVelocityYEach(Group group, double y); void groupSetVelocityEach(Group group, double x, double y); +void groupSetAccelerationXEach(Group group, double x); +void groupSetAccelerationYEach(Group group, double y); +void groupSetAccelerationEach(Group group, double x, double y); void groupSetLifetimeEach(Group group, double lifetime); void groupSetRotateToDirectionEach(Group group, int rotateToDirection); void groupSetRotationEach(Group group, double rotation); @@ -71,6 +78,7 @@ void groupSetUserTextEach(Group group, const char *text); void groupSetUserDataEach(Group group, void *data); void groupSetDestroyEach(Group group, SpriteCallback destroy); +void groupSetColliderSensitiveDistance(Group group, double distance); void groupSetColliderEach(Group group, Collider type, double xOffset, double yOffset, double rotationOffset); void groupSetColliderCircleEach(Group group, double xOffset, double yOffset, double radius); void groupSetColliderRectangleEach( diff --git a/src/private.h b/src/private.h index 2fd1c90..b826966 100644 --- a/src/private.h +++ b/src/private.h @@ -191,15 +191,20 @@ typedef struct _HeliCollider { double rotation; double bounciness; double bouncinessThreshold; - double sliding; - double slidingThreshold; } HeliCollider; +typedef struct _HeliCollisionInfo { + int actualCollision; + double distance; + double dx, dy; + double vx, vy; + double ax, ay; +} HeliCollisionInfo; + int heliCheckCollision( HeliCollider *a, HeliCollider *b, - double *dx, double *dy, - double *vx, double *vy, - double extra ); + HeliCollisionInfo *info, + double distance ); int heliPointCollision(HeliCollider *c, double x, double y); @@ -210,6 +215,8 @@ typedef void (*HeliSpriteEashInt)(Sprite, int); typedef void (*HeliSpriteEashUInt)(Sprite, unsigned int); typedef void (*HeliSpriteEashDouble)(Sprite, double); HeliArray* heliSpriteGetGroups(Sprite sprite); +int heliSpriteCollisionCheck(Sprite a, Sprite b, HeliCollisionInfo *info); +void heliSpriteCollisionApply(Sprite a, Sprite b, HeliCollisionInfo *info); void heliSpriteSort(HeliArray *sprites); void heliSpriteUpdate(double dt); void heliSpriteFinish(); diff --git a/src/sprite.c b/src/sprite.c index 177360d..eb68379 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -18,10 +18,19 @@ struct _Sprite { double vx; double vy; + double ax; + double ay; double rotationSpeed; HeliCollider collider; - int weightLevel; + double colliderSensitiveDistance; + int massLevel; + + double wx; + double wy; + double friction; + double airFriction; + double touchFriction; int rotateToDirection; int mirrorX; @@ -88,6 +97,12 @@ static void prepareCollider(Sprite sprite, HeliCollider *collider) { } +static void autoRotate(Sprite sprite) { + if (sprite->rotateToDirection) + sprite->rotation = spriteGetDirection(sprite); +} + + Sprite createSpriteEx(double x, double y, double width, double height) { if (!heliInitialized) return NULL; @@ -100,8 +115,9 @@ Sprite createSpriteEx(double x, double y, double width, double height) { s->scale = 1; s->collider.type = COLLIDER_RECTANGLE; s->collider.width = s->collider.height = -1; + s->colliderSensitiveDistance = 0.001; s->collider.bounciness = 1; - s->collider.sliding = 1; + s->friction = 1; s->mirrorX = 1; s->mirrorY = 1; @@ -159,17 +175,29 @@ Sprite spriteClone(Sprite sprite) { double spriteGetX(Sprite sprite) { return sprite->x; } void spriteSetX(Sprite sprite, double x) { sprite->x = x; } - double spriteGetY(Sprite sprite) { return sprite->y; } void spriteSetY(Sprite sprite, double y) { sprite->y = y; } +void spriteSetXY(Sprite sprite, double x, double y) + { spriteSetX(sprite, x); spriteSetY(sprite, y); } double spriteGetVelocityX(Sprite sprite) { return sprite->vx; } void spriteSetVelocityX(Sprite sprite, double x) { spriteSetVelocityXY(sprite, x, sprite->vy); } - double spriteGetVelocityY(Sprite sprite) { return sprite->vy; } void spriteSetVelocityY(Sprite sprite, double y) { spriteSetVelocityXY(sprite, sprite->vx, y); } +void spriteSetVelocityXY(Sprite sprite, double x, double y) { + spriteResetTouch(sprite); + sprite->vx = x; sprite->vy = y; + autoRotate(sprite); +} + +double spriteGetAccelerationX(Sprite sprite) { return sprite->ax; } +void spriteSetAccelerationX(Sprite sprite, double x) { sprite->ax = x; } +double spriteGetAccelerationY(Sprite sprite) { return sprite->ay; } +void spriteSetAccelerationY(Sprite sprite, double y) { sprite->ay = y; } +void spriteSetAccelerationXY(Sprite sprite, double x, double y) + { spriteSetAccelerationX(sprite, x); spriteSetAccelerationY(sprite, y); } double spriteGetScale(Sprite sprite) { return sprite->scale; } void spriteSetScale(Sprite sprite, double scale) { sprite->scale = scale; } @@ -220,48 +248,89 @@ int spriteGetDebug(Sprite sprite) { return sprite->debug; } void spriteSetDebug(Sprite sprite, int debug) { sprite->debug = debug != FALSE; } -static int collide(Sprite a, Sprite b, double distance, int apply) { + +void heliSpriteCollisionApply(Sprite a, Sprite b, HeliCollisionInfo *info) { + if ( a->massLevel > b->massLevel) { + b->x -= info->dx; + b->y -= info->dy; + b->vx = a->vx - info->vx; + b->vy = a->vy - info->vy; + autoRotate(b); + if (b->wx*b->wx + b->wy*b->wy < info->ax*info->ax + info->ay*info->ay) { + b->wx = info->ax; + b->wy = info->ay; + b->touchFriction = a->friction; + } + } else + if ( b->massLevel > a->massLevel ) { + a->x += info->dx; + a->y += info->dy; + a->vx = b->vx + info->vx; + a->vy = b->vy + info->vy; + autoRotate(a); + if (a->wx*a->wx + a->wy*a->wy < info->ax*info->ax + info->ay*info->ay) { + a->wx = -info->ax; + a->wy = -info->ay; + a->touchFriction = b->friction; + } + } else { + double vxAvg = 0.5*(a->vx + b->vx); + double vyAvg = 0.5*(a->vy + b->vy); + double wx = info->ax; + double wy = info->ay; + double w = wx*wx + wy*wy; + + a->x += 0.5*info->dx; + a->y += 0.5*info->dy; + a->vx = vxAvg + 0.5*info->vx; + a->vy = vyAvg + 0.5*info->vy; + autoRotate(a); + if (a->wx*a->wx + a->wy*a->wy < w) { + a->wx = -wx; + a->wy = -wy; + a->touchFriction = b->friction; + } + + b->x -= 0.5*info->dx; + b->y -= 0.5*info->dy; + b->vx = vxAvg - 0.5*info->vx; + b->vy = vyAvg - 0.5*info->vy; + autoRotate(b); + if (b->wx*b->wx + b->wy*b->wy < w) { + b->wx = wx; + b->wy = wy; + b->touchFriction = a->friction; + } + } +} + +int heliSpriteCollisionCheck(Sprite a, Sprite b, HeliCollisionInfo *info) { if (a == b) return FALSE; HeliCollider ca = {}, cb = {}; prepareCollider(a, &ca); prepareCollider(b, &cb); - double dx = 0, dy = 0; - double vx = a->vx - b->vx; - double vy = a->vy - b->vy; - if (!heliCheckCollision(&ca, &cb, &dx, &dy, &vx, &vy, distance)) - return FALSE; - - if (apply) { - if ( a->weightLevel > b->weightLevel) { - b->x -= dx; - b->y -= dy; - spriteSetVelocityXY(b, a->vx - vx, a->vy - vy); - } else - if ( b->weightLevel > a->weightLevel ) { - a->x += dx; - a->y += dy; - spriteSetVelocityXY(a, b->vx + vx, b->vy + vy); - } else { - double vxAvg = 0.5*(a->vx + b->vx); - double vyAvg = 0.5*(a->vy + b->vy); - - a->x += 0.5*dx; - a->y += 0.5*dy; - spriteSetVelocityXY(a, vxAvg + 0.5*vx, vyAvg + 0.5*vy); - - b->x -= 0.5*dx; - b->y -= 0.5*dy; - spriteSetVelocityXY(b, vxAvg - 0.5*vx, vyAvg - 0.5*vy); - } - } - - return TRUE; + memset(info, 0, sizeof(*info)); + info->vx = a->vx - b->vx; + info->vy = a->vy - b->vy; + info->ax = a->ax - b->ax; + info->ay = a->ay - b->ay; + return heliCheckCollision(&ca, &cb, info, a->colliderSensitiveDistance + b->colliderSensitiveDistance); +} + +int spriteOverlap(Sprite a, Sprite b) { + HeliCollisionInfo info = {}; + heliSpriteCollisionCheck(a, b, &info); + return info.actualCollision; } -int spriteOverlap(Sprite a, Sprite b, double distance) - { return collide(a, b, distance, FALSE); } -int spriteCollide(Sprite a, Sprite b, double distance) - { return collide(a, b, distance, TRUE); } +int spriteCollide(Sprite a, Sprite b) { + HeliCollisionInfo info = {}; + if (heliSpriteCollisionCheck(a, b, &info)) { + heliSpriteCollisionApply(a, b, &info); + return info.actualCollision; + } + return FALSE; +} double spriteGetBounciness(Sprite sprite) @@ -273,20 +342,38 @@ double spriteGetBouncinessThreshold(Sprite sprite) void spriteSetBouncinessThreshold(Sprite sprite, double bouncinessThreshold) { sprite->collider.bouncinessThreshold = bouncinessThreshold > 0 ? bouncinessThreshold : 0; } -double spriteGetSliding(Sprite sprite) - { return sprite->collider.sliding; } -void spriteSetSliding(Sprite sprite, double sliding) - { sprite->collider.sliding = sliding > 0 ? sliding : 0; } -double spriteGetSlidingThreshold(Sprite sprite) - { return sprite->collider.slidingThreshold; } -void spriteSetSlidingThreshold(Sprite sprite, double slidingThreshold) - { sprite->collider.slidingThreshold = slidingThreshold > 0 ? slidingThreshold : 0; } - -int spriteGetWeightLevel(Sprite sprite) - { return sprite->weightLevel; } -void spriteSetWeightLevel(Sprite sprite, int weightLevel) - { sprite->weightLevel = weightLevel; } +double spriteGetFriction(Sprite sprite) + { return sprite->friction; } +void spriteSetFriction(Sprite sprite, double friction) + { sprite->friction = friction > 0 ? friction : 0; } +double spriteGetAirFriction(Sprite sprite) + { return sprite->airFriction; } +void spriteSetAirFriction(Sprite sprite, double friction) + { sprite->airFriction = friction > 0 ? friction : 0; } + +int spriteGetMassLevel(Sprite sprite) + { return sprite->massLevel; } +void spriteSetMassLevel(Sprite sprite, int massLevel) + { sprite->massLevel = massLevel; } + +double spriteGetTouchWeight(Sprite sprite) + { return sqrt(sprite->wx*sprite->wx + sprite->wy*sprite->wy); } +double spriteGetTouchWeightX(Sprite sprite) + { return sprite->wx; } +double spriteGetTouchWeightY(Sprite sprite) + { return sprite->wy; } +double spriteGetTouchFriction(Sprite sprite) + { return sprite->touchFriction; } +void spriteResetTouch(Sprite sprite) { + sprite->wx = 0; + sprite->wy = 0; + sprite->touchFriction = 0; +} +double spriteGetColliderSensitiveDistance(Sprite sprite) + { return sprite->colliderSensitiveDistance; } +void spriteSetColliderSensitiveDistance(Sprite sprite, double distance) + { sprite->colliderSensitiveDistance = distance > 10*HELI_PRECISION ? distance : 10*HELI_PRECISION; } void spriteSetCollider(Sprite sprite, Collider type, double xOffset, double yOffset, double rotationOffset) { spriteSetColliderEx(sprite, type, xOffset, yOffset, rotationOffset, -1, -1, -1); } @@ -347,13 +434,6 @@ void spriteSetShapeColor(Sprite sprite, unsigned int colorCode) void spriteSetTintColor(Sprite sprite, unsigned int colorCode) { heliColorToDouble(colorCode, sprite->tintColor); } -void spriteSetVelocityXY(Sprite sprite, double x, double y) { - sprite->vx = x; - sprite->vy = y; - if (sprite->rotateToDirection) - sprite->rotation = spriteGetDirection(sprite); -} - void spriteSetSpeedAndDirection(Sprite sprite, double speed, double angle) { double a = angle*(PI/180); spriteSetVelocityXY(sprite, cos(a)*speed, sin(a)*speed); @@ -519,6 +599,37 @@ void heliSpriteUpdate(double dt) { // update for(int i = 0; i < sprites.count; ++i) { Sprite s = (Sprite)sprites.items[i].value; + double vx = s->vx + s->ax*dt; + double vy = s->vy + s->ay*dt; + + double weight = spriteGetTouchWeight(s); + double dvf = fabs(weight*s->friction*s->touchFriction)*dt; + if (dvf > HELI_PRECISION) { + double nx = s->wx/weight; + double ny = s->wy/weight; + double vb = nx*vx + ny*vy; + double vs = ny*vx - nx*vy; + if (vs > dvf + HELI_PRECISION) vs -= dvf; else + if (vs < -dvf - HELI_PRECISION) vs += dvf; else vs = 0; + vx = nx*vb + ny*vs; + vy = ny*vb - nx*vs; + } + + double dvaf = fabs(s->airFriction)*dt; + if (dvaf > HELI_PRECISION) { + double v = sqrt(vx*vx + vy*vy), vn = v; + if (v > dvaf + HELI_PRECISION) vn -= dvaf; else + if (v < -dvaf - HELI_PRECISION) vn += dvaf; else vn = 0; + double k = vn > HELI_PRECISION ? vn/v : 0; + vx *= k; + vy *= k; + } + + s->vx = vx; + s->vy = vy; + autoRotate(s); + spriteResetTouch(s); + s->x += s->vx*dt; s->y += s->vy*dt; if (!s->rotateToDirection) diff --git a/src/sprite.h b/src/sprite.h index 325ec3f..c2451d3 100644 --- a/src/sprite.h +++ b/src/sprite.h @@ -26,15 +26,21 @@ Sprite spriteClone(Sprite sprite); double spriteGetX(Sprite sprite); void spriteSetX(Sprite sprite, double x); - double spriteGetY(Sprite sprite); void spriteSetY(Sprite sprite, double y); +void spriteSetXY(Sprite sprite, double x, double y); double spriteGetVelocityX(Sprite sprite); void spriteSetVelocityX(Sprite sprite, double x); - double spriteGetVelocityY(Sprite sprite); void spriteSetVelocityY(Sprite sprite, double y); +void spriteSetVelocityXY(Sprite sprite, double x, double y); + +double spriteGetAccelerationX(Sprite sprite); +void spriteSetAccelerationX(Sprite sprite, double x); +double spriteGetAccelerationY(Sprite sprite); +void spriteSetAccelerationY(Sprite sprite, double y); +void spriteSetAccelerationXY(Sprite sprite, double x, double y); double spriteGetScale(Sprite sprite); void spriteSetScale(Sprite sprite, double scale); @@ -69,22 +75,31 @@ void spriteSetVisible(Sprite sprite, int visible); int spriteGetDebug(Sprite sprite); void spriteSetDebug(Sprite sprite, int debug); -int spriteOverlap(Sprite a, Sprite b, double distance); -int spriteCollide(Sprite a, Sprite b, double distance); +int spriteOverlap(Sprite a, Sprite b); +int spriteCollide(Sprite a, Sprite b); int spriteIsPointInside(Sprite sprite, double x, double y); +double spriteGetTouchWeight(Sprite sprite); +double spriteGetTouchWeightX(Sprite sprite); +double spriteGetTouchWeightY(Sprite sprite); +double spriteGetTouchFriction(Sprite sprite); +void spriteResetTouch(Sprite sprite); + double spriteGetBounciness(Sprite sprite); void spriteSetBounciness(Sprite sprite, double bounciness); double spriteGetBouncinessThreshold(Sprite sprite); void spriteSetBouncinessThreshold(Sprite sprite, double bouncinessThreshold); -double spriteGetSliding(Sprite sprite); -void spriteSetSliding(Sprite sprite, double sliding); -double spriteGetSlidingThreshold(Sprite sprite); -void spriteSetSlidingThreshold(Sprite sprite, double slidingThreshold); +double spriteGetFriction(Sprite sprite); +void spriteSetFriction(Sprite sprite, double friction); +double spriteGetAirFriction(Sprite sprite); +void spriteSetAirFriction(Sprite sprite, double friction); + +int spriteGetMassLevel(Sprite sprite); +void spriteSetMassLevel(Sprite sprite, int massLevel); -int spriteGetWeightLevel(Sprite sprite); -void spriteSetWeightLevel(Sprite sprite, int weightLevel); +double spriteGetColliderSensitiveDistance(Sprite sprite); +void spriteSetColliderSensitiveDistance(Sprite sprite, double distance); void spriteSetCollider(Sprite sprite, Collider type, double xOffset, double yOffset, double rotationOffset); void spriteSetColliderCircle(Sprite sprite, double xOffset, double yOffset, double radius); @@ -103,7 +118,6 @@ void spriteSetNoAnimation(Sprite sprite); void spriteSetShapeColor(Sprite sprite, unsigned int colorCode); void spriteSetTintColor(Sprite sprite, unsigned int colorCode); -void spriteSetVelocityXY(Sprite sprite, double x, double y); void spriteSetSpeedAndDirection(Sprite sprite, double speed, double angle); double spriteGetSpeed(Sprite sprite); double spriteGetDirection(Sprite sprite);