Creating a 2D Space Game for iOS Using SpriteKit - Part 2

Introduction In the previous chapter, I started talking about the video game creation process, from project setup to adding the background. Now, I’m going to add the player and physics to it. You can download the project here. First Step The first step is to initialize player using SKSpriteNode, set up player.position, and add player as a child node. SKSpriteNode - is an onscreen graphical element that can be initialized from an image or a solid color. ...

July 3, 2024 · 3 min · Dmytro Chumakov

Creating a 2D Space Game for iOS Using SpriteKit - Part 1

Introduction I have never tried creating a game before; it feels like magic to me. I know that games have an enormous amount of underlying layers of abstractions and tools such as game engines, rendering, and so on. I have always been eager to learn at least 1% of the game creation process. In this article, I’m going to explore step-by-step instructions for creating a game for the iOS platform using SpriteKit. ...

June 28, 2024 · 2 min · Dmytro Chumakov

Combine practical usage examples

Introduction When working in a large codebase with a significant number of async events, I often found myself in situations where I couldn’t combine events effectively. This resulted in optimization problems and inefficient consumption of OS resources. The codebase contained closures and async/await, so it wasn’t possible to use operators like merge or combineLatest. After discovering this limitation, I decided to add new methods using Combine. I will be demonstrating this with a simple NetworkService responsible only for executing and validating requests using Combine. Let’s dive into the implementation. ...

June 22, 2024 · 2 min · Dmytro Chumakov

The Memento Pattern

What is a Memento Pattern? The Memento Pattern helps return an object to one of its previous states; for instance, if the user requests an “undo” operation. Source What problems does it solve? The Memento Pattern helps solve following problems: Undo/Redo Functionality: Memento allows you to capture an object’s state at a specific point in time and store it externally. This enables you to implement undo/redo functionality by restoring the object to its previous state. Checkpointing: In applications where users need to save progress or create checkpoints (such as in games or long processes), the Memento Pattern allows you to save the state of an object at various intervals so that users can return to those points later. Real-world code example // Memento: Represents the state of the TextEditor struct TextEditorMemento { let text: String } // Originator: Creates and stores states in Memento objects class TextEditor { private var text: String = "" func setText(_ text: String) { self.text = text } func getText() -> String { return text } func save() -> TextEditorMemento { return TextEditorMemento(text: text) } func restore(fromMemento memento: TextEditorMemento) { self.text = memento.text } } // Caretaker: Manages the mementos class TextEditorHistory { private var history: [TextEditorMemento] = [] private let editor: TextEditor init(editor: TextEditor) { self.editor = editor } func save() { let snapshot = editor.save() history.append(snapshot) } func undo() { guard let lastSnapshot = history.popLast() else { print("Nothing to undo.") return } editor.restore(fromMemento: lastSnapshot) } func printHistory() { print("Text Editor History:") for (index, snapshot) in history.enumerated() { print("Step \(index + 1): \(snapshot.text)") } print("Current text: \(editor.getText())") } } // Example usage let textEditor = TextEditor() let history = TextEditorHistory(editor: textEditor) textEditor.setText("Hello, World!") history.save() textEditor.setText("This is a Swift example.") history.save() textEditor.setText("Using Memento Pattern.") history.save() history.printHistory() history.undo() print("After Undo:") history.printHistory() Thank you for reading! 😊

March 22, 2024 · 2 min · Dmytro Chumakov

The Interpreter Pattern

What is an Interpreter Pattern? The Interpreter Pattern helps implement a simple language and defines a class based representation for its grammar along with an interpreter to interpret its sentences. Source What problems does it solve? The Interpreter Pattern helps solve following problems: Language Interpretation: When you have a language or syntax that needs to be interpreted, such as mathematical expressions, regular expressions, or domain-specific languages (DSLs), the Interpreter Pattern helps in implementing the logic to interpret and execute these expressions. Extensibility: The Interpreter Pattern allows for easy addition of new grammar rules or language constructs without modifying the core interpreter logic. This promotes extensibility, enabling the interpreter to support new features or languages with minimal changes. Separation of Concerns: It separates the grammar definition from the interpretation logic. This separation of concerns makes the codebase modular and easier to maintain. Changes to the grammar or language rules do not affect the interpretation logic, and vice versa. Real-world code example // Define the protocol for the expression protocol Expression { func interpret() -> Int } // Concrete expression for a number class NumberExpression: Expression { private var value: Int init(_ value: Int) { self.value = value } func interpret() -> Int { return value } } // Concrete expression for addition class AdditionExpression: Expression { private var left: Expression private var right: Expression init(_ left: Expression, _ right: Expression) { self.left = left self.right = right } func interpret() -> Int { return left.interpret() + right.interpret() } } // Concrete expression for subtraction class SubtractionExpression: Expression { private var left: Expression private var right: Expression init(_ left: Expression, _ right: Expression) { self.left = left self.right = right } func interpret() -> Int { return left.interpret() - right.interpret() } } // Concrete expression for multiplication class MultiplicationExpression: Expression { private var left: Expression private var right: Expression init(_ left: Expression, _ right: Expression) { self.left = left self.right = right } func interpret() -> Int { return left.interpret() * right.interpret() } } // Concrete expression for division class DivisionExpression: Expression { private var left: Expression private var right: Expression init(_ left: Expression, _ right: Expression) { self.left = left self.right = right } func interpret() -> Int { let divisor = right.interpret() if divisor != 0 { return left.interpret() / divisor } else { // Handle division by zero error fatalError("Division by zero") } } } // Usage let expression = AdditionExpression( MultiplicationExpression(NumberExpression(2), NumberExpression(3)), DivisionExpression(NumberExpression(10), NumberExpression(5)) ) // Interpret the expression let result = expression.interpret() print("Result: \(result)") Thank you for reading! 😊

March 18, 2024 · 2 min · Dmytro Chumakov