Initial commit: Star Explorer Solar2D Game

This commit is contained in:
atseirjo
2026-05-22 09:16:59 +02:00
commit 5ab78b4c20
62 changed files with 1258 additions and 0 deletions

27
.gitignore vendored Normal file
View File

@@ -0,0 +1,27 @@
# Solar2D / Corona SDK
*.bak
*.orig
*.tmp
*.log
# macOS
.DS_Store
.AppleDouble
.LSOverride
# Windows
Thumbs.db
ehthumbs.db
Desktop.ini
# Build directories
build/
*.apk
*.ipa
*.app
# IDE
.vscode/
.idea/
*.swp
*.swo

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 920 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#e2e2e2</color>
</resources>

BIN
Icon-120.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
Icon-152.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
Icon-167.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

BIN
Icon-180.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
Icon-40.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
Icon-58.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
Icon-76.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
Icon-80.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
Icon-87.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
Icon-hdpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
Icon-ldpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
Icon-mdpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

BIN
Icon-xhdpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
Icon-xxhdpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
Icon-xxxhdpi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
Icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 B

View File

@@ -0,0 +1,108 @@
{
"images" : [
{
"size" : "20x20",
"idiom" : "iphone",
"filename" : "Icon-40.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-58.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "Icon-87.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "Icon-80.png",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-120.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "Icon-180.png",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-76.png",
"scale" : "1x"
},
{
"size" : "76x76",
"idiom" : "ipad",
"filename" : "Icon-152.png",
"scale" : "2x"
},
{
"size" : "83.5x83.5",
"idiom" : "ipad",
"filename" : "Icon-167.png",
"scale" : "2x"
},
{
"size" : "1024x1024",
"idiom" : "ios-marketing",
"filename" : "Icon-1024.png",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 581 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 859 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16D32" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
<viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

25
README.md Normal file
View File

@@ -0,0 +1,25 @@
# Star Explorer
This is an example game built with [Corona](http://www.coronalabs.com) to go along with the [Getting Started](https://docs.coronalabs.com/guide/programming/index.html) tutorial. The included source code goes along with the respective chapter.
## Chapters
* [Introduction to Corona](https://docs.coronalabs.com/guide/programming/intro/index.html)
* [Chapter 1 — Creating an App](https://docs.coronalabs.com/guide/programming/01/index.html)
* [Chapter 2 — Upward & Onward](https://docs.coronalabs.com/guide/programming/02/index.html)
* [Chapter 3 — Bringing it to Life](https://docs.coronalabs.com/guide/programming/03/index.html)
* [Chapter 4 — Creating Scenes](https://docs.coronalabs.com/guide/programming/04/index.html)
* [Chapter 5 — Converting the Game to Composer](https://docs.coronalabs.com/guide/programming/05/index.html)
* [Chapter 6 — Implementing High Scores](https://docs.coronalabs.com/guide/programming/06/index.html)
* [Chapter 7 — Sounds and Music](https://docs.coronalabs.com/guide/programming/07/index.html)
* [Chapter 8 — Deployment](https://docs.coronalabs.com/guide/programming/08/index.html)
## Credits
[Corona Labs](http://www.coronalabs.com) would like to extend its gratitude to:
* Dr. Brian Burton ([burtonsmediagroup.com](http://www.burtonsmediagroup.com)) for his guidance, direction, and core tutorial content in creating this series. He has also created several [books](http://www.burtonsmediagroup.com/) about programming in Corona SDK.
* Eric Matyas ([soundimage.org](http://www.soundimage.org)) for the game's music and sound effects. Eric offers numerous audio tracks and sound effects on his website, available on a donation basis.
* ([Kenney](http://kenney.nl/)) for some of the game artwork. Kenney game studio supports other developers by creating free game assets and high quality learning material.

Binary file not shown.

BIN
audio/Escape_Looping.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
audio/explosion.wav Normal file

Binary file not shown.

BIN
audio/fire.wav Normal file

Binary file not shown.

BIN
background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 133 KiB

57
build.settings Normal file
View File

@@ -0,0 +1,57 @@
--
-- For more information on build.settings, see the Project Build Settings guide at:
-- https://docs.coronalabs.com/guide/distribution/buildSettings
--
settings =
{
orientation =
{
-- Supported values for orientation:
-- portrait, portraitUpsideDown, landscapeLeft, landscapeRight
default = "portrait",
supported = { "portrait", },
},
--
-- Android section
--
android =
{
usesPermissions =
{
"android.permission.INTERNET",
},
},
--
-- iOS section
--
iphone =
{
xcassets = "Images.xcassets",
plist =
{
UIStatusBarHidden = false,
UILaunchStoryboardName = "LaunchScreen",
},
},
--
-- Plugins section
--
plugins =
{
},
--
-- Project section
--
excludeFiles =
{
-- Exclude unnecessary files for each platform
all = { "Icon.png", "Icon-*dpi.png", "Images.xcassets", },
android = { "LaunchScreen.storyboardc", },
},
}

23
config.lua Normal file
View File

@@ -0,0 +1,23 @@
--
-- For more information on config.lua see the Project Configuration Guide at:
-- https://docs.coronalabs.com/guide/basics/configSettings
--
application =
{
content =
{
width = 768,
height = 1024,
scale = "zoomEven",
fps = 60,
--[[
imageSuffix =
{
["@2x"] = 2,
["@4x"] = 4,
},
--]]
},
}

360
game.lua Normal file
View File

@@ -0,0 +1,360 @@
local composer = require( "composer" )
local scene = composer.newScene()
-- -----------------------------------------------------------------------------------
-- Code outside of the scene event functions below will only be executed ONCE unless
-- the scene is removed entirely (not recycled) via "composer.removeScene()"
-- -----------------------------------------------------------------------------------
local physics = require( "physics" )
physics.start()
physics.setGravity( 0, 0 )
-- Configure image sheet
local sheetOptions =
{
frames =
{
{ -- 1) asteroid 1
x = 0,
y = 0,
width = 102,
height = 85
},
{ -- 2) asteroid 2
x = 0,
y = 85,
width = 90,
height = 83
},
{ -- 3) asteroid 3
x = 0,
y = 168,
width = 100,
height = 97
},
{ -- 4) ship
x = 0,
y = 265,
width = 98,
height = 79
},
{ -- 5) laser
x = 98,
y = 265,
width = 14,
height = 40
},
},
}
local objectSheet = graphics.newImageSheet( "gameObjects.png", sheetOptions )
-- Initialize variables
local lives = 3
local score = 0
local died = false
local asteroidsTable = {}
local ship
local gameLoopTimer
local livesText
local scoreText
local backGroup
local mainGroup
local uiGroup
local explosionSound
local fireSound
local musicTrack
local function updateText()
livesText.text = "Lives: " .. lives
scoreText.text = "Score: " .. score
end
local function createAsteroid()
local newAsteroid = display.newImageRect( mainGroup, objectSheet, 1, 102, 85 )
table.insert( asteroidsTable, newAsteroid )
physics.addBody( newAsteroid, "dynamic", { radius=40, bounce=0.8 } )
newAsteroid.myName = "asteroid"
local whereFrom = math.random( 3 )
if ( whereFrom == 1 ) then
-- From the left
newAsteroid.x = -60
newAsteroid.y = math.random( 500 )
newAsteroid:setLinearVelocity( math.random( 40,120 ), math.random( 20,60 ) )
elseif ( whereFrom == 2 ) then
-- From the top
newAsteroid.x = math.random( display.contentWidth )
newAsteroid.y = -60
newAsteroid:setLinearVelocity( math.random( -40,40 ), math.random( 40,120 ) )
elseif ( whereFrom == 3 ) then
-- From the right
newAsteroid.x = display.contentWidth + 60
newAsteroid.y = math.random( 500 )
newAsteroid:setLinearVelocity( math.random( -120,-40 ), math.random( 20,60 ) )
end
newAsteroid:applyTorque( math.random( -6,6 ) )
end
local function fireLaser()
-- Play fire sound!
audio.play( fireSound )
local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 )
physics.addBody( newLaser, "dynamic", { isSensor=true } )
newLaser.isBullet = true
newLaser.myName = "laser"
newLaser.x = ship.x
newLaser.y = ship.y
newLaser:toBack()
transition.to( newLaser, { y=-40, time=500,
onComplete = function() display.remove( newLaser ) end
} )
end
local function dragShip( event )
local ship = event.target
local phase = event.phase
if ( "began" == phase ) then
-- Set touch focus on the ship
display.currentStage:setFocus( ship )
-- Store initial offset position
ship.touchOffsetX = event.x - ship.x
elseif ( "moved" == phase ) then
-- Move the ship to the new touch position
ship.x = event.x - ship.touchOffsetX
elseif ( "ended" == phase or "cancelled" == phase ) then
-- Release touch focus on the ship
display.currentStage:setFocus( nil )
end
return true -- Prevents touch propagation to underlying objects
end
local function gameLoop()
-- Create new asteroid
createAsteroid()
-- Remove asteroids which have drifted off screen
for i = #asteroidsTable, 1, -1 do
local thisAsteroid = asteroidsTable[i]
if ( thisAsteroid.x < -100 or
thisAsteroid.x > display.contentWidth + 100 or
thisAsteroid.y < -100 or
thisAsteroid.y > display.contentHeight + 100 )
then
display.remove( thisAsteroid )
table.remove( asteroidsTable, i )
end
end
end
local function restoreShip()
ship.isBodyActive = false
ship.x = display.contentCenterX
ship.y = display.contentHeight - 100
-- Fade in the ship
transition.to( ship, { alpha=1, time=4000,
onComplete = function()
ship.isBodyActive = true
died = false
end
} )
end
local function endGame()
composer.setVariable( "finalScore", score )
composer.gotoScene( "highscores", { time=800, effect="crossFade" } )
end
local function onCollision( event )
if ( event.phase == "began" ) then
local obj1 = event.object1
local obj2 = event.object2
if ( ( obj1.myName == "laser" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "laser" ) )
then
-- Remove both the laser and asteroid
display.remove( obj1 )
display.remove( obj2 )
-- Play explosion sound!
audio.play( explosionSound )
for i = #asteroidsTable, 1, -1 do
if ( asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2 ) then
table.remove( asteroidsTable, i )
break
end
end
-- Increase score
score = score + 100
scoreText.text = "Score: " .. score
elseif ( ( obj1.myName == "ship" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "ship" ) )
then
if ( died == false ) then
died = true
-- Play explosion sound!
audio.play( explosionSound )
-- Update lives
lives = lives - 1
livesText.text = "Lives: " .. lives
if ( lives == 0 ) then
display.remove( ship )
timer.performWithDelay( 2000, endGame )
else
ship.alpha = 0
timer.performWithDelay( 1000, restoreShip )
end
end
end
end
end
-- -----------------------------------------------------------------------------------
-- Scene event functions
-- -----------------------------------------------------------------------------------
-- create()
function scene:create( event )
local sceneGroup = self.view
-- Code here runs when the scene is first created but has not yet appeared on screen
physics.pause() -- Temporarily pause the physics engine
-- Set up display groups
backGroup = display.newGroup() -- Display group for the background image
sceneGroup:insert( backGroup ) -- Insert into the scene's view group
mainGroup = display.newGroup() -- Display group for the ship, asteroids, lasers, etc.
sceneGroup:insert( mainGroup ) -- Insert into the scene's view group
uiGroup = display.newGroup() -- Display group for UI objects like the score
sceneGroup:insert( uiGroup ) -- Insert into the scene's view group
-- Load the background
local background = display.newImageRect( backGroup, "background.png", 800, 1400 )
background.x = display.contentCenterX
background.y = display.contentCenterY
ship = display.newImageRect( mainGroup, objectSheet, 4, 98, 79 )
ship.x = display.contentCenterX
ship.y = display.contentHeight - 100
physics.addBody( ship, { radius=30, isSensor=true } )
ship.myName = "ship"
-- Display lives and score
livesText = display.newText( uiGroup, "Lives: " .. lives, 200, 80, native.systemFont, 36 )
scoreText = display.newText( uiGroup, "Score: " .. score, 400, 80, native.systemFont, 36 )
ship:addEventListener( "tap", fireLaser )
ship:addEventListener( "touch", dragShip )
explosionSound = audio.loadSound( "audio/explosion.wav" )
fireSound = audio.loadSound( "audio/fire.wav" )
musicTrack = audio.loadStream( "audio/80s-Space-Game_Looping.wav" )
end
-- show()
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is still off screen (but is about to come on screen)
elseif ( phase == "did" ) then
-- Code here runs when the scene is entirely on screen
physics.start()
Runtime:addEventListener( "collision", onCollision )
gameLoopTimer = timer.performWithDelay( 500, gameLoop, 0 )
-- Start the music!
audio.play( musicTrack, { channel=1, loops=-1 } )
end
end
-- hide()
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is on screen (but is about to go off screen)
timer.cancel( gameLoopTimer )
elseif ( phase == "did" ) then
-- Code here runs immediately after the scene goes entirely off screen
Runtime:removeEventListener( "collision", onCollision )
physics.pause()
-- Stop the music!
audio.stop( 1 )
composer.removeScene( "game" )
end
end
-- destroy()
function scene:destroy( event )
local sceneGroup = self.view
-- Code here runs prior to the removal of scene's view
-- Dispose audio!
audio.dispose( explosionSound )
audio.dispose( fireSound )
audio.dispose( musicTrack )
end
-- -----------------------------------------------------------------------------------
-- Scene event function listeners
-- -----------------------------------------------------------------------------------
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -----------------------------------------------------------------------------------
return scene

BIN
gameObjects.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

156
highscores.lua Normal file
View File

@@ -0,0 +1,156 @@
local composer = require( "composer" )
local scene = composer.newScene()
-- -----------------------------------------------------------------------------------
-- Code outside of the scene event functions below will only be executed ONCE unless
-- the scene is removed entirely (not recycled) via "composer.removeScene()"
-- -----------------------------------------------------------------------------------
-- Initialize variables
local json = require( "json" )
local scoresTable = {}
local filePath = system.pathForFile( "scores.json", system.DocumentsDirectory )
local function loadScores()
local file = io.open( filePath, "r" )
if file then
local contents = file:read( "*a" )
io.close( file )
scoresTable = json.decode( contents )
end
if ( scoresTable == nil or #scoresTable == 0 ) then
scoresTable = { 10000, 7500, 5200, 4700, 3500, 3200, 1200, 1100, 800, 500 }
end
end
local function saveScores()
for i = #scoresTable, 11, -1 do
table.remove( scoresTable, i )
end
local file = io.open( filePath, "w" )
if file then
file:write( json.encode( scoresTable ) )
io.close( file )
end
end
local function gotoMenu()
composer.gotoScene( "menu", { time=800, effect="crossFade" } )
end
-- -----------------------------------------------------------------------------------
-- Scene event functions
-- -----------------------------------------------------------------------------------
-- create()
function scene:create( event )
local sceneGroup = self.view
-- Code here runs when the scene is first created but has not yet appeared on screen
-- Load the previous scores
loadScores()
-- Insert the saved score from the last game into the table, then reset it
table.insert( scoresTable, composer.getVariable( "finalScore" ) )
composer.setVariable( "finalScore", 0 )
-- Sort the table entries from highest to lowest
local function compare( a, b )
return a > b
end
table.sort( scoresTable, compare )
-- Save the scores
saveScores()
local background = display.newImageRect( sceneGroup, "background.png", 800, 1400 )
background.x = display.contentCenterX
background.y = display.contentCenterY
local highScoresHeader = display.newText( sceneGroup, "High Scores", display.contentCenterX, 100, native.systemFont, 44 )
for i = 1, 10 do
if ( scoresTable[i] ) then
local yPos = 150 + ( i * 56 )
local rankNum = display.newText( sceneGroup, i .. ")", display.contentCenterX-50, yPos, native.systemFont, 36 )
rankNum:setFillColor( 0.8 )
rankNum.anchorX = 1
local thisScore = display.newText( sceneGroup, scoresTable[i], display.contentCenterX-30, yPos, native.systemFont, 36 )
thisScore.anchorX = 0
end
end
local menuButton = display.newText( sceneGroup, "Menu", display.contentCenterX, 810, native.systemFont, 44 )
menuButton:setFillColor( 0.75, 0.78, 1 )
menuButton:addEventListener( "tap", gotoMenu )
end
-- show()
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is still off screen (but is about to come on screen)
elseif ( phase == "did" ) then
-- Code here runs when the scene is entirely on screen
end
end
-- hide()
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is on screen (but is about to go off screen)
elseif ( phase == "did" ) then
-- Code here runs immediately after the scene goes entirely off screen
composer.removeScene( "highscores" )
end
end
-- destroy()
function scene:destroy( event )
local sceneGroup = self.view
-- Code here runs prior to the removal of scene's view
end
-- -----------------------------------------------------------------------------------
-- Scene event function listeners
-- -----------------------------------------------------------------------------------
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -----------------------------------------------------------------------------------
return scene

25
main.lua Normal file
View File

@@ -0,0 +1,25 @@
-- Copyright (c) 2017 Corona Labs Inc.
-- Code is MIT licensed and can be re-used; see https://www.coronalabs.com/links/code/license
-- Other assets are licensed by their creators:
-- Art assets by Kenney: http://kenney.nl/assets
-- Music and sound effect assets by Eric Matyas: http://www.soundimage.org
print("main.lua file accessed")
local composer = require("composer")
-- Hide status bar
display.setStatusBar(display.HiddenStatusBar)
-- Seed the random number generator
math.randomseed(os.time())
-- Reserve channel 1 for background music
audio.reserveChannels(1)
-- Reduce the overall volume of the channel
audio.setVolume(0.5, { channel = 1 })
-- Go to the menu screen
composer.gotoScene("menu")

255
main_original.lua Normal file
View File

@@ -0,0 +1,255 @@
-- Copyright (c) 2017 Corona Labs Inc.
-- Code is MIT licensed and can be re-used; see https://www.coronalabs.com/links/code/license
-- Other assets are licensed by their creators:
-- Art assets by Kenney: http://kenney.nl/assets
-- Music and sound effect assets by Eric Matyas: http://www.soundimage.org
local physics = require( "physics" )
physics.start()
physics.setGravity( 0, 0 )
-- Seed the random number generator
math.randomseed( os.time() )
-- Configure image sheet
local sheetOptions =
{
frames =
{
{ -- 1) asteroid 1
x = 0,
y = 0,
width = 102,
height = 85
},
{ -- 2) asteroid 2
x = 0,
y = 85,
width = 90,
height = 83
},
{ -- 3) asteroid 3
x = 0,
y = 168,
width = 100,
height = 97
},
{ -- 4) ship
x = 0,
y = 265,
width = 98,
height = 79
},
{ -- 5) laser
x = 98,
y = 265,
width = 14,
height = 40
},
},
}
local objectSheet = graphics.newImageSheet( "gameObjects.png", sheetOptions )
-- Initialize variables
local lives = 3
local score = 0
local died = false
local asteroidsTable = {}
local ship
local gameLoopTimer
local livesText
local scoreText
-- Set up display groups
local backGroup = display.newGroup() -- Display group for the background image
local mainGroup = display.newGroup() -- Display group for the ship, asteroids, lasers, etc.
local uiGroup = display.newGroup() -- Display group for UI objects like the score
-- Load the background
local background = display.newImageRect( backGroup, "background.png", 800, 1400 )
background.x = display.contentCenterX
background.y = display.contentCenterY
ship = display.newImageRect( mainGroup, objectSheet, 4, 98, 79 )
ship.x = display.contentCenterX
ship.y = display.contentHeight - 100
physics.addBody( ship, { radius=30, isSensor=true } )
ship.myName = "ship"
-- Display lives and score
livesText = display.newText( uiGroup, "Lives: " .. lives, 200, 80, native.systemFont, 36 )
scoreText = display.newText( uiGroup, "Score: " .. score, 400, 80, native.systemFont, 36 )
-- Hide the status bar
display.setStatusBar( display.HiddenStatusBar )
local function updateText()
livesText.text = "Lives: " .. lives
scoreText.text = "Score: " .. score
end
local function createAsteroid()
local newAsteroid = display.newImageRect( mainGroup, objectSheet, 1, 102, 85 )
table.insert( asteroidsTable, newAsteroid )
physics.addBody( newAsteroid, "dynamic", { radius=40, bounce=0.8 } )
newAsteroid.myName = "asteroid"
local whereFrom = math.random( 3 )
if ( whereFrom == 1 ) then
-- From the left
newAsteroid.x = -60
newAsteroid.y = math.random( 500 )
newAsteroid:setLinearVelocity( math.random( 40,120 ), math.random( 20,60 ) )
elseif ( whereFrom == 2 ) then
-- From the top
newAsteroid.x = math.random( display.contentWidth )
newAsteroid.y = -60
newAsteroid:setLinearVelocity( math.random( -40,40 ), math.random( 40,120 ) )
elseif ( whereFrom == 3 ) then
-- From the right
newAsteroid.x = display.contentWidth + 60
newAsteroid.y = math.random( 500 )
newAsteroid:setLinearVelocity( math.random( -120,-40 ), math.random( 20,60 ) )
end
newAsteroid:applyTorque( math.random( -6,6 ) )
end
local function fireLaser()
local newLaser = display.newImageRect( mainGroup, objectSheet, 5, 14, 40 )
physics.addBody( newLaser, "dynamic", { isSensor=true } )
newLaser.isBullet = true
newLaser.myName = "laser"
newLaser.x = ship.x
newLaser.y = ship.y
newLaser:toBack()
transition.to( newLaser, { y=-40, time=500,
onComplete = function() display.remove( newLaser ) end
} )
end
ship:addEventListener( "tap", fireLaser )
local function dragShip( event )
local ship = event.target
local phase = event.phase
if ( "began" == phase ) then
-- Set touch focus on the ship
display.currentStage:setFocus( ship )
-- Store initial offset position
ship.touchOffsetX = event.x - ship.x
elseif ( "moved" == phase ) then
-- Move the ship to the new touch position
ship.x = event.x - ship.touchOffsetX
elseif ( "ended" == phase or "cancelled" == phase ) then
-- Release touch focus on the ship
display.currentStage:setFocus( nil )
end
return true -- Prevents touch propagation to underlying objects
end
ship:addEventListener( "touch", dragShip )
local function gameLoop()
-- Create new asteroid
createAsteroid()
-- Remove asteroids which have drifted off screen
for i = #asteroidsTable, 1, -1 do
local thisAsteroid = asteroidsTable[i]
if ( thisAsteroid.x < -100 or
thisAsteroid.x > display.contentWidth + 100 or
thisAsteroid.y < -100 or
thisAsteroid.y > display.contentHeight + 100 )
then
display.remove( thisAsteroid )
table.remove( asteroidsTable, i )
end
end
end
gameLoopTimer = timer.performWithDelay( 500, gameLoop, 0 )
local function restoreShip()
ship.isBodyActive = false
ship.x = display.contentCenterX
ship.y = display.contentHeight - 100
-- Fade in the ship
transition.to( ship, { alpha=1, time=4000,
onComplete = function()
ship.isBodyActive = true
died = false
end
} )
end
local function onCollision( event )
if ( event.phase == "began" ) then
local obj1 = event.object1
local obj2 = event.object2
if ( ( obj1.myName == "laser" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "laser" ) )
then
-- Remove both the laser and asteroid
display.remove( obj1 )
display.remove( obj2 )
for i = #asteroidsTable, 1, -1 do
if ( asteroidsTable[i] == obj1 or asteroidsTable[i] == obj2 ) then
table.remove( asteroidsTable, i )
break
end
end
-- Increase score
score = score + 100
scoreText.text = "Score: " .. score
elseif ( ( obj1.myName == "ship" and obj2.myName == "asteroid" ) or
( obj1.myName == "asteroid" and obj2.myName == "ship" ) )
then
if ( died == false ) then
died = true
-- Update lives
lives = lives - 1
livesText.text = "Lives: " .. lives
if ( lives == 0 ) then
display.remove( ship )
else
ship.alpha = 0
timer.performWithDelay( 1000, restoreShip )
end
end
end
end
end
Runtime:addEventListener( "collision", onCollision )

99
menu.lua Normal file
View File

@@ -0,0 +1,99 @@
local composer = require( "composer" )
local scene = composer.newScene()
-- -----------------------------------------------------------------------------------
-- Code outside of the scene event functions below will only be executed ONCE unless
-- the scene is removed entirely (not recycled) via "composer.removeScene()"
-- -----------------------------------------------------------------------------------
local function gotoGame()
composer.gotoScene( "game", { time=800, effect="crossFade" } )
end
local function gotoHighScores()
composer.gotoScene( "highscores", { time=800, effect="crossFade" } )
end
-- -----------------------------------------------------------------------------------
-- Scene event functions
-- -----------------------------------------------------------------------------------
-- create()
function scene:create( event )
local sceneGroup = self.view
-- Code here runs when the scene is first created but has not yet appeared on screen
local background = display.newImageRect( sceneGroup, "background.png", 800, 1400 )
background.x = display.contentCenterX
background.y = display.contentCenterY
local title = display.newImageRect( sceneGroup, "title.png", 500, 80 )
title.x = display.contentCenterX
title.y = 200
local playButton = display.newText( sceneGroup, "Play", display.contentCenterX, 700, native.systemFont, 44 )
playButton:setFillColor( 0.82, 0.86, 1 )
local highScoresButton = display.newText( sceneGroup, "High Scores", display.contentCenterX, 810, native.systemFont, 44 )
highScoresButton:setFillColor( 0.75, 0.78, 1 )
playButton:addEventListener( "tap", gotoGame )
highScoresButton:addEventListener( "tap", gotoHighScores )
end
-- show()
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is still off screen (but is about to come on screen)
elseif ( phase == "did" ) then
-- Code here runs when the scene is entirely on screen
end
end
-- hide()
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is on screen (but is about to go off screen)
elseif ( phase == "did" ) then
-- Code here runs immediately after the scene goes entirely off screen
end
end
-- destroy()
function scene:destroy( event )
local sceneGroup = self.view
-- Code here runs prior to the removal of scene's view
end
-- -----------------------------------------------------------------------------------
-- Scene event function listeners
-- -----------------------------------------------------------------------------------
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -----------------------------------------------------------------------------------
return scene

77
scene-template.lua Normal file
View File

@@ -0,0 +1,77 @@
local composer = require( "composer" )
local scene = composer.newScene()
-- -----------------------------------------------------------------------------------
-- Code outside of the scene event functions below will only be executed ONCE unless
-- the scene is removed entirely (not recycled) via "composer.removeScene()"
-- -----------------------------------------------------------------------------------
-- -----------------------------------------------------------------------------------
-- Scene event functions
-- -----------------------------------------------------------------------------------
-- create()
function scene:create( event )
local sceneGroup = self.view
-- Code here runs when the scene is first created but has not yet appeared on screen
end
-- show()
function scene:show( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is still off screen (but is about to come on screen)
elseif ( phase == "did" ) then
-- Code here runs when the scene is entirely on screen
end
end
-- hide()
function scene:hide( event )
local sceneGroup = self.view
local phase = event.phase
if ( phase == "will" ) then
-- Code here runs when the scene is on screen (but is about to go off screen)
elseif ( phase == "did" ) then
-- Code here runs immediately after the scene goes entirely off screen
end
end
-- destroy()
function scene:destroy( event )
local sceneGroup = self.view
-- Code here runs prior to the removal of scene's view
end
-- -----------------------------------------------------------------------------------
-- Scene event function listeners
-- -----------------------------------------------------------------------------------
scene:addEventListener( "create", scene )
scene:addEventListener( "show", scene )
scene:addEventListener( "hide", scene )
scene:addEventListener( "destroy", scene )
-- -----------------------------------------------------------------------------------
return scene

BIN
title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB