Skip to content

Commit

Permalink
Merge pull request #20 from cs3217-2324/feat/texture-and-animations
Browse files Browse the repository at this point in the history
Texture and Animations
  • Loading branch information
jasonqiu212 committed Mar 22, 2024
2 parents 11cc529 + 7edf3b1 commit b7ed0de
Show file tree
Hide file tree
Showing 19 changed files with 165 additions and 25 deletions.
Expand Up @@ -3,6 +3,7 @@ import SpriteKit
public class SDSpriteObject: SDObject {
let spriteNode: SKSpriteNode

static let textureActionKey = "animation"
public var activeTexture: String?

public init(imageNamed: String) {
Expand All @@ -19,11 +20,16 @@ public class SDSpriteObject: SDObject {
let texture = loadTexture(named: named)
spriteNode.run(SKAction.repeatForever(
SKAction.animate(with: texture, timePerFrame: TimeInterval(0.1), resize: false, restore: true)
))
), withKey: SDSpriteObject.textureActionKey)

activeTexture = named
}

public func cancelTexture() {
spriteNode.removeAction(forKey: SDSpriteObject.textureActionKey)
activeTexture = nil
}

private func loadTexture(named: String) -> [SKTexture] {
let textureAtlas = SKTextureAtlas(named: named)
var frames = [SKTexture]()
Expand Down
8 changes: 8 additions & 0 deletions star-dash/star-dash.xcodeproj/project.pbxproj
Expand Up @@ -100,6 +100,8 @@
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 */; };
E69FDDE42BADC2F10089D5F3 /* SpriteConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDE32BADC2F10089D5F3 /* SpriteConstants.swift */; };
E69FDDE62BADD11B0089D5F3 /* StopMovingEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E69FDDE52BADD11B0089D5F3 /* StopMovingEvent.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 @@ -241,6 +243,8 @@
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>"; };
E69FDDE32BADC2F10089D5F3 /* SpriteConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpriteConstants.swift; sourceTree = "<group>"; };
E69FDDE52BADD11B0089D5F3 /* StopMovingEvent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StopMovingEvent.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 @@ -346,6 +350,7 @@
14D14B792BA5AC1900386C3B /* CommonEvents */ = {
isa = PBXGroup;
children = (
E69FDDE52BADD11B0089D5F3 /* StopMovingEvent.swift */,
14E2478D2BA22FCE0071FFC0 /* MoveEvent.swift */,
143AA38B2BA4D3E3009C28E7 /* JumpEvent.swift */,
14D14B722BA5A3CD00386C3B /* RemoveEvent.swift */,
Expand Down Expand Up @@ -554,6 +559,7 @@
4E86605D2BA095CC0035530D /* Constants */ = {
isa = PBXGroup;
children = (
E69FDDE32BADC2F10089D5F3 /* SpriteConstants.swift */,
E69FDDE12BAD3DC40089D5F3 /* EntityConstants.swift */,
4E8660652BA097D40035530D /* PhysicsConstants.swift */,
14970F552BA8177B00CC1E8A /* GameConstants.swift */,
Expand Down Expand Up @@ -864,6 +870,7 @@
E6A745172BA057040080C1BE /* ControlView.swift in Sources */,
14970F562BA8177B00CC1E8A /* GameConstants.swift in Sources */,
1471B0A42BA6AAF200878B14 /* PlayerDeathEvent.swift in Sources */,
E69FDDE62BADD11B0089D5F3 /* StopMovingEvent.swift in Sources */,
46D418202BA5D3420091A38B /* Collectible+Collidable.swift in Sources */,
E6A7451D2BA0CAD90080C1BE /* JoystickView.swift in Sources */,
E6B550A12BA15E9C00DC7396 /* OverlayView.swift in Sources */,
Expand All @@ -872,6 +879,7 @@
4E630F342B9F8FC00008F887 /* Player.swift in Sources */,
4E630F372B9F91DE0008F887 /* PlayerSprite.swift in Sources */,
14970F502BA814D500CC1E8A /* ScoreComponent.swift in Sources */,
E69FDDE42BADC2F10089D5F3 /* SpriteConstants.swift in Sources */,
143AA3912BA4D7AC009C28E7 /* MonsterDeathEvent.swift in Sources */,
E64361102BA4C2CD003850FD /* SpriteModule.swift in Sources */,
4604BBD52BA819C70078B84C /* InventoryComponent.swift in Sources */,
Expand Down
21 changes: 21 additions & 0 deletions star-dash/star-dash/Assets.xcassets/Star.imageset/Contents.json
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "star.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 1 addition & 2 deletions star-dash/star-dash/Constants/EntityConstants.swift
@@ -1,9 +1,8 @@
import CoreGraphics

struct EntityConstants {
struct CoinCollectible {
struct StarCollectible {
static let points = 10
static let sprite = "Coin"
static let size = CGSize(width: 50, height: 50)
}
}
12 changes: 12 additions & 0 deletions star-dash/star-dash/Constants/SpriteConstants.swift
@@ -0,0 +1,12 @@
struct TextureSet {
let run: String
}

struct SpriteConstants {
static let PlayerRedNose = "PlayerRedNose"
static let PlayerRedNoseTexture = TextureSet(
run: "PlayerRedNoseRun"
)

static let star = "Star"
}
5 changes: 4 additions & 1 deletion star-dash/star-dash/Events/CommonEvents/MoveEvent.swift
Expand Up @@ -20,10 +20,13 @@ class MoveEvent: Event {
}

func execute(on target: EventModifiable) {
guard let physicsComponent = target.component(ofType: PhysicsComponent.self, ofEntity: entityId) else {
guard let physicsComponent = target.component(ofType: PhysicsComponent.self, ofEntity: entityId),
let spriteComponent = target.component(ofType: SpriteComponent.self, ofEntity: entityId),
let textureSet = spriteComponent.textureSet else {
return
}

physicsComponent.velocity = (toLeft ? -1 : 1) * PhysicsConstants.runVelocity
spriteComponent.textureAtlas = textureSet.run
}
}
22 changes: 22 additions & 0 deletions star-dash/star-dash/Events/CommonEvents/StopMovingEvent.swift
@@ -0,0 +1,22 @@
import Foundation

class StopMovingEvent: Event {
let timestamp: Date
let entityId: EntityId

init(on entityId: EntityId) {
timestamp = Date.now
self.entityId = entityId
}

func execute(on target: EventModifiable) {
guard let physicsComponent = target.component(ofType: PhysicsComponent.self, ofEntity: entityId),
let spriteComponent = target.component(ofType: SpriteComponent.self, ofEntity: entityId),
let textureSet = spriteComponent.textureSet else {
return
}

physicsComponent.velocity = .zero
spriteComponent.textureAtlas = nil
}
}
21 changes: 17 additions & 4 deletions star-dash/star-dash/GameBridge/SyncModule/SpriteModule.swift
Expand Up @@ -17,9 +17,22 @@ class SpriteModule: SyncModule {
return
}

// if spriteComponent.image != spriteObject.activeTexture {
// spriteObject.runTexture(named: spriteComponent.image)
// }
if spriteComponent.textureAtlas == nil && spriteObject.activeTexture != nil {
spriteObject.cancelTexture()
return
}

guard let textureAtlas = spriteComponent.textureAtlas else {
return // no texture to run
}

if let activeTexture = spriteObject.activeTexture,
activeTexture == textureAtlas {
return // correct texture is already running
}

spriteObject.cancelTexture()
spriteObject.runTexture(named: textureAtlas)
}

func create(for object: SDObject, from entity: Entity) {
Expand All @@ -30,7 +43,7 @@ extension SpriteModule: CreationModule {
func createObject(from entity: Entity) -> SDObject? {
var newObject = SDObject()
if let spriteComponent = entityManager.component(ofType: SpriteComponent.self, of: entity.id) {
let spriteObject = SDSpriteObject(imageNamed: "PlayerRedNose")
let spriteObject = SDSpriteObject(imageNamed: spriteComponent.image)

if let size = spriteComponent.size {
spriteObject.size = size
Expand Down
30 changes: 25 additions & 5 deletions star-dash/star-dash/GameEngine/Components/SpriteComponent.swift
Expand Up @@ -8,20 +8,40 @@
import Foundation

class SpriteComponent: Component {
// TODO: sprite could be single image or sprite set, could use enum to seperate,
// for sprite set will need to discuss how to rep animation
var image: String
var textureSet: TextureSet?
var textureAtlas: String?
var size: CGSize?

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

convenience init(entityId: EntityId, image: String, textureAtlas: String?, size: CGSize?) {
self.init(id: UUID(), entityId: entityId, image: image, textureAtlas: textureAtlas, size: size)
convenience init(
entityId: EntityId,
image: String,
textureSet: TextureSet?,
textureAtlas: String?,
size: CGSize?
) {
self.init(
id: UUID(),
entityId: entityId,
image: image,
textureSet: textureSet,
textureAtlas: textureAtlas,
size: size
)
}
}
Expand Up @@ -34,7 +34,13 @@ class Collectible: Entity {
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 spriteComponent = SpriteComponent(
entityId: self.id,
image: sprite,
textureSet: nil,
textureAtlas: nil,
size: size
)
let pointsComponent = PointsComponent(entityId: self.id, points: points)

to.add(entity: self)
Expand All @@ -44,12 +50,12 @@ class Collectible: Entity {
to.add(component: pointsComponent)
}

static func createCoinCollectible(position: CGPoint) -> Collectible {
static func createStarCollectible(position: CGPoint) -> Collectible {
Collectible(
position: position,
sprite: EntityConstants.CoinCollectible.sprite,
points: EntityConstants.CoinCollectible.points,
size: EntityConstants.CoinCollectible.size
sprite: SpriteConstants.star,
points: EntityConstants.StarCollectible.points,
size: EntityConstants.StarCollectible.size
)
}
}
Expand Up @@ -36,8 +36,9 @@ class Player: Entity {
physicsComponent.restitution = 0.0
let spriteComponent = SpriteComponent(
entityId: self.id,
image: "PlayerRedNose",
textureAtlas: "",
image: SpriteConstants.PlayerRedNose,
textureSet: SpriteConstants.PlayerRedNoseTexture,
textureAtlas: nil,
size: CGSize(width: 100, height: 140)
)
let scoreComponent = ScoreComponent(entityId: self.id, score: 0)
Expand Down
9 changes: 8 additions & 1 deletion star-dash/star-dash/GameEngine/GameEngine.swift
Expand Up @@ -57,7 +57,6 @@ class GameEngine {

func handlePlayerMove(toLeft: Bool) {
guard let playerEntityId = entityManager.playerEntityId(),
let physicsComponent = entityManager.component(ofType: PhysicsComponent.self, of: playerEntityId),
let playerComponent = entityManager.component(ofType: PlayerComponent.self, of: playerEntityId),
playerComponent.canMove else {
return
Expand All @@ -66,6 +65,14 @@ class GameEngine {
eventManager.add(event: MoveEvent(on: playerEntityId, toLeft: toLeft))
}

func handlePlayerStoppedMoving() {
guard let playerEntityId = entityManager.playerEntityId() else {
return
}

eventManager.add(event: StopMovingEvent(on: playerEntityId))
}

private func setUpSystems() {
systemManager.add(PositionSystem(entityManager, dispatcher: self))
systemManager.add(PhysicsSystem(entityManager, dispatcher: self))
Expand Down
6 changes: 5 additions & 1 deletion star-dash/star-dash/Persistence/Database.swift
Expand Up @@ -240,7 +240,11 @@ extension Database {
let jsonData = try Data(contentsOf: fileURL)
// Decode JSON data into LevelData
let levelData = try JSONDecoder().decode(LevelData.self, from: jsonData)
let levelPersistable = LevelPersistable(id: levelData.id, name: levelData.name, size: levelData.size)
let levelPersistable = LevelPersistable(
id: levelData.id,
name: levelData.name,
size: levelData.size
)
insert(persistable: levelPersistable)
for persistable in levelData.collectibles {
insert(persistable: persistable)
Expand Down
1 change: 1 addition & 0 deletions star-dash/star-dash/Rendering/ControlViewDelegate.swift
@@ -1,5 +1,6 @@
protocol ControlViewDelegate: AnyObject {

func joystickMoved(toLeft: Bool)
func joystickReleased()
func jumpButtonPressed()
}
12 changes: 10 additions & 2 deletions star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift
Expand Up @@ -65,13 +65,19 @@ class ControlView: UIView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)

guard let firstTouch = touches.first,
guard let joystickView = joystickView,
let firstTouch = touches.first,
firstTouch.location(in: self).x < self.frame.width / 2,
touches.count == 1 else {
return
}

joystickView?.moveJoystick(location: firstTouch.location(in: joystickView))
if shouldSendMoveEvent(location: firstTouch.location(in: self)) {
let isLeft = firstTouch.location(in: joystickView).x < joystickView.center.x
controlViewDelegate?.joystickMoved(toLeft: isLeft)
}

joystickView.moveJoystick(location: firstTouch.location(in: joystickView))
}

override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
Expand All @@ -82,6 +88,7 @@ class ControlView: UIView {
return
}

controlViewDelegate?.joystickReleased()
joystickView?.returnJoystick()
}

Expand All @@ -92,6 +99,7 @@ class ControlView: UIView {

let location = gesture.location(in: self)
if gesture.state == .ended {
controlViewDelegate?.joystickReleased()
joystickView.returnJoystick()
} else if location.x < self.frame.width / 2 {
joystickView.moveJoystick(location: gesture.location(in: joystickView))
Expand Down
4 changes: 4 additions & 0 deletions star-dash/star-dash/Rendering/MTKRenderer/MTKRenderer.swift
Expand Up @@ -78,6 +78,10 @@ extension MTKRenderer: ControlViewDelegate {
viewDelegate?.joystickMoved(toLeft: toLeft)
}

func joystickReleased() {
viewDelegate?.joystickReleased()
}

func jumpButtonPressed() {
viewDelegate?.jumpButtonPressed()
}
Expand Down
1 change: 1 addition & 0 deletions star-dash/star-dash/Rendering/ViewDelegate.swift
@@ -1,5 +1,6 @@
protocol ViewDelegate: AnyObject {

func joystickMoved(toLeft: Bool)
func joystickReleased()
func jumpButtonPressed()
}

0 comments on commit b7ed0de

Please sign in to comment.