Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon

24. maja 2017

 

Unreal Engine 4.16 was released today.  As is typical with Unreal Engine releases, this one is packed with new functionality and improved performance on mobile and console platforms.  This release adds new Volumetric Fog effects, a new lighter rigid body and cloth simulation tool.  This release also adds support for the Nintendo switch, as well as launching not just one, but two new audio engines.  Details of the new release:

 

What's New

Unreal Engine 4.16 includes exciting new rendering and animation features, significant performance improvements for mobile and console platforms, and tons of quality of life enhancements that will make it even easier to make stunning environments and engaging experiences that run smoothly on a wider variety of platforms.UE4


Enhance the mood of your environments using the amazing new Volumetric Fog feature, which can be enabled to automatically render realistic fog and smoke effects with consistent lighting anywhere in a scene, even at a large scale.


Breathe life into your characters using new dynamic lightweight rigid body and low level cloth simulation tools! Take greater control of the flow of movement using Animation Modifiers, spline IK solver, updated Pose Driver, and many other improvements to the Animation system.


Garbage Collection is now twice as fast! UI rendering performance and UMG widget creation speed are vastly improved to enable you to create even more compelling interfaces. Interfaces and workflows for VR Mode, Animation, Sequencer, and other tools have been updated to make your development process more streamlined than ever before.


Support for Nintendo Switch is fully-featured and ready for production in 4.16! Epic Games has teamed up with Nintendo to release the full UE4 source code for Nintendo Switch to approved developers for free. To learn more about how to get started, read more here.


DirectX 12 is now the default renderer for Xbox One, bringing both performance and feature enhancements to platform support in the engine. In addition, you can now develop HTML5 games using WebAssembly and WebGL 2, and this new path will continue to improve in UE4.


For mobile, the Android virtual keyboard is now supported, and runtime permissions have been exposed to both Blueprint and code. Plus, we have made even more strides to reduce executable sizes for mobile apps!

 

Check the full release notes for a great deal more information.  As always you can download the new release using the Epic Game Launcher.

GameDev News

23. maja 2017

 

Banshee is an in development C++ powered 3D game engine with an editor.  Written in modern C++14 with a comprehensive editor and supporting Vulkan rendering, Banshee3D is a project with a lot of potential. Two things impress me about Banshee3D, how fast it’s progressing and the fact it’s the work of a single guy.  He just updated on /r/gamedev the recent developments the editor has undergone.

  • Physically based renderer - About 70% complete. See link below for an early screenshot.
  • C++ framework - I plan to release the entire engine core under the MIT license. It will be usable as a pure C++ gamedev framework similar to SFML/SDL but with a larger scope.
  • Documentation enhancements - Over a HUNDRED new manuals have been added. image
  • Unified shading language - New unified shading language allows you to develop shaders that work on DirectX, OpenGL and Vulkan, while also supporting high level concepts not available in HLSL/GLSL.
  • Automatic script binding generation - Automatic code generation support for script bindings ensures C# API can now nearly transparently match the C++ API, as well as opening the door for easy addition of new scripting languages.
  • First stable release - Planned for late 2017/early 2018.

You can get a great deal more information from this blog post.  When Banshee 0.3 was released we did a hands-on walkthrough of the Banshee game engine available here and embedded in the video below.

GameDev News

18. maja 2017

 

Construct 3 release 29 was just, um... released.  This release brings 22 changes and fixes, including the App Build Service now being live.  The App Build Service enables you to create Android APK files, as well as the option to generate an XCode project for iOS deployment.  Construct 3 is a cross platform HTML5 powered 2D game engine that recently moved to run directly in the browser.  If you are new to Construct 3, we recently released this hands-on video which is also embedded below.  Right now is a great time to check out Construct 3 as it is currently available for free for a brief period of time for the C3Jam on Newgrounds.

 

Details of the r29 release

 

22 Changes

Feature

  • App Build Service is now live!

