-
Notifications
You must be signed in to change notification settings - Fork 71
Expand file tree
/
Copy pathDartStick.ts
More file actions
147 lines (116 loc) · 4.37 KB
/
Copy pathDartStick.ts
File metadata and controls
147 lines (116 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/**
* Handles dart sticking to the score board on collision.
* Works with GrabbableObject and MatchTransform system.
* Add this component to dart objects.
*/
@component
export class DartStick extends BaseScriptComponent {
@input
@hint("The score board object to stick to")
scoreBoard: SceneObject
@input
@hint("Sound to play when dart sticks to board")
hitSound: AudioComponent
@input
@hint("Sound to play when dart bounces off board")
bounceSound: AudioComponent
//@input
//@hint("Maximum angle in degrees for a successful stick (default: 66)")
private maxStickAngle: number = 170.0
@input
@hint("Offset for tip positioning (default: -0.66)")
tipOffset: number = -0.66
private bodyComponent: BodyComponent | null = null
private hasStuck: boolean = false
private scoreBoardTransform: Transform | null = null
onAwake() {
// Get the body component
this.bodyComponent = this.getSceneObject().getComponent("Physics.BodyComponent")
if (!this.bodyComponent) {
print("DartStick: Physics.BodyComponent is required!")
return
}
// Set up audio for low latency
if (this.hitSound) {
this.hitSound.playbackMode = Audio.PlaybackMode.LowLatency
}
if (this.bounceSound) {
this.bounceSound.playbackMode = Audio.PlaybackMode.LowLatency
}
// Get score board transform
if (this.scoreBoard) {
this.scoreBoardTransform = this.scoreBoard.getTransform()
}
// Set up collision event
this.bodyComponent.onCollisionEnter.add(this.onCollisionEnter.bind(this))
}
/**
* Called when dart collides with something
*/
private onCollisionEnter(e: CollisionEnterEventArgs) {
if (this.hasStuck) return
const collision = e.collision
// Check if we hit the score board
const hitObject = collision.collider.getSceneObject()
const isDartBoardHit = hitObject.name === "DartBoard" || hitObject === this.scoreBoard
if (!isDartBoardHit) {
// Hit something else, just bounce
if (this.bounceSound) {
this.bounceSound.play(1)
}
return
}
// Get current transform
const myTransform = this.getSceneObject().getTransform()
const touchPoint = myTransform.getWorldPosition()
const touchRotation = myTransform.getWorldRotation()
const touchScale = myTransform.getWorldScale()
// Check if this is a straight hit (good angle)
if (this.isStraightHit(touchRotation)) {
print(`DartStick: Straight hit detected! Sticking to board.`)
// Stop physics
this.bodyComponent.dynamic = false
this.bodyComponent.velocity = vec3.zero()
// Adjust position to account for dart tip
const childLocalPosition = new vec3(0, 0, this.tipOffset)
const parentWorldPosition = touchPoint.sub(touchRotation.multiplyVec3(childLocalPosition.mult(touchScale)))
// Parent to the score board
this.getSceneObject().setParent(hitObject)
// Set final transform
myTransform.setWorldPosition(parentWorldPosition)
myTransform.setWorldRotation(touchRotation)
myTransform.setWorldScale(touchScale)
this.hasStuck = true
// Play hit sound
if (this.hitSound) {
this.hitSound.play(1)
}
print(`DartStick: Dart stuck to board at ${parentWorldPosition}`)
} else {
// Not a straight hit, bounce off
print(`DartStick: Bounce - hit angle too steep`)
if (this.bounceSound) {
this.bounceSound.play(1)
}
}
}
/**
* Check if the dart hit at a good angle (straight enough to stick)
*/
private isStraightHit(dartRotation: quat): boolean {
if (!this.scoreBoardTransform) return false
// Get the board's forward direction
const boardForward = this.scoreBoardTransform.forward
// Get the dart's UP direction (because we rotate 90° on X, up becomes the pointing direction)
// The dart model's forward becomes up after the 90° X rotation
const dartPointingDirection = dartRotation.multiplyVec3(vec3.up())
// Calculate angle between board forward and where dart is pointing
const angle = boardForward.angleTo(dartPointingDirection) * MathUtils.RadToDeg
// Check if angle is within acceptable range
const isGoodAngle = angle < this.maxStickAngle && angle > 0
print(
`DartStick: Hit angle: ${angle.toFixed(1)}° (max: ${this.maxStickAngle}°) - ${isGoodAngle ? "STICK!" : "BOUNCE"}`
)
return isGoodAngle
}
}