Skip to content

Commit

Permalink
Merge pull request #52 from Ventus218/develop
Browse files Browse the repository at this point in the history
Update main from develop
  • Loading branch information
Ventus218 authored Jul 7, 2024
2 parents 24baccc + 2047f5f commit c768584
Show file tree
Hide file tree
Showing 86 changed files with 1,833 additions and 1,604 deletions.
44 changes: 22 additions & 22 deletions docs/05_Implementazione.md
Original file line number Diff line number Diff line change
Expand Up @@ -198,12 +198,12 @@ val io: SwingIO = SwingIO
Si è implementata la seguente architettura:
- SwingIO registra gli eventi di input generati dall'utente.
- Per gestire la concorrenza della ricezione degli eventi si è deciso di accumularli durante l'esecuzione di un frame e gestirli solo nel frame successivo.
- Il behaviour [SwingInputHandler](#swinginputhandler) permette all'utente di definire delle associazioni `tasto premuto -> azione da eseguire`, queste azioni verrano eseguite durante la fase di EarlyUpdate. Questo permette un approccio event driven piuttosto che a polling.
- Il behaviour [InputHandler](#inputhandler) permette all'utente di definire delle associazioni `tasto premuto -> azione da eseguire`, queste azioni verrano eseguite durante la fase di EarlyUpdate. Questo permette un approccio event driven piuttosto che a polling.

Le azioni devono essere eseguite ad ogni frame se il bottone è stato premuto e rilasciato, premuto o tenuto premuto.

### Implementazione
SwingIO (in particolare SwingInputEventsAccumulator) accoda tutti gli eventi (pressioni e rilasci di tasti) inviati da Swing. Una volta raggiunta la fine del frame la coda degli eventi viene copiata (in modo da renderla persistente fino al prossimo frame) e svuotata cosicchè i nuovi eventi possano continuare ad essere accodati.
SwingIO (in particolare InputEventsAccumulator) accoda tutti gli eventi (pressioni e rilasci di tasti) inviati da Swing. Una volta raggiunta la fine del frame la coda degli eventi viene copiata (in modo da renderla persistente fino al prossimo frame) e svuotata cosicchè i nuovi eventi possano continuare ad essere accodati.

Per semplicità si immagini che gli eventi siano raggruppati per tasto.

Expand Down Expand Up @@ -248,7 +248,7 @@ Da notare che ogni behaviour built-in è un mixin di Behaviour.
Un oggetto che viene mixato con il behaviour **Identifiable** avrà a disposizione un `id` e potrà essere cercato attraverso questo tra tutti gli altri oggetti.

### Positionable
Quando un behaviour usa **Positionable** come mixin, avrà accesso ad un campo position di tipo `Vector` settato a (0, 0) di default.
Quando un behaviour usa **Positionable** come mixin, avrà accesso ad un campo position di tipo `Vector2D` settato a (0, 0) di default.
E' anche possibile inizializzare **Positionable** con valori diversi così come modificare la posizione del behaviour a runtime.

*Esempio*
Expand All @@ -259,16 +259,16 @@ positionable.position = positionable.position.setX(3)
```

### PositionFollower
**PositionFollower** è un mixin che accetta come parametro un `followed` di tipo **Positionable** e un `positionOffset` del tipo `Vector`, ed esso stesso richiede in mixin un **Positionable**.
**PositionFollower** è un mixin che accetta come parametro un `followed` di tipo **Positionable** e un `positionOffset` del tipo `Vector2D`, ed esso stesso richiede in mixin un **Positionable**.
Il **PositionFollower** si occupa di tenere aggiornata la posizione del proprio **Positionable** in base alla posizione del `followed`, aggiungendoci il `positionOffset`.
La posizione viene inizializzata nella `onInit` e aggiornata nella `onLateUpdate`.

### Velocity
**Velocity** è un mixin che accetta come parametro di inizializzazione `velocity` di tipo `Vector`.
**Velocity** è un mixin che accetta come parametro di inizializzazione `velocity` di tipo `Vector2D`.
Un **Positionable** che ha questo trait come mixin si vedrà la propria posizione aggiornata ogni volta che verrà chiamata la `onUpdate`, secondo la velocità impostata. Tale velocità sarà moltiplicata per `engine.deltaTimeSeconds` per farsì che il behaviour si muovi secondo il frameRate (se in un secondo vengono eseguiti 60 frame, e la velocità è di 2, si vuole muovere il behaviour di 2 pixel nel giro di un secondo, quindi di 2/60 pixel ad ogni frame).

### Acceleration
**Acceleration** è un mixin che accetta come parametro di inizializzazione un tipo `acceleration` di tipo `Vector`.
**Acceleration** è un mixin che accetta come parametro di inizializzazione un tipo `acceleration` di tipo `Vector2D`.
Un **Velocity** che ha questo trait come mixin si vedrà la propria velocità aggiornata ogni volta che verrà chiamata la `onEarlyUpdate`, secondo l'accelerazione impostata. Tale accelerazione sarà moltiplicata per `engine.deltaTimeSeconds` per farsì che il behaviour acceleri secondo il frameRate.

### Scalable e SingleScalable
Expand All @@ -279,7 +279,7 @@ Se uno dei valori qualsiasi di scaling è inferiore o uguale a zero viene lancia
*Esempio*
```scala
// create a scalable that scales two dimensions, with (1, 1) as value of the scaling
val scalable: Scalable[Vector] = new Behaviour with Scalable(1d, 1d) // equivalent to Scalable((1d, 1d)) in Scala
val scalable: Scalable[Vector2D] = new Behaviour with Scalable(1d, 1d) // equivalent to Scalable((1d, 1d)) in Scala
scalable.scaleY = 3
println(scalable.scaleY) // 3
scalable.scaleX = 10
Expand Down Expand Up @@ -325,43 +325,43 @@ println(collider3.collides(collider2)) //false
**CircleCollider** è un mixin che aggiunge ad un oggetto un collider tondo con il centro in `(Positionable.x, Positionable.y)` e raggio passato in input.
Il suo raggio scala in base allo `scale` di **Scalable**.

### SwingRenderer
Un behaviour con **SwingRenderable** come mixin potrà essere rappresentato su un IO di tipo SwingIO.
### Renderer
Un behaviour con **Renderable** come mixin potrà essere rappresentato su un IO di tipo SwingIO.
Il rendering avviene nell'evento di `onLateUpdate` del game loop, e viene fatto invocando la funzione `renderer`, che contiene l'operazione da eseguire sul SwingIO e sul suo contesto grafico, insieme con la `rendereringPriority` che indica la priorità da passare allo SwingIO.
Se l'engine non contiene un IO di tipo SwingIO, allora SwingRenderer lancia un'eccezione di tipo `ClassCastException`.
Se l'engine non contiene un IO di tipo SwingIO, allora Renderer lancia un'eccezione di tipo `ClassCastException`.

SwingRenderable è esteso dal trait **SwingGameElementRenderer**, che dovrà avere in mixin anche **Positionable** e rappresenta un oggetto di gioco qualsiasi posizionato all'interno della scena.
Questo a sua volta è esteso dai trait **SwingShapeRenderer** che rappresenta una forma geometrica, **SwingImageRenderer** che rappresenta un'immagine, e da **SwingTextRenderer** che rappresenta un testo sulla scena.
Renderable è esteso dal trait **GameElementRenderer**, che dovrà avere in mixin anche **Positionable** e rappresenta un oggetto di gioco qualsiasi posizionato all'interno della scena.
Questo a sua volta è esteso dai trait **ShapeRenderer** che rappresenta una forma geometrica, **ImageRenderer** che rappresenta un'immagine, e da **TextRenderer** che rappresenta un testo sulla scena.

Entrambi i trait hanno delle dimensioni espresse in unità di gioco, che sono modificabili e non possono avere valori negativi o nulli. Inoltre questi trait sono di tipo `ScalableElement`, per cui le loro dimensioni vengono calcolate in proporzione ai propri fattori di scaling, sia che siano forniti da uno `Scalable` oppure da un `SingleScalable`.
Questi renderer hanno anche un `renderOffset`, che indica di quanto il disegno debba essere traslato rispetto alla posizione attuale del behaviour, e una `renderRotation`, che indica di quale angolo il renderer deve essere ruotato. La rotazione viene eseguita dopo la traslazione, e con centro di rotazione nella posizione non traslata dell'oggetto.

SwingRenderable è esteso dal trait **SwingUITextRenderer**, che disegna un testo su shermo, e che a differenza degli altri renderer rappresenta un elemento di overlay del gioco. Questo significa che non ha una posizione definita in termini di unità di gioco, bensì in pixel; Inoltre la sua posizione è
Renderable è esteso dal trait **UITextRenderer**, che disegna un testo su shermo, e che a differenza degli altri renderer rappresenta un elemento di overlay del gioco. Questo significa che non ha una posizione definita in termini di unità di gioco, bensì in pixel; Inoltre la sua posizione è
legata al `textAnchor`, ovvero il punto di partenza sullo schermo dal quale iniziare a disegnare l'elemento. In questo modo, gli elementi di overlay dipendono solamente dalla SwingIO dell'engine e non dalla scena nella quale sono istanziati.

*Esempio*
```scala
// Disegna un rettangolo in LateUpdate
val rect: SwingShapeRenderer = new Behaviour with SwingRectRenderer(width=1, height=2, color=Color.blue) with Positionable(0, 0)
val rect: ShapeRenderer = new Behaviour with RectRenderer(width=1, height=2, color=Color.blue) with Positionable(0, 0)

rect.shapeWidth = 2 // cambia le dimensioni
rect.shapeHeight = 1
rect.renderOffset = (1, 0) // cambia l'offset

// Disegna un cerchio in LateUpdate, con offset settato in input
val circle: SwingCircleRenderer = new Behaviour with SwingCircleRenderer(radius=2, offset=(1,0)) with Positionable(0, 0)
val circle: CircleRenderer = new Behaviour with CircleRenderer(radius=2, offset=(1,0)) with Positionable(0, 0)

circle.shapeRadius = 3 // cambia il raggio di un CircleRenderer

// Disegna un'immagine in LateUpdate, ruotata di 45 gradi
val image: SwingImageRenderer = new Behaviour with SwingImageRenderer("icon.png", width=1.5, height=1.5, rotation=45.degrees) with Positionable(0, 0)
val image: ImageRenderer = new Behaviour with ImageRenderer("icon.png", width=1.5, height=1.5, rotation=45.degrees) with Positionable(0, 0)

image.imageHeight = 2 // cambia le dimensioni
image.imageWidth = 2
image.renderRotation = 90.degrees // cambia l'angolo di rotazione

// Disegna del testo in LateUpdate, con posizione relativa alla finestra di gioco e non alla scena
val overlayText: SwingUITextRenderer = new Behaviour with SwingUITextRenderer(
val overlayText: UITextRenderer = new Behaviour with UITextRenderer(
"Hello!",
Font("Arial", Font.PLAIN, 10),
Color.green,
Expand All @@ -370,14 +370,14 @@ val overlayText: SwingUITextRenderer = new Behaviour with SwingUITextRenderer(

```

### SwingInputHandler
### InputHandler
Permette allo sviluppatore di definire associazioni del tipo `input -> azione`

```scala
class GameObject
extends Behaviour
// ...
with SwingInputHandler:
with InputHandler:

var inputHandlers: Map[InputButton, Handler] = Map(
D -> onMoveRight,
Expand Down Expand Up @@ -418,7 +418,7 @@ Come si può notare dall'esempio è anche possibile definire handler complessi:
> MouseButton1 -> (onTeleport.onlyWhenPressed and onTeleport.onlyWhenHeld)
> ```
Nel caso si preferisse comunque un approccio non event-driven è possibile utilizzare direttamente SwingIO senza SwingInputHandler:
Nel caso si preferisse comunque un approccio non event-driven è possibile utilizzare direttamente SwingIO senza InputHandler:
```scala
class GameObject extends Behaviour
Expand All @@ -431,9 +431,9 @@ class GameObject extends Behaviour
super.onUpdate(engine)
```
### SwingButton
### Swing
E' un bottone rettangolare con testo.
Mixa un SwingRectRenderer per lo sfondo e ha internamente un SwingTextRenderer per il testo (per questo è necessario chiamare su questo campo tutti gli eventi del game loop).
Mixa un RectRenderer per lo sfondo e ha internamente un TextRenderer per il testo (per questo è necessario chiamare su questo campo tutti gli eventi del game loop).

Permette di definire quali tasti (tastiera o mouse) possono premerlo.

Expand Down
1 change: 1 addition & 0 deletions docs/process/product_backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Priority goes from top to bottom.
|13|Scelta e design dei videogiochi di esempio||
|12|Refactor e pulizia di TestUtils||
|14|Realizzazione dei videogiochi di esempio||
|36|Aggiornare diagramma modello del dominio||


## Done
Expand Down
3 changes: 2 additions & 1 deletion docs/process/sprint_backlog.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@
|30|Bugfix: Fare in modo che swingIO crei i canvas in modo lazy|Alessandro|||X|
|31|Behaviour **Velocity**|Corrado|||X|
|31|Behaviour **Acceleration**|Corrado|||X|
|32|Refactor package|Tutti|X|||
|32|Refactor package|Tutti||X||
|32|Refactor package: aggiornare documentazione dopo refactor, controllare i nomi, gli esempi, e la conversion da Assertion a TestingFunction|Tutti||X||
|34|L'engine non deve essere runnabile più di una volta, aggiornare i test, e l'implementazione che deve lanciare delle eccezioni se necessario|Corrado|||X|
|35|Refactor: togliere tuple dove vengono passati x e y e mettere un tipo ad-hoc|Tutti|||X|
|13|Scelta e design dei videogiochi di esempio|Tutti|||X|
Expand Down
59 changes: 59 additions & 0 deletions packages.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
* -> package-private

- main
- scala
- sge
- swing
Utils.scala
SwingIO.scala
SwingIOBuilder.scala
- output
GameElements.scala
Shapes.scala
Images.scala
Text.scala
- input
InputEvent.scala
InputButton.scala
InputEventsAccumulator.scala*
- behaviours
- overlay
TextUIRenderer.scala
- ingame
Renderers.scala
Button.scala
InputHandler.scala
- core
Behaviour.scala
BehaviourUtils.scala*
Engine.scala
IO.scala
Scene.scala
Storage.scala
FPSLimiter*
- metrics
Vector2D.scala
Angle.scala
- behaviours
Identifiable.scala
- dimension2d
Positionable.scala
PositionFollower.scala
Scalable.scala
- phisics2d
Collider.scala
Velocity.scala
Acceleration.scala

- testing
TestUtils.scala ( le implementazioni in file package private*)
- behaviour
NFrameStopper.scala



- test
- scala
- mocks

(tutto il resto come in main)
30 changes: 0 additions & 30 deletions src/main/scala/Behaviours.scala

This file was deleted.

104 changes: 0 additions & 104 deletions src/main/scala/Dimensions2D.scala

This file was deleted.

Loading

0 comments on commit c768584

Please sign in to comment.