gamepadzilla
Version:
A plug-and-play gamepad frontend framework for HTML5 mobile games, supporting both virtual and physical joysticks. No scripting required.
96 lines (90 loc) • 4.59 kB
text/typescript
import { ObjectGpz, Vector2d } from "./interface";
import { nestFinger, desnormalize, tokens } from "./util";
import { angleInRadians, polyTransform } from "./math"
import geometry from "../geometry.json"
export function drawCircle(ctx: CanvasRenderingContext2D, fill: string, r: number, pos: Vector2d) {
ctx.beginPath()
ctx.arc(pos.x, pos.y, r, 0, 2 * Math.PI)
ctx.fillStyle = fill
ctx.fill()
ctx.fillStyle = 'black';
ctx.stroke();
ctx.closePath();
ctx.fillStyle = fill
}
const draw = {
Btn4(self: ObjectGpz) {
const centerX: number = self.canvas.width/2;
const centerY: number = self.canvas.height/2;
const radius: number = 20
const colors = [
self.stateNew[0]? 'yellow': '#88888880',
self.stateNew[1]? 'blue': '#88888880',
self.stateNew[2]? 'red': '#88888880',
self.stateNew[3]? 'green': '#88888880',
]
self.ctx2d.clearRect(0, 0, self.canvas.width, self.canvas.height)
drawCircle(self.ctx2d, colors[0], radius, {x: centerX, y: centerY/2})
drawCircle(self.ctx2d, colors[1], radius, {x: centerX/2, y: centerY})
drawCircle(self.ctx2d, colors[2], radius, {x: centerX, y: centerY + (centerY/2)})
drawCircle(self.ctx2d, colors[3], radius, {x: centerX + (centerX/2), y: centerY})
},
Btn(self: ObjectGpz) {
const centerX: number = self.canvas.width / 2;
const centerY: number = self.canvas.height / 2;
const radius: number = 25;
const color1: string = self.canvas.dataset.gpzColor ?? '#88888880'
const color2: string = self.canvas.dataset.gpzColorAction ?? 'red'
const color: string = self.stateNew[0]? color2: color1
self.ctx2d.clearRect(0, 0, self.canvas.width, self.canvas.height)
drawCircle(self.ctx2d, color, radius, {x: centerX, y: centerY})
},
Joy(self: ObjectGpz) {
const radius: number = 50
const radius2: number = radius/3
const percentage: number = 1.5
const center: Vector2d = {x: self.canvas.width / 2, y: self.canvas.height / 2}
const fakeFinger : Vector2d = {
x: desnormalize(self.axis2d!.x) * self.canvas.width,
y: desnormalize(self.axis2d!.y) * self.canvas.height,
}
const stick = nestFinger(center, [fakeFinger])
if ((stick.dis / percentage) > (radius - radius2)) {
const angle = Math.atan2(stick.pos.y - center.y, stick.pos.x - center.x)
stick.pos.x = center.x + (radius - radius2) * percentage * Math.cos(angle)
stick.pos.y = center.y + (radius - radius2) * percentage * Math.sin(angle)
}
self.ctx2d.clearRect(0, 0, self.canvas.width, self.canvas.height)
drawCircle(self.ctx2d, '#aaaaaa80', radius, {x: center.x, y: center.y})
drawCircle(self.ctx2d, '#88888880', radius2, {x: stick.pos.x, y: stick.pos.y})
},
Dpad(self: ObjectGpz) {
const offset = Number(self.canvas.dataset.gpzOffset ?? 6)
const sizeArr = tokens(self.canvas.dataset.gpzSize, '16', 2).map(n => Number(n))
const size2D = {x: sizeArr[0], y: sizeArr[1]}
const center: Vector2d = {x: self.canvas.width / 2, y: self.canvas.height / 2}
const color1: Array<string> = tokens(self.canvas.dataset.gpzColor, '#aaaaaa80', 4)
const color2: Array<string> = tokens(self.canvas.dataset.gpzColorAction, '#44444480', 4)
const colors: Array<string> = self.stateNew.map((state, index) => state? color2[index]: color1[index])
const pads: Array<Array<Vector2d>> = [
polyTransform(geometry['dpad'], {x: center.x, y: center.y - offset}, size2D, angleInRadians(0)),
polyTransform(geometry['dpad'], {x: center.x - offset, y: center.y}, size2D, angleInRadians(270)),
polyTransform(geometry['dpad'], {x: center.x, y: center.y + offset}, size2D, angleInRadians(180)),
polyTransform(geometry['dpad'], {x: center.x + offset, y: center.y}, size2D, angleInRadians(90))
]
self.ctx2d.clearRect(0, 0, self.canvas.width, self.canvas.height)
pads.forEach((pad, index) => {
self.ctx2d.beginPath();
self.ctx2d.moveTo(pad[0].x, pad[0].y)
pad.forEach(poly => {
self.ctx2d.lineTo(poly.x, poly.y)
})
self.ctx2d.fillStyle = colors[index]
self.ctx2d.fill()
self.ctx2d.fillStyle = 'black'
self.ctx2d.stroke()
self.ctx2d.closePath()
})
}
}
export { draw }