msqar msqar - 1 year ago 190
iOS Question

Attach static shadow to bottom of dynamic physicsBody ball in Swift SpriteKit

I would like to create this as the picture shows

enter image description here

I got a normal physicsBody ball, with dynamic, affectedByGravity and can rotate.
The thing is, whenever you attach a child to the ball that can rotate, the sprite will follow the same movement as the ball.

What's the best way to make the shadow stay on bottom of the ball? Can I directly do:


With some kind of attributes that will keep it static on bottom? Or should i


And then during update()

shadow.position(ball's position)

Thanks in advance.

Answer Source

I'd suggest using a SKShader to apply simple shadow effect.

You'll need to create an empty file with a .fsh extension, let's use shader.fsh. The shader code will generate a z property which is the "pseudo" depth based on the distance of each pixel to the center of the image. Using z, it calculates a normal, and the shadow strength is the dot product of the normal and the light position (here I've placed the light in the top left of the scene):

void main()
    vec2 coord = (v_tex_coord - 0.5) * 2.0;

    if (length(coord) > 1.0) {

    vec3 diffuseColor = v_color_mix.rgb;

    vec3 lightPosition = normalize(vec3(-1.0, 1.0, 1.0));

    float z = sqrt(1.0 - coord.x * coord.x - coord.y * coord.y);
    vec3 normal = normalize(vec3(coord.x, coord.y, z));

    float shadow = max(0.0, dot(normal, lightPosition));

    diffuseColor *= shadow;

    gl_FragColor = vec4(diffuseColor, 1.0);

You can now shade a shape node like this:

    let ball = SKShapeNode(circleOfRadius: 50)
    ball.fillColor = .yellow()
    ball.strokeColor = .clear()

    ball.fillShader = SKShader(fileNamed: "shader.fsh")

..and, for your sprite node, simply set the shader property:

    ball.shader = SKShader(fileNamed: "shader.fsh")