Initial commit: Star Explorer Solar2D Game
27
.gitignore
vendored
Normal 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
|
||||||
5
AndroidResources/res/mipmap-anydpi-v26/ic_launcher.xml
Normal 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>
|
||||||
BIN
AndroidResources/res/mipmap-hdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
BIN
AndroidResources/res/mipmap-hdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
AndroidResources/res/mipmap-mdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 664 B |
BIN
AndroidResources/res/mipmap-mdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 920 B |
BIN
AndroidResources/res/mipmap-xhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
AndroidResources/res/mipmap-xhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
AndroidResources/res/mipmap-xxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
AndroidResources/res/mipmap-xxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
AndroidResources/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
AndroidResources/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
4
AndroidResources/res/values/values.xml
Normal 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
|
After Width: | Height: | Size: 23 KiB |
BIN
Icon-152.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
Icon-167.png
Normal file
|
After Width: | Height: | Size: 38 KiB |
BIN
Icon-180.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
Icon-40.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Icon-58.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
Icon-76.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Icon-80.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
Icon-87.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
Icon-hdpi.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
Icon-ldpi.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
Icon-mdpi.png
Normal file
|
After Width: | Height: | Size: 6.1 KiB |
BIN
Icon-xhdpi.png
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
Icon-xxhdpi.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
Icon-xxxhdpi.png
Normal file
|
After Width: | Height: | Size: 52 KiB |
108
Images.xcassets/AppIcon.appiconset/Contents.json
Normal 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Images.xcassets/AppIcon.appiconset/Icon-1024.png
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-120.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-152.png
Normal file
|
After Width: | Height: | Size: 2.5 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-167.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-180.png
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-40.png
Normal file
|
After Width: | Height: | Size: 581 B |
BIN
Images.xcassets/AppIcon.appiconset/Icon-58.png
Normal file
|
After Width: | Height: | Size: 859 B |
BIN
Images.xcassets/AppIcon.appiconset/Icon-76.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-80.png
Normal file
|
After Width: | Height: | Size: 1.2 KiB |
BIN
Images.xcassets/AppIcon.appiconset/Icon-87.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
6
Images.xcassets/Contents.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
LaunchScreen.storyboardc/01J-lp-oVM-view-Ze5-6b-2t3.nib
generated
Normal file
BIN
LaunchScreen.storyboardc/Info.plist
Normal file
BIN
LaunchScreen.storyboardc/UIViewController-01J-lp-oVM.nib
generated
Normal file
31
LaunchScreen.storyboardc/designable.storyboard
Normal 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
@@ -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.
|
||||||
BIN
audio/80s-Space-Game_Looping.wav
Normal file
BIN
audio/Escape_Looping.wav
Normal file
BIN
audio/Midnight-Crawlers_Looping.wav
Normal file
BIN
audio/explosion.wav
Normal file
BIN
audio/fire.wav
Normal file
BIN
background.png
Normal file
|
After Width: | Height: | Size: 133 KiB |
57
build.settings
Normal 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
@@ -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
@@ -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
|
After Width: | Height: | Size: 19 KiB |
156
highscores.lua
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||