I'm dabbling with 2D physics and getting some funky (unexpected) results.
The problem:
I have a series of sprites that should all be travelling at a constant velocity but some choose to follow a curved path and randomly accelerate for no obvious reason!
The sprites are all set up in the following way:
They are all initialised with a random velocity and a random amount of angular velocity.
There is no gravity.
Each sprite has no friction.
They all have the same mass and restitution.
They are all set as Dynamic so that they can collide with each other and therefore change direction.
When they reach the edge of the screen their velocity and angular velocity is stored, the sprite is wrapped to the other side of the screen and then the velocity is restored.
Each sprite is made from the same looping animated spritesheet.
They are all set as polygon collision shapes which is recalculated every frame to account for the change in shape due to the animations.
Their mass is also reset each frame because recalculating the polygon shape also affects the mass.
Here's the sprite set up code:
function SpawnRock(x, y, size, style)
inc qtyRocks
k = qtyRocks
rock[k].velocity = CreateUnitVectorFromHeading(random(0, 360))
rock[k].speed = 1
rock[k].pos.x = x
rock[k].pos.y = y
rock[k].size = size
rock[k].hits = size
rock[k].style = style
MultiplyPassedVector2(rock[k].velocity, rock[k].speed)
SetSpriteImage(rock[k].spr, sourceRocks[style].img)
SetSpriteAnimation(rock[k].spr, sourceRocks[style].w, sourceRocks[style].h, sourceRocks[style].qty)
SetSpritePositionByOffset(rock[k].spr, rock[k].pos.x, rock[k].pos.y)
SetSpriteAngle(rock[k].spr, random(0, 360))
PlaySprite(rock[k].spr, 30, 1)
SetSpriteSize(rock[k].spr, rock[k].size*85, rock[k].size*85)
SetSpriteShape(rock[k].spr, SHAPE_POLYGON)
SetSpritePhysicsOn(rock[k].spr, PHYSICS_DYNAMIC)
v as tVect2
v.x = random(0,20)-10
v.y = random(0,20)-10
NormalizeVector2(v)
MultiplyPassedVector2(v, random(1,3))
SetSpritePhysicsVelocity(rock[k].spr, v.x, v.y)
SetSpritePhysicsAngularVelocity(rock[k].spr, random(0,5))
SetSpritePhysicsFriction(rock[k].spr, 0)
SetSpritePhysicsRestitution(rock[k].spr, 0.025)
SetSpritePhysicsMass(rock[k].spr, size)
SetSpriteVisible(rock[k].spr, TRUE)
if size = 1
SetSpriteShape(rock[k].spr, SHAPE_CIRCLE)
endif
endfunction
The array rock[] is prepopulated with blank sprites with no physics attributes.
The array sourcerocks[] holds the sprite images and the frame details for animation.
Here is the update code
function UpdateRocks()
for k = 0 to qtyRocks
if rock[k].size > 1
SetSpriteShape(rock[k].spr, SHAPE_POLYGON)
SetSpritePhysicsMass(rock[k].spr, rock[k].size)
endif
v as tVect2
v.x = GetSpritePhysicsVelocityX(rock[k].spr)
v.y = GetSpritePhysicsVelocityY(rock[k].spr)
av# = GetSpritePhysicsAngularVelocity(rock[k].spr)
//SetVector2Limit(v, 2)
WrapRock(k, v, av#)
CheckCollision(k)
next k
endfunction
function WrapRock(k, v ref as tVect2, av#)
offset# = 0.25
if GetSpriteXByOffset(rock[k].spr) > gamearea.r + (GetSpriteWidth(rock[k].spr)*offset#)+1
SetSpritePositionByOffset(rock[k].spr, gamearea.l - (GetSpriteWidth(rock[k].spr)*offset#), GetSpriteYByOffset(rock[k].spr))
SetSpritePhysicsAngularVelocity(rock[k].spr, av#)
SetSpritePhysicsVelocity(rock[k].spr, v.x, v.y)
exitfunction
endif
if GetSpriteXByOffset(rock[k].spr) < gamearea.l - (GetSpriteWidth(rock[k].spr)*offset#)-1
SetSpritePositionByOffset(rock[k].spr, gamearea.r + (GetSpriteWidth(rock[k].spr)*offset#), GetSpriteYByOffset(rock[k].spr))
SetSpritePhysicsAngularVelocity(rock[k].spr, av#)
SetSpritePhysicsVelocity(rock[k].spr, v.x, v.y)
exitfunction
endif
if GetSpriteYByOffset(rock[k].spr) > gamearea.b + (GetSpriteHeight(rock[k].spr)*offset#)
SetSpritePositionByOffset(rock[k].spr, GetSpriteXByOffset(rock[k].spr), gamearea.t - (GetSpriteHeight(rock[k].spr)*offset#))
SetSpritePhysicsAngularVelocity(rock[k].spr, av#)
SetSpritePhysicsVelocity(rock[k].spr, v.x, v.y)
exitfunction
endif
if GetSpriteYByOffset(rock[k].spr) < gamearea.t - (GetSpriteHeight(rock[k].spr)*offset#)
SetSpritePositionByOffset(rock[k].spr, GetSpriteXByOffset(rock[k].spr), gamearea.b + (GetSpriteHeight(rock[k].spr)*offset#))
SetSpritePhysicsAngularVelocity(rock[k].spr, av#)
SetSpritePhysicsVelocity(rock[k].spr, v.x, v.y)
exitfunction
endif
endfunction
The CheckCollision() function is not relevant because I can comment that out and the funky effect still persists.
There are no external forces and the change in velocity doesn't happen to all of the sprites, so I'm convinced that its something that I'm doing wrong and not a problem with the physics but I can see no reason why some of the sprites should randomly change velocity. So I'm open to suggestions.