Skip to content

Commit

Permalink
Merge pull request #68 from Ventus218/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
Ventus218 authored Jul 15, 2024
2 parents 040e6ed + 48f7f72 commit 7278734
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 50 deletions.
Binary file removed ExampleGame/src/main/resources/epic-crocodile.png
Binary file not shown.
21 changes: 0 additions & 21 deletions ExampleGame/src/main/scala/ExampleGame.scala

This file was deleted.

15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Scala Game Engine
![Logo](./docs/img/logo-SGE.jpg)

## Autori
- Alessandro Venturini
Expand All @@ -7,7 +8,7 @@

## Abstract
Si vuole realizzare un semplice game engine.
Inoltre verranno realizzati almeno due giochi diversi, per dimostrare che il framework sia abbastanza general purpose.
Inoltre verranno realizzati tre giochi diversi, per dimostrare che il framework sia abbastanza general purpose.

Le caratteristiche di base che verranno fornite sono le seguenti:
- Game loop
Expand All @@ -18,7 +19,12 @@ Le caratteristiche di base che verranno fornite sono le seguenti:

L'intenzione è quella di utilizzare le seguenti caratteristiche peculiari di scala:
- Mixin per realizzare quello che normalmente viene implementato con il pattern Component. In modo da fornire una esperienza di sviluppo più intuitiva.
- DSL per definire la struttura del gioco, delle scene e degli oggetti di gioco. Questo DSL avrà lo scopo di sostituire un editor grafico con un approccio dichiarativo.
- DSL per facilitare e rendere più intuitivo il testing dell'engine/game-loop

### Componente funzionale del progetto
Siccome si è deciso di sfruttare i mixin che sono un concetto strettamente legato alla programmazione ad oggetti, per permettere la valutazione delle nostre competenze in ambito di programmazione funzionale ci siamo concentrati nell'adottare questo paradigma nella realizzazione dei giochi piuttosto che nel motore di gioco.

Per questo ognuno dei partecipanti al progetto ha realizzato in maniera totalmente autonoma il proprio gioco.

## Indice
- [Processo di sviluppo](./docs/01_ProcessoSviluppo.md)
Expand All @@ -28,3 +34,8 @@ L'intenzione è quella di utilizzare le seguenti caratteristiche peculiari di sc
- [Implementazione](./docs/05_Implementazione.md)
- [Testing](./docs/06_Testing.md)
- [Retrospettiva](./docs/07_Retrospettiva.md)

## Documentazione ai giochi sviluppati
- [SpaceDefender](./docs/games/SpaceDefender.md) (Michele)
- [StealthGame](./docs/games/StealthGame.md) (Corrado)
- [Trump (Briscola)](./docs/games/Briscola.md) (Alessandro)
11 changes: 0 additions & 11 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,6 @@ lazy val sge = project
assembly / assemblyOutputPath := file("./SGE.jar")
)

lazy val exampleGame = project
.in(file("./ExampleGame"))
.dependsOn(sge)
.settings(
name := "ExampleGame",
version := "0.1.0-SNAPSHOT",
scalaVersion := scala3Version,
assembly / assemblyOutputPath := file("./ExampleGame.jar"),
assembly / mainClass := Some("ExampleGame")
)

lazy val spaceDefender = project
.in(file("./SpaceDefender"))
.dependsOn(sge)
Expand Down
11 changes: 8 additions & 3 deletions docs/01_ProcessoSviluppo.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ Si è inoltre deciso che lo sprint backlog manterrà una storia di tutte le spri
Le sprint dureranno una settimana ciascuna e ci si aspetta un quantitativo effettivo di lavoro da parte di ogni sviluppatore di circa 15 ore.

### Meeting
- Un incontro a inizio sprint per decidere come suddividere agli sivluppatori le task
- Per conciliare gli impegni degli studenti si è deciso di utilizzare un gruppo per comunicare giornalmente gli avanzamenti al posto del classico meeting ad inizio giornata
- Un incontro a inizio sprint per decidere come suddividere agli sviluppatori le task
- Per conciliare gli impegni degli studenti si è deciso di utilizzare un gruppo whatsapp per comunicare giornalmente gli avanzamenti al posto del classico meeting ad inizio giornata
- Un incontro a fine sprint per valutare il risultato e applicare eventuali correzioni al processo di sviluppo

