Help with shadow block

So, I was making a block for image shadow but if you type a input higher than 90, the code crops the image and still scale the sprite size.
Here’s the code:

   //% block="shadow $img|with color: $c|length: $leng|rotation: $rot"
    //% c.shadow="colorindexpicker"
    //% inlineInputMode=inline
    //% subcategory="Image"
    //% img.shadow="screen_image_picker"
    //% subcategory="Image"
    export function shadow(img: Image, c: number, leng: number, rot: number) {
        let picture = image.create(image.getDimension(img, image.Dimension.Width) + (leng + 1), image.getDimension(img, image.Dimension.Height) + (leng + 1))
        let clone = img.clone()
    for (let index = 0; index <= leng; index++) {
        picture.drawTransparentImage(CyberScripts.OneColorImage(img, c), index * Math.sin(rot * (Math.PI / 180)), index * Math.cos(rot * (Math.PI / 180)))
    }
    picture.drawTransparentImage(clone, 0, 0)
    return picture
    }

2 Likes

Im afraid i can only really help if its in blocks, i am bad at JavaScript…

1 Like

you have:
//% subcategory=“Image”
in there twice

but other than that idk

1 Like

Im not sure. I tried this:

    //% block="shadow $img|with color: $c|length: $leng|rotation: $rot"
    //% c.shadow="colorindexpicker"
    //% inlineInputMode=inline
    //% subcategory="Image"
    //% img.shadow="screen_image_picker"
    export function shadow(img: Image, c: number, size: number, rot: number) {
        rot = ((rot % 360) + 360) % 360
        const r = Math.PI * (rot / 180)
        const sin = Math.sin(r), cos = Math.cos(r)

        const picture = image.create(
            img.width + Math.abs(sin * size) | 0,
            img.height + Math.abs(cos * size) | 0
        )

        const im = OneColorImage(img, c)

        let stepX = sin, stepY = cos
        for (let i = 0; i < size; i++) {
            picture.drawTransparentImage(im, stepX | 0, stepY | 0)
            stepX += sin
            stepY += cos
        }

        const index = (rot / 90) | 0
        const offsetX = picture.width - img.width
        const offsetY = picture.height - img.height

        const xPos = [0, 0, offsetX, offsetX][index] || 0
        const yPos = [offsetY, 0, 0, offsetY][index] || 0

        picture.drawTransparentImage(img, xPos, yPos)
        return picture
    }

but it didn’t look right (when I used it).

asked Gemini, this works:

function OneColorImage(src: Image, color: number): Image {
    const result = src.clone()
    for (let c = 1; c <= 15; c++) result.replace(c, color)
    return result
}

// vvv FUNCTION HERE vvv 
function createDropShadow(img: Image, color: number, offset: number, angleDeg: number): Image {
    if (offset <= 0) return img.clone()

    const rad = (angleDeg * Math.PI) / 180
    const totalShiftX = Math.cos(rad) * offset
    const totalShiftY = Math.sin(rad) * offset

    const padX = Math.ceil(Math.abs(totalShiftX))
    const padY = Math.ceil(Math.abs(totalShiftY))

    const canvas = image.create(
        img.width + padX,
        img.height + padY
    )

    // Calculate original image offset so it stays in bounds
    const origX = totalShiftX < 0 ? padX : 0
    const origY = totalShiftY < 0 ? padY : 0

    const shadowImg = OneColorImage(img, color)

    // Interpolate shadow steps outwards from original image position
    for (let i = 1; i <= offset; i++) {
        const stepX = origX + (totalShiftX * (i / offset))
        const stepY = origY + (totalShiftY * (i / offset))
        canvas.drawTransparentImage(shadowImg, Math.round(stepX), Math.round(stepY))
    }

    // Draw the source image on top
    canvas.drawTransparentImage(img, origX, origY)
    return canvas
}
// ^^^ FUNCTION HERE ^^^

const sourceImage = assets.image`pizza with hole`

let shadowDistance = 0
let shadowAngle = 45
let cachedRender: Image = sourceImage
let needsUpdate = true

controller.A.onEvent(ControllerButtonEvent.Pressed, function () {
    shadowDistance++
    needsUpdate = true
})

controller.B.onEvent(ControllerButtonEvent.Pressed, function () {
    shadowDistance = Math.max(shadowDistance - 1, 0)
    needsUpdate = true
})

game.onUpdate(function () {
    if (controller.left.isPressed()) {
        shadowAngle -= 2
        needsUpdate = true
    }
    if (controller.right.isPressed()) {
        shadowAngle += 2
        needsUpdate = true
    }

    if (needsUpdate) {
        cachedRender = createDropShadow(sourceImage, 4, shadowDistance, shadowAngle)
        needsUpdate = false
    }
})

game.onPaint(function () {
    const drawX = 80 - (cachedRender.width >> 1)
    const drawY = 60 - (cachedRender.height >> 1)
    screen.drawTransparentImage(cachedRender, drawX, drawY)
})

but i want to be assessable to all images

what do you mean? I’m not understanding.

i want to be used to all images

do you mean make your own images? You should need to change the //% lines a little, but this works fine:

(they are in a DELEYE.ts file)

it dident work with multiple colors