forked from MeloNX/MeloNX
refactor virtual pad composition
This commit is contained in:
parent
452d01f7bc
commit
35a85241c6
@ -28,6 +28,7 @@
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true"
|
||||
android:hardwareAccelerated="false"
|
||||
android:configChanges="density|fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode"
|
||||
android:theme="@style/Theme.RyujinxAndroid">
|
||||
<intent-filter>
|
||||
|
@ -13,6 +13,7 @@ import androidx.compose.ui.viewinterop.AndroidView
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.lifecycle.Lifecycle
|
||||
import androidx.lifecycle.LifecycleCoroutineScope
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import com.swordfish.radialgamepad.library.RadialGamePad
|
||||
import com.swordfish.radialgamepad.library.config.ButtonConfig
|
||||
import com.swordfish.radialgamepad.library.config.CrossConfig
|
||||
@ -27,11 +28,47 @@ import kotlinx.coroutines.flow.catch
|
||||
import kotlinx.coroutines.flow.merge
|
||||
import kotlinx.coroutines.flow.shareIn
|
||||
import kotlinx.coroutines.launch
|
||||
import org.ryujinx.android.viewmodels.MainViewModel
|
||||
|
||||
typealias GamePad = RadialGamePad
|
||||
typealias GamePadConfig = RadialGamePadConfig
|
||||
|
||||
class GameController(var activity: Activity, var ryujinxNative: RyujinxNative = RyujinxNative()) {
|
||||
class GameController(var activity: Activity) {
|
||||
|
||||
companion object{
|
||||
private fun Create(context: Context, activity: Activity, controller: GameController) : View
|
||||
{
|
||||
val inflator = LayoutInflater.from(context)
|
||||
val view = inflator.inflate(R.layout.game_layout, null)
|
||||
view.findViewById<FrameLayout>(R.id.leftcontainer)!!.addView(controller.leftGamePad)
|
||||
view.findViewById<FrameLayout>(R.id.rightcontainer)!!.addView(controller.rightGamePad)
|
||||
|
||||
return view
|
||||
}
|
||||
@Composable
|
||||
fun Compose(viewModel: MainViewModel) : Unit
|
||||
{
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(), factory = { context ->
|
||||
val controller = GameController(viewModel.activity)
|
||||
val c = Create(context, viewModel.activity, controller)
|
||||
viewModel.activity.lifecycleScope.apply {
|
||||
viewModel.activity.lifecycleScope.launch {
|
||||
val events = merge(controller.leftGamePad.events(),controller.rightGamePad.events())
|
||||
.shareIn(viewModel.activity.lifecycleScope, SharingStarted.Lazily)
|
||||
events.safeCollect {
|
||||
controller.handleEvent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
controller.controllerView = c
|
||||
viewModel.setGameController(controller)
|
||||
c
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private var ryujinxNative: RyujinxNative
|
||||
private var controllerView: View? = null
|
||||
var leftGamePad: GamePad
|
||||
var rightGamePad: GamePad
|
||||
@ -56,36 +93,8 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
|
||||
leftGamePad.gravityY = 1f
|
||||
rightGamePad.gravityX = 1f
|
||||
rightGamePad.gravityY = 1f
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun Compose(lifecycleScope: LifecycleCoroutineScope, lifecycle:Lifecycle) : Unit
|
||||
{
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(), factory = { context -> Create(context)})
|
||||
|
||||
lifecycleScope.apply {
|
||||
lifecycleScope.launch {
|
||||
val events = merge(leftGamePad.events(),rightGamePad.events())
|
||||
.shareIn(lifecycleScope, SharingStarted.Lazily)
|
||||
|
||||
events.safeCollect {
|
||||
handleEvent(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Create(context: Context) : View
|
||||
{
|
||||
val inflator = LayoutInflater.from(context)
|
||||
val view = inflator.inflate(R.layout.game_layout, null)
|
||||
view.findViewById<FrameLayout>(R.id.leftcontainer)!!.addView(leftGamePad)
|
||||
view.findViewById<FrameLayout>(R.id.rightcontainer)!!.addView(rightGamePad)
|
||||
|
||||
controllerView = view
|
||||
|
||||
return controllerView as View
|
||||
ryujinxNative = RyujinxNative()
|
||||
}
|
||||
|
||||
fun setVisible(isVisible: Boolean){
|
||||
@ -99,7 +108,7 @@ class GameController(var activity: Activity, var ryujinxNative: RyujinxNative =
|
||||
|
||||
fun connect(){
|
||||
if(controllerId == -1)
|
||||
controllerId = ryujinxNative.inputConnectGamepad(0)
|
||||
controllerId = RyujinxNative().inputConnectGamepad(0)
|
||||
}
|
||||
|
||||
private fun handleEvent(ev: Event) {
|
||||
|
@ -11,7 +11,7 @@ import org.ryujinx.android.viewmodels.VulkanDriverViewModel
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
class GameHost(context: Context?, val controller: GameController, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
|
||||
class GameHost(context: Context?, val mainViewModel: MainViewModel) : SurfaceView(context), SurfaceHolder.Callback {
|
||||
private var _renderingThreadWatcher: Thread? = null
|
||||
private var _height: Int = 0
|
||||
private var _width: Int = 0
|
||||
@ -142,16 +142,14 @@ class GameHost(context: Context?, val controller: GameController, val mainViewMo
|
||||
_nativeRyujinx.inputInitialize(width, height)
|
||||
|
||||
if(!settings.useVirtualController){
|
||||
controller.setVisible(false)
|
||||
mainViewModel.controller?.setVisible(false)
|
||||
}
|
||||
else{
|
||||
controller.connect()
|
||||
mainViewModel.controller?.connect()
|
||||
}
|
||||
|
||||
mainViewModel.activity.physicalControllerManager.connect()
|
||||
|
||||
//
|
||||
|
||||
_nativeRyujinx.graphicsRendererSetSize(
|
||||
surfaceHolder.surfaceFrame.width(),
|
||||
surfaceHolder.surfaceFrame.height()
|
||||
|
@ -6,12 +6,14 @@ import android.os.Build
|
||||
import android.os.PerformanceHintManager
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.navigation.NavHostController
|
||||
import org.ryujinx.android.GameController
|
||||
import org.ryujinx.android.GameHost
|
||||
import org.ryujinx.android.MainActivity
|
||||
import org.ryujinx.android.PerformanceManager
|
||||
|
||||
@SuppressLint("WrongConstant")
|
||||
class MainViewModel(val activity: MainActivity) {
|
||||
var controller: GameController? = null
|
||||
var performanceManager: PerformanceManager? = null
|
||||
var selected: GameModel? = null
|
||||
private var gameTimeState: MutableState<Double>? = null
|
||||
@ -65,4 +67,8 @@ class MainViewModel(val activity: MainActivity) {
|
||||
this.value = gameTime
|
||||
}
|
||||
}
|
||||
|
||||
fun setGameController(controller: GameController) {
|
||||
this.controller = controller
|
||||
}
|
||||
}
|
@ -40,35 +40,39 @@ import kotlin.math.roundToInt
|
||||
class MainView {
|
||||
companion object {
|
||||
@Composable
|
||||
fun Main(mainViewModel: MainViewModel){
|
||||
fun Main(mainViewModel: MainViewModel) {
|
||||
val navController = rememberNavController()
|
||||
mainViewModel.setNavController(navController)
|
||||
|
||||
NavHost(navController = navController, startDestination = "home") {
|
||||
composable("home") { HomeViews.Home(mainViewModel.homeViewModel, navController) }
|
||||
composable("game") { GameView(mainViewModel) }
|
||||
composable("settings") { SettingViews.Main(SettingsViewModel(navController, mainViewModel.activity)) }
|
||||
composable("settings") {
|
||||
SettingViews.Main(
|
||||
SettingsViewModel(
|
||||
navController,
|
||||
mainViewModel.activity
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GameView(mainViewModel: MainViewModel){
|
||||
fun GameView(mainViewModel: MainViewModel) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
val controller = remember {
|
||||
GameController(mainViewModel.activity)
|
||||
}
|
||||
AndroidView(
|
||||
modifier = Modifier.fillMaxSize(),
|
||||
factory = { context ->
|
||||
GameHost(context, controller, mainViewModel)
|
||||
GameHost(context, mainViewModel)
|
||||
}
|
||||
)
|
||||
GameOverlay(mainViewModel, controller)
|
||||
GameOverlay(mainViewModel)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GameOverlay(mainViewModel: MainViewModel, controller: GameController){
|
||||
fun GameOverlay(mainViewModel: MainViewModel) {
|
||||
Box(modifier = Modifier.fillMaxSize()) {
|
||||
GameStats(mainViewModel)
|
||||
|
||||
@ -84,9 +88,6 @@ class MainView {
|
||||
Thread.sleep(2)
|
||||
val event = awaitPointerEvent()
|
||||
|
||||
if(controller.isVisible)
|
||||
continue
|
||||
|
||||
val change = event
|
||||
.component1()
|
||||
.firstOrNull()
|
||||
@ -100,10 +101,12 @@ class MainView {
|
||||
position.y.roundToInt()
|
||||
)
|
||||
}
|
||||
|
||||
PointerEventType.Release -> {
|
||||
ryujinxNative.inputReleaseTouchPoint()
|
||||
|
||||
}
|
||||
|
||||
PointerEventType.Move -> {
|
||||
ryujinxNative.inputSetTouchPoint(
|
||||
position.x.roundToInt(),
|
||||
@ -117,18 +120,24 @@ class MainView {
|
||||
}
|
||||
}) {
|
||||
}
|
||||
controller.Compose(mainViewModel.activity.lifecycleScope, mainViewModel.activity.lifecycle)
|
||||
Row(modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(8.dp)) {
|
||||
IconButton(modifier = Modifier.padding(4.dp),onClick = {
|
||||
controller.setVisible(!controller.isVisible)
|
||||
GameController.Compose(mainViewModel)
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.align(Alignment.BottomCenter)
|
||||
.padding(8.dp)
|
||||
) {
|
||||
IconButton(modifier = Modifier.padding(4.dp), onClick = {
|
||||
mainViewModel.controller?.setVisible(!mainViewModel.controller!!.isVisible)
|
||||
}) {
|
||||
Icon(imageVector = rememberVideogameAsset(), contentDescription = "Toggle Virtual Pad")
|
||||
Icon(
|
||||
imageVector = rememberVideogameAsset(),
|
||||
contentDescription = "Toggle Virtual Pad"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun rememberVideogameAsset(): ImageVector {
|
||||
val primaryColor = MaterialTheme.colorScheme.primary
|
||||
@ -226,7 +235,7 @@ class MainView {
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun GameStats(mainViewModel: MainViewModel){
|
||||
fun GameStats(mainViewModel: MainViewModel) {
|
||||
val fifo = remember {
|
||||
mutableStateOf(0.0)
|
||||
}
|
||||
@ -237,8 +246,10 @@ class MainView {
|
||||
mutableStateOf(0.0)
|
||||
}
|
||||
|
||||
Surface(modifier = Modifier.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.surface.copy(0.4f)) {
|
||||
Surface(
|
||||
modifier = Modifier.padding(16.dp),
|
||||
color = MaterialTheme.colorScheme.surface.copy(0.4f)
|
||||
) {
|
||||
Column {
|
||||
var gameTimeVal = 0.0
|
||||
if (!gameTime.value.isInfinite())
|
||||
|
Loading…
x
Reference in New Issue
Block a user