Posted: 3rd Nov 2021 23:48
I wish to create a simple solid circle using a sprite.

+ Code Snippet
SetWindowSize( 100, 100, 0 )

CreateSprite(1,0)
SetSpritePosition(1,20,20)
SetSpriteShape(1,1) // circle
SetSpriteColor(1,255,0,0,255) // red

CreateSprite(2,0)
SetSpritePosition(2,20,40)
SetSpriteShapeCircle(2, 20, 20, 20) // circle
SetSpriteColor(2,0,255,0,255) // green

sync()
do
loop


Instead of circles I get squares.

They do look nice, but I really want circles.

https://www.appgamekit.com/documentation/Reference/Sprite/SetSpriteShape.htm does state:
This function will not work on dummy sprites as there is no image to use when calculating a shape, in these cases shapes must be specified manually using SetSpriteShapeBox, SetSpriteShapeCircle, or SetSpriteShapePolygon.


This is why the second attempt in the sample code tries that approach.

I am aware of DrawEllipse() but I want to change colors and set position and visibility later.
Posted: 4th Nov 2021 0:43
The shape there is referring to the collision shape not the visual image of the sprite so, if using native commands only, u'll need to (also) draw a (white) ellipse/circle, GetImage(), then assign that image to the sprite via SetSpriteImage(). u can later SetSpriteColor(), Position() or alter it in any way that u want.

Ur code is using image 0 (basically a 10x10 px (white) image scaled to whatever u SetSpriteSize() to) while setting the collision shape to a circle. If u keep ur code as-is and SetPhysicsDebugOn(), u'll see the circle (collision) shape.
Posted: 4th Nov 2021 2:31
Found this by searching

+ Code Snippet
setVirtualResolution(640,480)


dim circles[100]

t = getMilliseconds()
for i = 1 to 100
    circles[i] = createSprite(getImageCircle(random(8,128), 255,255,255))
    r = random(0, 255)
    g = random(0, 255)
    b = random(0, 255)
    setSpriteColor(circles[i], r, g, b, 255)
    setSpritePosition(circles[i], random(0,640), random(0,480))
next i
t = getMilliseconds() - t



do


    if getrawkeypressed(32) = 1
        for i = 1 to 100
            r = random(0, 255)
            g = random(0, 255)
            b = random(0, 255)
            setSpriteColor(circles[i], r, g, b, 255)
            setSpritePosition(circles[i], random(0,704)-64, random(0,544)-64)
        next i
    endif


    print(t)
    sync()
loop





function getImageCircle(radius, red, green, blue)
    mem = 1
    diameter = radius+radius
    memSize = diameter*diameter*4 + 12
    createMemblock(mem, memSize)

    // 12-byte Header
    setMemblockInt(mem, 0, diameter)
    setMemblockInt(mem, 4, diameter)
    setMemblockInt(mem, 8, 32)

    //Color value
    base  = (blue*65536) + (green*256) + red
    color = (255*16777216) + base

    // Unfortunately, we have to fill the entire image
    // to prevent random artifacts from showing up.
    for y = 0 to diameter-1
        for x = 0 to diameter-1
            pos = (y*diameter + x)*4 + 12
            setMemblockInt(mem, pos, 0)
        next x
    next y


    cx = radius-1
    cy = radius-1
    x  = radius-1
    y  = -1
    t# = 0

    while x > y
        inc y
        cur_dist# = E2DC_Distance#(radius, y)
        if cur_dist# <= t# then dec x

        a = 127*cur_dist# : alpha1 = (a*16777216) + base
        a = 127 - a       : alpha2 = (a*16777216) + base

        // octant 1
        E2DC_MemDot(mem, cx-y, cy-x,   color)
        E2DC_MemDot(mem, cx-y, cy-x-1, alpha2)
        E2DC_MemDot(mem, cx-y, cy-x+1, alpha1)
        // octant 2
        E2DC_MemDot(mem, cx-x,   cy-y, color)
        E2DC_MemDot(mem, cx-x-1, cy-y, alpha2)
        E2DC_MemDot(mem, cx-x+1, cy-y, alpha1)
        // octant 3
        E2DC_MemDot(mem, cx-x,   cy+y, color)
        E2DC_MemDot(mem, cx-x-1, cy+y, alpha2)
        E2DC_MemDot(mem, cx-x+1, cy+y, alpha1)
        // octant 4
        E2DC_MemDot(mem, cx-y, cy+x,   color)
        E2DC_MemDot(mem, cx-y, cy+x+1, alpha2)
        E2DC_MemDot(mem, cx-y, cy+x-1, alpha1)
        // octant 5
        E2DC_MemDot(mem, cx+y, cy+x,   color)
        E2DC_MemDot(mem, cx+y, cy+x+1, alpha2)
        E2DC_MemDot(mem, cx+y, cy+x-1, alpha1)
        // octant 6
        E2DC_MemDot(mem, cx+x,   cy+y, color)
        E2DC_MemDot(mem, cx+x+1, cy+y, alpha2)
        E2DC_MemDot(mem, cx+x-1, cy+y, alpha1)
        // octant 7
        E2DC_MemDot(mem, cx+x, cy-y,   color)
        E2DC_MemDot(mem, cx+x+1, cy-y, alpha2)
        E2DC_MemDot(mem, cx+x-1, cy-y, alpha1)
        // octant 8
        E2DC_MemDot(mem, cx+y, cy-x,   color)
        E2DC_MemDot(mem, cx+y, cy-x-1, alpha2)
        E2DC_MemDot(mem, cx+y, cy-x+1, alpha1)


        t# = cur_dist#
    endwhile

    img = createImageFromMemblock(mem)
    deleteMemblock(mem)
