Initial commit
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import { Component } from "$/common/ecs/mod.ts";
|
||||
|
||||
export class Camera extends Component {
|
||||
active = true;
|
||||
x: number;
|
||||
y: number;
|
||||
zoom: number;
|
||||
|
||||
constructor(x = 0, y = 0, zoom = 1) {
|
||||
super();
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.zoom = zoom;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import { Component } from "$/common/ecs/mod.ts";
|
||||
import { SLOT_SIZE } from "$/common/constants.ts";
|
||||
|
||||
export class ItemStack {
|
||||
type_id: string;
|
||||
amount: number;
|
||||
max_amount: number;
|
||||
|
||||
constructor(type_id: string | string, amount: number = 1, max_amount: number = 64) {
|
||||
this.type_id = type_id;
|
||||
this.amount = amount;
|
||||
this.max_amount = max_amount;
|
||||
}
|
||||
|
||||
clone(): ItemStack {
|
||||
return new ItemStack(this.type_id, this.amount, this.max_amount);
|
||||
}
|
||||
}
|
||||
|
||||
export class ContainerSlot {
|
||||
#item_stack: ItemStack | undefined;
|
||||
|
||||
has_item() {
|
||||
return this.#item_stack !== undefined;
|
||||
}
|
||||
|
||||
set_item(item_stack: ItemStack | undefined) {
|
||||
this.#item_stack = item_stack;
|
||||
}
|
||||
|
||||
get_item() {
|
||||
return this.#item_stack;
|
||||
}
|
||||
|
||||
get type_id() {
|
||||
return this.#item_stack?.type_id;
|
||||
}
|
||||
|
||||
get amount() {
|
||||
return this.#item_stack?.amount;
|
||||
}
|
||||
|
||||
get max_amount() {
|
||||
return this.#item_stack?.max_amount;
|
||||
}
|
||||
}
|
||||
|
||||
export class Container {
|
||||
#slots: ContainerSlot[] = [];
|
||||
readonly size: number;
|
||||
|
||||
constructor(size: number) {
|
||||
this.size = size;
|
||||
for (let i = 0; i < size; i += 1) {
|
||||
this.#slots.push(new ContainerSlot());
|
||||
}
|
||||
}
|
||||
|
||||
add_item(item_stack: ItemStack) {
|
||||
// TODO: merge stacks
|
||||
for (const slot of this.#slots) {
|
||||
if (!slot.has_item()) {
|
||||
slot.set_item(item_stack);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: drop item on ground
|
||||
console.error("Failed to place item in container");
|
||||
}
|
||||
|
||||
get_item(slot: number): ItemStack | undefined {
|
||||
return this.#slots[slot].get_item();
|
||||
}
|
||||
|
||||
get_slot(slot: number): ContainerSlot {
|
||||
return this.#slots[slot];
|
||||
}
|
||||
}
|
||||
|
||||
export interface ContainerLayout {
|
||||
slots: { type: string; x: number; y: number }[];
|
||||
offset_x: number;
|
||||
offset_y: number;
|
||||
}
|
||||
|
||||
export class Inventory extends Component {
|
||||
container: Container;
|
||||
|
||||
is_open: boolean = false;
|
||||
layout: ContainerLayout;
|
||||
|
||||
hovering_slot: number = -1;
|
||||
|
||||
constructor(container: Container, layout: ContainerLayout) {
|
||||
super();
|
||||
this.container = container;
|
||||
this.layout = layout;
|
||||
}
|
||||
}
|
||||
|
||||
export class PlayerInventory extends Inventory {
|
||||
owner_id: string;
|
||||
holding_item: ItemStack | undefined;
|
||||
|
||||
constructor(owner_id: string) {
|
||||
const container = new Container(9 * 4);
|
||||
const layout: ContainerLayout = {
|
||||
slots: [],
|
||||
offset_x: 10,
|
||||
offset_y: 10,
|
||||
};
|
||||
|
||||
for (let row = 0; row < 4; row += 1) {
|
||||
for (let column = 0; column < 9; column += 1) {
|
||||
layout.slots.push({ type: "*", x: column * SLOT_SIZE, y: row * SLOT_SIZE });
|
||||
}
|
||||
}
|
||||
super(container, layout);
|
||||
this.owner_id = owner_id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Component } from "$/common/ecs/mod.ts";
|
||||
import { KeyCode } from "$/client/input_manager.ts";
|
||||
|
||||
export class PlayerControls extends Component {
|
||||
move_speed: number = 100;
|
||||
|
||||
// Keys
|
||||
move_up: KeyCode = "KeyW";
|
||||
move_down: KeyCode = "KeyS";
|
||||
move_left: KeyCode = "KeyA";
|
||||
move_right: KeyCode = "KeyD";
|
||||
|
||||
open_inventory: KeyCode = "KeyE";
|
||||
|
||||
open_debug: KeyCode = "F3";
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
import { Component } from "$/common/ecs/mod.ts";
|
||||
import { AssetManager } from "$/client/assets.ts";
|
||||
|
||||
export class Sprite extends Component {
|
||||
image: HTMLImageElement;
|
||||
width: number;
|
||||
height: number;
|
||||
source_x: number;
|
||||
source_y: number;
|
||||
source_width: number;
|
||||
source_height: number;
|
||||
flip_x = false;
|
||||
flip_y = false;
|
||||
|
||||
constructor(
|
||||
image: HTMLImageElement | string,
|
||||
width: number,
|
||||
height: number,
|
||||
source_x = 0,
|
||||
source_y = 0,
|
||||
source_width = width,
|
||||
source_height = height,
|
||||
) {
|
||||
super();
|
||||
if (typeof image === "string") {
|
||||
this.image = AssetManager.instance.get<HTMLImageElement>(image);
|
||||
} else {
|
||||
this.image = image;
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
this.source_x = source_x;
|
||||
this.source_y = source_y;
|
||||
this.source_width = source_width;
|
||||
this.source_height = source_height;
|
||||
}
|
||||
}
|
||||
|
||||
interface AnimatedSpritePiece {
|
||||
source_x: number[];
|
||||
source_y: number[];
|
||||
source_width: number;
|
||||
source_height: number;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export class AnimatedSprite extends Component {
|
||||
image: HTMLImageElement;
|
||||
width: number;
|
||||
height: number;
|
||||
flip_x = false;
|
||||
flip_y = false;
|
||||
|
||||
current_state: string;
|
||||
states: Record<string, AnimatedSpritePiece>;
|
||||
timer = 0;
|
||||
animation_frame = 0;
|
||||
|
||||
constructor(
|
||||
image: HTMLImageElement | string,
|
||||
width: number,
|
||||
height: number,
|
||||
states: Record<string, AnimatedSpritePiece>,
|
||||
initial_state: string,
|
||||
) {
|
||||
super();
|
||||
if (typeof image === "string") {
|
||||
this.image = AssetManager.instance.get<HTMLImageElement>(image);
|
||||
} else {
|
||||
this.image = image;
|
||||
}
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
|
||||
this.states = states;
|
||||
this.current_state = initial_state;
|
||||
}
|
||||
|
||||
set_state(state: string) {
|
||||
if (this.current_state !== state) {
|
||||
this.current_state = state;
|
||||
this.timer = 0;
|
||||
this.animation_frame = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { Component } from "$/common/ecs/mod.ts";
|
||||
|
||||
interface Tile {
|
||||
x: number;
|
||||
y: number;
|
||||
index: number;
|
||||
}
|
||||
|
||||
export class Tilemap extends Component {
|
||||
image: HTMLImageElement;
|
||||
tile_size: number;
|
||||
rows: number;
|
||||
columns: number;
|
||||
tiles: Tile[];
|
||||
scale: number;
|
||||
margin: number;
|
||||
|
||||
selected_tile = 0;
|
||||
editing = false;
|
||||
|
||||
constructor(
|
||||
image: HTMLImageElement,
|
||||
tile_size: number,
|
||||
tiles: Tile[],
|
||||
scale: number = 1,
|
||||
margin: number = 0,
|
||||
) {
|
||||
super();
|
||||
this.image = image;
|
||||
this.tile_size = tile_size;
|
||||
this.columns = Math.floor((image.width + margin) / (tile_size + margin));
|
||||
this.rows = Math.floor((image.height + margin) / (tile_size + margin));
|
||||
this.tiles = tiles;
|
||||
this.scale = scale;
|
||||
this.margin = margin;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user