Skip to content

Commit

Permalink
Merge pull request #18 from cs3217-2324/feat/concrete-collectibles
Browse files Browse the repository at this point in the history
Collectibles
  • Loading branch information
Junyi00 committed Mar 22, 2024
2 parents fb52cc4 + 6c9ae2c commit e01793f
Show file tree
Hide file tree
Showing 24 changed files with 172 additions and 17 deletions.
5 changes: 5 additions & 0 deletions SDPhysicsEngine/Sources/SDPhysicsEngine/GameScene.swift
Expand Up @@ -38,6 +38,11 @@ extension GameScene: SDScene {
objectMap[object.node] = object
addChild(object.node)
}

public func removeObject(_ object: SDObject) {
objectMap[object.node] = nil
object.removeFromParent()
}
}

extension GameScene: SKPhysicsContactDelegate {
Expand Down
4 changes: 4 additions & 0 deletions SDPhysicsEngine/Sources/SDPhysicsEngine/Object/SDObject.swift
Expand Up @@ -39,4 +39,8 @@ public class SDObject {
public var physicsBody: SDPhysicsBody? {
willSet { node.physicsBody = newValue?.body }
}

func removeFromParent() {
node.removeFromParent()
}
}
1 change: 1 addition & 0 deletions SDPhysicsEngine/Sources/SDPhysicsEngine/SDScene.swift
Expand Up @@ -5,4 +5,5 @@ public protocol SDScene {
var size: CGSize { get }

func addObject(_ object: SDObject)
func removeObject(_ object: SDObject)
}
16 changes: 16 additions & 0 deletions star-dash/star-dash.xcodeproj/project.pbxproj
Expand Up @@ -83,6 +83,10 @@
E64361132BA4C2CD003850FD /* PhysicsModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610D2BA4C2CC003850FD /* PhysicsModule.swift */; };
E64361142BA4C2CD003850FD /* CreationModule.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610E2BA4C2CC003850FD /* CreationModule.swift */; };
E64361152BA4C2CD003850FD /* GameBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = E643610F2BA4C2CC003850FD /* GameBridge.swift */; };
E69EE9322BAC6CBB00033AB5 /* GameInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */; };
E69EE9342BAC6CC300033AB5 /* OverlayInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */; };
E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */; };
E69FDDE22BAD3DC40089D5F3 /* EntityConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */; };
E6A011172BA5F4AD006904D9 /* EntitySyncInterface.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A011162BA5F4AD006904D9 /* EntitySyncInterface.swift */; };
E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745112BA057040080C1BE /* MTKRenderer.swift */; };
E6A745172BA057040080C1BE /* ControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = E6A745122BA057040080C1BE /* ControlView.swift */; };
Expand Down Expand Up @@ -208,6 +212,10 @@
E643610D2BA4C2CC003850FD /* PhysicsModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PhysicsModule.swift; sourceTree = "<group>"; };
E643610E2BA4C2CC003850FD /* CreationModule.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreationModule.swift; sourceTree = "<group>"; };
E643610F2BA4C2CC003850FD /* GameBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameBridge.swift; sourceTree = "<group>"; };
E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameInfo.swift; sourceTree = "<group>"; };
E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OverlayInfo.swift; sourceTree = "<group>"; };
E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PointsComponent.swift; sourceTree = "<group>"; };
E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntityConstants.swift; sourceTree = "<group>"; };
E6A011162BA5F4AD006904D9 /* EntitySyncInterface.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntitySyncInterface.swift; sourceTree = "<group>"; };
E6A745112BA057040080C1BE /* MTKRenderer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MTKRenderer.swift; sourceTree = "<group>"; };
E6A745122BA057040080C1BE /* ControlView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ControlView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -342,6 +350,7 @@
4E630F282B9F7EC20008F887 /* Components */,
4E630F252B9F7E500008F887 /* Entities */,
46B8C0992BA328D900498705 /* GameEngine.swift */,
E69EE9312BAC6CBB00033AB5 /* GameInfo.swift */,
);
path = GameEngine;
sourceTree = "<group>";
Expand Down Expand Up @@ -459,6 +468,7 @@
4E630F282B9F7EC20008F887 /* Components */ = {
isa = PBXGroup;
children = (
E69FDDDF2BAD3DAD0089D5F3 /* PointsComponent.swift */,
E6B34A462BAA03AF0009A60B /* PlayerComponent.swift */,
4E630F292B9F7EF60008F887 /* PositionComponent.swift */,
14970F4F2BA814D500CC1E8A /* ScoreComponent.swift */,
Expand All @@ -482,6 +492,7 @@
4E86605D2BA095CC0035530D /* Constants */ = {
isa = PBXGroup;
children = (
E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */,
4E8660652BA097D40035530D /* PhysicsConstants.swift */,
14970F552BA8177B00CC1E8A /* GameConstants.swift */,
);
Expand Down Expand Up @@ -527,6 +538,7 @@
E6A745102BA057040080C1BE /* Rendering */ = {
isa = PBXGroup;
children = (
E69EE9332BAC6CC300033AB5 /* OverlayInfo.swift */,
E6B5509F2BA15D2000DC7396 /* MTKRenderer */,
E6A745132BA057040080C1BE /* Renderer.swift */,
E6B0AAD02BAAE3DC009CB939 /* ViewDelegate.swift */,
Expand Down Expand Up @@ -719,6 +731,7 @@
files = (
46D418182BA5CD840091A38B /* Player+Collidable.swift in Sources */,
46D4181E2BA5D2620091A38B /* Monster+Collidable.swift in Sources */,
E69EE9342BAC6CC300033AB5 /* OverlayInfo.swift in Sources */,
E6B1DC902BA34A4800473563 /* SDPhysicsEngine in Sources */,
4E630F272B9F7E770008F887 /* Entity.swift in Sources */,
4E630F2C2B9F7F460008F887 /* Component.swift in Sources */,
Expand Down Expand Up @@ -758,10 +771,12 @@
4604BBD92BA81C940078B84C /* InventorySystem.swift in Sources */,
14E247952BA2CB480071FFC0 /* EventManager.swift in Sources */,
4E630EF82B9F7E070008F887 /* SceneDelegate.swift in Sources */,
E69FDDE02BAD3DAD0089D5F3 /* PointsComponent.swift in Sources */,
14970F542BA8163300CC1E8A /* ScoreSystem.swift in Sources */,
E64361112BA4C2CD003850FD /* SyncModule.swift in Sources */,
E6A7451B2BA0C1890080C1BE /* PlayerView.swift in Sources */,
46D418282BA5D6800091A38B /* Floor+Collidable.swift in Sources */,
E69EE9322BAC6CBB00033AB5 /* GameInfo.swift in Sources */,
46D418222BA5D4E60091A38B /* Obstacle+Collidable.swift in Sources */,
E638B9CF2BAB3C5D00931CC2 /* TeleportEvent.swift in Sources */,
E6A745162BA057040080C1BE /* MTKRenderer.swift in Sources */,
Expand All @@ -778,6 +793,7 @@
E6A7451D2BA0CAD90080C1BE /* JoystickView.swift in Sources */,
E6B550A12BA15E9C00DC7396 /* OverlayView.swift in Sources */,
46D418262BA5D6500091A38B /* Wall+Collidable.swift in Sources */,
E69FDDE22BAD3DC40089D5F3 /* EntityConstants.swift in Sources */,
4E630F342B9F8FC00008F887 /* Player.swift in Sources */,
4E630F372B9F91DE0008F887 /* PlayerSprite.swift in Sources */,
14970F502BA814D500CC1E8A /* ScoreComponent.swift in Sources */,
Expand Down
9 changes: 9 additions & 0 deletions star-dash/star-dash/Constants/EntityConstants.swift
@@ -0,0 +1,9 @@
import CoreGraphics

struct EntityConstants {
struct CoinCollectible {
static let points = 10
static let sprite = "Coin"
static let size = CGSize(width: 50, height: 50)
}
}
14 changes: 12 additions & 2 deletions star-dash/star-dash/Constants/PhysicsConstants.swift
Expand Up @@ -21,15 +21,25 @@ struct PhysicsConstants {
}

struct CollisionMask {
static let player = CollisionCategory.max ^ CollisionCategory.player
static let player = CollisionCategory.max ^ CollisionCategory.player ^ CollisionCategory.collectible
static let monster = CollisionCategory.player | CollisionCategory.tool
static let collectible = CollisionCategory.player
static let collectible = CollisionCategory.none
static let obstacle = CollisionCategory.player | CollisionCategory.monster | CollisionMask.tool
static let tool = CollisionCategory.max ^ CollisionCategory.collectible ^ CollisionCategory.tool
static let wall = CollisionCategory.player | CollisionCategory.monster | CollisionCategory.tool
static let floor = CollisionCategory.player | CollisionCategory.monster | CollisionCategory.tool
}

struct ContactMask {
static let player = CollisionCategory.floor | CollisionCategory.collectible
static let monster = CollisionCategory.player
static let collectible = CollisionCategory.player
static let obstacle = CollisionCategory.none
static let tool = CollisionCategory.obstacle
static let wall = CollisionCategory.tool | CollisionCategory.player
static let floor = CollisionCategory.player
}

struct Dimensions {
// TODO: determine appropriate size for each
static let player = CGSize(width: 60, height: 60)
Expand Down
Expand Up @@ -20,10 +20,11 @@ class PickupCollectibleEvent: Event {
}

func execute(on target: EventModifiable) {
guard let scoreSystem = target.system(ofType: ScoreSystem.self) else {
guard let scoreSystem = target.system(ofType: ScoreSystem.self),
let pointsComponent = target.component(ofType: PointsComponent.self, ofEntity: collectibleEntityId) else {
return
}
scoreSystem.applyScoreChange(to: entityId, scoreChange: GameConstants.ScoreChange.pickupCollectible)
scoreSystem.applyScoreChange(to: entityId, scoreChange: pointsComponent.points)
target.add(event: RemoveEvent(on: collectibleEntityId))
}
}
8 changes: 8 additions & 0 deletions star-dash/star-dash/GameBridge/GameBridge.swift
Expand Up @@ -88,5 +88,13 @@ class GameBridge {
}

private func removeObject(from entityId: EntityId) {
guard let object = entitiesMap[entityId] else {
return
}

entitiesMap[entityId] = nil
objectsMap[object.id] = nil

self.scene.removeObject(object)
}
}
Expand Up @@ -38,6 +38,7 @@ class PhysicsModule: SyncModule {
object.physicsBody = createRectanglePhysicsBody(physicsComponent: physicsComponent)
object.physicsBody?.restitution = physicsComponent.restitution
object.physicsBody?.isDynamic = physicsComponent.isDynamic
object.physicsBody?.affectedByGravity = physicsComponent.affectedByGravity
object.physicsBody?.categoryBitMask = physicsComponent.categoryBitMask
object.physicsBody?.contactTestMask = physicsComponent.contactTestMask
object.physicsBody?.collisionBitMask = physicsComponent.collisionBitMask
Expand Down
6 changes: 5 additions & 1 deletion star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift
Expand Up @@ -31,7 +31,11 @@ extension SpriteModule: CreationModule {
var newObject = SDObject()
if let spriteComponent = entityManager.component(ofType: SpriteComponent.self, of: entity.id) {
let spriteObject = SDSpriteObject(imageNamed: "PlayerRedNose")
spriteObject.size = CGSize(width: 100, height: 140)

if let size = spriteComponent.size {
spriteObject.size = size
}

newObject = spriteObject
}

Expand Down
14 changes: 14 additions & 0 deletions star-dash/star-dash/GameEngine/Components/PointsComponent.swift
@@ -0,0 +1,14 @@
import Foundation

class PointsComponent: Component {
let points: Int

init(id: UUID, entityId: UUID, points: Int) {
self.points = points
super.init(id: id, entityId: entityId)
}

convenience init(entityId: UUID, points: Int) {
self.init(id: UUID(), entityId: entityId, points: points)
}
}
Expand Up @@ -12,16 +12,16 @@ class SpriteComponent: Component {
// for sprite set will need to discuss how to rep animation
var image: String
var textureAtlas: String?
var size: CGSize
var size: CGSize?

init(id: ComponentId, entityId: EntityId, image: String, textureAtlas: String?, size: CGSize) {
init(id: ComponentId, entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) {
self.image = image
self.size = size
self.textureAtlas = textureAtlas
super.init(id: id, entityId: entityId)
}

convenience init(entityId: EntityId, image: String, textureAtlas: String?, size: CGSize) {
convenience init(entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) {
self.init(id: UUID(), entityId: entityId, image: image, textureAtlas: textureAtlas, size: size)
}
}
Expand Up @@ -10,23 +10,46 @@ import Foundation
class Collectible: Entity {
let id: EntityId
private let position: CGPoint
private let sprite: String
private let points: Int
private let size: CGSize

init(id: EntityId, position: CGPoint) {
init(id: EntityId, position: CGPoint, sprite: String, points: Int, size: CGSize) {
self.id = id
self.position = position
self.sprite = sprite
self.points = points
self.size = size
}

convenience init(position: CGPoint) {
self.init(id: UUID(), position: position)
convenience init(position: CGPoint, sprite: String, points: Int, size: CGSize) {
self.init(id: UUID(), position: position, sprite: sprite, points: points, size: size)
}

func setUpAndAdd(to: EntityManager) {
let positionComponent = PositionComponent(entityId: self.id, position: self.position, rotation: .zero)
let physicsComponent = PhysicsComponent(entityId: self.id, size: PhysicsConstants.Dimensions.collectible)
let physicsComponent = PhysicsComponent(entityId: self.id, size: self.size)
physicsComponent.affectedByGravity = false
physicsComponent.isDynamic = false
physicsComponent.categoryBitMask = PhysicsConstants.CollisionCategory.collectible
physicsComponent.contactTestMask = PhysicsConstants.ContactMask.collectible
physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.collectible
let spriteComponent = SpriteComponent(entityId: self.id, image: sprite, textureAtlas: nil, size: size)
let pointsComponent = PointsComponent(entityId: self.id, points: points)

to.add(entity: self)
to.add(component: positionComponent)
to.add(component: physicsComponent)
to.add(component: spriteComponent)
to.add(component: pointsComponent)
}

static func createCoinCollectible(position: CGPoint) -> Collectible {
Collectible(
position: position,
sprite: EntityConstants.CoinCollectible.sprite,
points: EntityConstants.CoinCollectible.points,
size: EntityConstants.CoinCollectible.size
)
}
}
Expand Up @@ -27,7 +27,7 @@ class Floor: Entity {
physicsComponent.restitution = 0.0
physicsComponent.isDynamic = false
physicsComponent.categoryBitMask = PhysicsConstants.CollisionCategory.floor
physicsComponent.contactTestMask = PhysicsConstants.CollisionCategory.player
physicsComponent.contactTestMask = PhysicsConstants.ContactMask.floor
physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.floor

to.add(entity: self)
Expand Down
Expand Up @@ -30,11 +30,16 @@ class Player: Entity {
let healthComponent = HealthComponent(entityId: self.id, health: GameConstants.InitialHealth.player)
let physicsComponent = PhysicsComponent(entityId: self.id, size: PhysicsConstants.Dimensions.player)
physicsComponent.categoryBitMask = PhysicsConstants.CollisionCategory.player
physicsComponent.contactTestMask = PhysicsConstants.CollisionCategory.floor
physicsComponent.contactTestMask = PhysicsConstants.ContactMask.player
physicsComponent.collisionBitMask = PhysicsConstants.CollisionMask.player
physicsComponent.affectedByGravity = true
physicsComponent.restitution = 0.0
let spriteComponent = SpriteComponent(entityId: self.id, image: "", textureAtlas: "", size: .zero)
let spriteComponent = SpriteComponent(
entityId: self.id,
image: "PlayerRedNose",
textureAtlas: "",
size: CGSize(width: 100, height: 140)
)
let scoreComponent = ScoreComponent(entityId: self.id, score: 0)

to.add(entity: self)
Expand Down
13 changes: 13 additions & 0 deletions star-dash/star-dash/GameEngine/GameEngine.swift
Expand Up @@ -20,6 +20,18 @@ class GameEngine {
setUpSystems()
}

func gameInfo() -> GameInfo? {
guard let scoreSystem = systemManager.system(ofType: ScoreSystem.self),
let playerEntityId = entityManager.playerEntityId(),
let score = scoreSystem.score(of: playerEntityId) else {
return nil
}

return GameInfo(
playerScore: score
)
}

func update(by deltaTime: TimeInterval) {
systemManager.update(by: deltaTime)
eventManager.executeAll(on: self)
Expand Down Expand Up @@ -57,6 +69,7 @@ class GameEngine {
private func setUpSystems() {
systemManager.add(PositionSystem(entityManager, dispatcher: self))
systemManager.add(PhysicsSystem(entityManager, dispatcher: self))
systemManager.add(ScoreSystem(entityManager, dispatcher: self))
}
}

Expand Down
3 changes: 3 additions & 0 deletions star-dash/star-dash/GameEngine/GameInfo.swift
@@ -0,0 +1,3 @@
struct GameInfo {
let playerScore: Int
}
8 changes: 8 additions & 0 deletions star-dash/star-dash/GameEngine/Systems/ScoreSystem.swift
Expand Up @@ -18,6 +18,14 @@ class ScoreSystem: System {
self.dispatcher = dispatcher
}

func score(of entityId: EntityId) -> Int? {
guard let scoreComponent = getScoreComponent(of: entityId) else {
return nil
}

return scoreComponent.score
}

func applyScoreChange(to entityId: EntityId, scoreChange: Int) {
guard let scoreComponent = getScoreComponent(of: entityId) else {
return
Expand Down
4 changes: 4 additions & 0 deletions star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift
Expand Up @@ -35,6 +35,10 @@ class MTKRenderer: NSObject, Renderer {
super.init()
}

func updateOverlay(overlayInfo: OverlayInfo) {
playerView?.updateOverlay(score: overlayInfo.score)
}

/// Set ups the views for a single player game.
func createSinglePlayerView(at superview: UIView) {
let playerView = PlayerView(superview: superview, device: self.device, drawDelegate: self)
Expand Down
9 changes: 7 additions & 2 deletions star-dash/star-dash/Rendering/MTKRenderer/OverlayView.swift
Expand Up @@ -11,16 +11,21 @@ class OverlayView: UIView {
let scoreLabel = UILabel()

func setupSubviews() {
scoreLabel.text = "Score: 0"
scoreLabel.numberOfLines = 1
scoreLabel.translatesAutoresizingMaskIntoConstraints = false
scoreLabel.textColor = .white
scoreLabel.textColor = .black
addSubview(scoreLabel)

NSLayoutConstraint.activate([
scoreLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: margin),
scoreLabel.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -1 * margin),
scoreLabel.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor, constant: margin)
])

update(score: 0)
}

func update(score: Int) {
scoreLabel.text = "Score: \(score)"
}
}

0 comments on commit e01793f

Please sign in to comment.