"use strict"; class Bicycle { constructor(inPos, inSpeed) { this.pos = inPos; this.speed = inSpeed; this.wheelLeft = new Wheel(new Vector(-47, 20), 30, 200); this.wheelRight = new Wheel(new Vector(47, 20), 30, 200); this.mainColour = "#4f32d2"; this.seatColour = "#312b50"; this.pedalReflectorColour = "rgb(214, 104, 14)" this.seatSize = 10; this.gearWheelSize = 7; this.pedalRadius = 13; this.pedalSize = 4; this.pedalSpeed = this.speed * 0.02; this.pedalRotation = 0; } update(dt) { this.wheelLeft.update(dt); this.wheelRight.update(dt); this.pedalRotation += this.pedalSpeed * dt; } render(context) { context.save(); context.translate(this.pos.x, this.pos.y); var pedalPosition = this.wheelRight.pos.clone().subtract(new Vector(35, 0)), seatPosition = pedalPosition.clone().add(new Vector(15, -40)); this.renderPedalsBack(context, pedalPosition) this.wheelLeft.render(context); this.wheelRight.render(context); // Bicycle frame context.beginPath(); context.moveTo(this.wheelLeft.pos.x, this.wheelLeft.pos.y); context.lineTo(this.wheelLeft.pos.x + 20, this.wheelLeft.pos.y - 52); context.moveTo(this.wheelLeft.pos.x + 13, this.wheelLeft.pos.y - 35); context.lineTo(pedalPosition.x, pedalPosition.y); context.lineTo(seatPosition.x, seatPosition.y); context.moveTo(pedalPosition.x, pedalPosition.y); context.lineTo(this.wheelRight.pos.x, this.wheelRight.pos.y); context.lineTo(seatPosition.x - 4, seatPosition.y + 10); context.lineTo(this.wheelLeft.pos.x + 14, this.wheelLeft.pos.y - 40); context.lineWidth = 5; context.strokeStyle = this.mainColour; context.stroke(); context.beginPath(); context.moveTo(this.wheelLeft.pos.x + 20 + 14, this.wheelLeft.pos.y - 52 - 6); context.lineTo(this.wheelLeft.pos.x + 20 - 18, this.wheelLeft.pos.y - 52 + 11); context.lineWidth = 3; context.strokeStyle = this.mainColour; context.stroke(); this.renderPedalsFront(context, pedalPosition); this.renderSeat(context, seatPosition); context.restore(); } renderSeat(context, pos) { context.save(); context.translate(pos.x - this.seatSize * 0.3, pos.y); context.beginPath(); context.moveTo(this.seatSize, -this.seatSize / 2.4); context.lineTo(-this.seatSize * 1.5, 0); context.lineTo(this.seatSize * 1.3, this.seatSize / 2.3); context.closePath(); context.fillStyle = this.seatColour; context.fill(); context.restore(); } renderPedalsFront(context, pos) { context.save(); context.translate(pos.x, pos.y); // Pedal attachment circle context.beginPath(); context.ellipse(0, 0, this.gearWheelSize * 0.3, this.gearWheelSize * 0.3, 0, 0, Math.PI * 2, false); context.lineWidth = 2; context.strokeStyle = this.wheelLeft.spokeColour; context.stroke(); context.strokeStyle = "rgba(0, 0, 0, 0.8)"; context.stroke(); // Front pedal var pedalOuterPosition = new Vector(this.pedalRadius * Math.sin(this.pedalRotation), this.pedalRadius * Math.cos(this.pedalRotation)); context.beginPath(); context.moveTo(0, 0); context.lineTo(pedalOuterPosition.x, pedalOuterPosition.y); context.strokeStyle = this.wheelLeft.spokeColour; context.stroke(); context.strokeStyle = "rgba(0, 0, 0, 0.4)"; context.stroke(); this.renderPedal(context, pedalOuterPosition); context.restore(); } renderPedalsBack(context, pos) { context.save(); context.translate(pos.x, pos.y); // Outer gear wheel context.beginPath(); context.ellipse(0, 0, this.gearWheelSize, this.gearWheelSize, 0, 0, Math.PI * 2, false); context.lineWidth = 3; context.strokeStyle = this.wheelLeft.spokeColour; context.stroke(); // Inner gear wheel context.beginPath(); context.ellipse(0, 0, this.gearWheelSize * 0.8, this.gearWheelSize * 0.8, 0, 0, Math.PI * 2, false); context.lineWidth = 2; context.strokeStyle = this.wheelLeft.spokeColour; context.stroke(); context.strokeStyle = "rgba(0, 0, 0, 0.4)"; context.stroke(); // Back pedal var pedalOuterPosition = new Vector(this.pedalRadius * Math.sin(this.pedalRotation + Math.PI), this.pedalRadius * Math.cos(this.pedalRotation + Math.PI)); context.beginPath(); context.moveTo(0, 0); context.lineTo(pedalOuterPosition.x, pedalOuterPosition.y); context.strokeStyle = this.wheelLeft.spokeColour; context.stroke(); context.strokeStyle = "rgba(0, 0, 0, 0.4)"; context.stroke(); this.renderPedal(context, pedalOuterPosition); context.restore(); } renderPedal(context, pos) { context.save(); context.translate(pos.x, pos.y); context.beginPath(); context.moveTo(-this.pedalSize, 0); context.lineTo(this.pedalSize, 0); context.lineWidth = 3; context.strokeStyle = this.mainColour; context.stroke(); context.strokeStyle = "rgba(70, 70, 70, 0.4)"; context.stroke(); context.beginPath(); context.moveTo(-this.pedalSize * 0.5, 0); context.lineTo(this.pedalSize * 0.5, 0); context.lineWidth = 2; context.strokeStyle = this.pedalReflectorColour; context.stroke(); context.restore(); } } class Wheel { constructor(inPos, inRadius, inSpeed) { this.pos = inPos; this.radius = inRadius; this.speed = inSpeed / (Math.PI * 18); this.rotation = 0; this.rimColour = "#1f1e1e"; this.spokeColour = "rgb(198, 176, 172)"; this.spokeCount = 12; this.spokeSpacing = (Math.PI*2) / this.spokeCount; } update(dt) { this.rotation -= this.speed * dt; } render(context) { context.save(); context.translate(this.pos.x, this.pos.y); context.rotate(this.rotation); context.beginPath(); for (let r = 0; r < Math.PI; r += this.spokeSpacing) { context.moveTo(this.radius * Math.cos(r), this.radius * Math.sin(r)); context.lineTo(this.radius * Math.cos(r + Math.PI), this.radius * Math.sin(r + Math.PI)); } context.lineWidth = 1; context.strokeStyle = this.spokeColour; context.stroke(); context.beginPath(); context.ellipse(0, 0, this.radius * 0.95, this.radius * 0.95, 0, 0, Math.PI * 2, false); context.lineWidth = 3; context.stroke(); context.beginPath(); context.ellipse(0, 0, this.radius, this.radius, 0, 0, Math.PI * 2, false); context.strokeStyle = this.rimColour; context.lineWidth = 4; context.stroke(); context.restore(); } }