Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 13 additions & 3 deletions 20230304/tetris/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,17 @@ parcel.js - https://parceljs.org/getting-started/webapp/
press `r` key

## 해야할 일
- [ ] Game Scene 만들기
- [ ] Block Entity
- [ ] 화면에 표시
- [x] Game Scene 만들기
- [x] Block Entity
- [x] 화면에 표시
- [ ] 낙하

### 낙하기능 구체화
화면에 네모블럭이 나타나고 시간이 감에 따라 위치가 아래로 이동한다(낙하한다)

### 가변변수 인자로 전달

```scala
val myList = List("a", "b", "c")
processList(myList: _*)
```
2 changes: 2 additions & 0 deletions 20230304/tetris/src/main/scala/tetris/TetrisGame.scala
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import tetris.models.ViewModel
import tetris.models.GameModel

import tetris.scenes.StartScene
import tetris.scenes.GameScene
import tetris.scenes.EndScene

final case class MyStartupData(maxParticles: Int)
Expand Down Expand Up @@ -92,6 +93,7 @@ object TetrisGame extends IndigoGame[Unit, MyStartupData, GameModel, ViewModel]:
bootData: Unit
): NonEmptyList[Scene[MyStartupData, GameModel, ViewModel]] = NonEmptyList(
StartScene,
GameScene,
EndScene
)

Expand Down
15 changes: 15 additions & 0 deletions 20230304/tetris/src/main/scala/tetris/models/BlockModel.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package tetris.models

import indigo.shared.datatypes.Point
import indigo.shared.time.Seconds

final class BlockModel(
private var positionX: Double = 1,
private var positionY: Double = 1
):
def cellX = this.positionX.toInt
def cellY = this.positionY.toInt

def moveDown(duration: Seconds) =
val velocityY = 10
new BlockModel(positionX, positionY + duration.toDouble * velocityY)
4 changes: 3 additions & 1 deletion 20230304/tetris/src/main/scala/tetris/models/GameModel.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,6 @@ package tetris

package models

final class GameModel
final class GameModel(var block: BlockModel = BlockModel()):
def update(newBlock: BlockModel) =
GameModel(newBlock)
107 changes: 107 additions & 0 deletions 20230304/tetris/src/main/scala/tetris/scenes/GameScene.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package tetris

package scenes

import indigo.scenes.Scene
import indigo.scenes.SceneEvent
import indigo.scenes.SceneContext
import indigo.scenes.SceneName

import indigo.shared.Outcome
import indigo.shared.utils.Lens
import indigo.shared.constants.Key
import indigo.shared.subsystems.SubSystem
import indigo.shared.time.Seconds

import indigo.shared.events.GlobalEvent
import indigo.shared.events.EventFilters
import indigo.shared.events.KeyboardEvent
import indigo.shared.events.FrameTick

import indigo.shared.scenegraph.SceneUpdateFragment
import indigo.shared.scenegraph.Shape
import indigo.shared.scenegraph.Group
import indigo.shared.scenegraph.SceneNode

import indigo.shared.datatypes.Rectangle
import indigo.shared.datatypes.Size
import indigo.shared.datatypes.Fill
import indigo.shared.datatypes.RGBA
import indigo.shared.datatypes.Point
import indigo.shared.datatypes.Stroke

import tetris.scenes.GameScene.viewportWidth
import tetris.scenes.GameScene.viewportHeight

import tetris.models.GameModel
import tetris.models.ViewModel
import tetris.models.BlockModel

import tetris.viewModels.Block
import tetris.viewModels.BlockType
import tetris.viewModels.Cell
import tetris.viewModels.Grid
import tetris.viewModels.Board
import scala.scalajs.js.Date
import org.scalajs.dom.WindowConsole

