Skip to content

Commit

Permalink
blur and freeze game when paused
Browse files Browse the repository at this point in the history
  • Loading branch information
j0code committed Mar 23, 2024
1 parent ec7e02c commit 93259a1
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@
}],
"lines-between-class-members": ["error", "always", {"exceptAfterSingleLine": true}],
"max-len": ["warn", {
"code": 160, "tabWidth": 2, "comments": 160, "ignoreUrls": true
"code": 180, "tabWidth": 2, "comments": 160, "ignoreUrls": true
}],
"max-statements-per-line": ["error", {"max": 1}],
"multiline-ternary": ["warn", "never"],
Expand Down
56 changes: 48 additions & 8 deletions src/Graphics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,22 @@ import TextRenderer, { type TextRenderingOptions } from "./util/TextRenderer.js"

export default class Graphics {

readonly ctx: CanvasRenderingContext2D
readonly ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D

constructor(private readonly canvas: HTMLCanvasElement, private readonly blockSize: number) {
private filters: {
brightness?: number,
blur?: number
}

private filterSaves: ({
brightness?: number,
blur?: number
})[]

constructor(readonly canvas: HTMLCanvasElement | OffscreenCanvas, private readonly blockSize: number) {
this.ctx = canvas.getContext("2d")!
this.filters = {}
this.filterSaves = []
}

get fillStyle() { return this.ctx.fillStyle }
Expand All @@ -18,20 +30,48 @@ export default class Graphics {
set lineWidth(x) { this.ctx.lineWidth = x }
set globalAlpha(x) { this.ctx.globalAlpha = x }

brightness(x: number) {
this.ctx.filter = `brightness(${x})`
brightness(x?: number) {
this.filters.brightness = x
this.applyFilters()
}

save() { this.ctx.save() }
restore() { this.ctx.restore() }
blur(x?: number) {
this.filters.blur = x
this.applyFilters()
}

private applyFilters() {
const filter: string[] = []

if (this.filters.brightness != undefined) {
filter.push(`brightness(${this.filters.brightness})`)
}
if (this.filters.blur != undefined) {
filter.push(`blur(${this.filters.blur}px)`)
}

this.ctx.filter = filter.join(" ")
}

save() {
this.ctx.save()
this.filterSaves.push(structuredClone(this.filters))
}

restore() {
this.ctx.restore()
this.filters = this.filterSaves.pop() || {}
this.applyFilters()
}

reset() {
this.ctx.reset()
this.filters = {}
this.filterSaves = []
this.applyFilters()
this.ctx.imageSmoothingEnabled = false
this.ctx.fillStyle = "#78A7FF"
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height)

this.ctx.translate(this.canvas.width/2, this.canvas.height/2) // center game
}


Expand Down
179 changes: 104 additions & 75 deletions src/gui/state/ingame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import ContainerBlock from "../../block/ContainerBlock.js"
import CreativeInventory from "../../CreativeInventory.js"
import DebugScreen from "../../util/DebugScreen.js"
import Dim2 from "../../dim/Dim2.js"
import type Graphics from "../../Graphics.js"
import Graphics from "../../Graphics.js"
import Hotbar from "../../util/Hotbar.js"
import ItemStack from "../../ItemStack.js"
import MenuState from "../../enums/MenuState.js"
Expand All @@ -26,6 +26,13 @@ export let world: World
export let player: Player
export let cam: Cam

// offscreen graphics
let og: Graphics

export function init() {
og = new Graphics(new OffscreenCanvas(game.width, game.height), blockSize)
}

export function createWorld(name: string): World {
world = new World(name, [-20, 20, -20, 20, -1, 1])
player = new Player("jens", "TinyJens", 0)
Expand Down Expand Up @@ -56,92 +63,26 @@ export function tick() {
}

export function draw(g: Graphics) {
g.reset()

g.save()
g.translate(gameOffset.x, gameOffset.y) // move game by offset
g.translate(-cam.x, -cam.y) // move game into view

// world
world.draw(g)

// hitboxes
if (debug.showDebugScreen && debug.showHitboxes) world.drawBoundingBoxes(g)


// origin / axis
if (debug.showDebugScreen && debug.showOrigin) {
g.ctx.strokeStyle = "lime"
g.ctx.beginPath()
g.ctx.moveTo(0, -100)
g.ctx.lineTo(0, 100)
g.ctx.moveTo(-100, 0)
g.ctx.lineTo(100, 0)
g.ctx.stroke()
}

const mouseBlock = getMouseBlock()
const reachable = isBlockReachable(mouseBlock)

// block highlight
if (menuState == MenuState.INGAME) {
g.save()
g.translate(mouseBlock.x, mouseBlock.y)

g.fillStyle = "transparent"
g.strokeStyle = reachable ? "white" : "#707070"
g.lineWidth = reachable ? 2 : 1
g.strokeRect(1, 1)
if (menuState == MenuState.INGAME) drawGame()

g.restore()
}

// distance and player range (debug)
if (debug.showDebugScreen && debug.showRange) {
const range = (player.attributes.get("player.block_interaction_range", 0)!) * blockSize

g.lineWidth = 2
g.strokeStyle = "white"
g.fillStyle = "white"

const blockpos = mouseBlock.add(new Dim2(0.5, 0.5))
const playerpos = player.position.copy().add(new Dim2(0, player.eyeHeight))
g.reset()

if (menuState == MenuState.INGAME_MENU) {
g.save()
g.translate(blockpos.x + 0.2, blockpos.y)
g.drawText(blockpos.distanceTo(playerpos).toFixed(2))
g.blur(4)
g.ctx.drawImage(og.canvas, 0, 0)
g.restore()

blockpos.scale(blockSize)
playerpos.scale(blockSize)
const { x, y } = playerpos

g.ctx.beginPath()
g.ctx.ellipse(x, -y, range, range, 0, 0, 2 * Math.PI)
g.ctx.stroke()

g.ctx.beginPath()
g.ctx.ellipse(blockpos.x, -blockpos.y, 10, 10, 0, 0, 2 * Math.PI)
g.ctx.moveTo(blockpos.x, -blockpos.y)
g.ctx.lineTo(playerpos.x, -playerpos.y)
g.ctx.ellipse(playerpos.x, -playerpos.y, 10, 10, 0, 0, 2 * Math.PI)
g.ctx.stroke()
} else {
g.ctx.drawImage(og.canvas, 0, 0)
}

g.restore()

// hotbar
Hotbar.drawHotbar(g)

// container
Container.drawContainer(g)

// cursor
if (menuState == MenuState.INGAME) {
const { x, y } = getMousePos()
const size = blockSize/2

g.save()
g.ctx.translate(game.width/2, game.height/2) // center game
g.translate(gameOffset.x, gameOffset.y) // move game by offset
g.translate(-cam.x, -cam.y) // move game into view
g.translate(x, y)
Expand All @@ -152,6 +93,9 @@ export function draw(g: Graphics) {
const targetBlock = world.getBlock(x, y, z)
const inaccessible = z < frontZ && frontBlock?.full

const mouseBlock = getMouseBlock()
const reachable = isBlockReachable(mouseBlock)

if (!reachable) {
drawCrosshair(g, size, "#707070")
} else if (floatingStack) {
Expand All @@ -175,6 +119,91 @@ export function draw(g: Graphics) {
if (debug.showDebugScreen) DebugScreen.draw(g, world, player)
}

function drawGame() {
og.canvas.width = game.width
og.canvas.height = game.height
og.reset()
og.ctx.translate(og.canvas.width/2, og.canvas.height/2) // center game

og.save()
og.translate(gameOffset.x, gameOffset.y) // move game by offset
og.translate(-cam.x, -cam.y) // move game into view

// world
world.draw(og)

// hitboxes
if (debug.showDebugScreen && debug.showHitboxes) world.drawBoundingBoxes(og)


// origin / axis
if (debug.showDebugScreen && debug.showOrigin) {
og.ctx.strokeStyle = "lime"
og.ctx.beginPath()
og.ctx.moveTo(0, -100)
og.ctx.lineTo(0, 100)
og.ctx.moveTo(-100, 0)
og.ctx.lineTo(100, 0)
og.ctx.stroke()
}

const mouseBlock = getMouseBlock()
const reachable = isBlockReachable(mouseBlock)

// block highlight
if (menuState == MenuState.INGAME) {
og.save()
og.translate(mouseBlock.x, mouseBlock.y)

og.fillStyle = "transparent"
og.strokeStyle = reachable ? "white" : "#707070"
og.lineWidth = reachable ? 2 : 1
og.strokeRect(1, 1)

og.restore()
}

// distance and player range (debug)
if (debug.showDebugScreen && debug.showRange) {
const range = (player.attributes.get("player.block_interaction_range", 0)!) * blockSize

og.lineWidth = 2
og.strokeStyle = "white"
og.fillStyle = "white"

const blockpos = mouseBlock.add(new Dim2(0.5, 0.5))
const playerpos = player.position.copy().add(new Dim2(0, player.eyeHeight))

og.save()
og.translate(blockpos.x + 0.2, blockpos.y)
og.drawText(blockpos.distanceTo(playerpos).toFixed(2))
og.restore()

blockpos.scale(blockSize)
playerpos.scale(blockSize)
const { x, y } = playerpos

og.ctx.beginPath()
og.ctx.ellipse(x, -y, range, range, 0, 0, 2 * Math.PI)
og.ctx.stroke()

og.ctx.beginPath()
og.ctx.ellipse(blockpos.x, -blockpos.y, 10, 10, 0, 0, 2 * Math.PI)
og.ctx.moveTo(blockpos.x, -blockpos.y)
og.ctx.lineTo(playerpos.x, -playerpos.y)
og.ctx.ellipse(playerpos.x, -playerpos.y, 10, 10, 0, 0, 2 * Math.PI)
og.ctx.stroke()
}

og.restore()

// hotbar
Hotbar.drawHotbar(og)

// container
Container.drawContainer(og)
}

export function onKey(key: string) {
if (Container.showingInventory()) if (Container.onKey(key)) return

Expand Down
2 changes: 2 additions & 0 deletions src/gui/state/ingameMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ quitButton.on("click", () => {
export function draw(g: Graphics) {
const { ctx } = g

ctx.translate(g.canvas.width/2, g.canvas.height/2) // center game

ctx.textAlign = "center"
TextRenderer.drawText(ctx, "Saved game!", 0, -280, {
font: { size: 50 },
Expand Down
1 change: 1 addition & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Button.loadAssets()
Hotbar.loadTexture()
Container.loadAssets()
Entity.loadAssets()
ingameState.init()

export const perf = {
tick: [] as number[],
Expand Down
3 changes: 1 addition & 2 deletions src/util/DebugScreen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ function gameInfo(g: Graphics, world: World, player: Player) {
const lookingAtFluid = getFirstFluid(world, mouseBlock.x, mouseBlock.y)

ctx.save()
ctx.translate(-game.width/2, -game.height/2) // uncenter
ctx.translate(2, 2)
ctx.textAlign = "left"

Expand Down Expand Up @@ -76,7 +75,7 @@ function envInfo(g: Graphics) { // some of this might break
const { ctx } = g

ctx.save()
ctx.translate(game.width/2, -game.height/2) // uncenter (-> top right corner)
ctx.translate(game.width, 0) // -> top right corner
ctx.translate(-2, 2)
ctx.textAlign = "right"

Expand Down
6 changes: 3 additions & 3 deletions src/util/TextRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const SHADOW_BRIGHTNESS = "0.314"

export default class TextRenderer {

static drawText(ctx: CanvasRenderingContext2D, text: string, x: number = 0, y: number = 0, options?: TextRenderingOptions) {
static drawText(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, text: string, x: number = 0, y: number = 0, options?: TextRenderingOptions) {
const {
color = ctx.fillStyle || "white",
opacity = 1, bgOpacity = 0.35,
Expand Down Expand Up @@ -87,7 +87,7 @@ export type TextRenderingOptions = {
}

function drawDecoratedText(
ctx: CanvasRenderingContext2D,
ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
text: string,
x: number,
y: number,
Expand All @@ -104,7 +104,7 @@ function drawDecoratedText(
if (strikethrough) drawLine(ctx, x, y - unit * 5, textWidth, unit)
}

function drawLine(ctx: CanvasRenderingContext2D, x: number, y: number, width: number, height: number) {
function drawLine(ctx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D, x: number, y: number, width: number, height: number) {
if (ctx.textAlign == "right") x -= width
else if (ctx.textAlign == "center") x -= width / 2

Expand Down

0 comments on commit 93259a1

Please sign in to comment.