Jump to content
  • Advertisement
  • entries
    151
  • comments
    8
  • views
    6929

About this blog

Announcements, stories and industry interest posts for users of Corona, the 2D game engine from Corona Labs.

Entries in this blog

 

Corona now supports Dark Mode

Apple recently added support for Dark Mode. Dark Mode first appeared in macOS Mojave and continues with macOS Catalina. On iOS Dark Mode first appeared in iOS 13. Even tvOS supports it! Dark Mode is a popular feature because many people prefer light text on a dark background and there is evidence that it’s more energy friendly as well. Android supports “Dark Theme” starting with Android 10. Corona now supports this across all supported platforms as well. Starting with daily build 2019.3545 , Corona now recognizes Dark Mode automatically and updates native.newTextField() and native.newTextBox() objects to work with the selected mode. In addition, system.getInfo(“darkMode”) will return a true or false value, so you can now theme your app to the mode selected. local darkMode = system.getInfo("darkMode") On Apple based builds, you can force your your app into “light” mode by adding an entry into the plist: settings = { iphone = { plist = { UIUserInterfaceStyle = "Light", } } } Please note, “Light” is case sensitive and must be capitalized. This works on older Corona builds and if you don’t want to update to the latest daily build, this is a way to keep the native text objects themed with your current app.
View the full article

CoronaRob

CoronaRob

 

App Sign In for your Corona apps

Thanks to master plugin creator, Scott Harrison for this guest post on using Google and Apple Sign-In in your apps. Many apps and games have there own login system. Whether you need a login for storing data, sharing, or multiplayer, setting up a login system is an important part of your app. While an email and password system is usually what most apps use, you should consider looking at using a third-party login system. Third-party systems allow the user to log in in faster and save the user from having to make another password. This tutorial will show you how to integrate both Google and Apple sign in. Google Sign In Start of by going to Corona Labs Marketplace and activate the Google Sign In Plugin. Next you need to get a client ID for Android and iOS. Go to Google console and enable “Identity Toolkit API”. Next create client id in Credentials section. Setup a client ID for iOS and Web (which is used for Android).

Also make sure to add to put your iOS URL scheme inside you build.settings
settings = { android = { useGoogleServicesJson = true, usesPermissions = { "android.permission.INTERNET" }, }, iphone = { plist = { CFBundleURLTypes = { { CFBundleURLSchemes = { "com.googleusercontent.apps.REPLACE_WITH_YOUR_URL_SCHEME", } } }, }, }, plugins = { ["plugin.firestore"] = { publisherId = "tech.scotth", }, }, } Note: if you are using Firebase, just grab the iOS client ID from the GoogleService-Info.plist file under CLIENT_ID key and for Android go to google-services.json under the keys client >oauth_client>client_id, Next use the code snippet below to insert the client id based on the platform you are using. local googleSignIn = require( "plugin.googleSignIn" ) local json = require( "json" ) googleSignIn.init() local androidClientID = "Your Android client id" local clientID = "Your iOS client id" -- iOS default if ( system.getInfo( "platform" ) == "android" ) then clientID = androidClientID end googleSignIn.signIn( clientID, nil, nil, function ( event ) print( json.encode( event ) ) end ) Read more about the Google Sign In Plugin in the documentation. Apple Sign In Apple introduced a new way to sign in on iOS 13+. They are requiring app makers to add Apple Sign In if they use other third-party sign in options like Google or Facebook. It is easy for developers to implement Apple Sign In for iOS devices. To set up all you need to do is start by activating the free Apple Sign In Plugin in the Corona Marketplace. Make sure your App ID is setup with the Apple Sign In entitlement. This will require you to generate and download a new provisioning profile after adding the entitlement.
Add Apple Sign In entitlements to build.settings iphone = { plist = { -- put entitlements outside plist }, entitlements = { ["com.apple.developer.applesignin"] = {"Default"}, } }, plugins = { ["plugin.appleSignIn"] = { publisherId = "tech.scotth", }, }, Then just use the Apple Sign In plugin in your app to login on your iOS 13+ device local appleSignIn = require( "plugin.appleSignIn" ) local json = require( "json" ) appleSignIn.show( "name", function( event ) print( json.encode( event ) ) end ) Note: The first value in appleSignIn.show() can either be “name“, which will get the name of the user, “email“, will get the email of the user, or “nameAndEmail“, which will get the email and name. Read more about the Apple Sign In Plugin in the documentation.
View the full article

CoronaRob

CoronaRob

 

A simple progressView for Corona

One of the things that makes Corona great is that we offer over 1,000 API calls to make your life as a developer easier. This includes various convenience APIs that make our simple-to-use APIs even simpler. However, sometimes those convenience methods can be less of a convenience and more of a headache when you try to use them beyond what they were designed for. Let’s examine the widget.* library as an example. The widget.* library contains API’s to create buttons, switches, tableViews and more, but they were created with the intention of emulating the look and feel of iOS and Android UI elements. Corona Labs eventually added options to alter their look so they could be themed to fit your game or app better. The problem is trying to theme these widgets can be more complex than building a custom widget on your own. One of these widgets is the widget.newProgressView. In its simplest setup, the widget.newProgressView is quite simple: local widget = require( "widget" ) local progressView = widget.newProgressView({ left = 50, top = 100, width = 220, isAnimated = true }) progressView:setProgress( 0.5 ) And you get:
when the progress is set to 50%. It’s a simple iOS-like progressView. If you change the widget theme to Android, it will be more familiar to native Android apps. But what if you want to do something that fits your app better? Well you can use image sheets to do that. Let’s look at the code first: local options = { width = 64, height = 64, numFrames = 6, sheetContentWidth = 384, sheetContentHeight = 64 } local progressSheet = graphics.newImageSheet( "widget-progress-view.png", options ) local progressView = widget.newProgressView({ sheet = progressSheet, fillOuterLeftFrame = 1, fillOuterMiddleFrame = 2, fillOuterRightFrame = 3, fillOuterWidth = 64, fillOuterHeight = 64, fillInnerLeftFrame = 4, fillInnerMiddleFrame = 5, fillInnerRightFrame = 6, fillWidth = 64, fillHeight = 64, left = 50, top = 200, width = 220, isAnimated = true }) progressView:setProgress( 0.5 ) There is a lot more you have to do to set it up code wise, but in addition you have to provide an image sheet that has to be specially constructed. It’s a six frame, 64px X 64px per frame image, where you have an outer frame and an inner fill. Frames 1 & 3 represent the end-caps of the outer frame, frames 4 & 6 represent the fill of the end caps. Frame 2 is the outer frame that’s stretched to fill the size you’ve set (width = 220 above) and frame 5 is the actual progress image that will be stretched to the percentages the view is set to. Even with this, it’s limited. This image sheet (ignore the background colors, they are there just to show you each frame):