Add

  • Settings option to hide 'Add action' rows in event sheets

Change

  • Drag-dropping multiple image files now creates a single sprite with an animation like C2 does, rather than separate sprites
  • Event Sheet View: comments now preserve spaces/tabs
  • Image editor eraser tool erases single pixel at size 1 and 4 pixels at size 2 for precise editing

Bug fix

  • Added handling of storage errors, which ought to prevent crashes due to QuotaExceededError. Instead an error is shown suggesting to free up storage space.
  • Inserting new objects in a popup layout view window didn't work correctly
  • Dialogs in popup windows should now work correctly
  • Possible crash closing a popup window with a dialog open in that window
  • Double-clicking Text or SpriteFont objects in a popup window now opens the text dialog in the correct window
  • 'On function' events referring to global constant strings now trigger correctly
  • Rename family crash
  • Eraser hardness when using a size of 1 or 2
  • Image editor cut tool crashes
  • Setting of the cursor when dragging a selection in the image editor
  • Crash in the Tilemap Editor when trying to edit a tilemap in a locked layer
  • Bug causing instances to change size when adding or deleting animations or frames in the animations editor
  • Crash when opening the project bar from the main view menu while there is more than 1 active project
  • Crash when closing the image editor
  • Crash opening project that includes a layout with a partially valid name
  • Autosave not reading setting object correctly

SDK

  • Support for third-party behavior addons in the SDK

18. maja 2017

 

Version 1.2.104 of the Defold game engine was just released.  The primary new feature is the ability to do PUT and HEAD requests using the http.request object.  In addition there are a number of fixes and improvements.  The Defold game engine is a mobile focused Lua powered 2D game engine.  If you are interested in learning more, we have a complete tutorial series available here.

 

Details from the release announcement:

Engine
  • DEF-2468 - Added: http.request supports PUT and HEAD.
  • DEF-2702 - Fixed: Index out of range when spine draw order slot exceeds mesh count.
  • DEF-2692 - Fixed: Spine blending fixes for draw order animations.
  • DEF-2661 - Fixed: Reverse hashing usage in Collection factories to not impact performance.
  • DEF-2689 - Fixed: Engine crash when async loading is in progress during engine quit.
  • DEF-2566 - Fixed: GUI functions new_texture, delete_texture and set_texture_data now also accept hash.
Native Extension Server
  • Fixed so that packages/classes provided by Jar libraries can be imported in Java sources.
  • Fixed missing usage of compiler and link flags for Android builds.
Documentation
  • New Color grading post processing shader tutorial4.
  • Merged large pull request from @ross.grams containing proofread pass on all manuals.

GameDev News

17. maja 2017

 

Amazon have just released a comprehensive new starter game for their Lumberyard game engine, a fork of the AAA CryEngine.  This new example is a complete 3rd person view title with high quality production values authored by Climax Studios, the developer behind Silent Hills: Shattered Memories and the Assassin’s Creed Chronicles series of games.   This new demo game is critical, as several underlying systems in Lumberyard have changed, making this the primary example of how modern Lumberyard development is done.  Details of the release from the Lumberyard blog:

We first gave you a glimpse of Starter Game at GDC 2017, and now we’re happy to give you the entire project for free, including full source and assets. Whether it serves as inspiration for a game of your own, or as a way of learning Lumberyard’s features, Starter Game is another tool for helping you reach your game dev goals.

Watch this video on how to download and install Starter Game.

In many ways, Starter Game started with you. We heard your requests for more sample content—please keep that great feedback coming by the way!—and then looked for ways to incorporate features from 1.9. So we started working with Climax Studios, known for their great work onLY Silent Hill: Shattered Memories and the Assassin’s Creed Chronicles series. With Climax’s decades of experience, and your great suggestions, Starter Game was born.

