1
0
Fork 0
Nibriboard/Nibriboard/ClientFiles/Chunk.js

150 lines
4.2 KiB
JavaScript

"use strict";
import { point_line_distance_multi } from 'line-distance-calculator';
/**
* Represents a single chunk on a plane.
* Note that this is the client's representation of the chunk, so it's likely
* to be a little different to the server's representation.
*/
class Chunk
{
/**
* Creates a new chunk.
* @param {ChunkReference} inChunkRef The location of the new chunk.
* @param {number} inSize The size of this chunk.
*/
constructor(inChunkRef, inSize)
{
/** @type {ChunkReference} */
this.chunkRef = inChunkRef;
/** @type {number} */
this.size = inSize;
/** @type {[ { Points: [Vector], Width: number, Color: string }] */
this.lines = [];
}
/**
* Fetches a line in this chunk by it's unique id.
* @param {string} uniqueLineId The target unique id to search for.
* @return {object|null} The requested line, or null if it wasn't found.
*/
getLineByUniqueId(uniqueLineId)
{
for (let line of this.lines) {
if(line.UniqueId == uniqueLineId)
return line;
}
return null;
}
/**
* Whether this chunk is located at the specified chunk reference.
* @param {ChunkReference} otherChunkRef The chunk reference to check
* ourselves against.
* @return {bool} Whether this chunk is located at the
* specified chunk reference.
*/
isAt(otherChunkRef)
{
if(this.chunkRef.toString() == otherChunkPos.toString())
return true;
return false;
}
/**
* Whether this chunk falls inside the specified rectangle.
* @param {Rectangle} area The rectangle to test against, in location-space
* @return {Boolean} Whether this chunk falls inside the specified rectangle.
*/
isVisible(area)
{
let chunkArea = new Rectangle(
this.chunkRef.x * this.size,
this.chunkRef.y * this.size,
this.size, this.size
);
return area.overlaps(area);
}
/**
* Fetches the last line segment that lies underneath the specified point.
* Prefers lines drawn later to lines drawn earlier.
* @param {Vector} point The point to find the line underneath.
* @return {object|null} The first line (segment) that lies underneath the specified point, or null if one couldn't be found.
*/
getLineUnderPoint(point)
{
// Prefer lines that have been drawn later (i.e. on top)
for (let i = this.lines.length - 1; i > 0; i--) {
// If our distance to the line is less than half the width (i.e.
// the radius), then we must be inside it
if(point_line_distance_multi(point, this.lines[i].Points) <= this.lines[i].Width / 2)
return this.lines[i];
}
}
update(dt)
{
}
/**
* Renders this chunk to the given canvas with the given context.
* @param {HTMLCanvasElement} canvas The canvas to render to.
* @param {CanvasRenderingContext2D} context The context to render with.
* @param {ChunkCache} chunkCache The chunk cache to use to fetch data from surrounding chunks.
* @param {Rectangle} chunkArea The area in which chunks are being rendered.
*/
render(canvas, context, chunkCache, chunkArea)
{
var planeSpaceRef = this.chunkRef.inPlaneSpace(this.size);
context.save();
context.translate(planeSpaceRef.x, planeSpaceRef.y);
for(let line of this.lines)
{
// Don't draw lines that are walked by other chunks
if(line.ContinuesFrom != null &&
!(chunkCache.fetchChunk(line.ContinuesFrom) instanceof Chunk))
continue;
let linePoints = line.Points;
// Fetch all the points on fragments of this line forwards from here
if(line.ContinuesIn != null) {
let nextLines = chunkCache.fetchLineFragments(line.ContainingChunk, line.UniqueId);
linePoints = [];
for (let nextLine of nextLines) {
linePoints = linePoints.concat(nextLine.Points);
}
}
context.beginPath();
context.moveTo(
linePoints[0].x - planeSpaceRef.x,
linePoints[0].y - planeSpaceRef.y
);
for(let i = 1; i < linePoints.length; i++)
{
context.lineTo(
linePoints[i].x - planeSpaceRef.x,
linePoints[i].y - planeSpaceRef.y
);
}
context.lineCap = "round";
context.lineJoin = "round";
context.lineWidth = line.Width;
context.strokeStyle = line.Colour;
context.stroke();
}
context.restore();
}
}
export default Chunk;