will result in a progressView that looks like:
That frame and fill may not be what you want. What if you want to have something like a red to yellow to green gradient and perhaps have a pointer that shows where in the red to green range you are? Well you can’t really do that with this widget. Why? Because the middle frames stretch to the width and then the end caps are added. But you can do this with one image and one display.newRect() if you don’t mind rectangles, or a third image to act as a mask if you want rounded corners. Let’s look at an example that will give you that gradient “temperature gauge”. Starting with this image and mask:
and:
The image will be the background of our progressView and the mask will be used to give it rounded corners. We will also use a display.newRect() and fill it with a navy blue color that will block out the percentage of the gradient that hasn’t been reached yet. At 75% progress we should have something that looks like: The code for this is quite simple. Let’s make a function to create a new gradient progressView and also create a method to set the percentage. local function customProgressView(percent) local thisProgressView = display.newGroup() thisProgressView.backgound = display.newImageRect(thisProgressView, "pvBackground.png", 200, 40) local mask = graphics.newMask("pvMask.png") thisProgressView:setMask(mask) thisProgressView.progress = display.newRect(thisProgressView, 100, 0, 200, 40) thisProgressView.progress:setFillColor(0,0.25, 0.5) thisProgressView.progress.anchorX = 1 thisProgressView.progress.width = 200 - (percent * 200) function thisProgressView:setProgress( percent ) self.progress.width = 200 - (percent * 200) end return thisProgressView end local progressView3 = customProgressView(0) progressView3:setProgress( 0.75 ) progressView3.x = display.contentCenterX progressView3.y = 350 Start by creating a display.newGroup() to hold the progressView. This will not only serve as a single display object that we can easily position, but also act as a table to hold the three display objects and the function to set the percentage. The function will return a handle to the display.newGroup() that you will manipulate in your code. Next set the background image using a display.newImageRect() to load our gradient background image. This tutorial hard codes the size, but you can easily pass size parameters to the creation function. A graphics.newMask() is added to the group, so that any other display objects added to the group will be affected by the mask. A display.newRect() is created and stored in the group as well. This will hide the progress yet to be achieved. This requires a little trickery to work right. Anchor the rectangle to the right side. Set the color and use the .width value of the rectangle to size it to how much you want to block. Add a function to the group that can be used to set the percentage after the initial creation. It’s the same math used above. Finally return the group to the calling function. Then in the calling function, you can initialize the progressView and then set the percentage. The entire function and code to position and set the value 22 lines of code. Trying to use the widget.newProgressView()‘s theming option is 28 lines (plus the widget itself!), can’t do this kind of customization, and is more code. Hopefully this will demonstrate that some things you think are hard are actually pretty simple.
View the full article

CoronaRob

CoronaRob

 

Functions and return statements in Corona