One feature that Starter Game leverages in particular is our new Component Entity system, which was recently updated in 1.9. This system provides a modular and intuitive way of constructing game elements, helping you create complex entities faster and with minimal effort. Starter Game uses the Component Entity system wherever possible, including Player Control, AI, UI and Particles. It also shows how this new system can be used in conjunction with legacy tools and APIs (e.g. terrain brush, FlowGraph, etc.), freeing you to adopt new features as you see fit.

In addition to components, another request we got from developers was to include an example of bipedal locomotion, since humanoids are the most common form of player characters. Enter Jack: the fully modifiable, two-legged robot of Starter Game, complete with a trailing third-person camera. You can learn from Jack’s setup, tweak parameters to change the feel, and bring it into your game to accelerate your prototyping. Jack also utilizes AimIK, an inverse kinematics system to point the held-weapon appropriately at targets, without creating bespoke animations. Thanks to AimIK’s procedural generation, you won’t need to create individual animations for every single angle or posture, saving you time and effort.

 

With all of the recent changes in Lumberyard, including the launch of this new sample game, I have decided to take another hands on look at the Lumberyard game engine, available here and embedded below.

GameDev News

Month List

Popular Comments

Creating a Game on an iPad -- Building an Animation Tool in Codea Part 1
Subscribe to GameFromScratch on YouTube Support GameFromScratch on Patreon


5. November 2014

 

One of the challenges of working on the iPad only is the lack of animation and composition tools.  There are tons of art applications out there as we saw earlier, but nothing for getting them into game ready form.  So I had a bit of an idea and ran with it.

 

The basic idea is I am using iDraw to create individual body parts, which I then add to shape libraries so I can see how it will look all put together.  My game is going to be giant robots, so I can take a mix and match approach to character composition.  By building out the characters from parts, I can then create a variety of characters using minimal art.  Here is the process in iDraw:

IDrawAssembly

 

The problem is, when I export the end result into Codea, I don’t have something that I can use.  I would have to export each frame of animation for each mech combination one by one from iDraw to Codea to get an animated resulted, which ruins almost all of the benefits.

 

So, essentially, what I have to do, at least initially, is reproduce this functionality in Codea, so I can then create animations and variations without a massive increase in body parts.  So that is exactly what I did.  In a second you are going to see massive walls of code that I used to accomplish the task.  First I should make a few things clear.

 

The biggest one is, this is one of those things I am doing for fun, so most of this code was written during intermission between hockey periods, while waiting for something or while falling asleep in bed.  On the one hand, it’s really really cool that you can code at those times.  On the other hand… code quality tends to suffer a bit.

 

The next is along the same lines.  Lua is one of those languages that encourages experimentation… and a language that I haven’t used in a while.  A lot of times I got something to work and refactored later, if at all.  So if you see some things that make you aghast… that is probably why! :)  I am by no means done… at this point I’ve mostly just replicated the functioning above, I still intend to add several features before the tool is usable.  First and foremost I need to keyframe animations.  I added the controls, just no logic.  Of course I also need to save the results so they can be used in another game.  On top I want to polish the functionality by adding parenting, different control modes ( selection, parenting, positioning, animating ).  That all said, you do see the skeleton of a genuinely useful tool written entirely in Lua on an iPad.

 

This is VectorPoser

 

VectorPoser

 

The code, although rather ugly and in need of refactoring, is pretty well commented, so it should require minimal explanation… I hope.

 

Main.lua This is the application entry point.  Most of the touch logic is currently handled here, but should slowly be moved out

 

-- VectorPoser

-- welcome to the league of evil globals
imageList = nil  -- The image selector down the side of the screen
cachedWidth = WIDTH -- The original width, used to check if screen width changes
character = nil -- The character you are working on
selectedPart = nil -- The currently selected part of the character, if any
animationControl = nil -- Functionality, coming soon, stay tuned!

