Skip to content

Commit

Permalink
Merge pull request #14 from poeticAndroid/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
poeticAndroid authored Jul 4, 2021
2 parents 7554213 + df0c851 commit f2aa288
Show file tree
Hide file tree
Showing 13 changed files with 406 additions and 86 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Essential game components for [A-Frame](https://aframe.io/)!
<html>
<head>
<script src="https://aframe.io/releases/1.2.0/aframe.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/poeticAndroid/a-game@v0.14.0/dist/a-game.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/poeticAndroid/a-game@v0.15.0/dist/a-game.min.js"></script>
</head>
<body>
<a-scene physics>
Expand All @@ -33,6 +33,7 @@ Essential game components for [A-Frame](https://aframe.io/)!
## Components

- [grabbing](./src/components/grabbing.md)
- [climbable](./src/components/grabbing/climbable.md)
- [fingerflex](./src/components/grabbing/fingerflex.md)
- [grabbable](./src/components/grabbing/grabbable.md)
- [receptacle](./src/components/grabbing/receptacle.md)
Expand Down
229 changes: 183 additions & 46 deletions dist/a-game.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/a-game.min.js

Large diffs are not rendered by default.

6 changes: 5 additions & 1 deletion dist/scenes/demo.html
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<a-main>
<a-sky src="#skyImg"></a-sky>
<a-entity start position="0 1 1"></a-entity>
<a-entity start position="0 16 1"></a-entity>
<a-box rotation="-90 0 0" src="#floorImg" width="16" height="16" depth="0.01" floor></a-box>
<a-box color="#9fc" position="1.55 .55 -3" scale=".5 .5 .5" grabbable
onevent__reachable="property:color; value:yellow;" onevent__unreachable="property:color; value:blue;"
Expand All @@ -18,6 +18,8 @@
</a-gltf-model>
<a-box src="#granite" width="5" depth="1" material="repeat: 5 1" floor wall position="0 0 5" rotation="0 0 10">
</a-box>
<a-box src="#granite" width="6" depth="0.125" height="20" material="repeat: 6 20" climbable wall position="0 8 9">
</a-box>
<a-cylinder trigger onevent__trigger="entity:#triggerIndicator; property:color; value:green;"
onevent__untrigger="entity:#triggerIndicator; property:color; value:red;" position="-3 1 0" height="2" radius="2"
material="opacity:0.5">
Expand Down Expand Up @@ -55,6 +57,8 @@
<a-sphere radius="0.125" receptacle position="-1 1 0"></a-sphere>
<a-sphere radius="0.125" receptacle position="2 1 0"></a-sphere>
<a-sphere radius="0.125" receptacle position="-2 1 0"></a-sphere>
<a-cylinder src="#granite" climbable height="20" position="0 10 4"></a-cylinder>
<a-cylinder src="#granite" floor height="0.125" position="0 20 4"></a-cylinder>
</a-entity>
<a-box floor src="#granite" position="-8 0 0" scale="2 1 2" body="type:kinematic;"
animation="dur: 20000; property: position; to: -16 0 0; dir: alternate; loop:true;"></a-box>
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

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,7 +1,7 @@
{
"name": "a-game",
"title": "A-Game",
"version": "0.14.0",
"version": "0.15.0",
"description": "game components for A-Frame",
"homepage": "https://github.com/poeticAndroid/a-game/blob/master/README.md",
"main": "index.js",
Expand Down
79 changes: 67 additions & 12 deletions src/components/grabbing.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,17 @@ AFRAME.registerComponent("grabbing", {
init() {
this._enableHands = this._enableHands.bind(this)
this._onKeyDown = this._onKeyDown.bind(this)
this._onKeyUp = this._onKeyUp.bind(this)
this._onMouseDown = this._onMouseDown.bind(this)
this._onMouseUp = this._onMouseUp.bind(this)
this._onWheel = this._onWheel.bind(this)
this._onButtonChanged = this._onButtonChanged.bind(this)
this._onTouchTap = this._onTouchTap.bind(this)
this._onTouchHold = this._onTouchHold.bind(this)

this._btnPress = {}
this._btnFlex = {}
this._keysDown = {}

this._hands = ["head", "left", "right"]
this._head = {}
Expand All @@ -25,7 +28,7 @@ AFRAME.registerComponent("grabbing", {
this._head.hand = this.el.querySelector("a-camera")
this._left.hand = this.el.querySelector("a-hand[side=\"left\"]")
this._right.hand = this.el.querySelector("a-hand[side=\"right\"]")
this._head.glove = this._head.hand
this._head.glove = this._head.hand.ensure(".hitbox", "a-sphere", { class: "hitbox", body: "type:kinematic;", radius: 0.25 })
this._left.glove = this._ensureGlove(this._left.hand)
this._right.glove = this._ensureGlove(this._right.hand)

Expand All @@ -36,17 +39,21 @@ AFRAME.registerComponent("grabbing", {
this[_hand].hand.addEventListener("buttonchanged", this._enableHands)
}

this._head.glove.ensure(".hitbox", "a-sphere", { class: "hitbox", radius: 0.5 })
this._head.glove.setAttribute("body", "type:kinematic;")
this._head.ray = this._head.glove.ensure(".grabbing-ray", "a-entity", {
this._head.ray = this._head.hand.ensure(".grabbing-ray", "a-entity", {
class: "grabbing-ray", position: "0 -0.125 0",
raycaster: {
objects: "[wall], [grabbable]",
autoRefresh: false,
// showLine: true,
}
})
this._head.anchor = this._head.ray.ensure(".grabbing-anchor", "a-entity", { class: "grabbing-anchor", visible: false, body: "type:kinematic;autoShape:false;" })
this._head.reticle = this._head.ray.ensure(".reticle", "a-sphere", {
class: "reticle",
radius: 0.015625,
// color: "black",
position: "0 0 -1"
}, `<a-torus color="black" radius="0.015625" radius-tubular="0.001953125"></a-torus>`)
this._head.anchor = this._head.ray.ensure(".grabbing.anchor", "a-entity", { class: "grabbing anchor", visible: false, body: "type:kinematic;autoShape:false;" })
},

update(oldData) {
Expand All @@ -59,8 +66,10 @@ AFRAME.registerComponent("grabbing", {

play() {
document.addEventListener("keydown", this._onKeyDown)
document.addEventListener("keyup", this._onKeyUp)
this.el.sceneEl.canvas.addEventListener("mousedown", this._onMouseDown)
this.el.sceneEl.canvas.addEventListener("mouseup", this._onMouseUp)
this.el.sceneEl.canvas.addEventListener("wheel", this._onWheel)
for (let hand of [this._left.hand, this._right.hand]) {
// hand.addEventListener("buttonchanged", this._enableHands)
hand.addEventListener("buttonchanged", this._onButtonChanged)
Expand All @@ -71,8 +80,10 @@ AFRAME.registerComponent("grabbing", {

pause() {
document.removeEventListener("keydown", this._onKeyDown)
document.removeEventListener("keyup", this._onKeyUp)
this.el.sceneEl.canvas.removeEventListener("mousedown", this._onMouseDown)
this.el.sceneEl.canvas.removeEventListener("mouseup", this._onMouseUp)
this.el.sceneEl.canvas.removeEventListener("wheel", this._onWheel)
for (let hand of [this._left.hand, this._right.hand]) {
// hand.removeEventListener("buttonchanged", this._enableHands)
hand.removeEventListener("buttonchanged", this._onButtonChanged)
Expand Down Expand Up @@ -101,6 +112,17 @@ AFRAME.registerComponent("grabbing", {
if ((gamepad.buttons[6].pressed || gamepad.buttons[7].pressed) && !this._useBtn0) this.useDown()
if ((gamepad.buttons[0].pressed) && !this._useBtn1) this.useDown("head", 1)
if ((gamepad.buttons[1].pressed) && !this._useBtn2) this.useDown("head", 2)
if (gamepad.buttons[2].pressed) {
if (gamepad.buttons[12].pressed) this.moveHeadHand(0, -0.03125)
if (gamepad.buttons[13].pressed) this.moveHeadHand(0, 0.03125)
if (gamepad.buttons[14].pressed) this.moveHeadHand(0, 0, -0.03125)
if (gamepad.buttons[15].pressed) this.moveHeadHand(0, 0, 0.03125)
} else {
if (gamepad.buttons[12].pressed) this.moveHeadHand(-0.03125)
if (gamepad.buttons[13].pressed) this.moveHeadHand(0.03125)
if (gamepad.buttons[14].pressed) this.moveHeadHand(0, 0, 0, 0.03125)
if (gamepad.buttons[15].pressed) this.moveHeadHand(0, 0, 0, -0.03125)
}
}
}
this._grabBtn = false
Expand Down Expand Up @@ -152,8 +174,15 @@ AFRAME.registerComponent("grabbing", {
}

if (this[_hand].grabbed) {
// if (!this[_hand].isPhysical)
let ray = this[_hand].ray.components.raycaster
ray.refreshObjects()
for (let hit of ray.intersections) {
if (hit && hit.el.getAttribute("wall") != null && hit.distance < -this[_hand].anchor.object3D.position.z) {
this[_hand].anchor.object3D.position.multiplyScalar(0.5)
}
}
this[_hand].grabbed.copyWorldPosRot(this[_hand].anchor)
if (this[_hand].reticle) this[_hand].reticle.object3D.position.z = 1
} else if (this[_hand].ray) {
let ray = this[_hand].ray.components.raycaster
ray.refreshObjects()
Expand All @@ -165,10 +194,12 @@ AFRAME.registerComponent("grabbing", {
this[_hand]._lastHit = hit.el
this.emit("reachable", this[_hand].glove, this[_hand]._lastHit)
}
if (this[_hand].reticle) this[_hand].reticle.object3D.position.z = -hit.distance
} else {
if (this[_hand]._lastHit)
this.emit("unreachable", this[_hand].glove, this[_hand]._lastHit)
this[_hand]._lastHit = null
if (this[_hand].reticle) this[_hand].reticle.object3D.position.z = 1
}
}
}
Expand Down Expand Up @@ -231,8 +262,9 @@ AFRAME.registerComponent("grabbing", {
}
if (this.data.hideOnGrab)
this[_hand].glove.setAttribute("visible", false)
// if (this[_hand].glove.getAttribute("body"))
this[_hand].glove.setAttribute("body", "collidesWith", 0)
this.emit("grab", this[_hand].glove, this[_hand].grabbed)
this.emit("grab", this[_hand].glove, this[_hand].grabbed, { intersection: hit })
this.el.addState("grabbing")
this[_hand].grabbed.addState("grabbed")
this.sticky = true
Expand All @@ -250,8 +282,11 @@ AFRAME.registerComponent("grabbing", {
this[_hand].glove.setAttribute("visible", true)
setTimeout(() => {
this[_hand].anchor.removeAttribute("joint__grab")
this[_hand].anchor.setAttribute("position", "0 0 0")
this[_hand].anchor.setAttribute("rotation", "0 0 0")
}, 32)
setTimeout(() => {
// if (this[_hand].glove.getAttribute("body"))
this[_hand].glove.setAttribute("body", "collidesWith", 1)
}, 1024)
this.emit("drop", this[_hand].glove, this[_hand].grabbed)
Expand Down Expand Up @@ -284,13 +319,18 @@ AFRAME.registerComponent("grabbing", {
let _hand = "_" + hand
this.emit("useup", this[_hand].glove, this[_hand].grabbed, { button: button })
},
moveHeadHand(pz = 0, rx = 0, ry = 0, rz = 0) {
this._head.anchor.object3D.position.z = Math.min(Math.max(-1.5, this._head.anchor.object3D.position.z + pz), -0.125)
let quat = THREE.Quaternion.temp().set(rx, ry, rz, 1).normalize()
this._head.anchor.object3D.quaternion.premultiply(quat)
},

emit(eventtype, glove, grabbed, e = {}) {
e.grabbing = this.el
e.grabbedElement = grabbed
e.gloveElement = glove
for (let _hand of this._hands) {
if (this["_" + _hand].hand === glove) e.hand = _hand
if (this["_" + _hand].glove === glove) e.hand = _hand
}
glove.emit(eventtype, e)
if (grabbed) grabbed.emit(eventtype, e)
Expand Down Expand Up @@ -332,8 +372,8 @@ AFRAME.registerComponent("grabbing", {
// showLine: true,
}
})
this._left.anchor = this._left.ray.ensure(".grabbing-anchor", "a-entity", { class: "grabbing-anchor", visible: "false", body: "type:kinematic;autoShape:false;" })
this._right.anchor = this._right.ray.ensure(".grabbing-anchor", "a-entity", { class: "grabbing-anchor", visible: "false", body: "type:kinematic;autoShape:false;" })
this._left.anchor = this._left.ray.ensure(".grabbing.anchor", "a-entity", { class: "grabbing anchor", visible: "false", body: "type:kinematic;autoShape:false;" })
this._right.anchor = this._right.ray.ensure(".grabbing.anchor", "a-entity", { class: "grabbing anchor", visible: "false", body: "type:kinematic;autoShape:false;" })
this._left.glove.setAttribute("visible", true)
this._right.glove.setAttribute("visible", true)

Expand Down Expand Up @@ -407,11 +447,25 @@ AFRAME.registerComponent("grabbing", {
}
},

_onKeyDown(e) { if (e.key === "e") this.toggleGrab() },
_onKeyDown(e) {
this._keysDown[e.code] = true
if (e.key === "e") this.toggleGrab()
},
_onKeyUp(e) { this._keysDown[e.code] = false },
_onMouseDown(e) {
let btn = e.button
this.useDown("head", btn ? ((btn % 2) ? btn + 1 : btn - 1) : btn)
},
_onWheel(e) {
if (e.shiftKey && this._keysDown["KeyX"] && e.deltaY > 0) return this.moveHeadHand(0, 0, 0, -0.125)
if (e.shiftKey && this._keysDown["KeyX"] && e.deltaY < 0) return this.moveHeadHand(0, 0, 0, 0.125)
if (e.shiftKey && e.deltaY > 0) return this.moveHeadHand(0, 0, -0.125)
if (e.shiftKey && e.deltaY < 0) return this.moveHeadHand(0, 0, 0.125)
if (this._keysDown["KeyX"] && e.deltaY > 0) return this.moveHeadHand(0, 0.125)
if (this._keysDown["KeyX"] && e.deltaY < 0) return this.moveHeadHand(0, -0.125)
if (e.deltaY > 0) return this.moveHeadHand(0.125)
if (e.deltaY < 0) return this.moveHeadHand(-0.125)
},
_onMouseUp(e) {
let btn = e.button
this.useUp("head", btn ? ((btn % 2) ? btn + 1 : btn - 1) : btn)
Expand Down Expand Up @@ -464,6 +518,7 @@ AFRAME.registerComponent("grabbing", {
},
})

require("./grabbing/grabbable")
require("./grabbing/climbable")
require("./grabbing/fingerflex")
require("./grabbing/grabbable")
require("./grabbing/receptacle")
35 changes: 19 additions & 16 deletions src/components/grabbing.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,13 @@ Add the `grabbing` component to your player rig like so:

This makes it possible to grab and use grabbable objects using the following controls.

| Action | Controller | Desktop | Touch |
| ----------- | -------------------- | ------------ | -------- |
| Grab/drop | Grip/shoulder Button | E | Long tap |
| Primary use | Trigger | Left click | Tap |
| Secondary | A | Right click |
| Tertiary | B | Middle click |
| Action | Controller | Desktop | Touch |
| ----------- | -------------------- | ---------------- | -------- |
| Grab/drop | Grip/shoulder Button | E | Long tap |
| Primary use | Trigger | Left click | Tap |
| Secondary | A | Right click |
| Tertiary | B | Middle click |
| Move hand | X, D-pad | Shift, X, scroll |


## Properties
Expand All @@ -31,15 +32,16 @@ This makes it possible to grab and use grabbable objects using the following con
`hand` parameter is either `"head"`(default), `"left"` or `"right"`.
`button` parameter is 0 - 2, where 0 is the primary use button.

| Method | Description |
| --------------------- | ----------------------------------------------------- |
| toggleGrab(hand) | Drop if holding something, attempt to grab otherwise. |
| grab(hand) | Attempt to grab something. |
| use(hand, button) | Shortly use grabbable. |
| useDown(hand, button) | Start using grabbable. |
| useUp(hand, button) | Stop using grabbable. |
| drop(hand) | Drop grabbable. |
| dropObject(el) | Drop specified grabbable if held. |
| Method | Description |
| ------------------------- | ----------------------------------------------------- |
| toggleGrab(hand) | Drop if holding something, attempt to grab otherwise. |
| grab(hand) | Attempt to grab something. |
| use(hand, button) | Shortly use grabbable. |
| useDown(hand, button) | Start using grabbable. |
| useUp(hand, button) | Stop using grabbable. |
| drop(hand) | Drop grabbable. |
| dropObject(el) | Drop specified grabbable if held. |
| moveHeadHand(pz,rx,ry,rz) | Move/rotate non-VR hand. |


## Events
Expand All @@ -59,6 +61,7 @@ These events are emitted by both the glove and the `grabbable` that it's grabbin

## Related components

- [climbable](./grabbing/climbable.md)
- [fingerflex](./grabbing/fingerflex.md)
- [grabbable](./grabbing/grabbable.md)
- [receptacle](./grabbing/receptacle.md)
- [fingerflex](./grabbing/fingerflex.md)
68 changes: 68 additions & 0 deletions src/components/grabbing/climbable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/* global AFRAME, THREE */

AFRAME.registerComponent("climbable", {
dependencies: ["wall"],
schema: {
},

init() {
this.el.setAttribute("grabbable", "physics:false; kinematicGrab:false;")
this._player = this.el.sceneEl.querySelector("[locomotion")
this._quat = new THREE.Quaternion()
this._lpos = new THREE.Vector3()
this._wpos = new THREE.Vector3()
this._handpos = new THREE.Vector3()

this._onBump = this._onBump.bind(this)

setTimeout(() => {
this._quat.copy(this.el.object3D.quaternion)
this._lpos.copy(this.el.object3D.position)
this.el.object3D.getWorldPosition(this._wpos)
this._top = parseFloat(this.el.getAttribute("height") || 1) / 2 + 2
}, 256)
},

play() {
this._player.addEventListener("bump", this._onBump)
},
pause() {
this._player.removeEventListener("bump", this._onBump)
},

tick() {
if (!this._climbing) return
let delta = THREE.Vector3.temp()
this._hand.object3D.getWorldPosition(delta)
delta.sub(this._handpos).multiplyScalar(-1)
if (this._handName === "head") {
delta.y = 0
delta.y = delta.length()
this._handpos.y += delta.y
}
this._player.components.locomotion.stopFall()
this._player.components.locomotion.move(delta)
if (this._handpos.y - this._wpos.y > this._top) this._onBump()

this.el.object3D.quaternion.copy(this._quat)
this.el.object3D.position.copy(this._lpos)
},

events: {
grab(e) {
this._climbing = true
this._handName = e.detail.hand
this._hand = e.detail.gloveElement.parentNode//.querySelector(".anchor")
this._hand.object3D.getWorldPosition(this._handpos)
if (e.detail.intersection.distance > (this._handName === "head" ? 0.5 : 0.25)) setTimeout(this._onBump, 260)
else this._player.components.locomotion.jump()
},
drop(e) {
this._climbing = false
},
},

_onBump(e) {
this._player.components.grabbing.dropObject(this.el)
}
})
Loading

0 comments on commit f2aa288

Please sign in to comment.