object GameScene extends Scene[MyStartupData, GameModel, ViewModel] {

val viewportWidth = TetrisGame.config.viewport.width
val viewportHeight = TetrisGame.config.viewport.height

type SceneModel = GameModel
type SceneViewModel = Unit

override def subSystems: Set[SubSystem] = Set()

override def updateModel(
context: SceneContext[MyStartupData],
model: SceneModel
): GlobalEvent => Outcome[SceneModel] =
case KeyboardEvent.KeyDown(Key.ENTER) =>
Outcome(model)
.addGlobalEvents(SceneEvent.JumpTo(SceneName("end")))
case FrameTick =>
Outcome(
model.update(
model.block.moveDown(duration = context.delta)
)
)
case _ => Outcome(model)

override def updateViewModel(
context: SceneContext[MyStartupData],
model: SceneModel,
viewModel: SceneViewModel
): GlobalEvent => Outcome[SceneViewModel] = (e: GlobalEvent) =>
Outcome(viewModel)

override def name: SceneName = SceneName("game")

override def eventFilters: EventFilters = EventFilters.Restricted

val viewModelLens: Lens[ViewModel, SceneViewModel] = Lens.unit

override def modelLens: Lens[GameModel, GameModel] = Lens.keepLatest

override def present(
context: SceneContext[MyStartupData],
model: GameModel,
viewModel: Unit
): Outcome[SceneUpdateFragment] =
val block = model.block
Outcome(
SceneUpdateFragment.empty
.addLayer(
Board()
)
.addLayer(
Block(
blockType = BlockType.L,
leftTopPosition = Grid(block.cellX, block.cellY)
),
Block(blockType = BlockType.I, leftTopPosition = Grid(8, 1))
)
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ object StartScene extends Scene[MyStartupData, GameModel, ViewModel] {
): GlobalEvent => Outcome[SceneModel] =
case KeyboardEvent.KeyDown(Key.ENTER) =>
Outcome(model)
.addGlobalEvents(SceneEvent.JumpTo(SceneName("end")))
.addGlobalEvents(SceneEvent.JumpTo(SceneName("game")))
case _ => Outcome(model)

override def updateViewModel(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package tetris

package viewModels

import indigo.shared.datatypes.RGBA
import indigo.shared.datatypes.Rectangle
import indigo.shared.datatypes.Point
import indigo.shared.datatypes.Size
import indigo.shared.datatypes.Fill
import indigo.shared.datatypes.Stroke

import indigo.shared.scenegraph.Group
import indigo.shared.scenegraph.SceneNode
import indigo.shared.scenegraph.Shape

enum BlockType(val shape: List[(Int, Int)], val color: RGBA):
case L
extends BlockType(
shape = List((0, 0), (0, 1), (0, 2), (1, 2)),
color = RGBA.Green
)
case I
extends BlockType(
shape = List((0, 0), (0, 1), (0, 2), (0, 3)),
color = RGBA.Red
)

case class Block(blockType: BlockType, leftTopPosition: Grid)

object Block:
def apply(blockType: BlockType, leftTopPosition: Grid) =
val x = leftTopPosition.x
val y = leftTopPosition.y

Group(
blockType.shape.map(cooridinates =>
val (a, b) = cooridinates
Cell(position = Grid(x + a, y + b), color = blockType.color)
): _*
)

case class Grid(x: Int, y: Int)

case class Cell(position: Grid, color: RGBA)

object Cell:
val unitSize = 20

def apply(position: Grid, color: RGBA): SceneNode =
Shape.Box(
dimensions = Rectangle(
position = Point(position.x * unitSize, position.y * unitSize),
size = Size(unitSize)
),
fill = Fill.Color(color),
stroke = Stroke(1).withColor(RGBA.SlateGray)
)
44 changes: 44 additions & 0 deletions 20230304/tetris/src/main/scala/tetris/viewModels/BoardView.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package tetris.viewModels

import indigo.shared.scenegraph.Shape
import indigo.shared.scenegraph.Group
import indigo.shared.scenegraph.SceneNode

import indigo.shared.datatypes.Rectangle
import indigo.shared.datatypes.Point
import indigo.shared.datatypes.Size
import indigo.shared.datatypes.Fill
import indigo.shared.datatypes.RGBA

import tetris.scenes.EndScene.viewportWidth
import tetris.scenes.EndScene.viewportHeight

final case class Board()

object Board:
val Background =
Shape.Box(
dimensions = Rectangle(
position = Point(0, 0),
size =
Size(width = viewportWidth, height = viewportHeight - Cell.unitSize)
),
fill = Fill.Color(RGBA.Black)
)

val lastX = viewportWidth / Cell.unitSize - 1
val lastY = viewportHeight / Cell.unitSize - 1

val Border =
Group(
Range(0, lastX + 1)
.flatMap(x => Range(0, lastY + 1).map(y => (x, y)))
.filter((x, y) => x == 0 || x == lastX || y == 0 || y == lastY)
.map((x, y) => Cell(Grid(x, y), RGBA.Silver)): _*
)

def apply(): SceneNode =
Group(
Background,
Border
)