Cloud Jumpers is a competitive 1-4 player platformer game for iPadOS, jumping through clouds and be the winner!

Overview

Cloud Jumpers

Overview

Cloud Jumpers is a competitive 1-4 player iOS platformer game. There are power-ups, different game modes, kill mechanics, and more!

Race against the clock in single-player mode, and compete against the rest of the world on the high scores. Alternatively, create a lobby with up to three others and compete for the top ranking in two unique multiplayer modes.

Every round you play is randomly generated and different from previous encounters. However, if you wish to relive a particular experience, you can always specify a level seed.

We can't wait to race against you on Cloud Jumpers!

Details

You can view our final report here.

Cloud Jumpers was awarded Best Project Award (First Winner) in The 20th NUS School of Computing Term Project Showcase (STePS) on 13 April 2022. You may view our project page at The 20th STePS here.

Preview

Multiplayer: King of the Hill

Reach the top and be a Cloud God, giving you the power to scroll the entire world and get random power-ups for free to maintain your throne within two minutes!

finalCJ.mp4

Single Player: Time Trials

Practice your cloud jumping and beat your own best trial with a shadow player!

FinalCJShadowPlayer.mp4

Development

  • Install CocoaPods (https://guides.cocoapods.org/using/getting-started.html)
  • From repository root, run pod install
    • This is to be run everytime you switch branches
  • Set up a Firebase project and replace the GoogleService-Info.plist in CloudJumpers/ with yours
  • Work on the project using File > Open > CloudJumpers.xcworkspace
Comments
  • Levels API

    Levels API

    ~~❗ Potential breaking changes~~

    • ~~GameEngine protocol is now deprecated~~
    • ~~SinglePlayerGameEngine is now GameEngine, closes #69~~
    • ~~GameEngine.setUpGame() is now GameEngine.setUpGame(with:)~~

    Introducing the Levels API (closes #18)

    The Levels API allows for procedural content generation of Entitys in the game world. It consists of 3 constructs:

    • Blueprint is a Codable struct that defines the parameters for LevelGenerator.
    • LevelGenerator is a singleton class, with .from(_:seed:) that returns a list of CGPoints for each of the entities to be created. This list can be mapped to a concrete entity constructor.
    • SeedGenerator is a seed-based RandomNumberGenerator that uses srand48(_:) and drand48(). It is fileprivate in LevelGenerator.swift and should not be exposed.

    To use SeedGenerator, only use Float.random(in:using:). Using Double.random(in:using:) or CGFloat.random(in:using:) will lead to same numbers generated every time.

    Examples

    The following levels were generated with the following snippet with seeds 69420 and 119081 respectively.

    let blueprint = Blueprint(
        worldSize: scene.size,
        platformSize: Constants.cloudNodeSize,
        tolerance: CGVector(dx: 150, dy: Constants.jumpImpulse.dy),
        xToleranceRange: 0.2...0.8,
        yToleranceRange: 0.2...0.8,
        firstPlatformPosition: Constants.playerInitialPosition)
    
    let clouds = LevelGenerator.from(blueprint, seed: <insert_seed_here>).map { Cloud(at: $0) }
    
    gameEngine?.setUpGame(with: clouds)
    

    Ignore the codes in the pictures. The xToleranceRange and yToleranceRange were mismatched. Ideally, we should be using 0.4...1.0 because 0.4 * 150 = 60, which is Constants.playerSize.width, to ensure that there is no gap that the player cannot jump through. I condensed these examples to 0.2...0.8 so you can see more clouds in the screenshot.

    | 69420 | 119081 | |----|----| | IMG_0049 | IMG_0048 |

    enhancement 
    opened by purfectliterature 6
  • Power-ups (Beta)

    Power-ups (Beta)

    • player can now get power-up by hitting the power-up nodes on the gameArea, storing it in a queue (currently queue not shown yet)
    • dequeue and activate power up in the queue
    • powerUp effects disappear after a few seconds
    • show queues of powerUps

    definitely need some inputs here

    Currently spriteSystem is the only one in charge of adding / removing node to/from scene during gameplay. Some events (such as obtainEvent and activatePowerUpEvent) require removal of nodes from scene. So how I handled this currently is that there is a boolean variable shouldBeRemoved inside SpriteComponent that will be set by these two events to true. Then on every update, spriteSystem will check every entity see whether this flag is set to true, then it will removeNodeFromScene and then remove node from entityManager

    What do yall think?

    enhancement high-priority 
    opened by EricBryann 5
  • (Major) Refactor rendering system

    (Major) Refactor rendering system

    WIP: Attempt to remove all current rendering abstraction from game engine

    Request @EricBryann assistance to fix the touchable components

    Request @purfectliterature and @rssujay review on general structure

    breaking-changes 
    opened by jushg 5
  • Sounds and Sounds API

    Sounds and Sounds API

    Introducing the Sounds API (partially closes #93)

    The Sounds API uses AVFoundation to manage sounds in the entire app's lifecycle. It is a singleton class that initialises and stores its own instance. The Sounds API consists of 2 constructs:

    • Sounds is an enum that stores the sound file name in Resources/Sounds. It also allows for the creation of a sound's respective AVAudioPlayer.
    • SoundManager is a singleton class that manages sounds globally. Every method is to be used on the SoundManager.i object. It memoises all AVAudioPlayers in a dictionary to prevent overinitialisation of AVAudioPlayers with the same sound.

    i was used for short of "instance" and a reference to "me" or "this." If you feel this name should change, you may propose one that is (a) short, and (b) semantically descriptive (e.g., SoundManager.do.pause(_:)).

    Examples

    To play the .background BGM, simply execute the following command from anywhere:

    SoundManager.i.play(.background)
    

    To play with loop, supply the loopsBy: parameter. To loop forever, set loopsBy: to -1.

    SoundManager.i.play(.background, loopsBy: 10)
    

    Known bug on FPS drops (opened #98)

    Every time a sound is played (especially in the game scene), the FPS drops from 60 to 50-53. This results in a noticeable stuttering and jerking when moving or jumping the player around.

    Possible fix is to instead use SKAudioNode, but this means that sound management can longer be done globally, and some sounds can only be controlled from the GameScene. Open to suggestions on how to fix this issue.

    enhancement 
    opened by purfectliterature 4
  • Events API (Beta)

    Events API (Beta)

    The Events API provides a global modifier access to entities and components. It is resolved by GameEngine at every GameEngine.update(within:).

    There are 3 new constructs introduced in this PR:

    1. Event is a Codable protocol that stores a timestamp, execute(in:) executable, and serialisable payload customisable by its conformers (see MoveEvent and JumpEvent for reference implementations).
    2. EventManager is the global access point for adding and executing Events. It stores and executes Events with a priority queue based on Event.timestamp.
    3. Events is an enum that stores all the types of supported Events.

    So, now it is clear that EventManager should be the only interface to directly mutate anything ECS-related. Anyone who wishes to mutate entities and components should fire an Event and not directly talk to EntityManager.

    EventManager.timestamp generates a new timestamp based on epoch time. You may use this to initialise a new Event.

    Use Events.type(of:) to check for the type of an Event. Remember that for every new Event you create, extend this enum appropriately.


    @jushg, In Events, you may wish to see that I have created .animateIdle, .animateWalking, and .animateJumping. If this makes sense, we would need to create AnimateIdleEvent.swift, AnimateWalkingEvent.swift, and AnimateJumpingEvent.swift accordingly to change the entity's AnimationComponent.kind. I thought your ContactResolver can fire these events.


    @rssujay, For the network queues, I was thinking of something like this in EventManager:

    // * indicates line that currently does not exist in EventManager.swift
    
    class EventManager {
        ...
    
    *   typealias UnsubscriptionAction = () -> Void
    
        private var events: EventQueue
    *   private var subscribedEvents: EventQueue?
    *   private var publisher: SomeNetworkPublisher?
    
        ...
    
        func executeAll(in entityManager: EntityManager) {
            while let event = events.dequeue() {
                event.execute(in: entityManager)
            }
    
    *       while let subscribedEvent = subscribedEvents?.dequeue() {
    *           subscribedEvent?.execute(in: entityManager)
    *       }
        }
    
        func publish(_ event: Event) {
    *       publisher?.publish(event)
        }
    
        func subscribe(to subscriber: SomeNetworkSubscriber) -> UnsubscriptionAction {
    *       subscribedEvents = EventQueue()
    * 
    *       return subscriber.subscribe { fetchedEvents in
    *           fetchedEvents.forEach(subscribedEvents?.enqueue)
    *       }
        }
    }
    

    Would this be possible? At first, I thought why not enqueue subscribedEvents into events, but that would probably cause our "internal" Events be blocked by subscribedEvents. So, I thought we can handle subscribedEvents on a separate queue.

    I am still nervous about delay, since we are handling the queues separately and synchronously. Maybe we should experiment with handling queues asynchronously? Maybe not per-event, but per-queue. I suspect async per-event may cause issues, e.g., power-up obtained by later timestamp gets executed first before earlier ones. But this means that it is still sync among events, but the "internal" queue (events) and subscribed queue (subscribedEvents) get resolved asynchronously.

    enhancement high-priority 
    opened by purfectliterature 4
  • Achievements

    Achievements

    Closes #181

    • [x] Achievement, which has title, description, currentProgress: String, requiredProgress: String
    • [x] AchievementDataDelegate, which handles fetch (within achievements page) and updates (from game)
    • [x] AchievementManager, which uses observer pattern to update any Achievement associated with a given key
    • [x] AchievementFactory, which instantiates all concrete Achievement objects
    • [x] JumpAchievement, a concrete implementation
    • [x] UI page to view user achievements
    • [x] Periodic poll of GameWorld.getMetrics() to get latest achievement statuses
    • [x] Changes to GameWorld to support periodic poll
    • [x] MetricsSystem that accumulates <metric: value> until GameWorld calls in to retrieve KV pairs
    enhancement 
    opened by rssujay 3
  • Dynamic hostID on gameEngine

    Dynamic hostID on gameEngine

    Not sure if this is a good way. I passed in a function for gameEngine to call everytime gameEngine needs to check who's the current hostId (Closes #162)

    EDIT: now the gameEngine will ask the lobby directly whether it is a host, instead of asking lobby for who is the current Host and compare it with its own playerId

    opened by EricBryann 3
  • player displacement cannot be determined by touchLocation

    player displacement cannot be determined by touchLocation

    @purfectliterature player displacement cannot be determined by touchLocation... should be by innerJoyStick displacement reason being if touchLocation is too far, player move too fast, there is a possibility that player go through the side wall... collision with side walls not detected and player go out of your ipad...

    My code make it worse coz currently I check if a node is out of scene, I remove the node (for meteors, but player is affected by this as well and app will crash)

    opened by EricBryann 3
  • Synchronize power ups inventory/removed across devices

    Synchronize power ups inventory/removed across devices

    Ideally, the guest should not touch any object inside the player machine, so the power up removal should be fired by the guest's local device, then sent through network

    high-priority 
    opened by jushg 2
  • Generalize `TimedSystem` and `TimedComponent` to support various time functions

    Generalize `TimedSystem` and `TimedComponent` to support various time functions

    Some examples of usage:

    • Count down instead of count up
    • Event after finish count down

    @purfectliterature if generalize correctly we can use this to count an effect's active time

    opened by jushg 2
  • Visual desync issue with other players falling

    Visual desync issue with other players falling

    Sometimes, when a non-device (networked) player is falling, they appear to be falling in slow-motion and teleporting back up.

    1. Determined to not be an issue with network updates (yellow = expected behaviour, red = issue noticed) image

    2. explored @jushg's theory, that differences in screen sizes causes foreign player entity to collide with local entities, such as clouds, which may be in different positions under absolute (x, y) positioning.

    Switching to relative positioning can mitigate the issue, unlikely to solve due to loss of accuracy during conversion, as well as current plans to only resolve via scaling width. If this is something we can live with, that's okay.

    Considered other possibilities:

    • Should player entities from other devices be affected by local device non-player entities?
    • Should player entities from other devices be affected by local device gravity?

    An approach that looks like this also appears to fix the issue: image

    bug 
    opened by rssujay 2
Owner
The Cloud Jumpers Development Team
Cloud Jumpers is a competitive 1-4 player platformer game for iPadOS, jumping through clouds and be the winner!
The Cloud Jumpers Development Team
Game in development in Swift through XCode.

Space-Cruise-App Est. September 2021 Author: Tony Le Game in development in Swift through XCode. This game lets user dodge and shoot incoming enemies.

null 0 Nov 14, 2021
This is a game in which the player has to match cards with the correct pair.

This is a game in which the player has to match cards with the correct pair. When they are paired, a funny record of a Peruvian influencer is played. Made with Swift and SwiftUI.

Augusto Galindo Ali 6 Jun 21, 2022
The one and only open source 4X MMO mid-core strategy game for iOS. Similar to Game of War and Mobile Strike

4X MMO Strategy Game for iOS I have spent 4 years of my life and a significant amount of money into completing this game and I hope you enjoy it. For

shankqr 69 Nov 16, 2022
🦁 🃏 📱 An animal matching puzzle card game– built with turn-based game engine boardgame.io and React-Native + React-Native-Web

Matchimals.fun an animal matching puzzle card game ?? ?? ?? Download for iOS from the App Store ?? Download for Android from the Google Play Store ??

iGravity Studios 137 Nov 24, 2022
Switshot is a game media manager helps you transfer your game media from Nintendo Switch to your phone, and manage your media just few taps.

Switshot is a game media manager helps you transfer your game media from Nintendo Switch to your phone, and manage your media just few taps.

Astrian Zheng 55 Jun 28, 2022
Gravity Switch - A dynamic game that integrates swiping and tapping to create a fun interactive game

GravitySwitch Gravity Switch is a dynamic game that integrates swiping and tappi

null 3 Nov 19, 2022
A little arcade game that uses SwiftUI as a game engine.

SwiftUI Game A little arcade game that uses SwiftUI as a game engine :) Just copy the code into the Blank playgroundbook in Swift Playgrounds app on i

Roman Gaditskiy 10 Sep 30, 2022
IOS Spin Game - A simple spin game using SwiftUI

IOS_Spin_Game A simple spin game using Swift UI.

Md. Masum Musfique 4 Mar 23, 2022
FlagGuess-Game - A game to collect points by guessing flags

Flag Guess Game A game to collect points by guessing flags! Wrong Choice

Ahmet Onur Sahin 3 Apr 18, 2022
CardGameEngine - Prototyping a game engine for the Bang card game

CardGameEngine Prototyping a game engine for the Bang card game. Features Engine is open source Powerful scripting language using JSON Card design is

stephtelolahy 5 Nov 22, 2022
A 99-player last-bird-flapping battle royale

Flappy Royale A HTML5 Game, built to be embedded in apps using Phaser 3. Setup Clone, and run yarn install, run yarn start to load up into the app: cd

Flappy Royale 149 Dec 17, 2022
iPhone and iPod Touch version of Skeleton Key: is an addictive and unique puzzle game in which you shift keys around the board unlocking treasure chests. Made with cocos2d-iphone.

Skeleton Key (iOS) Skeleton Key is an addictive and unique puzzle game in which you shift keys around the board unlocking treasure chests. It's availa

null 117 Jun 6, 2022
XCode and Swift game based on the generation of random cards and some functions related to the comparison of the results.

war-card-game-V1 XCode and Swift game based on the generation of random cards and some functions related to the comparison of the results. Once a card

Eduard 1 Dec 10, 2021
A game engine built with SDL and Swift.

Lark A game engine made with Swift and SDL. This is a pre-alpha work-in-progress. Don't try to use this unless you really know what you're doing. I ba

June Bash 41 Mar 11, 2022
Solitaire mahjong game with several themes and layouts. For android/iphone/ubuntu/firefoxos

green-mahjong Green Mahjong is a HTML5 based GPLv3 solitaire mahjong game. It features three nice themes, six different layouts and works accross all

Daniel Beck 82 Dec 25, 2022
Spare Parts is a 2D physics game that lets you build silly contraptions and machines.

Spare Parts Spare Parts is a 2D physics game that lets you build silly contraptions and machines. The goal for this project is: 100% of the code is op

Adam Wulf 14 Feb 9, 2022
Mobile IOS Game App Developed by Haemi Lee, Dominika Popov, and Dylan Walsh

VroombaWars Mobile IOS Game App Developed by Haemi Lee, Dominika Popov, and Dylan Walsh Why clean your room in real life when you can have a virtual v

Haemi Lee 1 Oct 16, 2021
The Classic game TicTacToe made using SwiftUI and MVVM architecture

The Classic game TicTacToe made using SwiftUI and MVVM architecture

Mehrdad 0 Oct 20, 2022
This project is a 2D game for iOS users built with Swift and SpriteKit.

PANDA CLICKER Description Panda Clicker is a 2D game and the aim is to touch the Panda image on the center of the screen. In each touch of the panda i

iremkaraoglu 6 Dec 21, 2022