Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,8 +342,7 @@ Like `MX` and `MY`, Litecanvas also declares these other variables:
- `H`: the height of the game canvas
- `T`: the amount of seconds since the game started
- `PI`: approximately 3.14 radians (or 180 degrees)
- `TWO_PI`: approximately 6.28 radians (or 360 degrees)
- `HALF_PI`: approximately 1.57 radians (or 90 degrees)
- `TAU`: approximately 6.28 radians (or 360 degrees)

### And much more!

Expand Down
2 changes: 1 addition & 1 deletion bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "litecanvas",
"version": "0.209.0",
"version": "0.300.0",
"description": "Lightweight HTML5 canvas 2D game engine suitable for small projects and creative coding. Inspired by PICO-8 and p5.js/Processing.",
"license": "MIT",
"author": "Luiz Bills <luizbills@pm.me>",
Expand Down
2 changes: 1 addition & 1 deletion samples/bench/bench.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ litecanvas({
width: state.width,
height: state.height,
canvas: '#c',
autoscale: false,
// autoscale: false,
})

use(pluginFrameRateMeter)
Expand Down
2 changes: 1 addition & 1 deletion samples/clip/clip.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function draw() {
}

function clipcirc(x, y, radius) {
clip((_ctx) => _ctx.arc(x, y, radius, 0, TWO_PI))
clip((_ctx) => _ctx.arc(x, y, radius, 0, TAU))
}

function cliprect(x, y, width, height) {
Expand Down
6 changes: 3 additions & 3 deletions samples/clock/clock.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ function draw() {
const minutes = date.getMinutes()
const hour = date.getHours()

const s = map(seconds, 0, 60, 0, TWO_PI) - HALF_PI
const m = map(minutes + norm(seconds, 0, 60), 0, 60, 0, TWO_PI) - HALF_PI
const h = map(hour + norm(minutes, 0, 60), 0, 24, 0, TWO_PI * 2) - HALF_PI
const s = map(seconds, 0, 60, 0, TAU) - PI / 2
const m = map(minutes + norm(seconds, 0, 60), 0, 60, 0, TAU) - PI / 2
const h = map(hour + norm(minutes, 0, 60), 0, 24, 0, TAU * 2) - PI / 2

// Draw the hands of the clock
linewidth(1)
Expand Down
37 changes: 19 additions & 18 deletions samples/raycast/raycast.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ litecanvas()
// const 3 = 3
// const 2 = 2

const ONE_AND_HALF_PI = (3 * Math.PI) / 2
const ONE_AND_HALF_PI = (3 * PI) / 2
const HALF_PI = PI / 2

const MIDPOINT = 600

Expand Down Expand Up @@ -46,21 +47,21 @@ const player = {
},

init: function () {
this.heading = Math.PI / 2 // player angle
this.heading = HALF_PI
this.position = { x: 100, y: 100 }
this.velocity = { x: 0, y: 0 }
},
}

function rayLength(ax, ay, bx, by) {
return Math.sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay))
return sqrt((bx - ax) * (bx - ax) + (by - ay) * (by - ay))
}