A question was raised on the various Corona support channels: “What is the return statement and when do I need to use it?” Before that question can be answered, you need to understand what functions are and how Lua uses them. Functions are blocks of code that can be reused. Consider changing a car tire: Take out jack, lug wrench and spare tire from trunk Put the lug wrench on nut #1 Rotate counter-clockwise until the nut comes off Put the lug nut in a safe place Put the lug wrench on nut #2 Rotate counter-clockwise until the nut comes off Put the lug nut in a safe place Put the lug wrench on nut #3 Rotate counter-clockwise until the nut comes off Put the lug nut in a safe place Put the lug wrench on nut #4 Rotate counter-clockwise until the nut comes off Put the lug nut in a safe place Put the lug wrench on nut #5 Rotate counter-clockwise until the nut comes off Put the lug nut in a safe place Jack up the car Remove the flat tire Put the spare tire on etc. Computer code executes in a linear fashion. If you were to write this out in computer code you end up repeating yourself multiple times. It makes more sense to take the lug nut removal code and put it in a function. Consider this pseudo-code: Function removeLugNut( lugNutNunber ) Put the lug wrench on nut # lugNutNumber Rotate counter-wise until the nut comes off. Put the lug nut in a safe place This reduces our algorithm to: Take out jack, lug wrench and spare tire from trunk For each lugNutNumber removeLugNut( lugNutNumber) Jack up the car Remove the flat tire Put the spare tire on The code is much more compact. It follows a main developer principle called DRY – Don’t Repeat Yourself. Functions can be used in a variety of ways in Corona apps. Let’s look at a basic example: local function movePlayer() player.x = player.x + 1 end This function does not need any information. It uses an existing defined object: player and increments its .x position by one. It takes no parameters and doesn’t pass any data back to the calling code. You might use this inside another function that runs every clock tick: local function enterFrameListener() movePlayer() end Since you don’t put anything inside the parentheses, you are sending nothing to the function. But you could easily pass information to the function. You may want to make this function a little more generic. Instead of movePlayer, you could say moveObject. You could also provide the speed: local function moveObject( object, speed ) object.x = object.x + speed end local function enterFrameListener() moveObject( player, 1) end Now that you know how to pass information to a function what about getting it back? First, not all functions need to send data back, but when you do, you can do so using Lua’s return statement. At the machine code level, all of the above functions have an implied return statement. As a convenience to Lua developers, you don’t need to specify one if you don’t need it, thus: local function moveObject( object, speed ) object.x = object.x + speed end and local function moveObject( object, speed ) object.x = object.x + speed return nil end are identical. The return statement has two main purposes. First, it can be used to force a function to end early. Let’s look at that example: local function moveObject( object, speed ) If object == nil or object.x == nil then -- This isn't a display object, so exit the function without doing any more work return end object.x = object.x + speed end Since the code didn’t have a valid object to change the value of x on, you can exit the function and avoid a potential error. The second use of a return statement is to pass information back to the code that called the function, That information could be a simple success or failure indicator, or it could pass back values that are more useful. Let’s look at the simple success/failure situation modifying above function. local function moveObject( object, speed ) if object == nil or object.x == nil then -- This isn't a display object, so exit the function without doing any more work return false -- let the calling code know it failed end object.x = object.x + speed return true -- the function successful, so let the caller know. end To receive the data, the code calling the function can either store the return value in a variable or test it in a conditional test. local function enterFrameListener() if not moveObject( player, 1) then print("The object failed to move since object isn't a display object") end end Sometimes you need to capture the values. Let’s look at this simple function that adds two numbers together: local function addTwoNumbers( num1, num2 ) local sum = num1 + num2 return sum end local sum = addTwoNumbers(10, 20) print("The sum is", sum) Now you can pass data to the function as well as receive information back using the return statement. Most programming languages can only return one value (though it could be a table, dictionary, or list with multiple values). Lua, however lets you return multiple values. Lets go back to the moveObject function. local function moveObject( object, speed ) if object == nil or object.x == nil then -- This isn't a display object, so exit the function without doing any more work return false, "This does not appear to be a display object" -- let the calling code know it failed end object.x = object.x + speed return true, "Success" -- the function successful, so let the caller know. end local function enterFrameListener() local success, message = moveObject( player, 1) if not success then print( message ) end end You can see from this tutorial how the return statement can be useful in your Corona adventures.
View the full article

CoronaRob

CoronaRob

 

Android 64-bit is here…

Whew! That was a challenging update… But our engineering team has been working very hard and with much fanfare, we would like to introduce to you a publicly available Android 64-bit build of Corona. If you check the daily builds, you will find a new daily build: 2019.3504. This build should be stable enough for a public beta and for you to release apps to Google Play that meets all of their current new requirements. This includes: The August 1 deadline for 64-bit support for new apps (updated apps have a year to implement). The August 1 deadline to support Android SDK 28/Android 9/Pie (updated apps have to be using them by November 1, 2019) The recently changed AdMob requirements that require the AppId be included in the AndroidManifest.xml (build.settings file.) All Corona controlled plugins, updated to 64-bit, and many have been updated to the most recent SDK for those app plugins. Support for Android responsive icons Faster builds that are less dependent on network connections. Support for Android App Bundles (.aab files) While we are certain that there may still be edge-cases that need addressed, the only way to find them is to open this up to a wider audience. If you run into any edge case, please start a new thread in our Community Forums Android 64-bit testing channel (please don’t add it to an existing thread.) There are a few things to be aware of. .aab files require you to use Google’s new App Signing procedure. While we have discouraged this in the past over your standard keystores, you have to use this now and once you convert your app to use Google’s new App Signing, you have to use it going forward, but the gains by having your app size reduced is worth it. Your first Android 64-bit build may take some time as we need to download additional content (about 250 Mb total) to support the more local-natured building. Future builds should run noticeably faster. Android’s new responsive icons require a completely different file/folder structure than putting a few Icon-*dpi.png files alongside main.lua. The best thing you can do is to use the Corona “Welcome” window, create a new project and copy the AndroidResources folder to your project. Look at how the files in each of the various folders are named and sized, and create your new app icons using those names and sizes and overwrite our template icons. We are working on the guide explaining the topic. If you’re using AdMob or Appodeal, you must add some new content to your build.settings. See yesterday’s post for details. If you’re still using the legacy AdMob plugin [plugin.google.play.services], you must remove it.
Several plugins still doesn’t have full 64-bit support. It is recommended that anyone building for Google Play, using ad or other plugins, update to this build as soon as possible. Remember to report issues regarding this update to the Forums!
View the full article

CoronaRob

CoronaRob

 

Important AdMob and other ad plugin changes

