Created
November 3, 2024 20:53
-
-
Save naosim/3b294dcd490bbd633c442ef6357e4202 to your computer and use it in GitHub Desktop.
【microStudio】スマホ用スクリーンゲームパッド
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ScreenGamePad { | |
UP = false; | |
DOWN = false; | |
RIGHT = false; | |
LEFT = false; | |
A = false; | |
B = false; | |
press = { | |
UP: false, | |
DOWN: false, | |
RIGHT: false, | |
LEFT: false, | |
A: false, | |
B: false, | |
}; | |
release = { | |
UP: false, | |
DOWN: false, | |
RIGHT: false, | |
LEFT: false, | |
A: false, | |
B: false, | |
}; | |
arrowKey; | |
buttons = []; | |
init() { | |
const marginBottom = 6; | |
const marginLeft = 6; | |
const width = 42; | |
const height = 30; | |
// 十字キーの中心位置 | |
const arrowCenter = { | |
x: -screen.width/2 + ArrowKey.maxRadius + marginLeft, | |
y: -screen.height/2 + ArrowKey.maxRadius + marginBottom, | |
}; | |
// 十字キー生成 | |
const arrowKey = this.arrowKey = new ArrowKey({arrowCenter}).init(); | |
// ABボタン生成 | |
const A = {x:screen.width/2-marginLeft-width/2, y:arrowCenter.y}; | |
const B = {x:A.x - width, y:A.y} | |
Object.entries({A, B}).forEach(([key, value]) => { | |
const button = new Button({name:key, label:key, pos:value, width, height}).init(); | |
this.buttons.push(button); | |
}); | |
return this; | |
} | |
update() { | |
this.arrowKey.update(); | |
["UP", "DOWN", "RIGHT", "LEFT"].forEach(key => { | |
this[key] = this.arrowKey[key]; | |
this.press[key] = this.arrowKey.press[key]; | |
this.release[key] = this.arrowKey.release[key]; | |
}) | |
this.buttons.forEach(b => { | |
b.update(); | |
this[b.name] = b.touching; | |
this.press[b.name] = b.press; | |
this.release[b.name] = b.release; | |
}) | |
} | |
draw() { | |
this.arrowKey.draw(); | |
this.buttons.forEach(b => b.draw()) | |
screen.setAlpha(1); // リセット | |
} | |
} | |
class Button { | |
touching = false; | |
press = false; | |
release = false; | |
constructor({name, label, pos, width, height}) { | |
this.name = name; | |
this.label = label; | |
this.pos = pos; | |
this.width = width; | |
this.height = height; | |
this.drawer = new ButtonDrawer(); | |
} | |
init() { return this; } | |
update() { | |
var current = false; | |
touch.touches.forEach(t => { | |
if(Button.isPointInRect(t, this)) { | |
current = true; | |
} | |
}); | |
this.press = !this.touching && current; | |
this.release = this.touching && !current; | |
this.touching = current; | |
} | |
draw() { | |
if(this.drawer) { | |
this.drawer.draw(this); | |
} | |
} | |
static isPointInRect(pos, rect) { | |
const rectLeft = rect.pos.x - rect.width / 2; | |
const rectTop = rect.pos.y - rect.height / 2; | |
const rectRight = rect.pos.x + rect.width / 2; | |
const rectBottom = rect.pos.y + rect.height / 2; | |
return pos.x >= rectLeft && pos.x <= rectRight && | |
pos.y >= rectTop && pos.y <= rectBottom; | |
} | |
} | |
class ButtonDrawer { | |
draw(b) { | |
// 押されているボタン | |
if(b.touching) { | |
screen.setLineWidth(0) | |
screen.setAlpha(0.5) | |
screen.fillRect( b.pos.x, b.pos.y, b.width, b.height ,"#FFF"); | |
} | |
// ボタンの位置 | |
screen.setLineWidth(2) | |
screen.setAlpha(0.8) | |
screen.drawTextOutline(b.name[0],b.pos.x,b.pos.y,30,'black') | |
screen.drawText(b.name[0],b.pos.x,b.pos.y,30,'white') | |
screen.drawRect( b.pos.x, b.pos.y, b.width, b.height ,"#FFF" ) | |
} | |
} | |
/** | |
* 十字キー | |
*/ | |
class ArrowKey { | |
arrowCenter; | |
arrowRadius = 42; | |
arrowMinRadius = 4; | |
UP = false; | |
DOWN = false; | |
RIGHT = false; | |
LEFT = false; | |
press = { | |
UP: false, | |
DOWN: false, | |
RIGHT: false, | |
LEFT: false, | |
}; | |
release = { | |
UP: false, | |
DOWN: false, | |
RIGHT: false, | |
LEFT: false, | |
} | |
static maxRadius = 42; | |
static minRadius = 4; | |
constructor({arrowCenter}) { | |
this.arrowCenter = arrowCenter; | |
this.maxRadius = ArrowKey.maxRadius; | |
this.minRadius = ArrowKey.minRadius; | |
this.drawer = new ArrowKeyDrawer(); | |
} | |
init() { return this; } | |
update() { | |
// 現在のボタンの状態 | |
var current = { | |
UP: false, | |
DOWN: false, | |
RIGHT: false, | |
LEFT: false, | |
}; | |
// 十字キーの状態 | |
const arrowTouches = touch.touches | |
.map(t => ArrowKey.diff(this.arrowCenter, t)) | |
.map(t => ({...t, distance:ArrowKey.distance(t)})) | |
.filter(t => t.distance <= this.maxRadius && t.distance > this.minRadius); | |
if(arrowTouches.length > 0) { | |
const pos = arrowTouches[0]; | |
const rad = Math.atan2(pos.y, pos.x); | |
const unit = Math.PI / 8;// rad | |
if(unit * 1 <= rad && rad < unit * 7) { | |
current.UP = true; | |
} | |
if(-unit * 7 <= rad && rad < -unit * 1) { | |
current.DOWN = true; | |
} | |
if(-unit * 3 <= rad && rad < unit * 3) { | |
current.RIGHT = true; | |
} | |
if(rad <= -unit * 5 || unit * 5 < rad) { | |
current.LEFT = true; | |
} | |
} | |
// 前の状態と比較して、releaseやpressを確定 | |
["UP", "DOWN", "RIGHT", "LEFT"].forEach(key => { | |
this.release[key] = this[key] && !current[key]; | |
this.press[key] = !this[key] && current[key]; | |
this[key] = current[key]; | |
}) | |
} | |
/** | |
* 差 | |
* posB - posA | |
*/ | |
static diff(posA, posB) { | |
return {x: posB.x - posA.x, y: posB.y - posA.y} | |
} | |
static distance(t) { | |
return Math.sqrt(t.x*t.x + t.y*t.y) | |
} | |
draw() { | |
if(this.drawer) { | |
this.drawer.draw(this); | |
} | |
} | |
} | |
class ArrowKeyDrawer { | |
draw(arrowKey) { | |
// 押されているキーを描画 | |
screen.setLineWidth(0) | |
screen.setAlpha(0.5) | |
// 押されている十字キー | |
const unit = 22.5; // deg 45度の半分 | |
if(arrowKey.RIGHT && arrowKey.DOWN) { | |
this.drawPressedArrow(arrowKey, -unit*3 , -unit); | |
}else if(arrowKey.RIGHT && arrowKey.UP) { | |
this.drawPressedArrow(arrowKey, unit*3 , unit); | |
}else if(arrowKey.LEFT && arrowKey.UP) { | |
this.drawPressedArrow(arrowKey, unit*5 , unit*7); | |
}else if(arrowKey.LEFT && arrowKey.DOWN) { | |
this.drawPressedArrow(arrowKey, -unit*5 , -unit*7); | |
}else if(arrowKey.UP) { | |
this.drawPressedArrow(arrowKey, unit*5, unit*3); | |
}else if(arrowKey.DOWN) { | |
this.drawPressedArrow(arrowKey, -unit*5, -unit*3); | |
}else if(arrowKey.RIGHT) { | |
this.drawPressedArrow(arrowKey, -unit, unit); | |
}else if(arrowKey.LEFT) { | |
this.drawPressedArrow(arrowKey, -unit*7, unit*7); | |
} | |
// キーの配置を描画 | |
screen.setLineWidth(2) | |
screen.setAlpha(0.8) | |
screen.drawArc( | |
arrowKey.arrowCenter.x, arrowKey.arrowCenter.y, | |
arrowKey.maxRadius, 0, 360, 0, "#FFF"); | |
} | |
drawPressedArrow(arrowKey, startArc, endArc) { | |
screen.fillPolygon( | |
arrowKey.arrowCenter.x, arrowKey.arrowCenter.y, | |
Math.cos(startArc*Math.PI/180)*arrowKey.maxRadius + arrowKey.arrowCenter.x, Math.sin(startArc*Math.PI/180)*arrowKey.maxRadius + arrowKey.arrowCenter.y, | |
Math.cos( endArc*Math.PI/180)*arrowKey.maxRadius + arrowKey.arrowCenter.x, Math.sin( endArc*Math.PI/180)*arrowKey.maxRadius + arrowKey.arrowCenter.y, | |
"#FFF"); | |
} | |
} | |
window.ScreenGamePad = ScreenGamePad; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment