Skip to content

Commit

Permalink
Implement level & rocket
Browse files Browse the repository at this point in the history
  • Loading branch information
phisn committed Sep 21, 2024
1 parent a882bb3 commit 148a9ef
Show file tree
Hide file tree
Showing 5 changed files with 367 additions and 55 deletions.
2 changes: 1 addition & 1 deletion packages/game/proto/world.proto
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ message RocketConfig {
float position_y = 2;
float rotation = 3;

RocketConfig default_config = 4;
RocketBehaviorConfig default_config = 4;
}

message LevelConfig {
Expand Down
12 changes: 10 additions & 2 deletions packages/game/src/model/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { EventStore } from "../framework/event"
import { ResourceStore } from "../framework/resource"
import { LevelComponent, LevelEntity } from "../modules/module-level"
import { RocketComponent, RocketEntity } from "../modules/module-rocket"
import { Point } from "./utils"

export class GameStore {
public resources: ResourceStore<GameResources>
Expand Down Expand Up @@ -42,12 +43,19 @@ export interface GameEvents {
c1: RAPIER.Collider
c2: RAPIER.Collider

e1: EntityWith<GameComponents, "body">
e2: EntityWith<GameComponents, "body">
e1?: EntityWith<GameComponents, "body">
e2?: EntityWith<GameComponents, "body">

started: boolean
}): void

death(props: {
rocket: RocketEntity

contactPoint: Point
normal: Point
}): void

captureChanged(props: { rocket: RocketEntity; level: LevelEntity; started: boolean }): void
captured(props: { rocket: RocketEntity; level: LevelEntity }): void
}
112 changes: 88 additions & 24 deletions packages/game/src/modules/module-level.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import RAPIER from "@dimforge/rapier2d"
import { LevelConfig } from "../../proto/world"
import { EntityWith } from "../framework/entity"
import { GameInput } from "../game"
Expand All @@ -6,29 +7,37 @@ import { Point, Rect, Size, changeAnchor } from "../model/utils"
import { RocketEntity, rocketComponents } from "./module-rocket"

export interface LevelComponent {
config: LevelConfig
start: boolean

cameraRect: Rect
position: Point
rotation: number

capturing: boolean
completed: boolean

cameraRect: Rect
}

export const levelComponents = ["level", "body"] satisfies (keyof GameComponents)[]
export type LevelEntity = EntityWith<GameComponents, (typeof levelComponents)[number]>

export class ModuleLevel {
private getRocket: () => RocketEntity

private progress?: number
private progressLevel?: LevelEntity

private previousBorder?: RAPIER.Collider

constructor(private store: GameStore) {
this.getRocket = store.entities.single(...rocketComponents)

store.events.listen({
collision: ({ e1, e2, started }) => {
if (e1.has(...levelComponents) && e2.has(...rocketComponents)) {
if (e1?.has(...levelComponents) && e2?.has(...rocketComponents)) {
this.handleCollision(e1, e2, started)
}

if (e1.has(...rocketComponents) && e2.has(...levelComponents)) {
if (e1?.has(...rocketComponents) && e2?.has(...levelComponents)) {
this.handleCollision(e2, e1, started)
}
},
Expand Down Expand Up @@ -67,31 +76,48 @@ export class ModuleLevel {
}

const level = nearestLevel.get("level")
level.start = true
level.completed = true
this.constructBorder(level)
}

onUpdate(_input: GameInput) {
if (this.progress && this.progressLevel) {
this.progress -= 1

if (this.progress <= 0) {
const captured = this.progressLevel
this.progressLevel = undefined

const world = this.store.resources.get("world")
const body = captured.get("body")
world.removeRigidBody(body)
this.handleFinish(this.progressLevel)
}
}
}

const level = captured.get("level")
level.completed = true
level.capturing = false
private handleFinish(level: LevelEntity) {
const rocketBody = this.getRocket().get("body")
const rocketVelocity = rocketBody.linvel()

this.store.events.invoke.captured?.({
rocket: this.store.entities.single(...rocketComponents)(),
level: captured,
})
}
if (
Math.abs(rocketVelocity.x) > ROCKET_SPEED_TOLERANCE ||
Math.abs(rocketVelocity.y) > ROCKET_SPEED_TOLERANCE
) {
return
}

const captured = level
this.progressLevel = undefined

const world = this.store.resources.get("world")
const body = captured.get("body")
world.removeRigidBody(body)

const levelComponent = captured.get("level")
levelComponent.completed = true
levelComponent.capturing = false
this.constructBorder(levelComponent)

this.store.events.invoke.captured?.({
rocket: this.store.entities.single(...rocketComponents)(),
level: captured,
})
}

private handleCollision(level: LevelEntity, rocket: RocketEntity, started: boolean) {
Expand All @@ -114,14 +140,49 @@ export class ModuleLevel {
})
}

private constructBorder(levelComponent: LevelComponent) {
const rapier = this.store.resources.get("rapier")
const world = this.store.resources.get("world")

if (this.previousBorder) {
world.removeCollider(this.previousBorder, false)
}

const colliderDesc = rapier.ColliderDesc.polyline(
new Float32Array([
levelComponent.cameraRect.left,
levelComponent.cameraRect.top,

levelComponent.cameraRect.left,
levelComponent.cameraRect.bottom,

levelComponent.cameraRect.right,
levelComponent.cameraRect.bottom,

levelComponent.cameraRect.right,
levelComponent.cameraRect.top,

levelComponent.cameraRect.left,
levelComponent.cameraRect.top,
]),
)

this.previousBorder = world.createCollider(colliderDesc)
}

private constructLevel(levelConfig: LevelConfig) {
const rapier = this.store.resources.get("rapier")
const world = this.store.resources.get("world")

const position = {
x: levelConfig.positionX,
y: levelConfig.positionY,
}

const body = world.createRigidBody(new rapier.RigidBodyDesc(rapier.RigidBodyType.Fixed))

const captureBox = calculateCaptureBox(
{ x: levelConfig.positionX, y: levelConfig.positionY },
position,
levelConfig.rotation,
levelConfig.captureAreaLeft,
levelConfig.captureAreaRight,
Expand All @@ -138,24 +199,27 @@ export class ModuleLevel {
const level = this.store.entities.create({
body,
level: {
config: levelConfig,

capturing: false,
completed: false,
start: false,

cameraRect: {
left: levelConfig.cameraTopLeftX,
top: levelConfig.cameraTopLeftY,
right: levelConfig.cameraBottomRightX,
bottom: levelConfig.cameraBottomRightY,
},
position,
rotation: levelConfig.rotation,

capturing: false,
completed: false,
},
})

return level
}
}

const ROCKET_SPEED_TOLERANCE = 0.001
const TICKS_TO_CAPTURE = 60
const FLAG_CAPTURE_HEIGHT = 0.5

Expand Down
Loading

0 comments on commit 148a9ef

Please sign in to comment.