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

Texture and Animations #20

Merged
merged 6 commits into from Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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 @@ -58,20 +58,26 @@

// MARK: Gesture handler methods

@objc func jumpButtonTapped() {

Check failure on line 61 in star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift

View workflow job for this annotation

GitHub Actions / build

Attributes should be on their own lines in functions and types, but on the same line as variables and imports. (attributes)
controlViewDelegate?.jumpButtonPressed()
}

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,16 +88,18 @@
return
}

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

@objc func handlePan(_ gesture: UIPanGestureRecognizer) {

Check failure on line 95 in star-dash/star-dash/Rendering/MTKRenderer/ControlView.swift

View workflow job for this annotation

GitHub Actions / build

Attributes should be on their own lines in functions and types, but on the same line as variables and imports. (attributes)
guard let joystickView = self.joystickView else {
return
}

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()
}