It seems that all of our news lately has been wrapped around Google, and so it is again. AdMob has update their libraries again, and in doing so, created a breaking change. Your app’s App Id previously was only needed at the time you initialized the plugin. Google is now looking for it inside the AndroidManifest.XML file. If you wish to use AdMob as well as Appodeal (since it includes AdMob), you must add this to your build.settings: settings = { android = { applicationChildElements = { [[ <meta-data android:name="com.google.android.gms.ads.APPLICATION_ID" android:value="[YOUR_ADMOB_APP_ID]"/> -- replace with your app id. See: https://goo.gl/fQ2neu ]], } }, plugins = { ["plugin.admob"] = { publisherId = "com.coronalabs" }, }, } Simply replace the [YOUR_ADMOB_APP_ID] with your actual App ID inside the quotes and with out the square brackets. In addition, many of you are still referencing the old legacy AdMob plugin since it was a dependency for many other ad plugins. Please look through your build.settings and remove any references to: ["plugin.google.play.services"] If you do not remove this, your build will fail and you should get an error message in your console using the latest builds. You should make these changes before your next attempt to build for Android. See the AdMob implementation documentation for more details.
View the full article

CoronaRob

CoronaRob

 

Extending Corona libraries without native coding

This is a guest post by long time Corona user Matthew Webster. While Corona is simple, powerful and has many useful APIs, there’s always that one extra thing. Often, the one thing is apparently simple enough to be incorporated into an existing Lua API, but may appear forgotten about. This tutorial will show you how to: Add new functionality to the existing libraries Extend the existing functionality Corona library APIs All functionality in Corona are provided by library APIs. The documentation for which is found here. If we take a look at the 'string.*' API we can see a collection of functions such as: string.find() string.format() string.gsub() string.len() string.lower() It happens that all of these functions are not written in Lua, they are handles into lower level functions provided in either C++ (cross platform), Objective-C (for iOS) or Java (for Android.) The same is true for libraries like the 'math.*' APIs. Some APIs, however, are provided completely in Lua, for example Corona’s 'widget.*' API is entirely written in Lua. Corona Labs have even made the original source code available! Whichever implementation the Corona Labs engineers have chosen to go with their code, the fact still stands that in our Lua world each function has its hands firmly tied to the rules of Lua. In fact, every library (including the 'string.*' API) is actually a table. That’s right: 'string' is a table and all the functions defined above are members of that table. This allows us to do some really clever things quite easily. A Useful Function The first thing we’ll learn is how to add our own functions to Corona SDKs own API Libraries. Why would we want to do that? Well, let’s say you’ve written a really useful function which removes the leading and trailing spaces from a string. In most languages this is usually called 'trim()': local function trim( str ) return (str:gsub("^%s*(.-)%s*$", "%1")) end Don’t worry about what is actually happening inside the function. Just know that you’ve written it, it’s awesome and works really well when you want have a string which has really annoying spaces at the startand end: print( trim( " Hello World! " ) ) Outputs: Hello World! The normal practice for many Corona developers is to put this 'trim()' function into a library file, such as
“utils.lua“. What we want to do is make it a bit more memorable and categorically accurate… This function is
a string function, so it should be accessed like the other string functions. Adding to Corona’s APIs To be clear, our function is in a file called "utils.lua" so we want all the work done in that file. Of course, "utils.lua" will be loaded into memory in our "main.lua" with a standard 'require' call: require("utils") The function in the "utils.lua" looks like this: local function trim( str ) return (str:gsub("^%s*(.-)%s*$", "%1")) end So let’s add this function to the 'string.*' API. In "utils.lua" after we define our function we follow it with a standard table value assignment (this is the magic bit): string.trim = trim And that’s it. Easy. You can now call 'string.trim(" Hello World! ")' from anywhere in your code and it will print: Hello World! The Beauty of a Library Let’s say we have a string defined: local str = " Hello World! " What’s great about having the 'trim()' function in the string API is that we can now call the function as a member of any string variable: print( str:trim() ) Will output: Hello World! This is because the 'string' library represents string variables in general. It’s important to note, that this does not add your trim function to everyone’s Corona string.* library nor will it make it available to your next project. You will need to continue require your util.lua file. But the idea here that: string.trim() makes more semantical sense than: util.trim() Hopefully this simple trick will make your development with Corona a bit more easy.
View the full article

CoronaRob

CoronaRob

 

Corona Android 64-bit update July 4, 2019

We have some important (and good) updates regarding the Android 64-bit requirements. As you probably know, Google has been wanting developers to switch to 64-bit builds for some time. Converting Corona to Android 64-bit has been a major challenge for us given how our build system is constructed. Several months ago, Google set a hard date of August 1, 2019 for all apps to be 64-bit capable. If you do the math, that’s not far away. To make matters worse, all apps had to be updated by then or face removal. Today, Google granted Corona developers a break! According to the latest update to their “Getting ready for 64-bit” document, Corona developers will not have to convert all of their existing 32-bit apps until August 2020. What does this mean for you? If you are readying a new app and August 1, 2019 comes, you will have to use a 64-bit version of Corona. However, you do not have to rush and update your existing apps by August 1 and you can continue to update them with a 32-bit version of Corona until August 1, 2020. For existing apps in Google Play, this is a huge release of pressure on you as the deadline now only impacts new apps released after the deadline. Where is Corona at development wise? We have made really good progress on Android 64-bit builds. There is currently a hidden build of Corona that: Has 64-bit support Supports Android SDK 28 (Android 9/Pie) as the target SDK Supports Adaptive Icons Supports Android App Bundles (makes your apps smaller) Works with most existing plugins There are a couple of known bugs and our team is working relentlessly to knock them out. Some developers have had success updating their apps with it. Some plugins from third-party developers still have 32-bit only code in their packages. We’ve reached out to them and they are working on updates, but how fast those updates happen is out of our control.

How can I get involved? You can either visit our Android 64-bit testing forum or join our Commuity Slack and once in the system, join the #Android64 channel. From either place you can access this hidden build, get instructions needed to start using it and have a targeted place to report issues. If you readying a new app, you certainly should start testing with the 64-bit build. If you just need updates, you can stay with the latest published daily build for now, but with all the features in the 64-bit version, you will want to start taking advantage of them as soon as possible. Corona’s Android 64-bit forums Join Corona’s community Slack Read: Google’s announcement
View the full article

CoronaRob

CoronaRob

 

Corona, Google Play apps and 64-bit

Google has set a date of August 1, 2019 for all apps to be updated to 64bit. Currently Corona only supports building 32-bit apps. Our engineering team is working to convert our build process to support 64-bit for Corona apps, but this is a very complex process with many parts that have to be updated. iOS apps are already 64-bit. We cannot provide a date at this time when this will be complete, but we are very aware of the looming deadline and that you need time to update your apps in advance. Please follow the discussion in our forum post for this topic: https://forums.coronalabs.com/topic/74839-google-play-64-bit-requirement/ We will update you when we know more. In the mean time, you should have gotten an email from Google offering you an opportunity to take a survey about this process. It might be helpful to fill out this survey and let them know you’re being held up by third-party SDKs. You can see an example of the survey here:
You can subscribe to the forum post to get email notifications as more content is posted there. We will also update the blog here with updates as they become available. To see our progress, you can check out gradle branch from the open source version of Corona from our GitHub and build a Gradle-based 64-bit version of Corona. We’re working on integrating this build system into Corona Simulator/Native and supporting existing plugins and settings.
View the full article

CoronaRob

CoronaRob

 

Google Icon changes

This isn’t about adaptive icons. We are still working on those. This is about the 512×512 that you upload to Google Play. Google is changing the rules on what is required for the developer portal. Previously they allowed you to have arbitrary shaped icons, but as of May 1, you’re required to provide a square shaped icon. You can read more about the new requirements here. Google Play’s new icon requirements!
View the full article

CoronaRob

CoronaRob

 

Getting the community more involved…

Corona has always been about you, our fantastic developer community. And we love it when you get more involved. A community project that you may not be aware of is a new website collecting information about #madewithcorona apps. The site, curated by @sporkfin, is currently soliciting YouTube video submissions of your apps to show off. Learn more about this project! Guest submissions If you have a Corona related post you would like to share here on the blog we are open to your submissions. You can always email us with a link to a .zip file that we can download with your post. We like to keep it simple, so write the post using Markdown. Include any artwork in the .zip file and email us at devrel@coronalabs.com and if its appropriate and beneficial to the community we will post it here for you. Open source Just a friendly reminder, Corona is now open source. You can download the code that builds the simulator and you can add features and make changes that will make Corona better and submit a pull request back to us with your submission. Check out our open source repository
View the full article

CoronaRob

CoronaRob

 

I have a question where should I ask it?

It seems like we are seeing the same questions showing up in multiple places. We want you to get the best support possible and understanding the best places to ask your questions will help meet that goal. Support requests can be generally broken into three distinct categories: How do I use Corona? I’m having an account related issue. Letting people know about cool things you’re using Corona for. There are several support channels available for you: The Community Forums Emailing support@coronalabs.com The Community Slack Social Media like Facebook, Twitter, Stack Overflow, Reddit, etc. Private messages on all of the above channels Which should I use? If you have account related questions, or a plugin license issue or anything where we need something private (an email address, credit card or we need to reset your password) then emailing support@coronalabs.com is the proper choice. This helps keep your information safe.

If you have any questions about the product and in particular if code needs to be shared to help answer your question, you should always use the forums. While forums may seem SO 2000’s, they provide you with some very important features that not only benefit you, but also benefit the community: You have access to developers from around the world to get your answers. You will usually get answers faster than waiting for the Corona Staff to be online. The forums are a great knowledge base because it’s searchable. You can search the forums (or use Google since it indexes the forum posts) for your question before you ask and get an answer right away. If your question can’t be found, then ask. Once answered, other developers when they have your question can find your answer. This concept is so important, that we specifically discourage 1 on 1 messages to support. Many questions relate to how to do things like make a character jump or spawn monsters in an RPG. These questions are best answered by people who are using the product, not building the product. We are great at answering questions about how a particular API works, but when it comes to game mechanics, our community developers are the best! It should be noted that the first time you post to the forums, it will be held until our staff can review it to make sure it’s not spam. It make take several hours before the staff can review the new posts and approve them. Once your first post is approved, other posts will show up instantly. If you have an awesome game or tool that the community will probably enjoy, let them know everywhere, except to support. Post it on Slack, Twitter, Facebook, Reddit’s /r/gamedev and /r/CoronaSDK. It won’t do much good to email it to support@coronalabs.com or on any private channels, since we will see it on the other channels. Just a couple of other side notes. If you have a confirmed bug, hopefully after trying to solve the issue in the Forums, please use the “Report a bug” link at the top of the Forums page. If you see an issue with our documentation, there is a Report an Issue link at the bottom of the page. Please do not use these to ask for support or help. Use them only for confirmed problems.
View the full article

CoronaRob

CoronaRob

 

Using functions for onComplete listeners

Corona API’s are some of the best thought out in the industry. We’ve worked hard to make them consistent and easy to use. Lua follows a similar thought process, attempting to be consistent with minimal syntax rules. But there are times that some concepts may not be obvious to newer developers coming to a new language and API ecosystem. Recently a problem discussed in the forums falls into one of these “Gotcha” categories. Calling functions vs. providing an address to a function Let’s look at a basic Corona API, the timer.performWithDelay() API. This function requires two parameters and an optional third parameter. Let’s look at its definition: timer.performWithDelay( delay, listener [, iterations] ) The first parameter, delay is the time in milliseconds before the function passed as the listener fires. Finally, you can set a number of times for this to run. At its basic nature, you want to wait some period of time before listener runs. Lets create a simple listener function for this example: local function myListener( value ) print( "timer fired", value ) end It simply prints that the timer to the console log with a value. Your code could now look like: local myValue = 10 print( "timer start" ) timer.performWithDelay( 5000, myListener( myValue ) ) You would expect to see in your console log that the message “timer start” show up, then 5 seconds later, you would expect to see “timer fired”. But if you run this code, you will see the two messages print simultaneously with no delay. What happened? In Lua, and many other languages, there are two needs: Call the function Get the functions memory address In the case of Corona APIs that expect a function passed to it, or an onComplete option on functions like audio.play() or transition.to(), Corona is expecting an “address to a function“. When you call a function, it executes immediately and returns a value or nil if your function doesn’t return a value. How you do “call a function” vs “get a function’s address“ It’s pretty simple, if you put parentheses after the function name, it runs the function. If you leave off the parentheses, you get the address to the function. So in our example above, since we included myListener( value ), the function returns immediately and returns any return value. So we get the message from myListener() and the resulting timer call is compiled as: timer.performWithDelay( 5000, nil ) Since myListener() doesn’t return a value, a nil is returned. Then 5 seconds later, timer.performWithDelay() tries to run nothing. To make this work, you have to pass the address to the function. You do this by leaving off the parenthesis and not passing any parameters: timer.performWithDelay( 5000, myListener ) Now after 5 seconds, myListener() will be called, the message will print as expected. You’re probably noticing that the value never gets passed in this way. This is how Corona works. You can’t pass values without using the (), which runs the function immediately. There is an easy way to address this using anonymous functions, but that will be a topic for another day. Just remember if you’re providing a function to an onComplete parameter or a function to a listener, you have to pass the address of the function. Dream! Build! Ship!
View the full article

CoronaRob

CoronaRob

 

Adding speech recognition to HTML5 apps

Corona’s plugin system provides a great way to extend Corona’s capabilities without having to modify Corona’s core engine. Developers building HTML5 apps have great access to JavaScript to add really cool features and it’s pretty easy to do! Let’s look at an example… Recently someone was interested in adding support for speech recognition for their HTML5 apps. We have created a demo that shows how to do just that in Chrome using the Web Speech API. It serves as a great example of how to integrate JavaScript APIs into your HTML5 builds. Check it out! You can also view a live demo of this plugin in action here! You will need Google Chrome to view the demo. Learn more about the Web Speech Plugin
View the full article

CoronaRob

CoronaRob

 

Another #madewithcorona hit from Sphere Game Studios: Merge City

Sphere Game Studios has another hit on their hands with their new title: Merge City which is currently on Google Play’s “Indie Corner” in the “Our Indie Picks” section. Merge City is a blend of city building and merge gaming, similar to the game Merge Planes. The game play is simple: You merge two level 1 buildings to unlock a level 2 building. There are 30 different buildings to unlock in two neon-inspired worlds. You can visit other players from the leaderboard and compare your cities to theirs. Merge City is free to play with in-app purchases and is available on both the Apple App Store and Google Play. Check it out!  
View the full article

CoronaRob

CoronaRob

 

The Corona 2D game engine is going open source in 2019

After more than nine years of developing and evolving the Corona game engine, Corona Labs is releasing its technology to open source. It’s a move we’ve been planning for a few years now, with the goal of making the engine development process more transparent, and to empower the community to directly impact future growth and potential. As part of a series of steps on a longer evolution journey, entrusting Corona to the community is the surest way to quickly respond to market shifts and changes, ensuring Corona stays relevant and valuable to all mobile app developers. “The transition of Corona to the open source model of development has been our long-term vision since Corona Labs was acquired by Appodeal in 2017. We believe that this move will bring transparency to the development process, and will allow users to contribute features or bug fixes to make the project better for everyone,” said Vlad Sherban, product manager for Corona Labs. The open source model will bring more visibility and flexibility to the development process by allowing visibility into exactly what the engine team is working on and where the project is going, and by contributing valuable new features that will help spearhead Corona to the next level. Additional benefits for businesses include the potential to acquire a commercial license for source code and customize the engine for specific commercial projects. “Corona Labs will continue to have a dedicated team and infrastructure to support our flourishing plugin ecosystem and infrastructure, as well as to keep up to date with the ever-changing requirements and updates coming from applications stores. Powered by the new open source model and supported by the development of new features and bug fixes will make Corona more community driven — but not without our help and guidance. Ultimately, going open source will provide confidence in the future of the engine and an opportunity to grow community involvement in engine development,” said Vlad Sherban, product manager for Corona Labs. Details Most parts of Corona’s code will be open sourced except for some plugins, the Corona Marketplace, www.coronalabs.com, and the build infrastructure. This is not a final or exhaustive list as the team may open source even more as we move forward. More about Corona open source can be found on the FAQ page. Licenses Corona will be dual-licensed under both commercial and open source licenses. The open source license is the GNU GPLv3 license, and commercial license will be available upon agreement with Corona Labs. You can download the Corona source code under the GPLv3 license and build your games and apps, however, those games have to be distributed under the GPLv3 license, i.e you have to make your source available. Games and apps based on the open source distribution of Corona have to be distributed using the same license (GPLv3). You can download the Corona source code, negotiate a commercial license agreement with Corona Labs, and build a version of Corona that has a custom feature. You can then distribute your games and apps without opening your own source. About Corona Corona is a free, cross-platform framework ideal for creating 2D games and apps for mobile devices, desktop systems, TV platforms and the web. It is driven by the easy-to-learn Lua language, over 1,000 built-in APIs and plugins, and Corona Native extensions (C/C++/Obj-C/Java). The Corona engine has been updated with HTML5 and Linux (alpha-version) building during 2018 and celebrated our 9th anniversary from the date of the first release. You can find the full source code on GitHub. Contacts:
devrel@coronlabs.com
View the full article

CoronaRob

CoronaRob

 

Corona is now 100% analytics free!

Corona Labs will no longer be collecting any statistics from apps built with daily build 2018.3454 or later. Many developers have asked for this feature and we are happy to do this for the community. As a closed source product, Corona Labs needed to collect basic app usage such as the number of sessions, daily average users, etc. As we transition to an open source product, we no longer need to collect this data. Simply download the latest daily build to take advantage of this new feature! We are looking forward to bring more good news and features soon!
View the full article

CoronaRob

CoronaRob

 

There’s BIG open source news on our 9th birthday

Ten years ago, two guys got together with a goal to change the mobile development world. A year later, Corona SDK was born. My, how time has flown! Since those first days, we’ve frequently seen developers reach the #1 spot in various app stores. We’ve seen apps that have received millions of downloads, and app developers who have made a full time career out of mobile app development. But for many, it’s also a challenging time. The mobile app market has become over saturated. There has been a race-to-the-bottom in app pricing. New challenges extend up the development toolchain and impact the quality of top app engines. In this evolving industry landscape and these emerging challenges, change is good and necessary. With that in mind, we would like to introduce a big change for Corona. We have decided to get you — the developer community — more involved in Corona’s development, and open-source most of the engine. There are features you want, updates you need, and it’s simply time to get you more involved in Corona’s future. Corona Labs will continue to support the engine and going open source means more transparency to the process. We are certain you will have a lot of questions about how this will work, and as we have more to share, we will be continuously sharing new details with you. Also, feel free to discuss this in our community forums and in the CDN Slack. We’d like to assure you that our goal is to increase transparency by enabling access to the source, and allowing each and every one of you to add your unique contributions to Corona’s future. Any media questions should be directed to the Corona Labs Developer Relations team at devrel@coronalabs.com.
View the full article

CoronaRob

CoronaRob

 

Introducing the new Animation Plugin

Corona Labs is pleased to announce the immediate availability of a new plugin: Animations. This plugin was originally planned to be an extension to the existing transition.* library. During the design, there were sufficient changes that warranted it being a new library. We also decided to make this a plugin instead of a core feature to help keep the core lightweight. The plugin is broken into two main categories: tweens and timelines. Tweens are your standard transitions like moving an object over time, fading an object in and out, etc. Tweens have new features including scalable speeds and additional events. Timelines allow you to have more control over what happens to a tween over time. You can set timeline markers that you can advance or return to. You can have events fire when the timeline passes a marker. Since it’s a plugin, you will need to go to the Corona Marketplace and activate it. Next you will need to include it in your build.settings: plugins = { ["plugin.animation"] = { publisherId = "com.coronalabs" }, }, And require the plugin in modules where you will use it: local animation = require("plugins.animation") For normal transitions, the call is now: local myAnimation = animation.to( object, { x = 200, alpha = 0 }, { time = 1000, onComplete = whenDoneFunction } ) Notice there are two tables involved, the first table is for object parameters, the second one for transition parameters. For timelines, you can now program animations that can contain multiple sequential and/or overlapping tweens, each performing unique tweens on one or multiple objects. Additionally, you can set time markers anywhere across the span of the timeline as jump-to points. For example, you could: local function timelineListener( obj ) print( "Timeline completed; ID: " .. obj.id ) end -- Create a timeline object local timelineParams = { tweens = { { startTime=0, tween={ object1, { x=display.contentWidth-50 }, { time=4000, iterations=5, reflect=true } } }, { startTime=1000, tween={ object1, { y=400 }, { time=4000, easing=easing.outQuad } } } }, markers = { { name="marker_start", time=0 }, { name="marker_2000", time=2000 } }, id = "timeline1", onComplete = timelineListener } local newTimeline = animation.newTimeline( timelineParams ) Which will do a transition that moves an object back and forth on the X axis five times over four seconds. Then starting one second in, move the object down the screen over four seconds and setting markers to allow you to go back to the beginning of the timeline or jump to two seconds in. The animation plugin is free to use. You can learn more about the plugin and its new features by reading the documentation for the plugin. Like many of our other Lua based libraries, we are going to go ahead and make this open source so you can download the source code and make your own changes to the library. Let us know what you think about this new great addition to Corona in our Community Forums.
View the full article

CoronaRob

CoronaRob

 

Update on the new GPGS v2 plugin

Corona Labs would like to update you about our recent plugin for Google Play Games Services. This plugin is known as GPGS v2 and there is a breaking change to be aware of. We’ve worked hard to make it call compatible with the older GPGS v1 plugin, however Google has changed their initialization and login process significantly. We had to make a change that you will need to adapt to so that you can successfully login and know if your app is connected. Simply remove any calls to the gpgs.init() API and instead call gpgs.login() directly: gpgs.login( { userInitiated=true, listener=gpgsLoginListener } ) Where gpgsLoginListener is the name of your function to handle a successful login. If you have questions about the plugin, please joins us in our community forums.
View the full article

CoronaRob

CoronaRob

 

#madewithcorona: Mission Me!

Periodically a game comes along that breaks out and does something different. Corona Labs would like to introduce you to Mission Me by Sillysoft Games. Mission Me is a lifestyle game. In this game, you get missions that you frequently have to do in real life and may require you to get off of your device for a while to accomplish. As you complete missions, you gain experience and move up to more missions. Example missions include things like “Clean up your desk and add a decoration” or “Say something nice to a cashier”. You start with “Self” missions and move to “Family” missions and so on. This game is engaging and helps you with your own self-esteem. The game is available as a free app on Apple’s App Store and Google Play. Check it out! If you want you can leave feedback to the developer in our Community Forums!  
View the full article

CoronaRob

CoronaRob

 

A different approach to game difficulty

The concept of game difficulty is always a challenge for developers. Games that are too easy won’t get played. Games that are too hard will frustrate the users and they will quit. You have to find that right balance of difficulty where the player feels challenged yet feels as if they are progressing. To compound matters, no two players are the same. Some need an easier game, others need a lot more challenge. How do you strike that balance? Alex Vu, pixel artist and game designer working for Fine Monkeys, LLC has contemplated the problem, and discusses some solutions in his blog post A Different Approach to Difficulty. In this post, he talks about the problems with simple difficulty modes as well as Dynamic Difficulty Adjustment (DDA) and offers a deep dive into Organic Difficulty and Effectiveness-Ludoaesthetics Spectrum. This advice might just make your game more interesting to your players. Read: A Different Approach to Difficulty   View the full article  

CoronaRob

CoronaRob

 

Steamworks plugin is now open-source

Corona Labs is pleased to announce that the Steamworks plugin is now open-source. The Steamworks plugin is used by PC and macOS games published to Valve’s Steam service that allows support for leaderboards, achievements, user profile data, and microtransaction support. Now you can download the repository for the plugin and add your own features and extensions to it. You will have to have a Steam developer account to be able to test the plugin. Follow Steamworks documentation (available on Steam’s developer portal) to learn how to enable Steamworks debugging and development for your game. You can get the plugin source at our GitHub repository. You can learn more about the Steamworks plugin in our previous announcement.
View the full article

CoronaRob

CoronaRob

 

New Google Play Games Services plugin

Corona Labs is pleased to announce the immediate availability of a new, updated Google Play Games Services plugin. This plugin in a complete rewrite of the version one of the plugin using the latest GPGS core libraries and dependencies. One of the key reasons for the GPGS v2 plugin, besides staying with modern underlying SDK’s is support for preventing Google rejections for using invalid login scopes. The previous version of the underlying GPGS SDK contained Google Plus login scope which has been deprecated. The new version has this removed. The GPGS v2 plugin should be a drop in replacement for the GPGS v1 plugin. First, visit the Marketplace and activate the plugin, then simply update your build.settings to include the plugin using: settings = { plugins = { ["plugin.gpgs.v2"] = { publisherId = "com.coronalabs", supportedPlatforms = { ["android"] = true, } } } } And where you require the plugin in your lua code: local gpgs = require( "plugin.gpgs.v2" ) This is a completely new version of the plugin and you should fully test your app against the code. If you have questions about the new plugin, please check out our documentation. Join us in the community forums to discuss this new plugin.
View the full article

CoronaRob

CoronaRob

 

Monetization best practices (and a new Ad Tutorial!)

New tutorial! First, we would like to take this opportunity to let you know about a new tutorial on implementing advertising in your Corona apps. The tutorial covers code and common code to implement an ad plugin in your app. You can view it here! Read the Implementing Ads tutorial Monetization best practices A great question was asked in our Community Forums about using in-app purchases (IAP) to turn off advertising. It may seem like a simple idea but there is more to it. When you sell your app for a fixed price, that person pays you once, ever. When you use ads, you get a continuous stream of income as long as your app or game is being used. If someone uses IAP to turn off ads, you get continuous income until they pay for the IAP, then you get the one-time fee and that’s it. For some apps, IAP subscriptions can provide ongoing income, but an app has to be pretty special, with lots of new content to convince users to continuously pay for it. Let’s look at the financial considerations in answering this question. Let’s say that you end up setting the IAP fee to turn off ads at $0.99 (or an initial purchase price with no ads). Because the app stores take 30% of your sales, that means you will make $0.69 from that user when they make the purchase. But the question is: Will you make more from advertising? Using Appodeal as an example and information from Appodeal’s E-Book “Monetizing Casual Games”, banner ads typically pay about $0.43 per thousand banner ads shown. To earn that same $0.69 from app sales, you need to display over 1,600 banner ads to your app user. Assuming your banner ads rotate every 45 seconds, it will take over 1,200 minutes or about 20 hours of view time to earn that same amount of money from the user. Note: eCPM values for the United States and Europe were averaged together from numbers in the e-Book. Banner ads may not be the best way to implement ads. If you’re using other ad forms, like interstitials which pay an average of $4.59 per thousand ads, you need to show about 150 interstitial ads to earn the equivalent purchase income. Note, video interstitials pay more than static interstitial ads. Let’s say you can show 2 interstitial ads per session on average, the user only has to play about 75 times to make up that income. You don’t want to over-show ads to keep it from becoming an annoyance causing your user to just quit your app. Rewarded video pays about $10 per 1000 rewarded videos. That means the user only needs to view 7 rewarded videos to earn you that same $0.69. How do you get to that many ad displays? Most users tend to play a game a lot at first, then over time, they play less and less. All games have a usage “tail”. If you view this generic usage graph, it looks like a dinosaur: Picture by Hay Kranen / PD The left side is your initial usage spike (the head) and then as time passes it gets used less and less (the tail). Some games will have a long tail, but many will have a short tail. No one can really predict in advance how long your game’s tail will be. Successful apps will have a longer tail and a taller tail. It indicates that you are retaining users longer. Games and apps with a long tail will make more money from advertising. If your game doesn’t have any longevity to it, you want to convert them to paid as soon as possible. This combination of retention and revenue is your game’s LTV or Lifetime Value. If your game is too short, offering an option to disable ads won’t be effective because you won’t have any retention to motivate them to disable ads. If your ads are too annoying, people may get turned off to your app and give up on it early. You have to strike a proper balance between advertising and entertainment or utility value of your app. Even short-lived apps can monetize successfully by … Using Rewarded Video Rewarded video is clearly the winner in the eCPM value for you, but you have to use them wisely. Rewarded video is the user volunteering their time in exchange for some in-game reward. You can’t just throw a rewarded video in front of a user automatically. That’s the job of an interstitial ad. If you force the user to watch an ad, even if you reward them, it’s still forcing them to watch the ad. Consider they have played your level and lost. Your game logic shows them an ad and resets back to the beginning. That is an Interstitial ad placement. If you prompt them “Would you like to view an ad to continue to the next level?” and if they agree, you should show them the video and let them move on to the next level. If they choose no, simply take them back to the beginning, but don’t force them to watch the ad. Rewarded ads encourage players to continue playing, either by not losing progress or by gaining some in-game feature which can extend your app’s LTV. Using these techniques, even games with shorter tails can be quite successful. Conclusion Every app is different. You should make the most entertaining game you can or the most useful business or utility app that brings real value to the user, then balance your advertising, in-app purchases and in-app currency to maximize your income.
View the full article

CoronaRob

CoronaRob

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!