-- Use this function to perform your initial setup
function setup()
    local files = spriteList("Dropbox")
    local vectors = {}
    for k,v in pairs(files) do
        table.insert(vectors,readImage("Dropbox:" .. v))
    end
    
    imageList = ImageList(WIDTH-100,HEIGHT,100,HEIGHT,vectors)
    character = Character(WIDTH/2,HEIGHT/2)
    
    animationControl = AnimationControl(60,0)
end

-- This function gets called once every frame
function draw()
    
    background(40, 40, 50)
    update()  -- put all non rendered updates in a single function so we can eventually decouple
              -- updating from the rendor loop, maybe, someday, I promise. Maybe.
    
    -- This sets the line thickness in pixels I think
    strokeWidth(5)
    
    -- render our image list, which again is the list of images down the right hand side
    imageList:draw()
    
    -- now draw our VCR style animation controls
    animationControl:draw()
    
    -- clip our viewport so it wont draw in the same space as the image list
    clip(0,0,imageList:getPosition())
    
    -- now draw our character
    character:draw()
end

function touched(touch)
    -- pass along touches to all the touchables so they can be touched, duh!
    imageList:touched(touch)
    animationControl:touched(touch)

    -- TODO, spin the following code out to a function or class so we can have different 
    -- touch handling in different modes 
        
    -- Check to see if there is a currently selected part
    if selectedPart then
       -- if something is already selected, continue until touch up 
        if(touch.state == ENDED or touch.state == BEGAN) then
            -- If the touch ended or paradoxally began, unselect the active part and trigger 
            -- changed so UI updates
            selectedPart = nil
            selectedPartChanged()
        else
            -- otherwise move the selected part to the touched location
            selectedPart.x = touch.x
            selectedPart.y = touch.y
            
            -- now update so parameters get updated
            selectedPartChanged()
        end
    else
        -- There is no currently selected part, check if this touch hits an existing part
        local hits = character:getPartsAtPoint(touch.x,touch.y)

        if #hits > 0 then
            -- find the highest z value and make it selected
            -- yes, this makes touches items behind other items a pain in the ass
            for i,v in pairs(hits) do
                if selectedPart == nil then selectedPart = v
                else
                    if v.z > selectedPart.z then
                        selectedPart = z
                    end
                 end
            end
            -- Notify UI of the change
            selectedPartChanged()
        end
    end
    
    -- if you swipe the right edge right, hide the ui off the screen to the right
    -- on swipe left nring it back on screen
    -- TODO: Move logic into the ImageList
    if touch.x > WIDTH-100 then
      -- clear selection if user clicks off main area
          selectedPart = nil
        if touch.deltaX < -20 then
            --left swipe
            local x,y = imageList:getPosition()
            if x == WIDTH then
                imageList:setPosition(WIDTH-100,HEIGHT)
            end
            end
        if touch.deltaX > 20 then
                -- right swipe
                imageList:setPosition(WIDTH,HEIGHT)
        end
    else
        -- otherwise lets clear selected if touched anywhere else
        local img = imageList:getSelected()
     
        if img then
            character:addPart(VectorPart(img,touch.x,touch.y))
         end
        
        imageList:clearSelected()
    end
    

end

    
-- handle all non graphical updates on a per frame basis
function update()
    checkResize()
end

-- called when device is changed from landscape to portrait and vice versa
-- we need to resize our ImageList
function orientationChanged(orientation)
    if imageList then
        imageList:setDimensions(100,HEIGHT)
    end
end

-- there may be a better way to do this, but check for a change in size, specifically
-- due to parameters windows going away and coming back causing a resize
function checkResize()
    if cachedWidth ~= WIDTH then
        -- resize occured, handle accordingly
        cachedWidth = WIDTH
        -- TODO: This currently brings hidden panel back on screen... probably shouldn't
        imageList:setPosition(WIDTH -100,HEIGHT)
    end
end

