mirror of
https://git.sr.ht/~thestr4ng3r/chiaki
synced 2025-08-19 21:13:12 -07:00
Decent Touch Detection for Android DPad
This commit is contained in:
parent
2df51efa38
commit
b007f93d16
2 changed files with 69 additions and 11 deletions
|
@ -26,6 +26,7 @@ import android.view.View
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat
|
||||||
import com.metallic.chiaki.R
|
import com.metallic.chiaki.R
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.sqrt
|
||||||
|
|
||||||
class DPadView @JvmOverloads constructor(
|
class DPadView @JvmOverloads constructor(
|
||||||
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
||||||
|
@ -36,9 +37,17 @@ class DPadView @JvmOverloads constructor(
|
||||||
var state: Direction? = null
|
var state: Direction? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Radius (as a fraction of the entire DPad Radius)
|
||||||
|
* to be used as a deadzone in the center on move events
|
||||||
|
*/
|
||||||
|
private val deadzoneRadius = 0.3f
|
||||||
|
|
||||||
private val dpadIdleDrawable = VectorDrawableCompat.create(resources, R.drawable.control_dpad_idle, null)
|
private val dpadIdleDrawable = VectorDrawableCompat.create(resources, R.drawable.control_dpad_idle, null)
|
||||||
private val dpadLeftDrawable = VectorDrawableCompat.create(resources, R.drawable.control_dpad_left, null)
|
private val dpadLeftDrawable = VectorDrawableCompat.create(resources, R.drawable.control_dpad_left, null)
|
||||||
|
|
||||||
|
private var pointerId: Int? = null
|
||||||
|
|
||||||
override fun onDraw(canvas: Canvas)
|
override fun onDraw(canvas: Canvas)
|
||||||
{
|
{
|
||||||
super.onDraw(canvas)
|
super.onDraw(canvas)
|
||||||
|
@ -64,7 +73,7 @@ class DPadView @JvmOverloads constructor(
|
||||||
drawable?.draw(canvas)
|
drawable?.draw(canvas)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun directionForPosition(x: Float, y: Float): Direction
|
private fun directionForPosition(x: Float, y: Float): Direction
|
||||||
{
|
{
|
||||||
val dx = x - width * 0.5f
|
val dx = x - width * 0.5f
|
||||||
val dy = y - height * 0.5f
|
val dy = y - height * 0.5f
|
||||||
|
@ -72,19 +81,68 @@ class DPadView @JvmOverloads constructor(
|
||||||
{
|
{
|
||||||
dx > abs(dy) -> Direction.RIGHT
|
dx > abs(dy) -> Direction.RIGHT
|
||||||
dx <= -abs(dy) -> Direction.LEFT
|
dx <= -abs(dy) -> Direction.LEFT
|
||||||
dy > abs(dx) -> Direction.DOWN
|
dy >= abs(dx) -> Direction.DOWN
|
||||||
else /*dy <= -abs(dx)*/ -> Direction.UP
|
else /*dy < -abs(dx)*/ -> Direction.UP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun updateState(x: Float?, y: Float?)
|
||||||
|
{
|
||||||
|
val newState =
|
||||||
|
if(x == null || y == null)
|
||||||
|
null
|
||||||
|
else
|
||||||
|
{
|
||||||
|
val xFrac = 2.0f * (x / width.toFloat() - 0.5f)
|
||||||
|
val yFrac = 2.0f * (y / height.toFloat() - 0.5f)
|
||||||
|
val radiusSq = xFrac * xFrac + yFrac * yFrac
|
||||||
|
if(radiusSq < deadzoneRadius * deadzoneRadius && state != null)
|
||||||
|
state
|
||||||
|
else
|
||||||
|
directionForPosition(x, y)
|
||||||
|
}
|
||||||
|
|
||||||
|
if(state != newState)
|
||||||
|
{
|
||||||
|
state = newState
|
||||||
|
invalidate()
|
||||||
|
// TODO: callback
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onTouchEvent(event: MotionEvent): Boolean
|
override fun onTouchEvent(event: MotionEvent): Boolean
|
||||||
{
|
{
|
||||||
val dir = directionForPosition(event.x, event.y)
|
when(event.actionMasked)
|
||||||
if(event.action == MotionEvent.ACTION_UP)
|
{
|
||||||
state = null
|
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_POINTER_DOWN ->
|
||||||
else if(event.action == MotionEvent.ACTION_DOWN)
|
{
|
||||||
state = dir
|
if(pointerId == null)
|
||||||
invalidate()
|
{
|
||||||
|
pointerId = event.getPointerId(event.actionIndex)
|
||||||
|
updateState(event.x, event.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_UP, MotionEvent.ACTION_POINTER_UP ->
|
||||||
|
{
|
||||||
|
if(event.getPointerId(event.actionIndex) == pointerId)
|
||||||
|
{
|
||||||
|
pointerId = null
|
||||||
|
updateState(null, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MotionEvent.ACTION_MOVE ->
|
||||||
|
{
|
||||||
|
val pointerId = pointerId
|
||||||
|
if(pointerId != null)
|
||||||
|
{
|
||||||
|
val pointerIndex = event.findPointerIndex(pointerId)
|
||||||
|
if(pointerIndex >= 0)
|
||||||
|
updateState(event.getX(pointerIndex), event.getY(pointerIndex))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,8 +52,8 @@
|
||||||
app:layout_constraintTop_toBottomOf="@+id/morningEditText" />
|
app:layout_constraintTop_toBottomOf="@+id/morningEditText" />
|
||||||
|
|
||||||
<com.metallic.chiaki.touchcontrols.DPadView
|
<com.metallic.chiaki.touchcontrols.DPadView
|
||||||
android:layout_width="100dp"
|
android:layout_width="200dp"
|
||||||
android:layout_height="100dp"
|
android:layout_height="200dp"
|
||||||
android:layout_marginTop="32dp"
|
android:layout_marginTop="32dp"
|
||||||
app:layout_constraintLeft_toLeftOf="parent"
|
app:layout_constraintLeft_toLeftOf="parent"
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
app:layout_constraintRight_toRightOf="parent"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue