├── .gitignore ├── README.md ├── assets ├── character.png ├── default.png ├── skins │ └── skin.json └── star.png ├── core ├── build.sbt ├── lib │ ├── gdx-natives.jar │ └── gdx.jar └── src │ └── main │ └── scala │ └── com │ └── rathboma │ └── playpen │ ├── PlaypenGame.scala │ ├── animation │ ├── Character.scala │ └── SpriteAnimationScreen.scala │ ├── box2dcharacter │ ├── Box2DPlayerScreen.scala │ └── Player.scala │ ├── buttons │ └── SimpleButton.scala │ ├── menu │ └── MenuScreen.scala │ ├── scene2d │ ├── Scene2dScreen.scala │ └── TextureActor.scala │ └── util │ └── Logging.scala ├── desktop ├── build.sbt ├── lib │ ├── gdx-backend-lwjgl-natives.jar │ └── gdx-backend-lwjgl.jar └── src │ └── main │ └── scala │ └── com │ └── rathboma │ └── playpen │ └── Main.scala ├── project ├── Build.scala └── plugins.sbt ├── run └── sbt /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | lib_managed/ 3 | src_managed/ 4 | project/boot/ 5 | sbtlib -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Libgdx examples in Scala 2 | ===== 3 | 4 | This repository is serving as both a learning tool for myself, and (eventually) as 5 | a reference for implementing a bunch of the libgdx examples in scala. 6 | 7 | Generally the scala in this project is not idomatic, and instead looks more like java. 8 | This is on purpose -- garbage generation is the enemy of smooth gaming. 9 | 10 | 11 | Compiling 12 | --- 13 | 14 | this should resolve all dependencies and compile: 15 | 16 | ./sbt 17 | > project desktop 18 | > compile 19 | 20 | 21 | Running: 22 | --- 23 | 24 | ./run 25 | 26 | 27 | Currently Implemented 28 | ===== 29 | 30 | 1. Box2D platformer character contols [demo'd on the badlogicgames blog](http://www.badlogicgames.com/wordpress/?p=2017) 31 | * see com/rathboma/playpen/box2dcharacter 32 | 2. Sprite Animation 33 | * see com/rathboma/playpen/animation 34 | 3. Scene2D 35 | * see com/rathboma/playpen/scene2d 36 | 37 | 38 | LICENSE: 39 | 40 | Apache 2.0 -------------------------------------------------------------------------------- /assets/character.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/assets/character.png -------------------------------------------------------------------------------- /assets/default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/assets/default.png -------------------------------------------------------------------------------- /assets/skins/skin.json: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/assets/skins/skin.json -------------------------------------------------------------------------------- /assets/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/assets/star.png -------------------------------------------------------------------------------- /core/build.sbt: -------------------------------------------------------------------------------- 1 | name := "LibGdx playpen" 2 | 3 | version := "0.1" 4 | 5 | scalaVersion := "2.8.2" 6 | 7 | libraryDependencies += "org.scalaj" % "scalaj-collection_2.8.1" % "1.2" 8 | 9 | libraryDependencies += "junit" % "junit" % "4.8.2" % "test" 10 | 11 | libraryDependencies += "org.mockito" % "mockito-all" % "1.8.4" % "test" 12 | 13 | libraryDependencies += "org.scala-tools.testing" % "specs_2.8.1" % "1.6.8" % "test" 14 | 15 | libraryDependencies += "com.novocode" % "junit-interface" % "0.8" % "test->default" -------------------------------------------------------------------------------- /core/lib/gdx-natives.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/core/lib/gdx-natives.jar -------------------------------------------------------------------------------- /core/lib/gdx.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/core/lib/gdx.jar -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/PlaypenGame.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen 2 | 3 | import com.badlogic.gdx.Gdx 4 | import com.badlogic.gdx.Game 5 | import com.badlogic.gdx.graphics.Color 6 | import com.badlogic.gdx.graphics.GL20 7 | import com.rathboma.playpen.box2dcharacter.Box2DPlayerScreen 8 | import com.rathboma.playpen.animation.SpriteAnimationScreen 9 | import com.rathboma.playpen.menu.MenuScreen 10 | 11 | 12 | class PlaypenGame(val width: Int, val height: Int) extends Game { 13 | 14 | override def create { 15 | setScreen(new MenuScreen(this)) 16 | } 17 | 18 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/animation/Character.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.animation 2 | 3 | import com.badlogic.gdx.{Gdx, Screen} 4 | import com.badlogic.gdx.graphics.{Texture} 5 | import com.badlogic.gdx.graphics.g2d.{SpriteBatch, Animation, TextureRegion} 6 | import com.badlogic.gdx.math.Vector2 7 | 8 | class Player(screen: SpriteAnimationScreen) { 9 | 10 | val position = new Vector2(screen.width / 2f, screen.height / 2f) 11 | val velocity = new Vector2(0f,0f) 12 | val COLS = 8 13 | val ROWS = 4 14 | val SPEED = 60f 15 | val TRANSITION_SPEED = 0.085f 16 | 17 | val walkSheet: Texture = SpriteAnimationScreen.characterSheet 18 | 19 | val tmp: Array[Array[TextureRegion]] = TextureRegion.split(walkSheet, walkSheet.getWidth() / COLS, walkSheet.getHeight() / ROWS) 20 | 21 | val downAnimation = new Animation(TRANSITION_SPEED, tmp(0): _*) 22 | val upAnimation = new Animation(TRANSITION_SPEED, tmp(1): _*) 23 | val leftAnimation = new Animation(TRANSITION_SPEED, tmp(2): _*) 24 | val rightAnimation = new Animation(TRANSITION_SPEED, tmp(3): _*) 25 | 26 | val spriteBatch = new SpriteBatch() 27 | 28 | val movementMappings = Map( 29 | Movement.UP -> upAnimation, 30 | Movement.DOWN -> downAnimation, 31 | Movement.LEFT -> leftAnimation, 32 | Movement.RIGHT -> rightAnimation 33 | ) 34 | var movement = Movement.NONE 35 | var currentAnimation = downAnimation 36 | var currentFrame: TextureRegion = null 37 | var stateTime = 0f 38 | 39 | def update(delta: Float) { 40 | movement match { 41 | case Movement.UP => velocity.set(0, SPEED) 42 | case Movement.DOWN => velocity.set(0, -SPEED) 43 | case Movement.RIGHT => velocity.set(SPEED, 0) 44 | case Movement.LEFT => velocity.set(-SPEED, 0) 45 | case _ => velocity.set(0f,0f) 46 | } 47 | position.add(velocity.mul(delta)) 48 | } 49 | 50 | def render() { 51 | currentAnimation = movementMappings.get(movement).getOrElse(currentAnimation) 52 | stateTime = if (movement == Movement.NONE) 0 else stateTime + Gdx.graphics.getDeltaTime() 53 | currentFrame = currentAnimation.getKeyFrame(stateTime, true) 54 | spriteBatch.begin() 55 | spriteBatch.draw(currentFrame, position.x, position.y) 56 | spriteBatch.end() 57 | } 58 | 59 | 60 | def move(int: Int) = { 61 | movement = int 62 | } 63 | 64 | 65 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/animation/SpriteAnimationScreen.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.animation 2 | 3 | import com.badlogic.gdx.{Gdx, Screen} 4 | import com.badlogic.gdx.graphics.{Texture} 5 | import com.badlogic.gdx.InputAdapter 6 | import com.badlogic.gdx.Input.Keys 7 | import com.badlogic.gdx.graphics.GL10 8 | import com.rathboma.playpen.util.Logging 9 | import com.rathboma.playpen.PlaypenGame 10 | import com.rathboma.playpen.menu.MenuScreen 11 | 12 | object Movement { 13 | val NONE = -2 14 | val LEFT = -1 15 | val RIGHT = 0 16 | val UP = 1 17 | val DOWN = 2 18 | } 19 | 20 | object SpriteAnimationScreen { 21 | val characterSheet = new Texture(Gdx.files.internal("assets/character.png")) 22 | } 23 | 24 | class SpriteAnimationScreen(game: PlaypenGame) extends InputAdapter with Screen with Logging { 25 | logger.info("SpriteAnimationScreen hi!") 26 | Gdx.input.setInputProcessor(this) 27 | val width = Gdx.graphics.getWidth 28 | val height = Gdx.graphics.getHeight 29 | 30 | var movement: Int = Movement.NONE 31 | val character = new Player(this) 32 | 33 | def render(delta: Float) { 34 | character.move(movement) 35 | character.update(delta) 36 | 37 | Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 38 | character.render() 39 | } 40 | 41 | def resize(width: Int, height: Int) { 42 | 43 | } 44 | 45 | def show { 46 | 47 | } 48 | 49 | def hide { 50 | 51 | } 52 | 53 | def pause { 54 | 55 | } 56 | 57 | def resume { 58 | 59 | } 60 | 61 | def dispose { 62 | 63 | } 64 | 65 | // input adapter 66 | 67 | override def keyDown(keycode: Int): Boolean = { 68 | 69 | movement = keycode match { 70 | case Keys.W => Movement.UP 71 | case Keys.A => Movement.LEFT 72 | case Keys.S => Movement.DOWN 73 | case Keys.D => Movement.RIGHT 74 | case Keys.ESCAPE => { 75 | game.setScreen(new MenuScreen(game)) 76 | Movement.NONE 77 | } 78 | case _ => Movement.NONE 79 | } 80 | false 81 | } 82 | 83 | override def keyUp(keycode: Int): Boolean = { 84 | movement = (movement, keycode) match { 85 | case (Movement.UP, Keys.W) => Movement.NONE 86 | case (Movement.LEFT, Keys.A) => Movement.NONE 87 | case (Movement.DOWN, Keys.S) => Movement.NONE 88 | case (Movement.RIGHT, Keys.D) => Movement.NONE 89 | case _ => movement 90 | } 91 | false 92 | } 93 | 94 | 95 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/box2dcharacter/Box2DPlayerScreen.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.box2dcharacter 2 | 3 | import com.rathboma.playpen.PlaypenGame 4 | import com.rathboma.playpen.menu.MenuScreen 5 | 6 | import com.badlogic.gdx.ApplicationListener 7 | import com.badlogic.gdx.{Gdx, Screen} 8 | import com.badlogic.gdx.Input 9 | import com.badlogic.gdx.Input.Keys 10 | import com.badlogic.gdx.InputAdapter 11 | import com.badlogic.gdx.graphics.GL10 12 | import com.badlogic.gdx.graphics.OrthographicCamera 13 | import com.badlogic.gdx.graphics.g2d.BitmapFont 14 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 15 | import com.badlogic.gdx.math.Vector2 16 | import com.badlogic.gdx.math.{Vector3, Matrix4, MathUtils} 17 | import com.badlogic.gdx.physics.box2d.BodyDef 18 | import com.badlogic.gdx.physics.box2d.BodyDef 19 | import com.badlogic.gdx.physics.box2d.BodyDef.BodyType 20 | import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer 21 | import com.badlogic.gdx.physics.box2d.CircleShape 22 | import com.badlogic.gdx.physics.box2d.Contact 23 | import com.badlogic.gdx.physics.box2d.Fixture 24 | import com.badlogic.gdx.physics.box2d.{PolygonShape, EdgeShape} 25 | import com.badlogic.gdx.physics.box2d.{World => Box2DWorld} 26 | import com.badlogic.gdx.physics.box2d.WorldManifold 27 | import com.badlogic.gdx.utils.Array 28 | import com.badlogic.gdx.graphics.Color 29 | 30 | 31 | 32 | class Box2DPlayerScreen(game: PlaypenGame) extends InputAdapter with Screen { 33 | 34 | val world = new Box2DWorld(new Vector2(0, -20), true) 35 | val player = new Player(world) 36 | val cam = new OrthographicCamera(28, 20) 37 | val renderer = new Box2DDebugRenderer() 38 | val matrix = new Matrix4() 39 | val font = new BitmapFont() 40 | font.setColor(Color.WHITE) 41 | val batch = new SpriteBatch() 42 | val point = new Vector3() 43 | Gdx.input.setInputProcessor(this) 44 | // VARS 45 | var shouldJump = false 46 | var rightPressed = false 47 | var leftPressed = false 48 | var grounded = false 49 | var stillTime = 0f 50 | 51 | 52 | 53 | createGround() 54 | for(i <- 0 to 19) { 55 | val box = createBox(BodyType.DynamicBody, MathUtils.random(), MathUtils.random(), 3) 56 | box.setTransform(MathUtils.random() * 10f - MathUtils.random() * 10f, MathUtils.random() * 10 + 6, MathUtils.random() * 2 * MathUtils.PI) 57 | } 58 | 59 | def render(delta: Float) { 60 | Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT) 61 | cam.position.set(player.position.x, player.position.y, 0) 62 | cam.update 63 | // cam.apply(Gdx.gl11) 64 | matrix.set(cam.combined) 65 | renderer.render(world, matrix) 66 | cam.project(point.set(player.position.x, player.position.y, 0)) 67 | batch.begin() 68 | font.drawMultiLine(batch, 69 | "friction: " + player.physicsFixture.getFriction() + "\ngrounded: " + grounded, 70 | point.x + 20, point.y) 71 | batch.end() 72 | update(delta) 73 | } 74 | 75 | def update(delta: Float) { 76 | val now = System.nanoTime 77 | grounded = { 78 | val g = player.isGrounded 79 | if (g) player.lastGroundTime = now 80 | g || now - player.lastGroundTime < 100000000 81 | } 82 | 83 | player.limitVelocity() 84 | 85 | if(!leftPressed && !rightPressed) { 86 | stillTime = stillTime + Gdx.graphics.getDeltaTime() 87 | player.box.setLinearVelocity(player.velocity.x * 0.9f, player.velocity.y) 88 | } 89 | 90 | if (grounded) { 91 | if(leftPressed || rightPressed) { 92 | player.physicsFixture.setFriction(0.2f) 93 | player.sensorFixture.setFriction(0.2f) 94 | stillTime = 0 95 | } else if(stillTime > 0.2) { 96 | player.physicsFixture.setFriction(100f) 97 | player.sensorFixture.setFriction(100f) 98 | } 99 | } else { 100 | player.physicsFixture.setFriction(0f) 101 | player.sensorFixture.setFriction(0f) 102 | } 103 | 104 | if (leftPressed) player.moveLeft 105 | if (rightPressed) player.moveRight 106 | 107 | if (shouldJump) { 108 | shouldJump = false 109 | if (grounded) { 110 | player.jump() 111 | } 112 | } 113 | world.step(Gdx.graphics.getDeltaTime(), 4, 4) 114 | player.box.setAwake(true) 115 | 116 | } 117 | 118 | override def keyDown(keycode: Int) = { 119 | if (keycode == Keys.W) shouldJump = true 120 | if (keycode == Keys.A) leftPressed = true 121 | if (keycode == Keys.D) rightPressed = true 122 | if (keycode == Keys.ESCAPE) game.setScreen(new MenuScreen(game)) 123 | false 124 | } 125 | 126 | override def keyUp(keycode: Int) = { 127 | if (keycode == Keys.W) shouldJump = false 128 | if (keycode == Keys.A) leftPressed = false 129 | if (keycode == Keys.D) rightPressed = false 130 | false 131 | } 132 | 133 | def createGround() = { 134 | var y1 = 1f 135 | var y2 = y1 136 | 137 | for (i <- 0 until 49) { 138 | val ground = createEdge(BodyType.StaticBody, -50 + i * 2, y1, -50 + i * 2 + 2, y2, 0) 139 | y1 = y2 140 | y2 = 1 //(float)Math.random() + 1; 141 | } 142 | } 143 | 144 | def createEdge(t: BodyType, x1: Float, y1: Float, x2: Float, y2: Float, density: Float) = { 145 | val bDef = new BodyDef 146 | bDef.`type` = t 147 | val box = world.createBody(bDef) 148 | val poly = new EdgeShape() 149 | poly.set(new Vector2(0, 0), new Vector2(x2 - x1, y2 - y1)) 150 | box.createFixture(poly, density) 151 | box.setTransform(x1, y1, 0) 152 | poly.dispose() 153 | box 154 | } 155 | 156 | def createBox(bType: BodyType, width: Float, height: Float, density: Float) = { 157 | val bDef = new BodyDef() 158 | bDef.`type` = bType 159 | val box = world.createBody(bDef) 160 | val poly = new PolygonShape() 161 | poly.setAsBox(width, height) 162 | box.createFixture(poly, density) 163 | poly.dispose() 164 | box 165 | } 166 | 167 | 168 | def resize(width: Int, height: Int) { 169 | 170 | } 171 | 172 | def show { 173 | 174 | } 175 | 176 | def hide { 177 | 178 | } 179 | 180 | def pause { 181 | 182 | } 183 | 184 | def resume { 185 | 186 | } 187 | 188 | def dispose { 189 | 190 | } 191 | 192 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/box2dcharacter/Player.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.box2dcharacter 2 | 3 | 4 | import scalaj.collection.Imports._ 5 | import com.badlogic.gdx.math.Vector2 6 | import com.badlogic.gdx.math.{Vector3, Matrix4, MathUtils} 7 | import com.badlogic.gdx.physics.box2d.Body 8 | import com.badlogic.gdx.physics.box2d.BodyDef 9 | import com.badlogic.gdx.physics.box2d.BodyDef.BodyType 10 | import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer 11 | import com.badlogic.gdx.physics.box2d.CircleShape 12 | import com.badlogic.gdx.physics.box2d.Contact 13 | import com.badlogic.gdx.physics.box2d.Fixture 14 | import com.badlogic.gdx.physics.box2d.PolygonShape 15 | import com.badlogic.gdx.physics.box2d.{World => Box2DWorld} 16 | 17 | 18 | class Player(world: Box2DWorld) { 19 | var doJump = false 20 | val MAX_VELOCITY = 7f 21 | 22 | val box = { 23 | val bodyDef = new BodyDef() 24 | bodyDef.`type` = BodyType.DynamicBody 25 | world.createBody(bodyDef) 26 | } 27 | 28 | val physicsFixture = { 29 | val poly = new PolygonShape 30 | poly.setAsBox(0.45f, 1.4f) 31 | val physicsFixture = box.createFixture(poly, 1) 32 | poly.dispose 33 | physicsFixture 34 | } 35 | 36 | val sensorFixture = { 37 | val circle = new CircleShape 38 | circle.setRadius(0.45f) 39 | circle.setPosition(new Vector2(0, -1.4f)) 40 | val sensorFixture = box.createFixture(circle, 0) 41 | circle.dispose 42 | sensorFixture 43 | } 44 | box.setBullet(true) 45 | 46 | box.setTransform(10.0f, 4.0f, 0) 47 | box.setFixedRotation(true) 48 | 49 | var lastGroundTime: Long = 0 50 | 51 | def velocity = box.getLinearVelocity 52 | def position = box.getPosition 53 | 54 | def limitVelocity() = { 55 | velocity.x = math.signum(velocity.x) * MAX_VELOCITY 56 | box.setLinearVelocity(velocity.x, velocity.y) 57 | } 58 | 59 | def jump(): Unit = { 60 | box.setLinearVelocity(velocity.x, 0) 61 | System.out.println("jump before: " + velocity) 62 | box.setTransform(position.x, position.y + 0.01f, 0) 63 | box.applyLinearImpulse(0, 30, position.x, position.y) 64 | System.out.println("jump, " + velocity) 65 | } 66 | 67 | def moveLeft(): Unit = if (velocity.x > -MAX_VELOCITY) { 68 | box.applyLinearImpulse(-2f, 0, position.x, position.y) 69 | } 70 | 71 | def moveRight(): Unit = if (velocity.x < MAX_VELOCITY) { 72 | box.applyLinearImpulse(2f, 0, position.x, position.y) 73 | } 74 | 75 | def isGrounded: Boolean = world.getContactList.asScala.exists{contact => 76 | if (contact.isTouching() && ( 77 | contact.getFixtureA == sensorFixture || 78 | contact.getFixtureB == sensorFixture)) { 79 | val position = box.getPosition 80 | val manifold = contact.getWorldManifold 81 | var below = false 82 | manifold.getPoints.foreach{point => 83 | below = (point.y < position.y - 1.5f) || below 84 | } 85 | if (below) true else false 86 | } else false 87 | } 88 | 89 | 90 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/buttons/SimpleButton.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.buttons 2 | 3 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 4 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer 5 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer._ 6 | import com.badlogic.gdx.graphics.g2d.BitmapFont 7 | import com.badlogic.gdx.graphics.Color 8 | import com.badlogic.gdx.graphics.g2d.BitmapFont.HAlignment 9 | import com.rathboma.playpen.util.Logging 10 | 11 | class SimpleButton(text: String, x: Int, y: Int)(func: => Boolean) extends Logging { 12 | 13 | val font = new BitmapFont() 14 | val bounds = font.getBounds(text) 15 | val w = bounds.width * 2 16 | val h = bounds.height * 2 17 | 18 | // evil vars 19 | var pressed = false 20 | var down = false 21 | 22 | 23 | def touchDown() = { 24 | down = true 25 | } 26 | 27 | def touchUp() = { 28 | down = false 29 | func 30 | } 31 | 32 | def includes(xt: Int, yt: Int): Boolean = { 33 | 34 | val result = xt >= x - (w/2) && xt <= x + (w/2) && yt >= y - (h / 2) && yt <= y + (h/2) 35 | logger.debug("button '%s' includes point? %s".format(text, result.toString)) 36 | result 37 | } 38 | 39 | def drawShapes(renderer: ShapeRenderer) = { 40 | renderer.begin(ShapeType.FilledRectangle) 41 | renderer.setColor(if (down) Color.RED else Color.BLUE) 42 | renderer.filledRect(x - (w/2), y - (h/2), w, h) 43 | renderer.end() 44 | } 45 | 46 | def draw(batch: SpriteBatch) = { 47 | batch.setColor(Color.WHITE) 48 | font.draw(batch, text, x - (bounds.width / 2), y + (bounds.height / 2)) 49 | } 50 | 51 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/menu/MenuScreen.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.menu 2 | 3 | import com.badlogic.gdx.{Gdx, Screen} 4 | import com.badlogic.gdx.scenes.scene2d.InputEvent 5 | import com.badlogic.gdx.scenes.scene2d.InputListener 6 | import com.badlogic.gdx.scenes.scene2d.Stage 7 | import com.badlogic.gdx.graphics.g2d.BitmapFont 8 | import com.badlogic.gdx.scenes.scene2d.ui.{Table, TextButton, Skin} 9 | import com.badlogic.gdx.scenes.scene2d.ui.TextButton.TextButtonStyle 10 | import com.rathboma.playpen.box2dcharacter.Box2DPlayerScreen 11 | import com.rathboma.playpen.animation.SpriteAnimationScreen 12 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 13 | import com.rathboma.playpen.buttons._ 14 | import com.badlogic.gdx.graphics.glutils.ShapeRenderer 15 | import com.badlogic.gdx.graphics.GL10 16 | import com.badlogic.gdx.InputAdapter 17 | import com.rathboma.playpen.util.Logging 18 | import com.rathboma.playpen.PlaypenGame 19 | import com.rathboma.playpen.scene2d.Scene2DScreen 20 | 21 | class MenuScreen(game: PlaypenGame) extends InputAdapter with Screen with Logging { 22 | Gdx.input.setInputProcessor(this) 23 | logger.info("menu screen start") 24 | val batch = new SpriteBatch() 25 | val renderer = new ShapeRenderer() 26 | 27 | val middle = game.width / 2 28 | val quarterHeight = game.height / 4 29 | 30 | val box2dButton = new SimpleButton("Box2D Demo", middle, quarterHeight)({ 31 | game.setScreen(new Box2DPlayerScreen(game)) 32 | true 33 | }) 34 | val animationButton = new SimpleButton("Character Animation",middle, quarterHeight*2)({ 35 | game.setScreen(new SpriteAnimationScreen(game)) 36 | true 37 | }) 38 | 39 | val scene2dButton = new SimpleButton("Scene2D", middle, quarterHeight*3)({ 40 | game.setScreen(new Scene2DScreen(game)) 41 | true 42 | }) 43 | 44 | val buttons = List(box2dButton, animationButton, scene2dButton) 45 | 46 | def render(delta: Float) { 47 | 48 | Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT); 49 | buttons.foreach{button => 50 | button.drawShapes(renderer) 51 | } 52 | 53 | batch.begin() 54 | buttons.foreach{button => 55 | button.draw(batch) 56 | } 57 | batch.end() 58 | } 59 | 60 | val dimensions: Tuple2[Int, Int] = (game.width, game.height) 61 | 62 | override def touchDown(x: Int, screenY: Int, pointer: Int, button: Int): Boolean = { 63 | val y = game.height - screenY 64 | logger.info("TOUCH DOWN %d, %d".format(x, y)) 65 | buttons.foreach{button => 66 | if (button.includes(x, y)) button.touchDown() 67 | } 68 | true 69 | } 70 | 71 | override def touchUp(x: Int, screenY: Int, pointer: Int, button: Int): Boolean = { 72 | val y = game.height - screenY 73 | logger.info("TOUCH UP %d, %d".format(x, y)) 74 | buttons.foreach{button => 75 | if (button.includes(x, y)) button.touchUp() 76 | } 77 | true 78 | } 79 | 80 | override def keyDown(kc: Int) = { 81 | logger.info("KEY DOWN: %d".format(kc)) 82 | true 83 | } 84 | 85 | 86 | def resize(width: Int, height: Int) { 87 | 88 | } 89 | 90 | def show { 91 | 92 | } 93 | 94 | def hide { 95 | 96 | } 97 | 98 | def pause { 99 | 100 | } 101 | 102 | def resume { 103 | 104 | } 105 | 106 | def dispose { 107 | 108 | } 109 | 110 | 111 | 112 | 113 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/scene2d/Scene2dScreen.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.scene2d 2 | 3 | import com.badlogic.gdx.graphics.OrthographicCamera 4 | import com.rathboma.playpen.PlaypenGame 5 | import com.badlogic.gdx.scenes.scene2d.{Stage, Group} 6 | import com.badlogic.gdx.scenes.scene2d.actions.Actions 7 | import com.badlogic.gdx.graphics.Texture 8 | import com.badlogic.gdx.graphics.GL10 9 | import com.badlogic.gdx.{InputAdapter, Gdx, Screen} 10 | 11 | 12 | class Scene2DScreen(game: PlaypenGame) extends InputAdapter with Screen { 13 | 14 | val camera = new OrthographicCamera() 15 | camera.setToOrtho(true) 16 | 17 | val stage = new Stage(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), true) 18 | stage.setCamera(camera) 19 | Gdx.input.setInputProcessor(stage) 20 | val character = new TextureActor(new Texture("assets/star.png")) 21 | val group = new Group() 22 | group.addActor(character) 23 | group.setOrigin(96, 96) 24 | group.setPosition(600,100) 25 | stage.addActor(group) 26 | 27 | val moveAction = Actions.moveTo(600, 400, 5) 28 | val moveAction2 = Actions.moveTo(100, 100, 5) 29 | val rotateAction = Actions.repeat(-1, Actions.rotateBy(360, 2)) 30 | val together = Actions.parallel(Actions.sequence(moveAction, moveAction2), rotateAction) 31 | group.addAction(together) 32 | 33 | def render(delta: Float) { 34 | Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT) 35 | camera.update() 36 | stage.act(Gdx.graphics.getDeltaTime()) 37 | stage.draw() 38 | } 39 | 40 | def resize(width: Int, height: Int) { 41 | stage.setViewport(width, height, true); 42 | } 43 | 44 | def show { 45 | 46 | } 47 | 48 | def hide { 49 | 50 | } 51 | 52 | def pause { 53 | 54 | } 55 | 56 | def resume { 57 | 58 | } 59 | 60 | def dispose { 61 | 62 | } 63 | 64 | 65 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/scene2d/TextureActor.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen.scene2d 2 | import com.badlogic.gdx.graphics.g2d.TextureRegion 3 | import com.badlogic.gdx.graphics.Texture 4 | import com.badlogic.gdx.scenes.scene2d.Actor 5 | import com.badlogic.gdx.graphics.g2d.SpriteBatch 6 | 7 | class TextureActor(texture: Texture) extends Actor { 8 | val region = new TextureRegion(texture) 9 | region.flip(false, true) 10 | 11 | override def draw(batch: SpriteBatch, parentAlpha: Float) { 12 | batch.draw(region, getX(), getY()) 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /core/src/main/scala/com/rathboma/playpen/util/Logging.scala: -------------------------------------------------------------------------------- 1 | 2 | package com.rathboma.playpen.util 3 | import com.badlogic.gdx.utils.Logger 4 | 5 | trait Logging { 6 | val logger = new Logger(getClass.getName, Logger.DEBUG) 7 | } -------------------------------------------------------------------------------- /desktop/build.sbt: -------------------------------------------------------------------------------- 1 | name := "Libgdx Playpen Desktop yo" 2 | 3 | scalaVersion := "2.8.2" 4 | 5 | version := "0.1" -------------------------------------------------------------------------------- /desktop/lib/gdx-backend-lwjgl-natives.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/desktop/lib/gdx-backend-lwjgl-natives.jar -------------------------------------------------------------------------------- /desktop/lib/gdx-backend-lwjgl.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rathboma/scala-libgdx-examples/3cef35948466ecf120acb2046d7cf304da27c730/desktop/lib/gdx-backend-lwjgl.jar -------------------------------------------------------------------------------- /desktop/src/main/scala/com/rathboma/playpen/Main.scala: -------------------------------------------------------------------------------- 1 | package com.rathboma.playpen 2 | 3 | 4 | import com.badlogic.gdx.backends.lwjgl.LwjglApplication; 5 | import com.badlogic.gdx.backends.lwjgl.LwjglApplicationConfiguration; 6 | 7 | object Main { 8 | def main(arg: Array[String]) = { 9 | val cfg = new LwjglApplicationConfiguration() 10 | cfg.title = "puzzleplatform" 11 | cfg.useGL20 = true 12 | cfg.width = 800 13 | cfg.height = 480 14 | cfg.resizable = false 15 | 16 | new LwjglApplication(new PlaypenGame(cfg.width, cfg.height), cfg) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /project/Build.scala: -------------------------------------------------------------------------------- 1 | import sbt._ 2 | 3 | import Keys._ 4 | import AndroidKeys._ 5 | import sbtassembly.Plugin._ 6 | import AssemblyKeys._ 7 | 8 | object General { 9 | val settings = Defaults.defaultSettings ++ Seq ( 10 | name := "Playpen", 11 | version := "0.1", 12 | versionCode := 0, 13 | scalaVersion := "2.8.2", 14 | platformName in Android := "android-10" 15 | ) 16 | 17 | val proguardSettings = Seq ( 18 | useProguard in Android := true 19 | ) 20 | 21 | lazy val fullAndroidSettings = 22 | General.settings ++ 23 | AndroidProject.androidSettings ++ 24 | TypedResources.settings ++ 25 | proguardSettings ++ 26 | AndroidManifestGenerator.settings ++ 27 | AndroidMarketPublish.settings ++ Seq ( 28 | keyalias in Android := "playpen", 29 | libraryDependencies += "org.scalatest" %% "scalatest" % "1.8.RC1" % "test" 30 | ) 31 | } 32 | 33 | object AndroidBuild extends Build { 34 | lazy val core = Project ( 35 | "core", 36 | file("core") 37 | ) 38 | 39 | // lazy val android = Project ( 40 | // "android", 41 | // file("android"), 42 | // settings = General.fullAndroidSettings 43 | // ) dependsOn core 44 | 45 | lazy val desktop = Project ( 46 | "desktop", 47 | file("desktop"), 48 | settings = Defaults.defaultSettings ++ assemblySettings ++ Seq ( 49 | mainClass in assembly := Some("com.rathboma.playpen.Main") 50 | ) 51 | ) dependsOn core 52 | 53 | // lazy val tests = Project ( 54 | // "tests", 55 | // file("tests"), 56 | // settings = General.settings ++ 57 | // AndroidTest.androidSettings ++ 58 | // General.proguardSettings ++ Seq ( 59 | // name := "Sheep HerderTests" 60 | // ) 61 | // ) dependsOn core 62 | } 63 | -------------------------------------------------------------------------------- /project/plugins.sbt: -------------------------------------------------------------------------------- 1 | resolvers += Resolver.url("scalasbt releases", new URL("http://scalasbt.artifactoryonline.com/scalasbt/sbt-plugin-releases"))(Resolver.ivyStylePatterns) 2 | 3 | addSbtPlugin("org.scala-sbt" % "sbt-android-plugin" % "0.6.1") 4 | 5 | addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.8.4") -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | ./sbt "project desktop" "run-main com.rathboma.playpen.Main" -------------------------------------------------------------------------------- /sbt: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #------------------------------------------------------------------ 3 | # sbt driver script. 4 | #------------------------------------------------------------------ 5 | 6 | sbtdir=./sbtlib 7 | version="0.11.3" 8 | jarname="sbt-launch-$version.jar" 9 | if [ ! -d "$sbtdir" ] || [ ! -f "$sbtdir/$jarname" ]; then 10 | 11 | echo "Fetching sbt version $version" 12 | mkdir -p sbtlib 13 | curl "http://typesafe.artifactoryonline.com/typesafe/ivy-releases/org.scala-sbt/sbt-launch/$version/sbt-launch.jar" > sbtlib/$jarname 14 | echo "sbt launch fetched, starting sbt proper...." 15 | sleep 2 16 | fi 17 | 18 | maxheap=2048M 19 | debug= 20 | 21 | if [ -n "$debug" ]; then 22 | echo "Running in debug mode, port: $debug" 23 | JAVA_OPTIONS="$JAVA_OPTIONS -verbosegc -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=$debug" 24 | fi 25 | 26 | # -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m is supposed to reduce PermGen errors. 27 | echo env java $JAVA_OPTIONS -Xmx$maxheap -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -jar sbtlib/$jarname "$@" 28 | env java $JAVA_OPTIONS -Xmx$maxheap -XX:+CMSClassUnloadingEnabled -XX:MaxPermSize=256m -jar sbtlib/$jarname "$@" --------------------------------------------------------------------------------