endfunction img



function E2DC_MemDot(id, x, y, color)
    width  = getMemblockInt(id, 0)
    pos = (y*width + x)*4 + 12
    setMemblockInt(id, pos, color)
endfunction



function E2DC_Distance#(a, b)
    real# = sqrt(a*a - b*b)
    d# = ceil(real#) - real#
endfunction d#
Posted: 4th Nov 2021 19:28
Technically there's little limit on how many octants (i guess the name would change) you can turn a circle into since it's such a uniform shape. 8 seemed efficient. The 3 pixels it writes at each octant is to take anti-aliasing into consideration.

When the memblock space is allocated, there's no guarantee what value each byte will have. So unlike DBP which would initialize each byte with 0 in the allocation, AppGameKit does not and therefore a 0 needs to be written all unused pixels.

Since the function writes 0s to the entire block before drawing the circle, a lot of bytes are written twice so there is room to improve efficiency. If anyone couldn't guess, I wrote that snippet :p
Posted: 4th Nov 2021 21:08
If anyone couldn't guess, I wrote that snippet


I was not sure if you wanted me to say anything lol.

It would be better and faster just to create a circle sprite out side of the program then clone sprite and change its size.
Posted: 5th Nov 2021 1:19
The shape there is referring to the collision shape not the visual image of the sprite

ah yes thanks, that makes sense.
I noticed that adding shapes were for collision shapes but glossed over that detail when I read the SetShape stuff.

Some interesting solutions to explore and in doing so I ran into the fact that the AppGameKit color definitions space is what what I thought it was. I was surprised that MakeColor() returns negative values!

I may revert back to DrawEllipse() in the main loop, I can simply keep the color needed in a global, and change that as needed and let it draw in every iteration of the sync() loop.

Thanks all.
Posted: 5th Nov 2021 17:33
I was surprised that MakeColor() returns negative values!


That's weird, it shouldn't. But you're right, I just tested it. It must store in a signed integer. All white (255,255,255) gives me -1 and they numbers only decrease from there. Black gives me -16777216
Posted: 5th Nov 2021 19:11
Tier 1 doesn't have unsigned integers. MakeColor returns negative due to the alpha value, which defaults to 255. The value is AARRGGBB in hex. so white = 0xFFFFFFFF and black = 0xFF000000.

I would think that creating a transparent image from a memblock and rendering a circle to it with DrawEllipse would be pretty quick.
Posted: 5th Nov 2021 19:19
@Phaelax: Looks like AppGameKit *does* zero out a memblock during CreateMemblock, despite what the docs say.

https://raw.githubusercontent.com/TheGameCreators/AGKTier2/master/common/Source/Wrapper.cpp

+ Code Snippet
void agk::CreateMemblock( UINT memID, UINT size )
//****
{
<code snipped>
	cMemblock *pMem = new cMemblock();
	pMem->m_iID = memID;
	pMem->m_iSize = size;
	pMem->m_pData = new unsigned char[ size ];
	for ( UINT i = 0; i < size; i++ ) pMem->m_pData[ i ] = 0;		  // looks like this 0's our the data.
	m_cMemblockList.AddItem( pMem, memID );
}
Posted: 5th Nov 2021 21:29
That's weird, it shouldn't.


Does it say somewhere that they should be positive?

Tier 1 doesn't have unsigned integers. MakeColor returns negative due to the alpha value, which defaults to 255. The value is AARRGGBB in hex. so white = 0xFFFFFFFF and black = 0xFF000000.

Intersting! So If Alpha is < 255 are they positive?

I would think that creating a transparent image from a memblock and rendering a circle to it with DrawEllipse would be pretty quick.


But why would one need to do that? DrawEllipse() does work (with colors etc.) all by itself with a single call.
Posted: 5th Nov 2021 22:59
Intersting! So If Alpha is < 255 are they positive?

No, the alpha would have to be 0x7f or less. 0x80 and higher has the sign bit set for negative integers.

But why would one need to do that? DrawEllipse() does work (with colors etc.) all by itself with a single call.

If one only wants to draw the circle, yes. I had assumed that it was to be used with a sprite, perhaps for physics or something. Just to render, yeah, the image isn't needed.
Posted: 8th Nov 2021 15:46
@Phaelax: Looks like AppGameKit *does* zero out a memblock during CreateMemblock, despite what the docs say.


AGK was still fairly new when I wrote that, it's possible it could have changed in an update. Or maybe I just did it to be safe, I can't remember that far back.