function rayNormalize(angle) {
let normalizedAngle = angle % TWO_PI
let normalizedAngle = angle % TAU

if (normalizedAngle < 0) {
normalizedAngle += TWO_PI
normalizedAngle += TAU
}

return normalizedAngle
Expand Down Expand Up @@ -111,30 +112,30 @@ function draw() {
hx = player.position.x,
hy = player.position.y

let rayAngle = player.heading - (Math.PI / 180) * 30
let rayAngle = player.heading - (PI / 180) * 30

for (let r = 0; r < 60; r++) {
// check horizontal lines

let depthOfFieldX = 0
const atan = -1 / Math.tan(rayAngle)
const atan = -1 / tan(rayAngle)

// looking down
if (rayAngle > Math.PI) {
if (rayAngle > PI) {
rayY = ((player.position.y >> 6) << 6) - 0.0001
rayX = (player.position.y - rayY) * atan + player.position.x
offsetY = -64
offsetX = -offsetY * atan
}
// looking up
if (rayAngle < Math.PI) {
if (rayAngle < PI) {
rayY = ((player.position.y >> 6) << 6) + 64
rayX = (player.position.y - rayY) * atan + player.position.x
offsetY = +64
offsetX = -offsetY * atan
}
// looking sideways
if (rayAngle === 0 || rayAngle === Math.PI) {
if (rayAngle === 0 || rayAngle === PI) {
rayX = player.position.x
rayY = player.position.y
depthOfFieldX = 8
Expand Down Expand Up @@ -165,7 +166,7 @@ function draw() {
vx = player.position.x,
vy = player.position.y
let depthOfFieldV = 0
const ntan = -Math.tan(rayAngle)
const ntan = -tan(rayAngle)

// looking left
if (rayAngle > HALF_PI && rayAngle < ONE_AND_HALF_PI) {
Expand All @@ -182,7 +183,7 @@ function draw() {
offsetY = -offsetX * ntan
}
// looking up or down
if (rayAngle === 0 || rayAngle === Math.PI) {
if (rayAngle === 0 || rayAngle === PI) {
rayX = player.position.x
rayY = player.position.y
depthOfFieldV = 8
Expand Down Expand Up @@ -230,7 +231,7 @@ function draw() {
// ray wall

const fishAngle = rayNormalize(player.heading - rayAngle)
const dist = Math.min(distH, distV) * Math.cos(fishAngle)
const dist = min(distH, distV) * cos(fishAngle)

let lineHeight = (map.size * 512) / dist
if (lineHeight > 512) {
Expand All @@ -245,7 +246,7 @@ function draw() {
linewidth(8)
line(MIDPOINT + r * 8, 0, MIDPOINT + r * 8, lineHeight + lineOffset, wallColor)

rayAngle = rayNormalize(rayAngle + Math.PI / 180)
rayAngle = rayNormalize(rayAngle + PI / 180)
alpha(1)
}
}
Expand All @@ -259,12 +260,12 @@ function draw() {
{
if (iskeydown('a') || iskeydown('ArrowLeft')) {
player.heading -= 0.05
player.velocity.x = Math.cos(player.heading) * 5
player.velocity.y = Math.sin(player.heading) * 5
player.velocity.x = cos(player.heading) * 5
player.velocity.y = sin(player.heading) * 5
} else if (iskeydown('d') || iskeydown('ArrowRight')) {
player.heading += 0.05
player.velocity.x = Math.cos(player.heading) * 5
player.velocity.y = Math.sin(player.heading) * 5
player.velocity.x = cos(player.heading) * 5
player.velocity.y = sin(player.heading) * 5
}

if (iskeydown('w') || iskeydown('ArrowUp')) {
Expand Down
4 changes: 2 additions & 2 deletions samples/starfield/starfield.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function update() {

if (stars.length < numberOfStars) {
for (let i = 0; i < numberOfStars - stars.length; i += 1) {
let angle = rand() * TWO_PI
let angle = rand() * TAU
let radius = Math.sqrt(rand()) * (W / 2)

let x = radius * Math.cos(angle)
Expand All @@ -47,7 +47,7 @@ function update() {
stars[i][3] = size

if (z < 1) {
let angle = rand() * TWO_PI
let angle = rand() * TAU
let radius = Math.sqrt(rand()) * (W / 2)
stars[i][0] = radius * Math.cos(angle)
stars[i][1] = radius * Math.sin(angle)
Expand Down
56 changes: 25 additions & 31 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export default function litecanvas(settings = {}) {
const root = window,
math = Math,
perf = performance,
TWO_PI = math.PI * 2,
TAU = math.PI * 2,
raf = requestAnimationFrame,
isNumber = Number.isFinite,
/** @type {Function[]} */
Expand Down Expand Up @@ -117,20 +117,9 @@ export default function litecanvas(settings = {}) {
* Twice the value of the mathematical constant PI (π).
* Approximately 6.28318
*
* Note: TWO_PI radians equals 360°, PI radians equals 180°,
* HALF_PI radians equals 90°, and HALF_PI/2 radians equals 45°.
*
* @type {number}
*/
TWO_PI,

/**
* Half the value of the mathematical constant PI (π).
* Approximately 1.57079
*
* @type {number}
*/
HALF_PI: TWO_PI / 4,
TAU,

/**
* Calculates a linear (interpolation) value over t%.
Expand Down Expand Up @@ -181,9 +170,6 @@ export default function litecanvas(settings = {}) {
* @param {number} a dividend
* @param {number} b divisor
* @returns {number} the remainder
* @example
* mod(-1, 5) // => 4
* -1 % 5 // => -1
*/
mod(a, b) {
DEV: assert(isNumber(a), 'mod() 1st parameter must be a number')
Expand Down Expand Up @@ -499,7 +485,7 @@ export default function litecanvas(settings = {}) {

beginPath(_ctx)

_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU)
instance.stroke(color)
},

Expand Down Expand Up @@ -530,7 +516,7 @@ export default function litecanvas(settings = {}) {

beginPath(_ctx)

_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TWO_PI)
_ctx.ellipse(~~x, ~~y, ~~radiusX, ~~radiusY, 0, 0, TAU)
instance.fill(color)
},

Expand Down Expand Up @@ -1336,6 +1322,15 @@ export default function litecanvas(settings = {}) {
return internals[index]
},

/**
* Returns `true` if the engine loop is paused.
*
* @returns {boolean}
*/
ispaused() {
return _paused
},

/**
* Pauses the engine loop (update & draw).
*/
Expand Down Expand Up @@ -1363,15 +1358,6 @@ export default function litecanvas(settings = {}) {
}
},

/**
* Returns `true` if the engine loop is paused.
*
* @returns {boolean}
*/
ispaused() {
return _paused
},

/**
* Shutdown the litecanvas instance and remove all event listeners.
*/
Expand Down Expand Up @@ -1421,6 +1407,8 @@ export default function litecanvas(settings = {}) {
}

function init() {
resizeCanvas()

// listen window resize event when "autoscale" is enabled
if (settings.autoscale) {
on(root, 'resize', resizeCanvas)
Expand Down Expand Up @@ -1748,16 +1736,14 @@ export default function litecanvas(settings = {}) {

on(_canvas, 'click', () => focus())

resizeCanvas()

if (!_canvas.parentNode) {
d.body.appendChild(_canvas)
}

_canvas.style.imageRendering = 'pixelated'

// disable default browser's right click in canvas
_canvas.oncontextmenu = () => false

resizeCanvas()
}

function resizeCanvas() {
Expand All @@ -1774,6 +1760,11 @@ export default function litecanvas(settings = {}) {

'litecanvas() option "width" is required when the option "height" is defined'
)
DEV: assert(
'boolean' === typeof settings.autoscale ||
(isNumber(settings.autoscale) && settings.autoscale > 1),
'litecanvas() option "autoscale" must be boolean or a number > 1'
)

const width = settings.width > 0 ? settings.width : innerWidth,
height = settings.width > 0 ? settings.height || settings.width : innerHeight
Expand All @@ -1784,6 +1775,9 @@ export default function litecanvas(settings = {}) {
_canvas.width = width
_canvas.height = height

/** @ts-ignore */
_canvas.style = 'image-rendering:pixelated'

if (settings.autoscale) {
let maxScale = +settings.autoscale
if (!_canvas.style.display) {
Expand Down
2 changes: 1 addition & 1 deletion src/version.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 12 additions & 8 deletions tests/math.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@ test('PI', async (t) => {
t.is(local.PI, Math.PI)
})

test('TWO_PI', async (t) => {
t.is(local.TWO_PI, Math.PI * 2)
})

test('HALF_PI', async (t) => {
t.is(local.HALF_PI, Math.PI / 2)
test('TAU', async (t) => {
t.is(local.TAU, Math.PI * 2)
})

test('lerp', async (t) => {
Expand All @@ -40,12 +36,12 @@ test('lerp', async (t) => {

test('deg2rad', async (t) => {
t.is(local.deg2rad(180), local.PI)
t.is(local.deg2rad(360), local.TWO_PI)
t.is(local.deg2rad(360), local.TAU)
})

test('rad2deg', async (t) => {
t.is(local.rad2deg(local.PI), 180)
t.is(local.rad2deg(local.HALF_PI), 90)
t.is(local.rad2deg(local.TAU), 360)
})

test('clamp', async (t) => {
Expand Down Expand Up @@ -99,3 +95,11 @@ test('dist', async (t) => {
const actual = local.dist(0, 0, 0, 100)
t.is(actual, expected)
})

test('mod', async (t) => {
{
const expected = 4
const actual = local.mod(-1, 5)
t.is(actual, expected)
}
})
Loading
Loading