corona sdk at gmic sv
TRANSCRIPT
coronalabs.comAMBASSADOR
CoronaCode Less. Play More.
®
NBC/Universal powers their campaign with Corona
coronalabs.comAMBASSADOR
coronalabs.comAMBASSADOR
Turning an idea into something real
+ + =
Software DevelopmentCreative
coronalabs.comAMBASSADOR
What is Corona?
same code, multiple stores
develop 5-10x faster
SDK for native apps
...
coronalabs.comAMBASSADOR
Breakthrough Productivity
36 hourscode+graphics+sound(complete 2 level game)
14 hourscode+graphics+sound
(gameplay only)
“Angry Birds” “Fruit Ninja” “Tiny Wings”
12 hourscode+graphics+sound
(gameplay only)
“Developing directly in Xcode would have been at least 5x more code than Corona”
– Unicorn Labs, Top 20 iPad eBook
Ship #1 apps 10x faster
coronalabs.comAMBASSADOR
High Performance
“Corona is a ‘godsend’. My game runs at 1 fps (frame/sec) in Flash but runs in full 30 fps in Corona.”
– Jeff Fulton, Flash Developer
coronalabs.comAMBASSADOR
#1 on all Major MarketsiOS and Android and Amazon
anscamobile.comCONFIDENTIAL
coronalabs.comAMBASSADOR
Developers like you
#1 #1
From Designers to Coders. From Indies to Studios.
coronalabs.comAMBASSADOR
Not just for games
Branded Apps
HTML5 + OpenGL
Cross-device/Skinnable UI
coronalabs.comAMBASSADOR
Business Apps
ESP Guitars CheeseMonger Planet Sushi Thai Cook
coronalabs.comAMBASSADOR
Performance
Simplicity
Flexibility
Corona
The Sweet Spot
Staff Pick
coronalabs.comAMBASSADOR
CoronaRendering Engine
Virtual Machine
UserInputNetworking
Device
Device/OS
Native Mobile App
TextStrokesFills
BitmapsShapes
Objects Behaviors Dynamic Layout Events Device Capabilities Etc
Camera MicGPS Etc
Artwork Compiled Code Localized Strings Work"ow DeveloperAssets
User Interface
Architecture
coronalabs.comAMBASSADOR
Lua: an industry standard
coronalabs.comAMBASSADOR
Small Code Size
1.4 MB Footprint
coronalabs.comAMBASSADOR
Lua types
nilbooleannumberstringfunctiontable
userdata
• JavaScript-like syntax• Functions are closures• Lexical scope (non-local vars)• Objects are tables
coronalabs.comAMBASSADOR
array = { "a", "b", 100, "hello" }
dictionary = { x=5, y=7, name="Joe" }
t = {} -‐-‐ empty table
t[1] = "a" -‐-‐ numerical index
t["x"] = 5 -‐-‐ key index
t.x = 5 -‐-‐ equivalent property access
t.hasProperties = true
t[array] = "Joe" -‐-‐ any type can be a key!!!
t["printJoe"] = function() print("Joe") end
Lua objects are Tables
coronalabs.comAMBASSADOR
Lua vs Other Languages
if (!carMoving) { // do something} else if (noGas) { // do something else}
for (i=1; i<=10; i++) { print(i)}
for (j=100; j>0; j-‐-‐) { print(j)}
if (not carMoving) then -‐-‐ do somethingelseif (noGas) then -‐-‐ do something elseend
for i = 1,10 do print(i)end
for j = 100,1,-‐1 do print(j)end
coronalabs.comAMBASSADOR
Lua is 1-based
// Other languages: index begins with 0 array=['a','b','c'];for ( var i=0; i<arr.length; i++) { log( array[i] )}
-‐-‐ Lua: index begins with 1local array = {'a','b','c'}
for i=1,#array do print( array[i] )end
coronalabs.comAMBASSADOR
Corona Enterprise
• Integrate native libraries• Wrap native code in your own Lua APIs• Automate builds
Lua and Objective-C/C++ and Java
coronalabs.comAMBASSADOR
APIApplication Programming Interface Interaction
coronalabs.comAMBASSADOR
WebKit browser vie
ws
SQLite databas
e
File read/write
Full Lua scr
ipting langua
ge
Hardware-accelerat
ed graphics
GPS, compass, a
ccelerometer
Simple and complex ph
ysical bodies
Networking (TCP, FTP, HTTP, etc.)
Video playback (strea
ming or local)
Physical prop
erties (mass, fr
iction, boun
ce)
Joints, wheels,
hinges, pulle
ys, etc.
Animated sprites with ind
ependent framerates
per sprite seq
uence
Collision detectio
n, including pre
- and post-collisio
n events
OpenFeint gam
e network suppo
rt
Vector drawing APIs (sh
apes and lines)
Native UI (ke
yboard, etc.)
Crypto (md4, md5, sha1
, sha512, etc.)
Audio (sound effect
s or MP3)
Animation and transi
tion libraries
Facebook and Twitter li
braries
Improved textur
e memory handling
2D physics si
mulation
Camera and photo
library
Tons of Features
<html5>
• OpenGL graphics• Open AL audio• Box2D Physics• Texture atlases, sprites, ...• Networking• GPS, multitouch, accelerometer, ...• Native web views, text#elds, ...• Camera, photo library, video, ...• Services: ads, analytics, IAP, ...• And much more!
CONFIDENTIALcoronalabs.com
Hard Problems Made Easy(e.g. how Corona taught me to love physics)
CONFIDENTIALcoronalabs.com
OpenGL in one linePhone SDK.// Display "myImage.png" // ----------------------------------------------------------------------------// OpenGLESTextureAppDelegate.m// ---------------------------------------------------------------------------- #import "OpenGLESTextureAppDelegate.h"#import "EAGLView.h"#import "OpenGLESTextureViewController.h" @implementation OpenGLESTextureAppDelegate @synthesize window=_window; @synthesize viewController=_viewController; - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ // Override point for customization after application launch. self.window.rootViewController = self.viewController; return YES;} - (void)applicationDidBecomeActive:(UIApplication *)application{ /* Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. */ [self.viewController drawFrame];} - (void)dealloc{ [_window release]; [_viewController release]; [super dealloc];} @end // ----------------------------------------------------------------------------// EAGLView.m// ---------------------------------------------------------------------------- #import <QuartzCore/QuartzCore.h>#import "EAGLView.h" @interface EAGLView (PrivateMethods)- (void)createFramebuffer;- (void)deleteFramebuffer;@end @implementation EAGLView @synthesize context; // You must implement this method+ (Class)layerClass{ return [CAEAGLLayer class];} //The EAGL view is stored in the nib file. When it's unarchived it's sent -initWithCoder:.- (id)initWithCoder:(NSCoder*)coder{ self = [super initWithCoder:coder]; if (self) { CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer; eaglLayer.opaque = TRUE; eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:FALSE], kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat, nil]; } return self;} - (void)dealloc{ [self deleteFramebuffer]; [context release]; [super dealloc];} - (void)setContext:(EAGLContext *)newContext{ if (context != newContext) { [self deleteFramebuffer]; [context release]; context = [newContext retain]; [EAGLContext setCurrentContext:nil]; }} - (void)createFramebuffer{ if (context && !defaultFramebuffer) {
[EAGLContext setCurrentContext:context]; // Create default framebuffer object. glGenFramebuffers(1, &defaultFramebuffer); glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer); // Create color render buffer and allocate backing store. glGenRenderbuffers(1, &colorRenderbuffer); glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); [context renderbufferStorage:GL_RENDERBUFFER fromDrawable:(CAEAGLLayer *)self.layer]; glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &framebufferWidth); glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &framebufferHeight); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer); if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) NSLog(@"Failed to make complete framebuffer object %x", glCheckFramebufferStatus(GL_FRAMEBUFFER)); }} - (void)deleteFramebuffer{ if (context) { [EAGLContext setCurrentContext:context]; if (defaultFramebuffer) { glDeleteFramebuffers(1, &defaultFramebuffer); defaultFramebuffer = 0; } if (colorRenderbuffer) { glDeleteRenderbuffers(1, &colorRenderbuffer); colorRenderbuffer = 0; } }} - (void)setFramebuffer{ if (context) { [EAGLContext setCurrentContext:context]; if (!defaultFramebuffer) [self createFramebuffer]; glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer); glViewport(0, 0, framebufferWidth, framebufferHeight); }} - (BOOL)presentFramebuffer{ BOOL success = FALSE; if (context) { [EAGLContext setCurrentContext:context]; glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); success = [context presentRenderbuffer:GL_RENDERBUFFER]; } return success;} - (void)layoutSubviews{ // The framebuffer will be re-created at the beginning of the next setFramebuffer method call. [self deleteFramebuffer];} @end // ----------------------------------------------------------------------------// OpenGLESTextureViewController.m// ---------------------------------------------------------------------------- #import <QuartzCore/QuartzCore.h>#import "OpenGLESTextureViewController.h"#import "EAGLView.h" @interface OpenGLESTextureViewController ()@property (nonatomic, retain) EAGLContext *context;@property (nonatomic, assign) CADisplayLink *displayLink;- (void) loadTexture;@end @implementation OpenGLESTextureViewController @synthesize animating, context, displayLink; - (void)awakeFromNib{ EAGLContext *aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1]; if (!aContext) NSLog(@"Failed to create ES context"); else if (![EAGLContext setCurrentContext:aContext]) NSLog(@"Failed to set ES context current"); self.context = aContext;
[aContext release]; [(EAGLView *)self.view setContext:context]; [(EAGLView *)self.view setFramebuffer]; [self loadTexture]; self.displayLink = nil;} - (void) loadTexture{ glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); NSString *path = [[NSBundle mainBundle] pathForResource:@"myImage" ofType:@"png"]; NSData *texData = [[NSData alloc] initWithContentsOfFile:path]; UIImage *image = [[UIImage alloc] initWithData:texData]; GLuint width = CGImageGetWidth(image.CGImage); GLuint height = CGImageGetHeight(image.CGImage); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); void *imageData = malloc( height width 4 ); CGContextRef image_context = CGBitmapContextCreate( imageData, width, height, 8, 4 width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big ); CGColorSpaceRelease( colorSpace ); CGContextClearRect( image_context, CGRectMake( 0, 0, width, height ) ); CGContextTranslateCTM( image_context, 0, height - height ); CGContextDrawImage( image_context, CGRectMake( 0, 0, width, height ), image.CGImage ); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData); CGContextRelease(image_context); free(imageData); [image release]; [texData release]; } - (void)dealloc{ glDeleteTextures(1, &textureID); // Tear down context. if ([EAGLContext currentContext] == context) [EAGLContext setCurrentContext:nil]; [context release]; [super dealloc];} - (void)viewDidUnload{ [super viewDidUnload]; // Tear down context. if ([EAGLContext currentContext] == context) [EAGLContext setCurrentContext:nil]; self.context = nil; } - (void)drawFrame{ [(EAGLView *)self.view setFramebuffer]; // Replace the implementation of this method to do your own custom drawing. static const GLfloat squareVertices[] = { -0.5f, -0.33f, 0.5f, -0.33f, -0.5f, 0.33f, 0.5f, 0.33f, }; static const GLfloat texCoords[] = { 0.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0 }; glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glVertexPointer(2, GL_FLOAT, 0, squareVertices); glEnableClientState(GL_VERTEX_ARRAY); glTexCoordPointer(2, GL_FLOAT, 0, texCoords); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); [(EAGLView *)self.view presentFramebuffer];} @end
display.newImage("myImage.png")
CONFIDENTIALcoronalabs.com
local sky = display.newImage( "clouds.png" )
CONFIDENTIALcoronalabs.com
local sky = display.newImage( "clouds.png" )
local ground = display.newImage( "ground.png" )ground.x = 160ground.y = 445
CONFIDENTIALcoronalabs.com
local sky = display.newImage( "clouds.png" )
local ground = display.newImage( "ground.png" )ground.x = 160ground.y = 445
local crate = display.newImage( "crate.png" )crate.x = 180crate.y = 80crate.rotation = 10
CONFIDENTIALcoronalabs.com
local sky = display.newImage( "clouds.png" )
local ground = display.newImage( "ground.png" )ground.x = 160ground.y = 445
local crate = display.newImage( "crate.png" )crate.x = 180crate.y = 80crate.rotation = 10
local physics = require( "physics" )physics.start()
CONFIDENTIALcoronalabs.com
local sky = display.newImage( "clouds.png" )
local ground = display.newImage( "ground.png" )ground.x = 160ground.y = 445
local crate = display.newImage( "crate.png" )crate.x = 180crate.y = 80crate.rotation = 10
local physics = require( "physics" )physics.start()
physics.addBody( ground, { friction=0.5 } )ground.bodyType = "static"
CONFIDENTIALcoronalabs.com
local sky = display.newImage( "clouds.png" )
local ground = display.newImage( "ground.png" )ground.x = 160ground.y = 445
local crate = display.newImage( "crate.png" )crate.x = 180crate.y = 80crate.rotation = 10
local physics = require( "physics" )physics.start()
physics.addBody( ground, { friction=0.5 } )ground.bodyType = "static"
physics.addBody( crate, { density=2.0, friction=0.5, bounce=0.3 } )
CONFIDENTIALcoronalabs.com
What if we wantlots of crates?
CONFIDENTIALcoronalabs.com
local crate = display.newImage( "crate.png" )crate.x = 180crate.y = -100crate.rotation = 10physics.addBody( crate, { density=2.0,
friction=0.5, bounce=0.3 } )
CONFIDENTIALcoronalabs.com
local function spawnCrate()! local crate = display.newImage( "crate.png" )! crate.x = math.random( 320 )! crate.y = -100! crate.rotation = 10! physics.addBody( crate, { density=2.0,
friction=0.5, bounce=0.3 } )end
timer.performWithDelay( 500, spawnCrate, 50 )
CONFIDENTIALcoronalabs.com
What if gravity was up rather than down?
CONFIDENTIALcoronalabs.com
physics.setGravity( 0, 9.8 )
CONFIDENTIALcoronalabs.com
physics.setGravity( 0, -9.8 )
coronalabs.comAMBASSADOR
• UI• Buttons• Animation• Timers• System
Events
coronalabs.comAMBASSADOR
Listeners
local listener = function(event) print( event.name, event.time )end
Runtime:addEventListener("enterFrame", listener)
coronalabs.comAMBASSADOR
• enterFrame• system• orientation• accelerometer• GPS• heading• touch• timer• ...
Event Types
coronalabs.comAMBASSADOR
Properties:• x, y• xStart, yStart• phase• id• time
Touch + Multitouch
object:addEventListener("touch", listener)
CONFIDENTIALcoronalabs.com
Let’s build a game on the fly!
coronalabs.comAMBASSADOR
www.coronalabs.com/gmic/pong.zip
coronalabs.comAMBASSADOR
Pong-Lesson 1
transition.to(ball, {time=1000,x=440,y=300} )
Basic Animation
coronalabs.comAMBASSADOR
Pong-Lesson 2
system.activate( "multitouch" )
local function startDrag( event ) -‐-‐ do somethingend
paddle1:addEventListener( "touch", startDrag )paddle2:addEventListener( "touch", startDrag )
Make paddles respond to touches
coronalabs.comAMBASSADOR
Pong-Lesson 2
local function startDrag( event ) local t = event.target local phase = event.phase
if "began" == phase then display.getCurrentStage():setFocus( t, event.id ) t.isFocus = true
-‐-‐ Store initial position t.x0 = event.x -‐ t.x t.y0 = event.y -‐ t.y...
coronalabs.comAMBASSADOR
Pong-Lesson 2
... elseif t.isFocus then if "moved" == phase then if ( event.y -‐ t.y0 > 20 ) and ( event.y -‐ t.y0 < _H-‐20 ) then t.y = event.y -‐ t.y0 end elseif "ended"==phase or "cancelled"== phase then display.getCurrentStage():setFocus( nil ) t.isFocus = false end end
return trueend
coronalabs.comAMBASSADOR
Pong-Lesson 3
local physics = require("physics")physics.start()physics.setGravity( 0, 0 )
Animate ball with physics
coronalabs.comAMBASSADOR
Pong-Lesson 3local function newBall() ball = display.newImage( "puck_yellow.png" ) ball.x = _W/2 -‐-‐ center it ball.y = _H/2 ball:scale( 0.2, 0.2 )
end
physics.addBody( ball, {density=0.3,friction=0.6,radius=radius} )
xVelocity = velocity yVelocity = 0
ball:setLinearVelocity(xVelocity, yVelocity)
coronalabs.comAMBASSADOR
Pong-Lesson 4
physics.addBody( paddle1, { density=0.3, friction=0.6 } )paddle1.isFixedRotation = truepaddle1.isPlatform = truepaddle1.bodyType = "kinematic"
physics.addBody( paddle2, { density=0.3, friction=0.6 } )paddle2.isFixedRotation = truepaddle2.isPlatform = truepaddle2.bodyType = "kinematic"
Balls should bounce on paddles
coronalabs.comAMBASSADOR
Pong-Lesson 5
local function paddleCollision( self, event ) -‐-‐ do somethingend
paddle1.collision = paddleCollisionpaddle1:addEventListener("collision", paddle1)
paddle2.collision = paddleCollisionpaddle2:addEventListener("collision", paddle2)
Paddles can change ball angle. Eliminate friction.
coronalabs.comAMBASSADOR
Pong-Lesson 5local function paddleCollision( self, event if( event.phase == "began" ) then local offset = self.y -‐ event.other.y local totalSize = (radius+paddleHeight)/2 local percent = math.abs(offset/totalSize) xVelocity = xVelocity * -‐1 if offset > 0 then yVelocity = (velocity*percent) * -‐1 else yVelocity = (velocity*percent) end ball:setLinearVelocity(xVelocity,yVelocity) endend
coronalabs.comAMBASSADOR
Pong-Lesson 6
local leftWall = display.newRect(10,0,2,_H)physics.addBody( leftWall )leftWall.bodyType = "kinematic"leftWall.myName = "leftWall"
local rightWall = display.newRect(470,0,2,_H)physics.addBody( rightWall )rightWall.bodyType = "kinematic"rightWall.myName = "rightWall"
Ball should bounce at edges of screen
coronalabs.comAMBASSADOR
Pong-Lesson 6
local topWall = display.newRect(0,0,_W,2)physics.addBody( topWall )topWall.bodyType = "kinematic"
local bottomWall = display.newRect(0,_H-‐2,_W,2)physics.addBody( bottomWall )bottomWall.bodyType = "kinematic"
coronalabs.comAMBASSADOR
Pong-Lesson 7
local function onCollide( event ) if( event.phase == "began" ) then yVelocity = yVelocity * -‐1 ball:setLinearVelocity(xVelocity,yVelocity) return true endend
topWall:addEventListener("collision",onCollide)bottomWall:addEventListener("collision",onCollide)
Maintain ball’s velocity after bouncing off top/bottom walls
coronalabs.comAMBASSADOR
Pong-Lesson 8
local function onSideCollision( event ) if ( event.phase == "began" ) then timer.performWithDelay( 33, removeBall ) timer.performWithDelay( 1000, newBall ) end return true end
leftWall:addEventListener( "collision", onSideCollision )
rightWall:addEventListener( "collision", onSideCollision )
Detect when ball gets past the paddle
coronalabs.comAMBASSADOR
Multiple Screen Sizes/Shapes
coronalabs.comAMBASSADOR
Content Scaling in Corona
coronalabs.comAMBASSADOR
Content Scaling
-‐-‐ config.luaapplication = { content = { width = 320, height = 480, scale = "letterbox", },}
• Code in content units (not screen pixels)• width/height specify content dimensions• Scale mode determines how physical display is #lled
coronalabs.comAMBASSADOR
Retina Imaging in Corona
-‐-‐ config.luaapplication = { content = { width = 320, height = 480, scale = "letterbox",
imageSuffix = { ["-‐x15"] = 1.5, ["-‐x2"] = 2, }, },}
coronalabs.comAMBASSADOR
Retina Imaging API
display.newImageRect( imageName, w, h )
• width/height in content units (not screen pixels)• Best matching image #le based on scale factor• Suffixes in con#g.lua determine image/scale mapping
coronalabs.comAMBASSADOR
The developer community loves Corona
“With Corona I felt right at home immediately, feels like JavaScript. I’m not sleeping because the development is so addicting!” —Angelo Yazar, Unity Developer
“Corona performanceis phenomenal! I love
the power and flexibility. It allows me to make better games!”
– Joe Kauffman, Flash developer,
ex-GameSalad user
“Thank you for making Corona. I found it to be the perfect SDK for a
Flash developer like me.” – Ferry Halim, famed Flash Developer and Webby Award winner
“I tried Obj-C but didn’t like the results. I found Gamesalad but wasn’t pleased with it and made the jump to Corona. I was loving it. It gave me a lot more control and speed.” – Robert Nay, 14 year old
“In the past, we had to drop projects made in cocos2D because it was much more time
consuming. Corona is simple enough for an artist or designer to code a feature themselves.”
— Randy Shepherd, Cocos2d/Xbox developer “If you're serious about developing apps and games but
don't want to get into Obj-C/Xcode, I don't think GameSalad is
the right choice. I moved from using GameSalad to Corona, which is IMHO 100x better.”
– Jon Beebe, ex-GameSalad user
“For movement and performance, Appcelerator Titanium really wasn’t
an option. Corona really impressed me when I saw how easy it was to get graphics on to the screen and have them look great on the device.” –
David Fox, web developer
“Many people think that mobile development is difficult because of the different programming languages (Objective-C, Java, etc.) For those people, Corona is probably the best solution — it’s accessible, simple,
powerful, and not a barrier to creativity.” – Julian Paté, web developer
“I explored many options for new iPhone developers and I have to say Corona just felt right. It was easy to pick up in a short time and powerful
enough to enable really cool things to be done.”– Matt Pringle, designer for EA/3DO
“We were able to develop our first application with Corona in just a few days! Porting
apps from Flash to Corona is quite easy and substantially lowers development costs.”
– Bohumil Vosicky, educational developer
“Coming from Flash, it looked a little too simplistic at the beginning, but Corona’s simplicity and ease of use doesn’t limit what you can do.”– Ruben Frosali, Flash Developer
“We chose Corona because we’d get new component functions out more rapidly than via Cocoa Touch or Cocos2d. Supporting all of the iOS devices was a lot more seamless for us than was the case with Cocos2d.”
— Mark Sigal, eBook publisher
CONFIDENTIALcoronalabs.com
Staff Pick
Award-winning Technology
coronalabs.comAMBASSADOR
Thriving Ecosystem
CoronaFireworksPhotoshop
Zwoptex
TextMate
Particle Candy
Corona Remote
Corona Project Manager
Lime
Sprite Deck
iAppHost
Texture Packer
coronalabs.comAMBASSADOR
Corona as a career
“In what I hope is a good omen of things to come, this December I'm on track to earn substantially more money developing Corona-based apps for clients than I will at my (pretty well-paid) day job.
2012 may just be the year I stop working for somebody else.”– Jason Schroedere, designer for EA/3DO
Over 1000+ studios in 75 countries around the world
coronalabs.comAMBASSADOR
Is it fun?
“What is so great about Corona is it is so easy to just write code and get things working. You immediately see your results on the screen. That is what was so great about Applesoft or Logo. But they were just toy graphic languages. Yours is first class.”
— Dave Lazarony,Creator of ADM
(Adobe’s UI Framework)
coronalabs.comAMBASSADOR
Anyone can be #1... with Corona
coronalabs.comAMBASSADOR
Get Corona free trial
www.CoronaLabs.com