Text Drop Shadow

here is an old link from  " That’s So Panda " ,  that might be helpful to you

http://thatssopanda.com/corona-sdk-tutorials/adding-drop-shadow-to-text-objects/

here is an old link from  " That’s So Panda " ,  that might be helpful to you

http://thatssopanda.com/corona-sdk-tutorials/adding-drop-shadow-to-text-objects/

The cool thing about the two copies of the text is you can now apply a blur filter to the drop shadow to get softer shadows.

I made a drop text shadow function a while back, it’s not perfect but it allows you to offset the x/y position of the shadow among other things. The only “catch” is that it returns a single group containing both objects (for easy repositioning later), so if you want to update the string you need to call the :setText function I’ve included:

function display.newShadowText(params) local group = display.newGroup() local parent = params.parent or nil--display group to insert the text into local txt = params.text or ""--the string to display local width = params.width or 0--width of the textbox, 0 for unlimited local height = params.height or 0--height of the textbox, 0 for unlimited local x = params.x or 0--x position local y = params.y or 0--y position local font = params.font or native.systemFont--font name local fontSize = params.fontSize or 50--font size local align = params.align or "left"--alignment left/right/center local shadowColor = params.shadowColor or {0, 0, 0, 0.4}--colour of the drop shadow local textColor = params.textColor or {1}--colour of the main text local xOffset = params.xOffset or 0--how much to offset the dropshadow's x position relative to the main text object local yOffset = params.yOffset or -fontSize / 15 --same for the y position local shadowOff = params.shadowOff or false --if you don't want to show a shadow local anchorX = params.anchorX or 0.5 --anchor points local anchorY = params.anchorY or 0.5 --offset text on OS as needed, since some fonts get displayed differently on different OS if system.getInfo("platformName") == "iPhone OS" then --y = y + 5 elseif system.getInfo("platformName") == "Android" then --y = y + 5 end local s = display.newText({ text = txt, width = width, height = height, x = 0, y = 0, font = font, align = align, fontSize = fontSize, }) s:setFillColor( unpack(shadowColor) ) group:insert(s) local t = display.newText({ text = txt, width = width, height = height, x = xOffset, y = yOffset, font = font, align = align, fontSize = fontSize, }) t:setFillColor( unpack(textColor) ) group:insert(t) group.x, group.y = x + (group.width \* 0.5) - (group.width \* anchorX), y + (group.height \* 0.5) - (group.height \* anchorY) group.s = s group.t = t if shadowOff then s.isVisible = false end if parent then parent:insert(group) end function group:setText(str, shouldMove) self.s.text = str self.t.text = str if shouldMove == true or shouldMove == nil then group.x, group.y = x + (group.width \* 0.5) - (group.width \* anchorX), y + (group.height \* 0.5) - (group.height \* anchorY) end end function group:getText() return self.t.text end function group:setShadowColor(...) if arg then if type(arg[1]) == "table" then self.s:setFillColor( unpack(arg[1]) ) elseif type(arg[1]) == "number" then self.s:setFillColor( unpack(arg) ) end end end function group:setFillColor(...) if arg then if type(arg[1]) == "table" then self.t:setFillColor( unpack(arg[1]) ) elseif type(arg[1]) == "number" then self.t:setFillColor( unpack(arg) ) end end end return group end

It takes a table of parameters as it’s only argument. The params all have defaults so you only need to set the ones that you need to customise.

Here’s a sample of it in use:

local myGroup = display.newGroup() local bg = display.newRect(myGroup, display.contentWidth \* 0.5, display.contentHeight \* 0.5, display.contentWidth, display.contentHeight) bg:setFillColor(0.8, 0.8, 1) local myText = display.newShadowText({ parent = myGroup, text = "show this string with a shadow please", width = display.contentWidth \* 0.5, height = 0, x = display.contentWidth \* 0.5, y = display.contentHeight \* 0.5, font = "someFontName", align = "center", fontSize = 75, xOffset = 0, yOffset = -5, anchorX = 0.5, shadowColor = {0, 0, 0, 0.8} }) local strings = { "hello", "world", "foo", "bar" } local function update() --can pass in a table or just numbers --myText:setFillColor( {math.random(), math.random(), math.random()} ) myText:setFillColor( math.random(), math.random(), math.random() ) --update the text myText:setText(strings[math.random(1, #strings)]) end timer.performWithDelay( 1000, update, -1 )

I was thinking about doing a tutorial on drop shadows or writing up a simple function for it. But I started thinking about the problem of not being able to simply update .text and there is a solution to it. See this tutorial:

https://coronalabs.com/blog/2012/05/01/tutorial-property-callbacks/

Basically you can use a feature of meta tables that lets you set properties like:

myDropText.text = “Hello World”

and it actually triggers a call back function in your object that will take that value and you can use it to update the front text and shadow text.

Rob

Good shout Rob. I made my function a few years ago before I knew anything about meta tables/methods, this way is much simpler (well once you’ve set it up it is).

I’ve hit a small snag though, I’ve tried converting my method to use property callbacks, but in the process this has stopped working (where “parent” is a display group):

local group = display.newGroup() group = proxy.get\_proxy\_for( group ) if parent then parent:insert(group) --this is now broken end

Is there something I’ve forgotten that would cause the proxy to stop insert from working. The error is:

bad argument #-2 to 'insert' (Proxy expected, got nil)

I think, based on a very quick glance, that you’d have to call as “parent:insert(group.raw)” given the way that proxy is written.

aside:  the proxy approach is useful when you just need to intercept getters/setters (for example, doing custom things on a display object in response to a transition call) but will fail if you also need to still pass an “isA/instanceOf” -type test.  that is, your “group” no longer IS A display object, instead it’s the proxy wrapper – whereas “group.raw” IS A display object.

even further aside: there’s another somewhat similar approach of metatable chaining that can preserve the isA() original object yet still allow you to intercept getters/setters like a proxy, but it’s a bit much to cover in a forum post, mentioned only for completeness.