UNPKG

p5.raycaster

Version:

a simple p5js library for semi 3d rendering with ray casting

224 lines (207 loc) 7.38 kB
class Sprite { /** * init a sprite * @param {p5.Image} source source image for the sprite, single image is load and use for animation and rotation (if any), see readme for more info * @param {Vector} pos {x, y} or a p5.Vector object * @param {number} width * @param {number} height * @param {number} [angle = 0] * @param {number} [yAdjustment=0] [-0.5, 0.5] -0.5 ~ 0.5, negative number will make the sprite appear lower and positive number will make it appear higher * @param {number} [animationGap=0] number of frame for before change to the next animation * @param {p5} [p5Inst = null] reference to the p5 instance if in instance mode, if not specified try to call functions blind to windows */ constructor(source, pos, width, height, angle = 0, yAdjustment = 0, animationGap = 0, p5Inst = null) { this.pos = { x: pos.x, y: pos.y }; this.ang = angle; this.src = source; this.width = width; this.height = height; this.pInst = p5Inst; this.yAdjustment = yAdjustment; this.animationGap = animationGap; this.scaleP = {x: 1, y: 1}; // this.buffer = null; if (this.pInst !== null) { this.buffer = this.pInst.createGraphics(this.width, this.height); } else { if (window.createGraphics) { this.buffer = window.createGraphics(this.width, this.height); } else { throw new Error("p5 is not found!") } } // this.animationFrames = Math.floor(this.src.height / this.height); this.animationGroups = []; let t = []; for (let i = 0; i < this.animationFrames; i++) { t.push(i); } this.animationGroups.push(t); this.rotationFrames = Math.floor(this.src.width / this.width); this.currentRotation = 0; this.currentAnimation = 0; this.currentAnimationGroup = 0; this.currentAnimationIdx = 0; if (this.rotationFrames > 1) { this.rotationDivision = (Math.PI * 2) / this.rotationFrames; this.updateRotationFrame(Math.PI); } this.drawBuffer(); } /** * * @param {number} gap number of frame (main canvas) for before change to the other animation */ setAnimationGap(gap) { this.animationGap = gap; } /** * advance animation control * @param {Array} grouping arrays of animation frames in group, e.g. [[0,1,2,3],[4,5,6]] */ setAnimationGroups(grouping) { this.animationGroups = grouping; } /** * * @param {number} group */ setCurrentAnimationGroup(group) { if (this.animationGroups && group > -1 && group < this.animationGroups.length) { this.currentAnimationGroup = group; this.currentAnimationIdx = 0; this.currentAnimation = this.animationGroups[this.currentAnimationGroup][this.currentAnimationIdx]; } } /** * * @param {number} ratio -0.5 ~ 0.5, negative number will make the sprite appear lower and positive number will make it appear higher */ setYAdjustment(ratio) { this.yAdjustment = ratio; } /** * update the animation, should have animation rate set * * @param {number} frameCount current frame count from main canvas */ update(frameCount) { if (this.animationGap <= 0 || this.animationFrames === 1) return; if (frameCount % this.animationGap === 0) this.nextAnimationFrame(); } nextAnimationFrame() { this.currentAnimationIdx++; this.currentAnimationIdx = this.currentAnimationIdx % this.animationGroups[this.currentAnimationGroup].length; this.currentAnimation = this.animationGroups[this.currentAnimationGroup][this.currentAnimationIdx]; this.drawBuffer(); } /** * update the new frame for the animation * @param {number} newFrame */ updateAnimationFrame(newFrame) { if (this.currentAnimation !== newFrame) { this.currentAnimation = newFrame; let g, i; this.animationGroups.forEach((group, id) => { let ii = group.indexOf(this.currentAnimation); if (ii > -1) { g = id; i = ii; } }); this.currentAnimationGroup = g; this.currentAnimationIdx = i; this.drawBuffer(); } } /** * * @param {number} angle */ updateRotationFrame(angle) { let deltaAng, newRotation; if (this.rotationFrames === 1) { newRotation = 0; } else { deltaAng = angle - this.ang + this.rotationDivision / 2; while (deltaAng < 0) { deltaAng += Math.PI * 2; } while (deltaAng > Math.PI * 2) { deltaAng -= Math.PI * 2; } newRotation = Math.floor((deltaAng) / this.rotationDivision); } if (this.currentRotation !== newRotation) { this.currentRotation = newRotation; this.drawBuffer(); } } /** * * @param {Vector} movement {x, y} or a p5.Vector */ move(movement) { if (!this.world) return; let idx1 = Math.floor(this.pos.x + movement.x) + Math.floor(this.pos.y) * this.world.width; let idx2 = Math.floor(this.pos.x) + Math.floor(this.pos.y + movement.y) * this.world.width; if (this.world.map[idx1] === this.world.table.MAP_FLOOR || this.world.doorStates[idx1] === this.world.table.DOOR_OPEN) { if (Math.floor(this.pos.x + movement.x) > -1 && Math.floor(this.pos.x + movement.x) < this.world.width) this.pos.x += movement.x; // can't go out sdie the world } if (this.world.map[idx2] === this.world.table.MAP_FLOOR || this.world.doorStates[idx2] === this.world.table.DOOR_OPEN) { if (Math.floor(this.pos.y + movement.y) > -1 && Math.floor(this.pos.y + movement.y) < this.world.height) this.pos.x += movement.y; } } /** * * @param {number} angle */ rotate(angle) { this.ang += angle; } /** * * @param {number} angle */ rotateTo(angle){ this.ang = angle } /** * * @param {number} xRatio * @param {number} yRatio */ scale(xRatio, yRatio){ if (arguments.length === 1) yRatio = xRatio this.scaleP.x *= xRatio; this.scaleP.y *= yRatio; } /** * scale to the ratio relative to the origin size * @param {number} xRatio * @param {number} yRatio */ scaleTo(xRatio, yRatio){ if (arguments.length === 1) yRatio = xRatio this.scaleP.x = xRatio; this.scaleP.y = yRatio; } /** * update image buffer of the sprite */ drawBuffer() { this.buffer.clear(); this.buffer.image(this.src, 0, 0, this.width, this.height, this.currentRotation * this.width, this.currentAnimation * this.height, this.width, this.height); } /** * destroy the sprite to free resources */ destroy() { this.drawBuffer.remove(); delete this; } } export default Sprite;