## La nostra definizione di "done"
Expand All @@ -36,9 +36,14 @@ Verrà utilizzato il modello Git-Flow.
Per il nostro caso sembra non sarà particolarmente utile l'utilizzo di *release branch* ma nel caso in cui dovesse diventarlo allora verranno utilizzate.

### Peer review
Ogni pull request deve essere approvata da almeno un altro componente del team prima che se ne possa fare il merge.
Ogni pull request (su main o develop) deve essere approvata da almeno un altro componente del team prima che se ne possa fare il merge.

### Github branch protection rules
Per rafforzare il processo di lavoro, si è applicata la seguente regola sui branch *main* e *develop*:

È possibile effettuare merge solo a seguito di una pull request con test verdi e almeno una revisione da parte di uno degli sviluppatori.

### Delivery
Si sono realizzati due workflow di delivery:
- Pubblicazione della documentazione sotto forma di GitHub Pages ([qui](/.github/workflows/deploy-gh-pages.yml) il file di configurazione)
- Creazione di una release a seguito di nuovi tag sul branch main. Con annessa costruzione e pubblicazione dei fat JAR ([esempio](https://github.com/Ventus218/PPS-23-SGE/releases/tag/1.1.1)). ([qui](/.github/workflows/delivery.yml) il file di configurazione)
7 changes: 4 additions & 3 deletions docs/02_RequisitiSpecifica.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ Il framework avrà le seguenti caratteristiche:
- Definizione di un renderer 2D con sprite e dimensione di visualizzazione
- Definizione di un collider 2D con dimensione.
- Possibilità di leggere l'input (tastiera e mouse)
- Fisica semplificata (velocità e accelerazione)
- avrà a disposizione un insieme di API che semplifichino il testing di dell'engine o degli elementi di gioco

### Sistema
- L'engine chiama dei metodi sui game object in momenti specifici del game loop.
Expand All @@ -58,11 +60,10 @@ Il framework avrà le seguenti caratteristiche:
## Non funzionali
- La flessibilità ed estensibilità del sistema sono le cose più importanti. L'obiettivo è quello di permettere potenzialmente all'utente di allargare le funzionalità del framework.
(Ad esempio si potrebbe introdurre la possibilità di realizzare giochi 3D semplicemente creando i propri behaviour specifici)

- La semplicità e intuitività di utilizzo dell'engine da parte dell'utente
- La semplicità e intuitività di utilizzo dell'engine da parte dell'utente (essendo gli sviluppatori anche stakeholders la realizzazione di questo requisito verrà controllata in base alla loro soddisfazione)

## Implementazione
- Dato lo scopo del progetto (dimostrare le competenze aquisite durante l'insegnamento) si utilizzerà Scala.
- Gli svilupattori intendono utilizzare i mixin per realizzare quello che normalmente viene implementato con il pattern Component, in quanto sembra essere un buon campo di applicazione di questo concetto.
- Per ottenere come risultato una codebase solida e di qualità si è deciso di implementare la tecnica del Test Driven Development (TDD).
- Per implementare l'editor testuale si è deciso di sviluppare un DSL che permetta di definire le scene.
- Per facilitare il testing dei componenti di gioco e dell'engine si svilupperà un DSL per il suddetto scopo.
9 changes: 7 additions & 2 deletions docs/03_DesignArchitetturale.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ L'utente che utilizza il framework ne ha la seguente visione a strati:
|:----:|
|Editor testuale di gioco|
|Comportamenti built-in e definiti dall'utente|
|Sistema di IO|
|Motore di gioco|

## Editor
Expand All @@ -20,6 +21,10 @@ I comportamenti sono sostanzialmente le funzionalità che gli oggetti con quel c

L'utente può utilizzare i comportamenti già forniti dal framework oppure definirne dei propri.

## Sistema di IO
Viene messo a disposizione un concetto di IO per la gestione dell'interazione con il videogiocatore.

Ne verrà fornito uno built-in ma potrà anche essere sostituito dall'utente con uno custom.

## Motore di gioco
Il motore di gioco orchestra tutte le entità presenti in modo da generare l'output previsto. Inoltre fornisce delle API che permettono all'utente di interagire (ad esempio per creare/distruggere oggetti, cercarne alcuni con specifici comportamenti, ecc....).
Inoltre il motore di gioco mette a disposizione un concetto di IO che permette all'utente di definire il proprio sistema di input/output (grafico o meno).
Il motore di gioco orchestra tutte le entità presenti in modo da generare l'output previsto. Inoltre fornisce delle API che permettono all'utente di interagirci (ad esempio per creare/distruggere oggetti, cercarne alcuni con specifici comportamenti, ecc....).
2 changes: 1 addition & 1 deletion docs/04_DesignDettaglio.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ IO è pensato per essere implementato in modo che si possa definire un qualsiasi

Le classi che implementano IO possono inoltre agganciarsi a un momento specifico del game loop ovvero la fine dell'elaborazione di un frame, attraverso il metodo `onFrameEnd`, oppure alla fine dell'intero game loop attraverso il metodo `onEngineStop`.

Le specifiche implementazioni di IO forniranno ai behaviour addetti all rendering o all'input tutte le informazioni e i riferimenti di cui hanno bisogno per svolgere il loro compito.
Le specifiche implementazioni di IO forniranno ai behaviour addetti al rendering o all'input tutte le informazioni e i riferimenti di cui hanno bisogno per svolgere il loro compito.

Questo implica che l'utente utilizzando una specifica implementazione di IO assuma nei behaviour che quella sia l'implementazione sottostante.

Expand Down
2 changes: 1 addition & 1 deletion docs/05_Implementazione.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ engine.loadScene(Scenes.MenuScene)
engine.loadScene(Scenes.GameScene)
```

## SwingIO
## SwingIO (Output)
SwingIO è il componente grafico dell'engine, e implementa il trait IO utilizzando le funzionalità del framework Swing.

Il metodo `draw` di SwingIO permette di registrare una funzione `Graphics2D => Unit`, ovvero l'operazione da applicare al contesto grafico della finestra, e la sua priorità, ovvero l'ordine con il quale queste operazioni vengono applicate.
Expand Down
111 changes: 111 additions & 0 deletions docs/07_Retrospettiva.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Retrospettiva

## Valutazione del processo di sviluppo
La realizzazione dell'intero progetto si è sviluppata nell'arco di 5 sprint. Delle quali la prima si è lavorato interamente in gruppo e l'ultima solo singolarmente.

Nel complesso ci siamo trovati bene ad adottare il modello SCRUM-like suggerito dal professore, ci ha aiutato a suddviderci equamente il lavoro e a favorire la collaborazione.

### Git Flow
Anche Git Flow è stato un'ottima scelta, non ci siamo mai trovati in particolari difficoltà dovute a questo branching model.

### Continuous integration
L'utilizzo di stumenti offerti da GitHub come code review, pull request, e actions hanno facilitato parecchio la coordinazione e velocizzato lo svolgimento di azioni ripetitive.

## Valutazione del risultato
Siamo complessivamente molto soddisfatti per quanto riguarda lo sviluppo dell'engine, tutti avevamo già avuto qualche esperienza nell'utilizzo di altri game engine (Unity), e riteniamo di aver catturato i concetti più importanti riguardanti lo sviluppo di videogiochi.

### Approccio basato su Mixin
E' stato sicuramente interessante seguire questo approccio, che ha dato vita a diverse soluzioni molto espressive. Riteniamo che renda la definizione di oggetti di gioco in maniera piuttosto intuitiva (in quanto è possibile vedere l'oggetto come un tutt'uno e non come un insieme di componenti scollegati tra di loro).

Siamo comunque venuti incontro anche a qualche problematica, in particolare riguardante conflitti che potevano generarsi tra i nomi dei campi utilizzati nei mixin, riteniamo che comunque non sia un problema grave in quanto con le giuste precauzioni è possibile ridurne l'occorrenza.

Una cosa che non ci ha soddisfatto a pieno è il fatto che se un mixin richiede dei parametri "nel costruttore" questi possano essere passati solo dalla classe che effettivamente lo include e non da altri mixin nel mezzo

```scala
// Questo non compila
trait A(var text: String, var color: Color) extends Behaviour
trait DefaultA(color: Color) extends Behaviour with A("Default", color)
class GameObject extends Behaviour with A with DefaultA

// Questo è invece il modo in cui si deve procedere
trait A(var text: String, var color: Color) extends Behaviour
trait DefaultA() extends Behaviour with A
class GameObject extends Behaviour with A("Default", Color.blue) with DefaultA

// Oppure è possibile utilizzare una classe,
// questo però impedirà di mixarla e permetterà solo di ereditare
trait A(var text: String, var color: Color) extends Behaviour
class DefaultA(var color: Color) extends Behaviour with A("Default", color)
class GameObject extends DefaultA(Color.blue)
```

### DSL
Inizialmente avevamo deciso di realizzare un DSL per permettere allo sviluppatore di definire le scene in maniera semplice e intuitiva. Ad un certo punto però ci siamo resi conto che l'approccio a mixin ci aveva portato direttamente in questa direzione e che un DSL in questo ambito non avrebbe portato a nessun tipo di vantaggio.

```scala
class GameObject(
initX: Double,
initY: Double,
circleRadius: Double,
val movementVelocity: Double = 40
) extends Behaviour
with Positionable(initX, initY)
with SingleScalable(1.0)
with CircleRenderer(circleRadius, Color.blue)
with CircleCollider(circleRadius)
with InputHandler
with Velocity
with Acceleration((0, -100)):
// implementazione specifica di GameObject

class Obstacle(initX: Double, initY: Double, squareSide: Double)
extends Behaviour
with Positionable(initX, initY)
with Scalable(1.0, 1.0)
with ImageRenderer("epic-crocodile.png", squareSide, squareSide)
with RectCollider(squareSide, squareSide):
// implementazione specifica di Obstacle

// Il fatto di aver realizzato degli oggetti (classi qui sopra) in maniera così
// componibile ci permette poi di avere una inizializzazione molto intuitiva
// e semplice, come è possibile vedere qui sotto
object GameScene extends Scene:
override def apply(): Iterable[Behaviour] =
Seq(
GameObject(
initX = 0,
initY = -20,
circleRadius = 5
),
Obstacle(
initX = 0,
initY = 0,
squareSide = 5
),
Obstacle(
initX = 10,
initY = 20,
squareSide = 25
),
Obstacle(
initX = -20,
initY = -30,
squareSide = 10
),
Obstacle(
initX = 40,
initY = 20,
squareSide = 2
)
)
```

Per questo motivo abbiamo deciso di realizzare invece un DSL per le API di testing dell'engine, per un esempio vedere [qui](./06_Testing.md#L55).

## Giochi realizzati
Abbiamo realizzato ben 3 giochi con caratteristiche e gameplay differenti, e riteniamo che l'engine si sia dimostrato sufficientemente general purpose.

Avendo ognuno di noi sviluppato il proprio gioco in maniera autonoma sono emersi diversi approcci all'integrazione di un approccio funzionale in un motore di gioco orientato agli oggetti.

## Ulteriori osservazioni
Avendo fatto dei refactoring importanti durante lo sviluppo l'aver utilizzato il TDD ci ha permesso di avere molta sicurezza nel effettuare cambiamenti e inoltre non ci siamo quasi mai trovati nella situazione di dover scovare bug particolarmente insidiosi.
Binary file modified docs/img/Design di dettaglio.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/img/logo-SGE.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions docs/process/product_backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ Priority goes from top to bottom.

|Id|Item|Details|
|--|----|-------|
|14|Realizzazione dei videogiochi di esempio||


## Done
Expand Down Expand Up @@ -46,4 +45,6 @@ Priority goes from top to bottom.
|13|Scelta e design dei videogiochi di esempio||
|12|Refactor e pulizia di TestUtils||
|36|Aggiornare diagramma modello del dominio||
|37|Fix: cache delle immagini scalate||
|37|Fix: cache delle immagini scalate||
|14|Realizzazione dei videogiochi di esempio||
|38|Finire documentazione (Retrospettiva)||
9 changes: 5 additions & 4 deletions docs/process/sprint_backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@
## Sprint 4 (inizio 8/07/2024)

|Backlog item Id|Sprint task|Assignee|Not started|Work in progress|Done|
|------------|-----------|------------|::|:-:|:-:|
|------------|-----------|------------|:-:|:-:|:-:|
|37|Fix: cache delle immagini scalate|Michele|||X|
|14|Realizzare gioco Corrado|Corrado|X|||
|14|Realizzare gioco Alessandro|Alessandro|X|||
|14|Realizzare gioco Michele|Michele|X|||
|14|Realizzare gioco Corrado|Corrado|||X|
|14|Realizzare gioco Alessandro|Alessandro|||X|
|14|Realizzare gioco Michele|Michele|||X|
|38|Finire documentazione (Retrospettiva)|Tutti|||X|

0 comments on commit 7278734

Please sign in to comment.