-- when the selected part changes update params
function selectedPartChanged()
    if selectedPart == nil then
        parameter.clear()
    else
        -- z axis changed
        parameter.integer("Z order",0,20,selectedPart.z,
        function(val) selectedPart.z = val end)
        
        -- delete button, remove selected part from character
        parameter.action("Delete",function()
            character:removePart(selectedPart)
            selectedPartChanged()
        end)
        
        parameter.number("Rotation",0,360,selectedPart.rotation,
        function(val) selectedPart.rotation = val end)
    end
    
end

 

ImageList.lua This is the control down the right hand side that enables you to select images.  It handles scrolling up and down, as well as flick left to hide flick right to show.  Most of the logic is in displaying the images and mapping from touch to selected image.

-- imagelist is for displaying a number of images for selection
-- supports scrolling via long drag up and down

ImageList = class()

function ImageList:init(x,y,width,height,imgs)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.width = width
    self.height = height
    self.imgs = imgs
    self.IMAGE_HEIGHT = 100
    self.maxVisibleImages = math.floor(self.height/self.IMAGE_HEIGHT)
    self.topImageIndex = 0
    self.selected = nil
    
    self.touchDeltaY = 0
end

function ImageList:draw()
        self:_drawFrame()
        self:_drawImages()
        self:_drawSelection()
end

function ImageList:touched(touch)
    self:_touchToSelected(touch)
    if self:_isTouchInFrame(touch) then
        if touch.state == ENDED then
            self.touchDeltaY = 0
        end
        
        -- as the user swipes up or down within the imagelist track the y delta
        -- if it exceeds 50 increase or decrease the topImageIndex
        -- thus scrolling the available images
        if touch.state == MOVING then
            
            self.touchDeltaY = self.touchDeltaY + touch.deltaY
            
            if self.touchDeltaY > 50 then
                if self.topImageIndex + self.maxVisibleImages <= #self.imgs then
                    self.topImageIndex = self.topImageIndex + 1
                end
                self.touchDeltaY = 0
            end
            
            if self.touchDeltaY < -50 then
                if self.topImageIndex > 0 then
                    self.topImageIndex = self.topImageIndex - 1
                end
                self.touchDeltaY = 0
            end
        end
    end
end



    

-- draw a frame around our control
function ImageList:_drawFrame()
    strokeWidth(2)
    rectMode(CORNER)
    stroke(13, 0, 255, 255)
    line(self.x,self.y,self.x + self.width, self.y)
    line(self.x+self.width,self.y,self.x+self.width,self.y-self.height)
    line(self.x+self.width,self.y-self.height,self.x,self.y-self.height)
    line(self.x,self.y-self.height,self.x,self.y)
    
end

-- draw the visible images within our control
function ImageList:_drawImages()
    
    local currentY = 0
    for i= self.topImageIndex,self.topImageIndex+self.maxVisibleImages do
        local curImage = self.imgs[i]
        if curImage then
            local aspect = curImage.width/curImage.height
            if aspect < 1 then -- taller than wide
            sprite(curImage,self.x +self.width/2,self.y-currentY-self.IMAGE_HEIGHT/2,self.width * aspect
,self.IMAGE_HEIGHT) else -- when its wider than tall, shrink it proportionally local newHeight = self.IMAGE_HEIGHT * aspect - self.IMAGE_HEIGHT sprite(curImage,self.x +self.width/2,self.y -currentY-self.IMAGE_HEIGHT/2,self.width,
newHeight) end currentY = currentY + self.IMAGE_HEIGHT end end end -- draw a line above and below selected image function ImageList:_drawSelection() if self.selected then rectMode(CORNER) strokeWidth(2) stroke(255, 16, 0, 255) local x = self.x local y = self.y - (self.selected -1)* self.IMAGE_HEIGHT fill(255, 4, 0, 255) line(x+5,y,x+self.width-5,y) line(x+ 5,y-self.IMAGE_HEIGHT,x + self.width-5, y-self.IMAGE_HEIGHT) end end -- convert to local coordinates and figure out which item is selected at touch position function ImageList:_touchToSelected(touch) -- convert touch relative to top left of screen if self:_isTouchInFrame(touch) then -- local localX = touch.x - self.x local localY = self.y - touch.y local offset =math.ceil(localY/self.IMAGE_HEIGHT) if offset <= #self.imgs then self.selected = offset else -- self.selected = nil end end end -- check if touch within the bounds of our control function ImageList:_isTouchInFrame(touch) if touch.x >= self.x and touch.x <= self.x + self.width and touch.y <= self.y and touch.y >= self.y - self.height then return true end return false end function ImageList:setPosition(x,y) self.x = x self.y = y end -- handle resize, mostly for orrientation change function ImageList:setDimensions(width,height) self.width = width self.height = height self.maxVisibleImages = math.floor(self.height/self.IMAGE_HEIGHT) end function ImageList:getPosition() return self.x,self.y end -- gets the index into the img array of the selected image function ImageList:getSelectedIndex() if self.selected then -- hack for foggy brain -- if self.topImageIndex > 1 then self.topImageIndex = self.topImageIndex - 1 end return self.selected + self.topImageIndex end return nil end function ImageList:clearSelected() self.selected = nil end -- gets the actual image function ImageList:getSelected() return self.imgs[self:getSelectedIndex()] end

 

