Skip to content

Commit

Permalink
Merge branch 'main' into f-menu-new
Browse files Browse the repository at this point in the history
  • Loading branch information
j0code committed Mar 1, 2024
2 parents b333eb8 + 798bd8f commit a2c0a54
Show file tree
Hide file tree
Showing 11 changed files with 114 additions and 28 deletions.
8 changes: 5 additions & 3 deletions src/AttributeList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { type ArrayElement, type HasData } from "./util/interfaces";

const AttributeNames = [
"generic.movement_speed",
"generic.jump_strength",
"generic.scale",
"player.block_interaction_range",
"player.entity_interaction_range"
] as const
] as const satisfies `${string}.${string}`[]

export type AttributeName = ArrayElement<typeof AttributeNames>

Expand Down Expand Up @@ -36,8 +38,8 @@ export default class AttributeList implements HasData {
})
}

get(name: AttributeName) {
return this.list.get(name)
get(name: AttributeName, defaultValue?: number) {
return this.list.get(name) || defaultValue
}

set(name: AttributeName, base: number) {
Expand Down
11 changes: 10 additions & 1 deletion src/defs/EntityDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ export default class EntityDef extends Base {

readonly hasFriction: boolean
readonly attributes: Attribute[]
readonly eyeHeight: number

constructor(namespace: string, idname: string, data: any) {
super(namespace, idname)
if (!validate(data)) throw new Error(`Invalid entitydef for ${namespace}:${idname}: ${JSON.stringify(data)}`)

this.hasFriction = data.hasFriction
this.attributes = data.attributes
this.eyeHeight = data.eyeHeight
}

get assetsPath() {
Expand All @@ -22,7 +24,8 @@ export default class EntityDef extends Base {

export type EntityDefData = {
hasFriction: boolean,
attributes: Attribute[]
attributes: Attribute[],
eyeHeight: number
}

function validate(data: any): data is EntityDefData {
Expand All @@ -42,5 +45,11 @@ function validate(data: any): data is EntityDefData {
data.attributes = []
}

if ("eyeHeight" in data) {
if (typeof data.eyeHeight != "number" || data.eyeHeight < 0 || data.eyeHeight > 1) return false
} else {
data.eyeHeight = 0.5
}

return true
}
9 changes: 8 additions & 1 deletion src/defs/PlayerDef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ export default class PlayerDef extends EntityDef {
attributes: [{
name: "generic.movement_speed",
base: 1
}, {
name: "generic.jump_strength",
base: 0.35
}, {
name: "generic.scale",
base: 1
}, {
name: "player.block_interaction_range",
base: 4.5
}, {
name: "player.entity_interaction_range",
base: 5
}]
}],
eyeHeight: 0.6
} satisfies Partial<EntityDefData>)
}

Expand Down
4 changes: 3 additions & 1 deletion src/dim/Dim.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ export default interface Dim {
sub(dim: Dim): Dim,
mult(dim: Dim): Dim,
set(dim: Dim | number): Dim,
scale(x: number): Dim,
scale(x: number): Dim
dot(dim: Dim): number,
sqMag(): number
mag(): number,
angle(): number
normalize(): Dim,
distanceTo(other: Dim): number
floor(): Dim,
Expand Down
24 changes: 23 additions & 1 deletion src/dim/Dim2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ import Dim from "./Dim.js"
import Dim3 from "./Dim3.js"

export default class Dim2 implements Dim {

static polar(theta: number, scale: number = 1) {
return new Dim2(Math.cos(theta) * scale, Math.sin(theta) * scale)
}

x: number
y: number
Expand All @@ -24,6 +28,8 @@ export default class Dim2 implements Dim {
}

mult(dim: Dim2): Dim2 {
this.x = this.x * dim.x - this.y * dim.y
this.y = this.x * dim.y + this.x * dim.x
return this
}

Expand All @@ -44,16 +50,32 @@ export default class Dim2 implements Dim {
return this
}

rotate(theta: number): Dim2 {
const {x, y} = this
const vec = Dim2.polar(theta)
this.mult(vec)
return this
}

dot(dim: Dim2 | Dim3): number {
return this.x * dim.x + this.y * dim.y
}

sqMag(): number {
return this.x ** 2 + this.y ** 2
return this.dot(this)
}

mag(): number {
return Math.sqrt(this.sqMag())
}

angle(): number {
return Math.acos(this.dot(new Dim2(1, 0)) / this.mag()) * Math.sign(this.y)
}

normalize(): Dim2 {
const mag = this.mag()
if (mag == 0) return this
return this.scale(1/mag)
}

Expand Down
14 changes: 12 additions & 2 deletions src/dim/Dim3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,26 @@ export default class Dim3 implements Dim {
return this
}

dot(dim: Dim2 | Dim3): number {
if (dim instanceof Dim2) return this.x * dim.x + this.y * dim.y
return this.x * dim.x + this.y * dim.y + this.z * dim.z
}

sqMag(): number {
return this.x ** 2 + this.y ** 2 + this.z ** 2
return this.dot(this)
}

mag(): number {
return Math.sqrt(this.sqMag())
}

normalize(): Dim2 {
angle(): number {
return Math.acos(this.dot(new Dim2(1, 0)) / this.mag()) * Math.sign(this.y)
}

normalize(): Dim3 {
const mag = this.mag()
if (mag == 0) return this
return this.scale(1/mag)
}

Expand Down
34 changes: 24 additions & 10 deletions src/entity/Entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default class Entity implements HasData {

readonly def: EntityDef
readonly position: Dim3
readonly rotation: Dim3
protected rotation: number
readonly motion: Dim3
protected readonly size: Dim2
readonly spawnTime: number
Expand All @@ -47,7 +47,7 @@ export default class Entity implements HasData {
}
}
this.position = new Dim3(...(data.position || [0, 0, 0]))
this.rotation = new Dim3(...(data.rotation || [0, 0, 0]))
this.rotation = data.rotation || 0
this.motion = new Dim3(...(data.motion || [0, 0, 0]))
this.size = new Dim2()
this.spawnTime = spawnTime
Expand All @@ -73,10 +73,23 @@ export default class Entity implements HasData {
return this.position.y
}

get eyeHeight() {
return this.attributes.get("generic.scale", 1)! * this.size.y * this.def.eyeHeight
}

get rotationAngle() {
return this.rotation
}

get eyes() {
return this.position.copy().add(new Dim2(0, this.eyeHeight))
}

getBoundingBox() {
let pos = this.position.copy()
pos.x -= this.size.x/2
return new BoundingBox(pos, this.size)
const size = this.size.copy().scale(this.attributes.get("generic.scale", 1)!)
const pos = this.position.copy()
pos.x -= size.x/2
return new BoundingBox(pos, size)
}

tick(world: World) {
Expand Down Expand Up @@ -143,13 +156,14 @@ export default class Entity implements HasData {
draw(g: Graphics, world: World) {
const block = world.getBlock(this.position.x, this.position.y, this.position.z)
const light = block?.lightLevel ?? 15
const box = this.getBoundingBox()

g.save()
g.translate(this.x, this.y)
g.translate(-this.size.x/2, 0) // to center (x)
g.translate(box.pos.x, box.pos.y)
//g.translate(-box.size.x/2, 0) // to center (x)

g.brightness(light / 15)
this.texture?.draw(g, this.size.x, this.size.y)
this.texture?.draw(g, box.size.x, box.size.y)

g.restore()
}
Expand All @@ -163,7 +177,7 @@ export default class Entity implements HasData {
id: this.id,
motion: this.motion.asArray(),
position: this.position.asArray(), // TODO: "pos" alias for compatibility
rotation: this.rotation.asArray(),
rotation: this.rotation,
noGravity: this.noGravity,
onGround: this.onGround,
spawnTime: this.spawnTime
Expand All @@ -175,7 +189,7 @@ export default class Entity implements HasData {
export type EntityData = Flatten<BaseData & {
motion: number[],
position: number[],
rotation: number[],
rotation: number,
noGravity: boolean,
onGround: boolean,
spawnTime: number
Expand Down
2 changes: 2 additions & 0 deletions src/entity/ItemEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ export default class ItemEntity extends Entity {
tick(world: World) {
if (this.inFluid) this.motion.y = Entity.TERMINAL_FLUID_VELOCITY
super.tick(world)
if (this.motion.sqMag() > 0) this.rotation = this.motion.angle()
else if (isNaN(this.rotation)) this.rotation = 0

const pickupDelay = Math.max(this.spawnTime + ItemEntity.PICKUP_TIME - world.tickTime, 0)
const boundingBox = this.getBoundingBox()
Expand Down
9 changes: 6 additions & 3 deletions src/entity/Player.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import PlayerDef from "../defs/PlayerDef.js"
import Texture from "../texture/Texture.js"
import World from "../world/World.js"
import { type Flatten } from "../util/interfaces.js"
import { player, world } from "../gui/state/ingame.js"
import { world, getMousePos } from "../gui/state/ingame.js"
import Dim2 from "../dim/Dim2.js"

const playerDef = new PlayerDef()

Expand Down Expand Up @@ -51,7 +52,7 @@ export default class Player extends Entity {

addItems(stack: ItemStack) {
let leftover = this.hotbar.addItems(stack)
if (leftover) world.spawn<ItemEntityData>("tiny:item", { item: new ItemStack(player.selectedItem.item.id), position: player.position.asArray() })
if (leftover) world.spawn<ItemEntityData>("tiny:item", { item: new ItemStack(this.selectedItem.item.id), position: this.position.asArray() })
}

pickBlock(block: Block) {
Expand All @@ -74,11 +75,13 @@ export default class Player extends Entity {
die() { // respawn
this.position.set(0, 1, 0) // TODO: spawn point
this.motion.set(0, 0, 0)
this.rotation.set(0, 0)
this.rotation = 0
}

tick(world: World) {
super.tick(world)
const eyes = this.position.copy().add(new Dim2(0, this.eyeHeight))
this.rotation = getMousePos().sub(eyes).angle()
}

getData(): PlayerData {
Expand Down
12 changes: 6 additions & 6 deletions src/gui/state/ingame.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function init() {
export function tick() {
if (input.keyPressed("Space")) {
if (player.inFluid) player.motion.y = Entity.TERMINAL_FLUID_VELOCITY
else if (player.onGround) player.motion.y = 0.35
else if (player.onGround) player.motion.y = player.attributes.get("generic.jump_strength", 0.35)!
}

player.motion.x = (Number(input.keyPressed("KeyD")) - Number(input.keyPressed("KeyA"))) * 0.15
Expand Down Expand Up @@ -88,13 +88,13 @@ export function draw(g: Graphics) {

// distance and player range (debug)
if (debug.showDebugScreen && debug.showRange) {
const range = (player.attributes.get("player.block_interaction_range") || 0) * blockSize
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, 1))
const playerpos = player.position.copy().add(new Dim2(0, player.eyeHeight))

g.save()
g.translate(blockpos.x + 0.2, blockpos.y)
Expand Down Expand Up @@ -244,8 +244,8 @@ export function whileKey(key: string) {
if (stack.item.id == "tiny:air") return

const entityData = {
position: player.position.asArray(),
motion: getMousePos().sub(player.position).normalize().scale(0.6).asArray()
position: player.eyes.asArray(),
motion: Dim2.polar(player.rotationAngle, 0.6).asArray()
}
let dropStack = stack

Expand Down Expand Up @@ -326,7 +326,7 @@ export function getMousePos() {
}

function isBlockReachable(pos: Dim2) {
return pos.copy().add(new Dim2(0.5, 0.5)).distanceTo(player.position.copy().add(new Dim2(0, 1))) <= player.attributes.get("player.block_interaction_range")!
return pos.copy().add(new Dim2(0.5, 0.5)).distanceTo(player.position.copy().add(new Dim2(0, player.eyeHeight))) <= player.attributes.get("player.block_interaction_range", 0)!
}

function openInventory() {
Expand Down
15 changes: 15 additions & 0 deletions src/world/World.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Player, { type PlayerData } from "../entity/Player.js"
import { type NamespacedId } from "../util/interfaces.js"
import { isNamespacedId } from "../util/typecheck.js"
import { createBlock, createEntity, getFirstBlock } from "../gui/state/ingame.js"
import Dim2 from "../dim/Dim2.js"

export default class World {

Expand Down Expand Up @@ -220,6 +221,20 @@ export default class World {
if (z == 0) {
for (let entity of this.getAllEntities()) {
entity.getBoundingBox().draw(g, "red")

// eye ray
const eyes = entity.eyes
const dir = Dim2.polar(entity.rotationAngle, 100)
const endpoint = eyes.copy().add(dir)

g.save()
g.strokeStyle = "red"
g.translate(eyes.x, eyes.y)
g.ctx.beginPath()
g.ctx.moveTo(0, 0)
g.ctx.lineTo(endpoint.x, -endpoint.y)
g.ctx.stroke()
g.restore()
}
}
}
Expand Down

0 comments on commit a2c0a54

Please sign in to comment.