Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added a SpriteKit Game for iOS and Mac OS X #43

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions ios/Escape/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
The MIT License (MIT)

Copyright (c) 2014 Mateus

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 changes: 21 additions & 0 deletions ios/Escape/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
Rubymotion Escape
======

Rubymotion Game developed in SpriteKit for iOS7, Apple's new game and physics engine. based on [@StevenVeshkini](https://github.com/StevenVeshkini/) Escape

#

While playing around with some ideas for [Coderdojo Cologne](http://zen.coderdojo.com/dojo/385) lessons,
I found [this post](http://www.reddit.com/r/iOSProgramming/comments/1wc0yi/made_a_small_game_with_spritekit_this_is_my_code/) by [@StevenVeshkini](https://github.com/StevenVeshkini/).
So I decided to port it to [Rubymotion](http://www.rubymotion.com) iOS and Mac OS X. At the end I hope to write this or similar games with the kids and
our next [Coderdojo Cologne](http://zen.coderdojo.com/dojo/385).

Thanks to [Steven Veshkini](https://github.com/StevenVeshkini/) for giving his code for free to ALL.

This code is under __I don't owe you nothing license__ and MIT.


![GameOver](ios_game_over_scene.PNG?raw=true "iOS Gameover Scene" =250x)
![GameScene](ios_game_scene.PNG?raw=true "iOS Game Scene" =250x)
![OSX](osx_game_scene.PNG?raw=true "OS X Game Scene" =250x)
![Start](osx_start_scene.PNG?raw=true "OS X Start A Game Scene" =250x)
33 changes: 33 additions & 0 deletions ios/Escape/app/helpers/constants.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Escape

SCREEN_FRAME = CGRect.new([0, 0], [380, 678])

unless defined?(SKColor)
SKColor = if defined?(UIColor)
UIColor
elsif defined?(NSColor)
NSColor
end
end

GAME_SCREEN_COLOR = SKColor.colorWithRed(0.15, green:0.15, blue:0.3, alpha:1.0)
# SKColor.colorWithRed(0.345, green:0.329, blue:0.314, alpha:1.0)

LEFT_RIGHT_WALL_WIDTH = 10
TOP_BOTTOM_WALL_HEIGHT = 10

module Wall
LEFT = 'leftWall'
RIGHT = 'rightWall'
TOP = 'topWall'
BOTTOM = 'bottomWall'
end

module Category
WALL = 1
MONSTER = 2
PLAYER = 4
PROJECTILE = 8
end

end
28 changes: 28 additions & 0 deletions ios/Escape/app/helpers/vector.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
module Escape # Vector
module Vector

module_function

def add(a, b)
CGPoint.new(a.x + b.x, a.y + b.y)
end

def subtract(a, b)
CGPoint.new(a.x - b.x, a.y - b.y)
end

def resultantLength(a)
Math.sqrt(a.x * a.x + a.y * a.y)
end

def multiply(a, withScalar:scalar)
CGPoint.new(a.x * scalar, a.y * scalar)
end

def normalize(a)
length = resultantLength(a)
CGPoint.new(a.x / length, a.y / length)
end

end
end
115 changes: 115 additions & 0 deletions ios/Escape/app/models/monster.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
module Escape # Monster

# states => :idle | :walking | :seek | :throw
class Monster < SKSpriteNode

def initWithImageNamed(name)
super.tap do
@score = 0
@currentState = :idle
end
end

def moveToSpriteNode(target, withTimeInterval:time)
if @currentState == :idle
targetVector = Vector.subtract(target.position, self.position)

unitizedVector = Vector.normalize(targetVector)

shootAmt = Vector.multiply(unitizedVector, withScalar:self.screenSize.height + self.screenSize.width)

actualDistance = Vector.add(shootAmt, self.position)

moveAction = SKAction.moveTo(actualDistance, duration:time)

self.runAction(moveAction)

@currentState = :seek
end
end


def endSeek
self.removeAllActions
self.chooseNextAction
end


def chooseNextAction
if randomizer(1..3) <= 1 # 67 % chance to walk
@currentState = :walk
self.monsterWalk
else
if self.score >= 0 && Random.rand(1).zero? # 100% chance to throw projectile (33% overall)
self.shootProjectile
end
end
end


def resetState
@currentState = :idle
end


def shootProjectile
@currentState = :throw
end


def monsterWalk
multiplier = 1.5
if @currentState == :walk
randomInterval = Random.rand * multiplier # Time between 0 and 1.5s

# Decide magnitude of walk
walkDistance = randomizer(-80..80)

# Decide direction of walk depending on the current wall
if self.wallIdentifier == Wall::LEFT || self.wallIdentifier == Wall::RIGHT
wallVertical = SKAction.moveByX(0, y:walkDistance, duration:randomInterval)
resetState = SKAction.performSelector(:resetState, onTarget:self)
self.runAction SKAction.sequence([wallVertical, resetState])

elsif self.wallIdentifier == Wall::BOTTOM || self.wallIdentifier == Wall::TOP
walkHorizontal = SKAction.moveByX(walkDistance, y:0, duration:randomInterval)
resetState = SKAction.performSelector(:resetState, onTarget:self)
self.runAction SKAction.sequence([walkHorizontal, resetState])
end
end
end


def updateWithTimeSinceLastUpdate(timeSinceLast)
if self.score >= 100
time = if self.score <= 1000
Random.rand + 2.0
elsif self.score.between?(1000, 3000)
Random.rand + 1.5
elsif self.score.between?(3000, 5000)
Random.rand + 1.0
else
Random.rand + 0.7
end

if @currentState == :idle
self.moveToSpriteNode(self.target, withTimeInterval:time)
end

end
end


attr_accessor :screenSize, :target, :score, :wallIdentifier
attr_reader :currentState


private

def randomizer(range)
@randomizer ||= Random.new
@randomizer.rand(range)
end
end

end
33 changes: 33 additions & 0 deletions ios/Escape/app/models/projectile.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module Escape # Projectile

class Projectile < SKSpriteNode

def moveToSpriteNode(target)
# Get vector from projectile to target
targetVector = Vector.subtract(target.position, self.position)

# Add a random x and y coordinate to the projectile path in order
# to confuse the user and end their game faster
randomizer = Random.new

x = 8 * randomizer.rand(-25..51)
y = 5 * randomizer.rand(-25..51)

randomVector = CGPoint.new(targetVector.x + x, targetVector.y + y)

# make unit vector
direction = Vector.normalize(randomVector)

# May cause glitches
shootAmount = Vector.multiply(direction, withScalar:self.scene.size.height + self.scene.size.width)
actualDistance = Vector.add(shootAmount, self.position)

velocity = 200.0 / 1.0
time = self.scene.size.width / velocity

actionMove = SKAction.moveTo(actualDistance, duration:time)
self.runAction(actionMove)
end

end
end
17 changes: 17 additions & 0 deletions ios/Escape/app/scenes/common_scene.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module Escape # CommonScene
class CommonScene < SKScene

def didMoveToView(view)
unless @_contentCreated
createSceneContents
@_contentCreated = true
end
end


# you better override this :-)
def createSceneContents
end

end
end
86 changes: 86 additions & 0 deletions ios/Escape/app/scenes/game_over_scene.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
module Escape # GameOverScene
class GameOverScene < CommonScene

def initWithSize(sceneSize, userData:userData)
initWithSize(sceneSize).tap do |newScene|
self.userData = userData
@_didTap = false
end
end

attr_accessor :score

def touchesBegan(touches, withEvent:event)
unless @_didTap # Called when user taps screen
presentMainScene = SKAction.runBlock(-> {
@_didTap = true
gameScene = MainGameScene.sceneWithSize(self.size)
transition = SKTransition.pushWithDirection(SKTransitionDirectionUp, duration:1.0)
backgroundMusicPlayer.stop
transition.pausesIncomingScene = true
self.scene.view.presentScene(gameScene, transition:transition)
})

self.runAction(presentMainScene)
end
end


def backgroundMusicPlayer
@backgroundMusicPlayer ||= begin
error = Pointer.new(:object)
musicURL = NSBundle.mainBundle.URLForResource('8-bit loop (loop)', withExtension:'mp3')
audioPlayer = AVAudioPlayer.alloc.initWithContentsOfURL(musicURL, error:error)
audioPlayer.volume = 0.2
audioPlayer.numberOfLoops = -1
audioPlayer.prepareToPlay
audioPlayer
end
end


private


def createSceneContents
# Start background music
backgroundMusicPlayer.play

# Configure background color
self.backgroundColor = GAME_SCREEN_COLOR
self.scaleMode = SKSceneScaleModeAspectFit

# Display labels
self.score = self.userData[:score]

labelPosition = CGPoint.new(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 200)
firstLabel = createLabel('GAME OVER', fontSize:42, position:labelPosition)
# firstLabel.fontColor = SKColor.blackColor

labelPosition = CGPoint.new(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) + 35)
secondLabel = createLabel('SCORE:', fontSize:28, position:labelPosition)

labelPosition = CGPoint.new(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame) - 175)
thirdLabel = createLabel('TAP TO PLAY AGAIN!', fontSize:16, position:labelPosition)

labelPosition = CGPoint.new(CGRectGetMidX(self.frame), CGRectGetMidY(self.frame))
fourthLabel = createLabel("#{self.score}", fontSize:36, position:labelPosition)

self.addChild(firstLabel)
self.addChild(secondLabel)
self.addChild(thirdLabel)
self.addChild(fourthLabel)
end


def createLabel(text, fontSize:fontSize, position:position)
SKLabelNode.labelNodeWithFontNamed('BankGothicBold').tap do |label|
label.text = text
label.name = text
label.fontSize = fontSize
label.position = position
end
end

end
end
Loading