Character.lua -- This holds the character we are creating. Mostly just a collection of VectorPart now, but more functionality will be coming in the future

-- a character is composed of several VectorParts.
-- this will ultimately be the class you use to control everything as a single entity
-- AKA, the end result

Character = class()

function Character:init(x,y)
    -- you can accept and set parameters here
    self.x = x
    self.y = y
    self.parts = {}
end

function Character:draw()
    -- order drawing by z order
        function comp(a,b)
            if a.z < b.z then return true end
            return false
        end

    table.sort(self.parts,comp)
    
    for i,v in ipairs(self.parts) do
        v:draw()
    end
end

function Character:touched(touch)
end

function Character:addPart(part)
     part.z = #self.parts +1 -- z order equal order added initially
    table.insert(self.parts,part)
end

function Character:removePart(part)
    if(part) then
        table.remove(self.parts,part.curIndex)
    end
end

function Character:getPartsAtPoint(x,y)
    local results = {}
    for i,v in pairs(self.parts) do
        if x >= v.x - v.img.width/2 and x <= v.x + v.img.width/2 and
            y >= v.y - v.img.height/2 and y <= v.y + v.img.height/2 then
            v.curIndex = i
            table.insert(results,v)
        end
    end
    return results
end

function Character:getParts()
    return self.parts
end

 

VectorPart.lua -- These are the individual parts, right now it's just the image, x,y and rotational data, but in the future it will have pivot and parenting information. Keyframe data will essentially be a snapshot of these values per animation frame

-- A vector part is simply the vector img, plus positional and rotation data
-- will be adding parenting information

VectorPart = class()

function VectorPart:init(img,x,y,z)
    -- you can accept and set parameters here
    self.img = img
    self.x = x
    self.y = y
    self.z = z
    self.rotation = 0
    self.curIndex = nil
end

function VectorPart:draw()
    pushMatrix()
    translate(self.x,self.y)
    rotate(self.rotation)
    sprite(self.img,0,0)
    popMatrix()
end

function VectorPart:touched(touch)
end

 

AnimationControl.lua -- This is a VCR style keyframe animation control, mostly just a placeholder for now

AnimationControl = class()


