summaryrefslogtreecommitdiff
path: root/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine
diff options
context:
space:
mode:
authorElizabeth Hunt <me@liz.coffee>2025-10-26 17:25:13 -0700
committerElizabeth Hunt <me@liz.coffee>2025-10-26 17:25:13 -0700
commit395aa7d1c312e495517701be11c21425d9a5838e (patch)
tree4ad184b082838c56149cc1d1efe191cfd3d0679b /composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine
parent64f825465de9fa30c4dfe2707067efdb96110db8 (diff)
downloadabstraction-engine-kt-395aa7d1c312e495517701be11c21425d9a5838e.tar.gz
abstraction-engine-kt-395aa7d1c312e495517701be11c21425d9a5838e.zip
Checkpoint
Diffstat (limited to 'composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine')
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/AbstractionEngine.kt5
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/App.kt28
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Greeting.kt9
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Platform.kt2
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/App.kt24
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/ui/Theme.kt (renamed from composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/Theme.kt)2
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt5
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt37
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt (renamed from composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt)11
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeButton.kt52
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeControls.kt130
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/DPad.kt105
-rw-r--r--composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/PCBBackground.kt85
13 files changed, 38 insertions, 457 deletions
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/AbstractionEngine.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/AbstractionEngine.kt
deleted file mode 100644
index d557fd8..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/AbstractionEngine.kt
+++ /dev/null
@@ -1,5 +0,0 @@
-package coffee.liz.abstractionengine
-
-class AbstractionEngine {
-
-} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/App.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/App.kt
deleted file mode 100644
index a69e711..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/App.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-package coffee.liz.abstractionengine
-
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.*
-import androidx.compose.ui.Modifier
-import coffee.liz.abstractionengine.ui.ArcadeControls
-import coffee.liz.abstractionengine.ui.GameBoyTheme
-import org.jetbrains.compose.ui.tooling.preview.Preview
-
-@Composable
-@Preview
-fun App() {
- MaterialTheme(colorScheme = GameBoyTheme) {
- ArcadeControls(
- onDirectionPressed = { direction ->
- println("Direction pressed: $direction")
- },
- onActionA = {
- println("Action A pressed!")
- },
- onActionB = {
- println("Action B pressed!")
- },
- modifier = Modifier.fillMaxSize()
- )
- }
-} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Greeting.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Greeting.kt
deleted file mode 100644
index 6f23320..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Greeting.kt
+++ /dev/null
@@ -1,9 +0,0 @@
-package coffee.liz.abstractionengine
-
-class Greeting {
- private val platform = getPlatform()
-
- fun greet(): String {
- return "Hello, ${platform.name}!"
- }
-} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Platform.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Platform.kt
index 91faf62..17ca317 100644
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Platform.kt
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/Platform.kt
@@ -1,7 +1,7 @@
package coffee.liz.abstractionengine
interface Platform {
- val name: String
+ val needsTouchscreenControls: Boolean
}
expect fun getPlatform(): Platform \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/App.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/App.kt
new file mode 100644
index 0000000..50e72f0
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/App.kt
@@ -0,0 +1,24 @@
+package coffee.liz.abstractionengine.app
+
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.*
+import androidx.compose.ui.Modifier
+import coffee.liz.abstractionengine.app.ui.GameBoyTheme
+import coffee.liz.abstractionengine.getPlatform
+import org.jetbrains.compose.ui.tooling.preview.Preview
+
+@Composable
+@Preview
+fun App() {
+
+ MaterialTheme(colorScheme = GameBoyTheme) {
+ Box(modifier = Modifier.fillMaxSize()) {
+ if (getPlatform().needsTouchscreenControls) {
+ Text("NEEDS TOUCHSCREEN CONTROLS")
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/Theme.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/ui/Theme.kt
index 661cb09..be6c3ad 100644
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/Theme.kt
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/app/ui/Theme.kt
@@ -1,4 +1,4 @@
-package coffee.liz.abstractionengine.ui
+package coffee.liz.abstractionengine.app.ui
import androidx.compose.material3.darkColorScheme
import androidx.compose.ui.graphics.Color
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt
new file mode 100644
index 0000000..18349c3
--- /dev/null
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/AbstractionEngine.kt
@@ -0,0 +1,5 @@
+package coffee.liz.abstractionengine.game
+
+class AbstractionEngine {
+
+} \ No newline at end of file
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt
index 9490f83..0c3a007 100644
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Game.kt
@@ -6,64 +6,35 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import coffee.liz.ecs.World
import kotlinx.coroutines.isActive
+import kotlin.time.Duration.Companion.nanoseconds
/**
- * Manages the game loop for an ECS world.
- * Syncs with Compose's frame rate (like requestAnimationFrame) and provides
- * the world to child content for custom rendering/UI.
- *
- * @param world The ECS world containing entities and systems
- * @param content Composable content that can use the world for rendering
+ * Manages and paints the [World].
*/
@Composable
fun Game(
world: World,
content: @Composable () -> Unit
) {
- // Trigger recomposition when we need to redraw
var frameCount by remember { mutableStateOf(0) }
- // Game loop - syncs with Compose's frame rate like requestAnimationFrame
LaunchedEffect(world) {
- var lastFrameTimeNanos = 0L
+ var lastUpdate: Long? = null
while (isActive) {
- // Wait for next frame (like requestAnimationFrame)
withFrameNanos { frameTimeNanos ->
- val deltaTime = if (lastFrameTimeNanos != 0L) {
- (frameTimeNanos - lastFrameTimeNanos) / 1_000_000_000f
- } else {
- 0f
- }
- lastFrameTimeNanos = frameTimeNanos
-
- // Update ECS world (runs all systems)
- if (deltaTime > 0f) {
- world.update(deltaTime)
- }
-
- // Trigger recomposition to redraw
frameCount++
}
}
}
- // Render content
content()
}
-/**
- * A Canvas that renders sprites from an ECS world using a RenderSystem.
- *
- * @param world The ECS world containing entities to render
- * @param renderSystem The system responsible for rendering sprites
- * @param backgroundColor Background color for the canvas
- * @param modifier Modifier for the Canvas
- */
@Composable
fun GameCanvas(
world: World,
- renderSystem: RenderSystem,
+ renderSystem: Renderer,
backgroundColor: Color = Color.Transparent,
modifier: Modifier = Modifier
) {
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt
index 1d22ae6..57511f3 100644
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/RenderSystem.kt
+++ b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/game/Renderer.kt
@@ -1,7 +1,5 @@
package coffee.liz.abstractionengine.game
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.geometry.Size
import androidx.compose.ui.graphics.drawscope.DrawScope
import androidx.compose.ui.unit.IntOffset
import androidx.compose.ui.unit.IntSize
@@ -12,6 +10,7 @@ import coffee.liz.ecs.animation.Animator
import coffee.liz.ecs.animation.Position
import coffee.liz.ecs.animation.SpriteSheet
import kotlin.reflect.KClass
+import kotlin.time.Duration
/**
* System that renders sprites to a DrawScope.
@@ -21,17 +20,13 @@ import kotlin.reflect.KClass
*
* Depends on AnimationSystem to ensure animations are updated before rendering.
*/
-class RenderSystem(
+class Renderer(
private val imageCache: ImageCache
) : System {
override val dependencies: Set<KClass<out System>> = setOf(AnimationSystem::class)
- /**
- * The update method is required by the System interface, but rendering
- * happens synchronously during Compose's draw phase via the render() method.
- */
- override fun update(world: World, deltaTime: Float) {
+ override fun update(world: World, duration: Duration) {
// Rendering happens in render() method, not here
}
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeButton.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeButton.kt
deleted file mode 100644
index 9d50192..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeButton.kt
+++ /dev/null
@@ -1,52 +0,0 @@
-package coffee.liz.abstractionengine.ui
-
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.PaddingValues
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-
-enum class ArcadeButtonColor {
- RED, YELLOW
-}
-
-@Composable
-fun ArcadeButton(
- label: String,
- color: ArcadeButtonColor = ArcadeButtonColor.RED,
- onClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- val buttonColor = when (color) {
- ArcadeButtonColor.RED -> GameBoyColors.ButtonRed
- ArcadeButtonColor.YELLOW -> GameBoyColors.ButtonYellow
- }
-
- Button(
- onClick = onClick,
- modifier = modifier
- .size(65.dp)
- .border(1.dp, MaterialTheme.colorScheme.outline, CircleShape),
- shape = CircleShape,
- colors = ButtonDefaults.buttonColors(
- containerColor = buttonColor,
- contentColor = MaterialTheme.colorScheme.onPrimary
- ),
- contentPadding = PaddingValues(0.dp)
- ) {
- Text(
- text = label,
- fontSize = 20.sp,
- fontWeight = FontWeight.Bold,
- color = MaterialTheme.colorScheme.onPrimary
- )
- }
-}
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeControls.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeControls.kt
deleted file mode 100644
index f5b4839..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/ArcadeControls.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-package coffee.liz.abstractionengine.ui
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.material3.Text
-import androidx.compose.runtime.*
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.text.font.FontFamily
-import androidx.compose.ui.text.font.FontWeight
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-
-@Composable
-fun ArcadeControls(
- onDirectionPressed: (Direction) -> Unit,
- onActionA: () -> Unit,
- onActionB: () -> Unit,
- modifier: Modifier = Modifier,
- gameContent: @Composable BoxScope.() -> Unit = {
- // Default placeholder content
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.spacedBy(16.dp)
- ) {
- Text(
- text = "GAME AREA",
- fontSize = 18.sp,
- fontWeight = FontWeight.Bold,
- fontFamily = FontFamily.Monospace,
- color = MaterialTheme.colorScheme.onPrimary
- )
- }
- }
-) {
- var lastDirection by remember { mutableStateOf<Direction?>(null) }
- var lastAction by remember { mutableStateOf<String?>(null) }
-
- Box(modifier = modifier.fillMaxSize()) {
- // PCB background layer
- PCBBackground()
-
- // Transparent casing overlay
- Box(
- modifier = Modifier
- .fillMaxSize()
- .background(Color(0x33000000))
- )
-
- // Content
- Column(
- modifier = Modifier
- .fillMaxSize()
- .padding(16.dp),
- horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.spacedBy(16.dp)
- ) {
- // Game area (square)
- Box(
- modifier = Modifier
- .fillMaxWidth(0.95f)
- .aspectRatio(1f)
- .background(
- color = GameBoyColors.ScreenGreen.copy(alpha = 0.85f),
- shape = RoundedCornerShape(8.dp)
- )
- .border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(8.dp))
- .padding(8.dp),
- contentAlignment = Alignment.Center,
- content = gameContent
- )
-
- // Control panel
- Box(
- modifier = Modifier
- .fillMaxWidth(0.95f)
- .background(
- color = MaterialTheme.colorScheme.surface.copy(alpha = 0.7f),
- shape = RoundedCornerShape(16.dp)
- )
- .border(1.dp, MaterialTheme.colorScheme.outline, RoundedCornerShape(16.dp))
- .padding(horizontal = 16.dp, vertical = 16.dp),
- contentAlignment = Alignment.Center
- ) {
- Row(
- modifier = Modifier.fillMaxWidth(),
- horizontalArrangement = Arrangement.SpaceEvenly,
- verticalAlignment = Alignment.CenterVertically
- ) {
- // D-Pad on the left
- DPad(
- onDirectionPressed = { direction ->
- lastDirection = direction
- lastAction = null
- onDirectionPressed(direction)
- }
- )
-
- // Action buttons on the right
- Row(
- horizontalArrangement = Arrangement.spacedBy(12.dp)
- ) {
- ArcadeButton(
- label = "B",
- color = ArcadeButtonColor.YELLOW,
- onClick = {
- lastAction = "B"
- lastDirection = null
- onActionB()
- }
- )
- ArcadeButton(
- label = "A",
- color = ArcadeButtonColor.RED,
- onClick = {
- lastAction = "A"
- lastDirection = null
- onActionA()
- }
- )
- }
- }
- }
- }
- }
-}
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/DPad.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/DPad.kt
deleted file mode 100644
index 52f5866..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/DPad.kt
+++ /dev/null
@@ -1,105 +0,0 @@
-package coffee.liz.abstractionengine.ui
-
-import androidx.compose.foundation.background
-import androidx.compose.foundation.border
-import androidx.compose.foundation.layout.*
-import androidx.compose.foundation.shape.CircleShape
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.*
-import androidx.compose.runtime.*
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.unit.sp
-
-enum class Direction {
- UP, DOWN, LEFT, RIGHT
-}
-
-@Composable
-fun DPad(
- onDirectionPressed: (Direction) -> Unit,
- modifier: Modifier = Modifier
-) {
- Box(
- modifier = modifier
- .size(140.dp)
- .background(
- color = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f),
- shape = CircleShape
- )
- .border(1.dp, MaterialTheme.colorScheme.outline, CircleShape)
- ) {
- // Up button
- DirectionButton(
- text = "▲",
- onClick = { onDirectionPressed(Direction.UP) },
- modifier = Modifier
- .align(Alignment.TopCenter)
- .offset(y = 20.dp)
- )
-
- // Down button
- DirectionButton(
- text = "▼",
- onClick = { onDirectionPressed(Direction.DOWN) },
- modifier = Modifier
- .align(Alignment.BottomCenter)
- .offset(y = (-20).dp)
- )
-
- // Left button
- DirectionButton(
- text = "◀",
- onClick = { onDirectionPressed(Direction.LEFT) },
- modifier = Modifier
- .align(Alignment.CenterStart)
- .offset(x = 20.dp)
- )
-
- // Right button
- DirectionButton(
- text = "▶",
- onClick = { onDirectionPressed(Direction.RIGHT) },
- modifier = Modifier
- .align(Alignment.CenterEnd)
- .offset(x = (-20).dp)
- )
-
- // Center circle
- Box(
- modifier = Modifier
- .align(Alignment.Center)
- .size(38.dp)
- .background(
- color = MaterialTheme.colorScheme.surface.copy(alpha = 0.5f),
- shape = CircleShape
- )
- .border(1.dp, MaterialTheme.colorScheme.outline, CircleShape)
- )
- }
-}
-
-@Composable
-private fun DirectionButton(
- text: String,
- onClick: () -> Unit,
- modifier: Modifier = Modifier
-) {
- Button(
- onClick = onClick,
- modifier = modifier.size(38.dp),
- shape = RoundedCornerShape(4.dp),
- colors = ButtonDefaults.buttonColors(
- containerColor = MaterialTheme.colorScheme.surfaceVariant.copy(alpha = 0.6f),
- contentColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.3f)
- ),
- contentPadding = PaddingValues(0.dp)
- ) {
- Text(
- text = text,
- fontSize = 14.sp,
- style = MaterialTheme.typography.headlineMedium
- )
- }
-}
diff --git a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/PCBBackground.kt b/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/PCBBackground.kt
deleted file mode 100644
index be35a1a..0000000
--- a/composeApp/src/commonMain/kotlin/coffee/liz/abstractionengine/ui/PCBBackground.kt
+++ /dev/null
@@ -1,85 +0,0 @@
-package coffee.liz.abstractionengine.ui
-
-import androidx.compose.foundation.Canvas
-import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.fillMaxSize
-import androidx.compose.material3.MaterialTheme
-import androidx.compose.runtime.Composable
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.geometry.Offset
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.PathEffect
-
-@Composable
-fun PCBBackground(modifier: Modifier = Modifier) {
- val pcbGreen = Color(0xFF0D5F0D)
- val traceColor = Color(0xFF1A7F1A)
- val padColor = Color(0xFFD4AF37)
-
- Canvas(modifier = modifier.fillMaxSize().background(pcbGreen)) {
- val width = size.width
- val height = size.height
-
- // Draw circuit traces (horizontal and vertical lines)
- val pathEffect = PathEffect.dashPathEffect(floatArrayOf(10f, 5f), 0f)
-
- // Horizontal traces
- for (i in 0..15) {
- val y = (i * height / 15)
- drawLine(
- color = traceColor,
- start = Offset(0f, y),
- end = Offset(width, y),
- strokeWidth = 2f,
- pathEffect = pathEffect
- )
- }
-
- // Vertical traces
- for (i in 0..10) {
- val x = (i * width / 10)
- drawLine(
- color = traceColor,
- start = Offset(x, 0f),
- end = Offset(x, height),
- strokeWidth = 2f,
- pathEffect = pathEffect
- )
- }
-
- // Draw pads/components (small circles at intersections)
- for (i in 0..10 step 2) {
- for (j in 0..15 step 3) {
- val x = i * width / 10
- val y = j * height / 15
- drawCircle(
- color = padColor,
- radius = 4f,
- center = Offset(x, y)
- )
- }
- }
-
- // Draw some resistor-like rectangles
- for (i in 1..9 step 4) {
- val x = i * width / 10
- val y = height / 2
- drawRect(
- color = Color(0xFF2A4A2A),
- topLeft = Offset(x - 15f, y - 8f),
- size = androidx.compose.ui.geometry.Size(30f, 16f)
- )
- // Resistor contacts
- drawCircle(
- color = padColor,
- radius = 3f,
- center = Offset(x - 15f, y)
- )
- drawCircle(
- color = padColor,
- radius = 3f,
- center = Offset(x + 15f, y)
- )
- }
- }
-}