function AnimationControl:init(x,y)
    self.x = x
    self.y = y
    
    self.buttonFirst = IconButton("First",x+0,y+0,64,64,"Documents:IconFirst","","")
    self.buttonFirst.callback = _firstButtonPressed
    
    self.buttonPrevious = IconButton("Previous",x+66,y+0,64,64,"Documents:IconPrevious","","")
    self.buttonPrevious.callback = _previousButtonPressed
    
    self.buttonPlay = IconButton("Play",x+66*2,0,64,64,"Documents:IconPlay","","")
    self.buttonPlay.callback = _playButtonPressed
    
    self.buttonNext = IconButton("Next",x+66*3,y+0,64,64,"Documents:IconNext","","")
    self.buttonNext.callback = _nextButtonPressed
    
    self.buttonLast = IconButton("Last",x+66*4,y+0,64,64,"Documents:IconLast","","")
    self.buttonLast.callback = _lastButtonPressed
    
    
end

function AnimationControl:draw()
    self.buttonFirst:draw()
    self.buttonPrevious:draw()
    self.buttonPlay:draw()
    self.buttonNext:draw()
    self.buttonLast:draw()
end

function AnimationControl:touched(touch)
    -- Codea does not automatically call this method
    self.buttonFirst:touched(touch)
    self.buttonPrevious:touched(touch)
    self.buttonPlay:touched(touch)
    self.buttonNext:touched(touch)
    self.buttonLast:touched(touch)
    
    
end

function _firstButtonPressed()
    
end
function _previousButtonPressed()
    print"fhdhdj"
end
function _playButtonPressed()
    
end
function _nextButtonPressed()
    
end
function _lastButtonPressed()
    
end

 

Finally I used a library called Cider for the UI controls. You can get Cider here. I used the IconButton class, but it didn't have callback support, so I hacked it in like so:

--# IconButton
IconButton = class(Control)

-- IconButton 
-- ver. 7.0
-- a simple control that centers an image in a frame
-- ====================

function IconButton:init(s, x, y, w, h, img, topText, bottomText)
    Control.init(self, s, x, y, w, h)
    self.controlName = "IconButton"
    self.background = color(255, 255, 255, 255)
    self.font = "HelveticaNeue-UltraLight"
    self.fontSize = 32
    self.img = img
    self.text = s
    self.topText = topText
    self.bottomText = bottomText
    self.textAlign = CENTER
    self.smallFontSize = 12
end

function IconButton:draw()
    local h, w
    w, h = textSize(self.text)
    pushStyle()
    fill(self.foreground)
    stroke(self.foreground)
    self:roundRect(4)
    fill(self.background)
    stroke(self.background)
    self:inset(1,1)
    self:roundRect(4)
    self:inset(-1,-1)
    font(self.font)
    fontSize(self. smallFontSize)
    textMode(CENTER)
    textAlign(CENTER)
    smooth()
    w, h = textSize(self.topText)
    fill(self.textColor)
    text(self.topText, self:midX(), self:top() - h / 2 - 4)
    if self.bottomText then
        text(self.bottomText, self:midX(), self:bottom() + h/2 + 4)
    end
    if self.img == nil then
        fontSize(self.fontSize)
        text(self.text, self:midX(), self:midY())
    else
        sprite(self.img, self:midX(), self:midY())
    end
    
    popStyle()
end

function IconButton:initString(ctlName)
    return "IconButton('"..self.text.."', " ..
        self.x..", "..self.y..", "..
        self.w..", "..self.h..", '"..
        self.img .. "', '"..
        self.topText .. "', '"..
        self.bottomText .. "', '"..
        "')"
end

-- added by mjf... not sure why there wasnt a touch handler on this control
function IconButton:touched(touch)
        if self:ptIn(touch) then
            if touch.state == ENDED then
                if self.callback ~= nil then self.callback() end
                return true
            end
        end
end

 

There is some bugginess around the selectedPart handling that leads to the occasional crash, and I am on occasion crashing Codea if I use lots of images, but for the most parts, it's the skeleton of a downright usable tool. It's never going to compete with the likes of Spline or Spriter, but it should suffice for making game ready models and animations from sprite and vector graphics and at the end of the day, that's all I need. Stay tuned for an update sometime in the future.

Programming

blog comments powered by Disqus

Month List

Popular Comments