actorwithbody splitted in favour of new particle type

Former-commit-id: 121bd069d0a9eeef60f5ecb085a11a93c4b4a84d
Former-commit-id: 539b4b6916e808c01298190cf347e928f61fe62e
This commit is contained in:
Song Minjae
2017-01-21 16:52:16 +09:00
parent c9d83455a9
commit 56a012d843
49 changed files with 752 additions and 428 deletions

View File

@@ -64,4 +64,9 @@ abstract class Actor(val renderOrder: ActorOrder) : Comparable<Actor>, Runnable
}
enum class ActorOrder { BEHIND, MIDDLE, MIDTOP, FRONT }
enum class ActorOrder {
BEHIND, // tapestries, some particles (obstructed by terrain)
MIDDLE, // actors
MIDTOP, // bullets, thrown items
FRONT // fake tiles
}

View File

@@ -361,7 +361,7 @@ open class ActorHumanoid(birth: GameDate, death: GameDate? = null)
* this code base, ACCELERATION must be changed (in other words, we must deal with JERK) accordingly
* to the FRICTION.
*
* So I'm adding walkX/Y and getting the ActorWithBody.setNewNextHitbox to use the velocity value of
* So I'm adding walkX/Y and getting the ActorWithSprite.setNewNextHitbox to use the velocity value of
* walkX/Y + velocity, which is stored in variable moveDelta.
*
* Be warned.

View File

@@ -0,0 +1,14 @@
package net.torvald.terrarum.gameactors
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
/**
* Created by SKYHi14 on 2017-01-21.
*/
abstract class ActorVisible(renderOrder: ActorOrder) : Actor(renderOrder) {
open val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0)
override abstract fun update(gc: GameContainer, delta: Int)
abstract fun drawBody(g: Graphics)
abstract fun drawGlow(g: Graphics)
}

View File

@@ -7,21 +7,29 @@ import net.torvald.terrarum.gameworld.GameWorld
import net.torvald.terrarum.mapdrawer.FeaturesDrawer
import net.torvald.terrarum.tileproperties.TileCodex
import net.torvald.spriteanimation.SpriteAnimation
import net.torvald.terrarum.gamecontroller.Key
import net.torvald.terrarum.gamecontroller.KeyToggler
import net.torvald.terrarum.mapdrawer.FeaturesDrawer.TILE_SIZE
import net.torvald.terrarum.tileproperties.Tile
import net.torvald.terrarum.tileproperties.TileProp
import org.dyn4j.Epsilon
import org.dyn4j.geometry.Vector2
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
import java.util.*
/**
* Base class for every actor that has physical (or echo) body. This includes furnishings, paintings, gadgets, etc.
* Base class for every actor that has animated sprites. This includes furnishings, paintings, gadgets, etc.
* Also has all the physics
*
* @param renderOrder Rendering order (BEHIND, MIDDLE, MIDTOP, FRONT)
* @param physics
*
* Created by minjaesong on 16-01-13.
*/
open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
open class ActorWithSprite(renderOrder: ActorOrder, physics: Boolean = true) : ActorVisible(renderOrder) {
/** !! ActorValue macros are on the very bottom of the source !! **/
@@ -38,14 +46,12 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
protected var hitboxTranslateY: Double = 0.0// relative to spritePosY
protected var baseHitboxW: Int = 0
protected var baseHitboxH: Int = 0
protected var baseSpriteWidth: Int = 0
protected var baseSpriteHeight: Int = 0
/**
* * Position: top-left point
* * Unit: pixel
* !! external class should not hitbox.set(); use setHitboxDimension() and setPosition()
*/
val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // Hitbox is implemented using Double;
override val hitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // Hitbox is implemented using Double;
@Transient val nextHitbox = Hitbox(0.0, 0.0, 0.0, 0.0) // 52 mantissas ought to be enough for anybody...
val tilewiseHitbox: Hitbox
@@ -100,7 +106,10 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
get() = (actorValue.getAsDouble(AVKey.SCALE) ?: 1.0) *
(actorValue.getAsDouble(AVKey.SCALEBUFF) ?: 1.0)
set(value) {
val scaleDelta = value - scale
actorValue[AVKey.SCALE] = value / (actorValue.getAsDouble(AVKey.SCALEBUFF) ?: 1.0)
// reposition
translatePosition(-baseHitboxW * scaleDelta / 2, -baseHitboxH * scaleDelta)
}
@Transient val MASS_LOWEST = 0.1 // Kilograms
/** Apparent mass. Use "avBaseMass" for base mass */
@@ -110,7 +119,7 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
if (value <= 0)
throw IllegalArgumentException("mass cannot be less than or equal to zero.")
else if (value < MASS_LOWEST) {
println("[ActorWithBody] input too small; using $MASS_LOWEST instead.")
println("[ActorWithSprite] input too small; using $MASS_LOWEST instead.")
actorValue[AVKey.BASEMASS] = MASS_LOWEST
}
@@ -123,7 +132,7 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
if (value < 0)
throw IllegalArgumentException("invalid elasticity value $value; valid elasticity value is [0, 1].")
else if (value >= ELASTICITY_MAX) {
println("[ActorWithBody] Elasticity were capped to $ELASTICITY_MAX.")
println("[ActorWithSprite] Elasticity were capped to $ELASTICITY_MAX.")
field = ELASTICITY_MAX
}
else
@@ -149,7 +158,7 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
var density = 1000.0
set(value) {
if (value < 0)
throw IllegalArgumentException("[ActorWithBody] $value: density cannot be negative.")
throw IllegalArgumentException("[ActorWithSprite] $value: density cannot be negative.")
field = value
}
@@ -164,7 +173,7 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
/** Default to 'true' */
var isVisible = true
/** Default to 'true' */
var isUpdate = true
var isUpdate = physics
var isNoSubjectToGrav = false
var isNoCollideWorld = false
var isNoSubjectToFluidResistance = false
@@ -177,19 +186,6 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
*/
@Volatile var isChronostasis = false
/**
* Constants
*/
@Transient private val METER = 24.0
/**
* [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2]
*/
@Transient private val SI_TO_GAME_ACC = METER / (Terrarum.TARGET_FPS * Terrarum.TARGET_FPS).toDouble()
/**
* [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame]
*/
@Transient private val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
/**
* Gravitational Constant G. Load from gameworld.
* [m / s^2]
@@ -203,7 +199,7 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
get() = actorValue.getAsDouble(AVKey.DRAGCOEFF) ?: DRAG_COEFF_DEFAULT
set(value) {
if (value < 0)
throw IllegalArgumentException("[ActorWithBody] drag coefficient cannot be negative.")
throw IllegalArgumentException("[ActorWithSprite] drag coefficient cannot be negative.")
actorValue[AVKey.DRAGCOEFF] = value
}
@@ -260,23 +256,33 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
// some initialiser goes here...
}
fun makeNewSprite(w: Int, h: Int) {
sprite = SpriteAnimation(this)
sprite!!.setDimension(w, h)
fun makeNewSprite(w: Int, h: Int, image: Image) {
sprite = SpriteAnimation(this, w, h)
sprite!!.setSpriteImage(image)
}
fun makeNewSpriteGlow(w: Int, h: Int) {
spriteGlow = SpriteAnimation(this)
spriteGlow!!.setDimension(w, h)
fun makeNewSprite(w: Int, h: Int, imageref: String) {
sprite = SpriteAnimation(this, w, h)
sprite!!.setSpriteImage(imageref)
}
fun makeNewSpriteGlow(w: Int, h: Int, image: Image) {
spriteGlow = SpriteAnimation(this, w, h)
spriteGlow!!.setSpriteImage(image)
}
fun makeNewSpriteGlow(w: Int, h: Int, imageref: String) {
spriteGlow = SpriteAnimation(this, w, h)
spriteGlow!!.setSpriteImage(imageref)
}
/**
* @param w
* @param h
* @param tx positive: translate drawn sprite to LEFT.
* @param ty positive: translate drawn sprite to DOWN.
* @see ActorWithBody.drawBody
* @see ActorWithBody.drawGlow
* @param tx positive: translate sprite to LEFT.
* @param ty positive: translate sprite to DOWN.
* @see ActorWithSprite.drawBody
* @see ActorWithSprite.drawGlow
*/
fun setHitboxDimension(w: Int, h: Int, tx: Int, ty: Int) {
baseHitboxH = h
@@ -296,18 +302,23 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
*/
fun setPosition(x: Double, y: Double) {
hitbox.setFromWidthHeight(
x - (baseHitboxW / 2 - hitboxTranslateX) * (1 - scale),
y - (baseHitboxH - hitboxTranslateY) * (1 - scale),
x - (baseHitboxW / 2 - hitboxTranslateX) * scale,
y - (baseHitboxH - hitboxTranslateY) * scale,
baseHitboxW * scale,
baseHitboxH * scale)
nextHitbox.setFromWidthHeight(
x - (baseHitboxW / 2 - hitboxTranslateX) * (1 - scale),
y - (baseHitboxH - hitboxTranslateY) * (1 - scale),
x - (baseHitboxW / 2 - hitboxTranslateX) * scale,
y - (baseHitboxH - hitboxTranslateY) * scale,
baseHitboxW * scale,
baseHitboxH * scale)
}
private fun translatePosition(dx: Double, dy: Double) {
hitbox.translate(dx, dy)
nextHitbox.translate(dx, dy)
}
val centrePosVector: Vector2
get() = Vector2(hitbox.centeredX, hitbox.centeredY)
val centrePosPoint: Point2d
@@ -344,12 +355,6 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
isNoSubjectToFluidResistance = isPlayerNoClip
}
// set sprite dimension vars if there IS sprite for the actor
if (sprite != null) {
baseSpriteHeight = sprite!!.height
baseSpriteWidth = sprite!!.width
}
/**
* Actual physics thing (altering velocity) starts from here
*/
@@ -987,50 +992,64 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
private fun updateHitbox() = hitbox.reassign(nextHitbox)
open fun drawGlow(g: Graphics) {
override open fun drawGlow(g: Graphics) {
if (isVisible && spriteGlow != null) {
blendLightenOnly()
if (!sprite!!.flippedHorizontal()) {
spriteGlow!!.render(g,
(hitbox.posX - hitboxTranslateX * scale).toFloat(),
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
// Q&D fix for Roundworld anomaly
spriteGlow!!.render(g,
(hitbox.posX - hitboxTranslateX * scale).toFloat() + world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
spriteGlow!!.render(g,
(hitbox.posX - hitboxTranslateX * scale).toFloat() - world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
}
else {
spriteGlow!!.render(g,
(hitbox.posX - scale).toFloat(),
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
// Q&D fix for Roundworld anomaly
spriteGlow!!.render(g,
(hitbox.posX - scale).toFloat() + world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
spriteGlow!!.render(g,
(hitbox.posX - scale).toFloat() - world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
}
}
// debug hitbox
if (KeyToggler.isOn(Key.F11)) {
g.color = Color(1f, 0f, 1f, 1f)
blendNormal()
g.lineWidth = 1f
g.drawRect(
hitbox.posX.toFloat(),
hitbox.posY.toFloat(),
hitbox.width.toFloat(),
hitbox.height.toFloat()
)
}
}
open fun drawBody(g: Graphics) {
override open fun drawBody(g: Graphics) {
if (isVisible && sprite != null) {
@@ -1043,36 +1062,36 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
if (!sprite!!.flippedHorizontal()) {
sprite!!.render(g,
(hitbox.posX - hitboxTranslateX * scale).toFloat(),
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
// Q&D fix for Roundworld anomaly
sprite!!.render(g,
(hitbox.posX - hitboxTranslateX * scale).toFloat() + world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
sprite!!.render(g,
(hitbox.posX - hitboxTranslateX * scale).toFloat() - world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
}
else {
sprite!!.render(g,
(hitbox.posX - scale).toFloat(),
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
// Q&D fix for Roundworld anomaly
sprite!!.render(g,
(hitbox.posX - scale).toFloat() + world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
sprite!!.render(g,
(hitbox.posX - scale).toFloat() - world.width * TILE_SIZE,
(hitbox.posY + hitboxTranslateY * scale - (baseSpriteHeight - baseHitboxH) * scale + 2).toFloat(),
(hitbox.posY + hitboxTranslateY * scale).toFloat(),
(scale).toFloat()
)
}
@@ -1129,9 +1148,9 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
// warnings
if (sprite == null && isVisible)
println("[ActorWithBody] Caution: actor ${this.javaClass.simpleName} is echo but the sprite was not set.")
println("[ActorWithSprite] Caution: actor ${this.javaClass.simpleName} is echo but the sprite was not set.")
else if (sprite != null && !isVisible)
println("[ActorWithBody] Caution: actor ${this.javaClass.simpleName} is invisible but the sprite was given.")
println("[ActorWithSprite] Caution: actor ${this.javaClass.simpleName} is invisible but the sprite was given.")
assertPrinted = true
}
@@ -1190,13 +1209,30 @@ open class ActorWithBody(renderOrder: ActorOrder) : Actor(renderOrder) {
companion object {
/**
* Constants
*/
@Transient private val METER = 24.0
/**
* [m / s^2] * SI_TO_GAME_ACC -> [px / InternalFrame^2]
*/
@Transient val SI_TO_GAME_ACC = METER / (Terrarum.TARGET_FPS * Terrarum.TARGET_FPS).toDouble()
/**
* [m / s] * SI_TO_GAME_VEL -> [px / InternalFrame]
*/
@Transient val SI_TO_GAME_VEL = METER / Terrarum.TARGET_FPS
/**
* Enumerations that exported to JSON
*/
@Transient const val COLLISION_NOCOLLIDE = 0
@Transient const val COLLISION_KINEMATIC = 1 // does not displaced by external forces when collided, but it still can move (e.g. player, elevator)
@Transient const val COLLISION_DYNAMIC = 2 // displaced by external forces
@Transient const val COLLISION_STATIC = 3 // does not displaced by external forces, target of collision (e.g. nonmoving static obj)
/** does not displaced by external forces when collided, but it still can move (e.g. player, elevator) */
@Transient const val COLLISION_KINEMATIC = 1
/** displaced by external forces */
@Transient const val COLLISION_DYNAMIC = 2
/** does not displaced by external forces, target of collision (e.g. nonmoving static obj) */
@Transient const val COLLISION_STATIC = 3
@Transient const val COLLISION_KNOCKBACK_GIVER = 4 // mobs
@Transient const val COLLISION_KNOCKBACK_TAKER = 5 // benevolent NPCs
@Transient const val BLEND_NORMAL = 4

View File

@@ -18,8 +18,8 @@ object CreatureBuilder {
* @Param jsonFileName with extension
*/
@Throws(IOException::class, SlickException::class)
operator fun invoke(jsonFileName: String): ActorWithBody {
val actor = ActorWithBody(ActorOrder.MIDDLE)
operator fun invoke(jsonFileName: String): ActorWithSprite {
val actor = ActorWithSprite(ActorOrder.MIDDLE)
InjectCreatureRaw(actor.actorValue, jsonFileName)
return actor

View File

@@ -9,7 +9,7 @@ import org.newdawn.slick.Graphics
/**
* Created by minjaesong on 16-03-15.
*/
class DroppedItem(private val item: InventoryItem) : ActorWithBody(ActorOrder.MIDTOP) {
class DroppedItem(private val item: InventoryItem) : ActorWithSprite(ActorOrder.MIDTOP) {
init {
if (item.id >= ItemCodex.ITEM_COUNT_MAX)

View File

@@ -5,7 +5,7 @@ import net.torvald.spriteanimation.SpriteAnimation
/**
* Created by minjaesong on 16-06-17.
*/
open class FixtureBase : ActorWithBody(ActorOrder.BEHIND) {
open class FixtureBase(physics: Boolean = true) : ActorWithSprite(ActorOrder.BEHIND, physics) {
/**
* 0: Open
* 1: Blocked

View File

@@ -25,8 +25,7 @@ class FixtureTikiTorch : FixtureBase(), Luminous {
lightBoxList = ArrayList(1)
lightBoxList.add(Hitbox(3.0, 0.0, 4.0, 3.0))
makeNewSprite(10, 27)
sprite!!.setSpriteImage("assets/graphics/sprites/fixtures/tiki_torch.tga")
makeNewSprite(10, 27, "assets/graphics/sprites/fixtures/tiki_torch.tga")
sprite!!.setDelay(200)
sprite!!.setRowsAndFrames(1, 1)

View File

@@ -11,7 +11,7 @@ import org.newdawn.slick.Input
*
* Created by minjaesong on 16-10-10.
*/
open class HistoricalFigure(val born: GameDate, val dead: GameDate? = null) : ActorWithBody(ActorOrder.MIDDLE) {
open class HistoricalFigure(val born: GameDate, val dead: GameDate? = null) : ActorWithSprite(ActorOrder.MIDDLE) {
init {
this.actorValue["_bornyear"] = born.year

View File

@@ -31,7 +31,7 @@ open class HumanoidNPC(override val scriptPath: String, born: GameDate) : ActorH
private val aiLuaAPI: AILuaAPI
companion object {
val DEFAULT_COLLISION_TYPE = ActorWithBody.COLLISION_DYNAMIC
val DEFAULT_COLLISION_TYPE = ActorWithSprite.COLLISION_DYNAMIC
}
init {

View File

@@ -0,0 +1,68 @@
package net.torvald.terrarum.gameactors
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.ActorWithSprite.Companion.SI_TO_GAME_ACC
import net.torvald.terrarum.mapdrawer.FeaturesDrawer.TILE_SIZE
import net.torvald.terrarum.tileproperties.Tile
import net.torvald.terrarum.tileproperties.TileCodex
import org.dyn4j.geometry.Vector2
import org.newdawn.slick.GameContainer
import org.newdawn.slick.Graphics
import org.newdawn.slick.Image
/**
* Actors with static sprites and very simple physics
*
* Created by SKYHi14 on 2017-01-20.
*/
open class ParticleBase(renderOrder: ActorOrder, maxLifeTime: Int? = null) : ActorVisible(renderOrder), Projectile {
override var actorValue = ActorValue()
override @Volatile var flagDespawn = false
override fun run() {
TODO("not implemented")
}
var isNoSubjectToGrav = false
var dragCoefficient = 3.0
private val lifetimeMax = maxLifeTime ?: 5000
private var lifetimeCounter = 0
open val velocity = Vector2(0.0, 0.0)
open lateinit var image: Image
init {
}
override fun update(gc: GameContainer, delta: Int) {
lifetimeCounter += delta
if (velocity.isZero || lifetimeCounter >= lifetimeMax ||
// simple stuck check
TileCodex[Terrarum.ingame.world.getTileFromTerrain(
hitbox.pointedX.div(TILE_SIZE).floorInt(),
hitbox.pointedY.div(TILE_SIZE).floorInt()
) ?: Tile.STONE].isSolid) {
flagDespawn = true
}
// gravity, winds, etc. (external forces)
if (!isNoSubjectToGrav) {
velocity += Terrarum.ingame.world.gravitation / dragCoefficient * SI_TO_GAME_ACC
}
// combine external forces
hitbox.translate(velocity)
}
override fun drawBody(g: Graphics) {
g.drawImage(image, hitbox.centeredX.toFloat(), hitbox.centeredY.toFloat())
}
override fun drawGlow(g: Graphics) {
}
}

View File

@@ -0,0 +1,24 @@
package net.torvald.terrarum.gameactors
import org.dyn4j.geometry.Vector2
import org.newdawn.slick.Image
/**
* Created by SKYHi14 on 2017-01-20.
*/
class ParticleTestRain(posX: Double, posY: Double) : ParticleBase(ActorOrder.BEHIND, 6000) {
init {
image = Image("./assets/graphics/weathers/raindrop.tga")
val w = image.width.toDouble()
val h = image.height.toDouble()
hitbox.setFromWidthHeight(
posX - w.times(0.5),
posY - h.times(0.5),
w, h
)
velocity.y = 16.0
}
}

View File

@@ -10,7 +10,7 @@ import org.newdawn.slick.Graphics
/**
* Created by minjaesong on 16-03-05.
*/
class PhysTestBall : ActorWithBody(ActorOrder.MIDDLE) {
class PhysTestBall : ActorWithSprite(ActorOrder.MIDDLE) {
private var color = Color.orange

View File

@@ -9,7 +9,7 @@ import net.torvald.terrarum.mapdrawer.FeaturesDrawer
*/
object PlayerBuilderCynthia {
operator fun invoke(): ActorWithBody {
operator fun invoke(): ActorWithSprite {
//val p: Player = Player(GameDate(100, 143)) // random value thrown
val p: HumanoidNPC = HumanoidNPC("/net/torvald/terrarum/gameactors/ai/scripts/PokemonNPCAI.lua",
GameDate(100, 143)) // random value thrown
@@ -19,8 +19,7 @@ object PlayerBuilderCynthia {
p.actorValue[AVKey.NAME] = "Cynthia"
p.makeNewSprite(26, 42)
p.sprite!!.setSpriteImage("assets/graphics/sprites/test_player_2.tga")
p.makeNewSprite(26, 42, "assets/graphics/sprites/test_player_2.tga")
p.sprite!!.setDelay(200)
p.sprite!!.setRowsAndFrames(1, 1)

View File

@@ -26,13 +26,11 @@ object PlayerBuilderSigrid {
p.referenceID = 0x51621D // the only constant of this procedural universe
p.makeNewSprite(28, 51)
p.sprite!!.setSpriteImage("assets/graphics/sprites/test_player.tga")
p.makeNewSprite(28, 51, "assets/graphics/sprites/test_player.tga")
p.sprite!!.setDelay(200)
p.sprite!!.setRowsAndFrames(1, 1)
p.makeNewSpriteGlow(28, 51)
p.spriteGlow!!.setSpriteImage("assets/graphics/sprites/test_player_glow.tga")
p.makeNewSpriteGlow(28, 51, "assets/graphics/sprites/test_player_glow.tga")
p.spriteGlow!!.setDelay(200)
p.spriteGlow!!.setRowsAndFrames(1, 1)
@@ -66,7 +64,7 @@ object PlayerBuilderSigrid {
//p.actorValue["__selectedtile"] = 147 // test code; replace with <tile_item>.primaryUse(gc, delta)
p.actorValue["__aimhelper"] = true // TODO when you'll gonna implement it?
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 10, 0)
p.setHitboxDimension(15, p.actorValue.getAsInt(AVKey.BASEHEIGHT)!!, 11, -2) // FIXME offsetY of -2: Have no idea about the error; it's just supposed to be zero
p.inventory = ActorInventory(0x7FFFFFFF, true)

View File

@@ -4,6 +4,8 @@ import net.torvald.colourutil.CIELabUtil.darkerLab
import net.torvald.point.Point2d
import net.torvald.spriteanimation.SpriteAnimation
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.tileproperties.Tile
import net.torvald.terrarum.tileproperties.TileCodex
import org.dyn4j.geometry.Vector2
import org.newdawn.slick.Color
import org.newdawn.slick.GameContainer
@@ -15,11 +17,13 @@ import java.util.*
*
* Created by minjaesong on 16-08-29.
*/
// TODO simplified, lightweight physics (does not call PhysicsSolver)
open class ProjectileSimple(
private val type: Int,
fromPoint: Vector2, // projected coord
toPoint: Vector2 // arriving coord
) : ActorWithBody(ActorOrder.MIDTOP), Luminous, Projectile {
) : ActorWithSprite(ActorOrder.MIDTOP), Luminous, Projectile {
val damage: Int
val displayColour: Color
@@ -69,7 +73,12 @@ open class ProjectileSimple(
override fun update(gc: GameContainer, delta: Int) {
// hit something and despawn
lifetimeCounter += delta
if ((ccdCollided || grounded) || lifetimeCounter >= lifetimeMax) flagDespawn()
if (ccdCollided || grounded || lifetimeCounter >= lifetimeMax ||
// stuck check
TileCodex[Terrarum.ingame.world.getTileFromTerrain(feetPosTile[0], feetPosTile[1]) ?: Tile.STONE].isSolid
) {
flagDespawn()
}
posPre.set(centrePosPoint)

View File

@@ -10,13 +10,14 @@ import org.newdawn.slick.Image
/**
* Created by SKYHi14 on 2017-01-07.
*/
class TapestryObject(val image: Image, val artName: String, val artAuthor: String) : FixtureBase() {
class TapestryObject(val image: Image, val artName: String, val artAuthor: String) : FixtureBase(physics = false) {
// physics = false only speeds up for ~2 frames with 50 tapestries
init {
makeNewSprite(image.width, image.height)
image.filter = Image.FILTER_NEAREST
makeNewSprite(image.width, image.height, image)
setHitboxDimension(image.width, image.height, 0, 0)
sprite!!.setSpriteImage(image)
isNoSubjectToGrav = true
setPosition(Terrarum.appgc.mouseX, Terrarum.appgc.mouseY)
}

View File

@@ -3,7 +3,7 @@ package net.torvald.terrarum.gameactors
/**
* Created by minjaesong on 16-04-26.
*/
class WeaponSwung(val itemID: Int) : ActorWithBody(ActorOrder.MIDTOP), Luminous {
class WeaponSwung(val itemID: Int) : ActorWithSprite(ActorOrder.MIDTOP), Luminous {
// just let the solver use AABB; it's cheap but works just enough
/**

View File

@@ -3,7 +3,7 @@ package net.torvald.terrarum.gameactors.ai
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.AIControlled
import net.torvald.terrarum.gameactors.AVKey
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.ActorWithSprite
import net.torvald.terrarum.mapdrawer.LightmapRenderer
import net.torvald.terrarum.tileproperties.Tile
import net.torvald.terrarum.tileproperties.TileCodex
@@ -14,7 +14,7 @@ import org.luaj.vm2.lib.ZeroArgFunction
/**
* Created by minjaesong on 16-10-24.
*/
internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
internal class AILuaAPI(g: Globals, actor: ActorWithSprite) {
// FIXME when actor jumps, the actor releases left/right stick
@@ -42,6 +42,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
g["ai"]["getNearbyTiles"] = GetNearbyTiles(actor)
g["ai"]["getFloorsHeight"] = GetFloorsHeight(actor)
g["ai"]["getCeilingsHeight"] = GetCeilingsHeight(actor)
g["ai"]["getLedgesHeight"] = GetLedgesHeight(actor)
g["game"] = LuaValue.tableOf()
g["game"]["version"] = GameVersion()
@@ -50,9 +51,9 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
companion object {
/**
* Reads arbitrary ActorWithBody and returns its information as Lua table
* Reads arbitrary ActorWithSprite and returns its information as Lua table
*/
fun composeActorObject(actor: ActorWithBody): LuaTable {
fun composeActorObject(actor: ActorWithSprite): LuaTable {
val t: LuaTable = LuaTable()
t["name"] = actor.actorValue.getAsString(AVKey.NAME).toLua()
@@ -94,7 +95,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
operator fun LuaTable.set(index: Int, value: Int) { this[index] = value.toLua() }
}
class GetSelfActorInfo(val actor: ActorWithBody) : ZeroArgFunction() {
class GetSelfActorInfo(val actor: ActorWithSprite) : ZeroArgFunction() {
override fun call(): LuaValue {
return composeActorObject(actor)
}
@@ -130,13 +131,13 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
}
}
class GetX(val actor: ActorWithBody) : ZeroArgFunction() {
class GetX(val actor: ActorWithSprite) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(actor.hitbox.centeredX)
}
}
class GetY(val actor: ActorWithBody) : ZeroArgFunction() {
class GetY(val actor: ActorWithSprite) : ZeroArgFunction() {
override fun call(): LuaValue {
return LuaValue.valueOf(actor.hitbox.centeredY)
}
@@ -219,7 +220,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
}
}
class GetNearbyTiles(val actor: ActorWithBody) : OneArgFunction() {
class GetNearbyTiles(val actor: ActorWithSprite) : OneArgFunction() {
/** @param radius
*
* 3 will return 7x7 array, 0 will return 1x1, 1 will return 3x3
@@ -261,7 +262,7 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
}
}
class GetFloorsHeight(val actor: ActorWithBody) : OneArgFunction() {
class GetFloorsHeight(val actor: ActorWithSprite) : OneArgFunction() {
/** @param radius
*
* 3 will return len:7 array, 0 will return len:1, 1 will return len:3
@@ -304,14 +305,13 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
}
}
class GetCeilingsHeight(val actor: ActorWithBody) : OneArgFunction() {
/** @param radius
class GetCeilingsHeight(val actor: ActorWithSprite) : OneArgFunction() {
/** @param arg radius
*
* 3 will return 7x7 array, 0 will return 1x1, 1 will return 3x3
*
* Index: [-3] .. [0] .. [3] for radius
* Return value: floor height
* (-1): tile you can stand on
* 0: body tile (legs area)
* 1: body tile (may be vary depend on the size of the actor)
* 2+: tiles up there
@@ -348,6 +348,48 @@ internal class AILuaAPI(g: Globals, actor: ActorWithBody) {
}
}
class GetLedgesHeight(val actor: ActorWithSprite) : OneArgFunction() {
/** @param arg radius
* ==
* <- (non-solid found)
* ==
* ==
* ==
* == @ -> ledge height: 4
* =================
*/
override fun call(arg: LuaValue): LuaValue {
val radius = arg.checkint()
val searchUpLimit = 12
if (radius < 0) {
return LuaValue.NONE
}
else if (radius > 8) {
throw IllegalArgumentException("Radius too large -- must be 8 or less")
}
else {
val luatable = LuaTable()
val feetTilePos = actor.feetPosTile
for (x in feetTilePos[0] - radius..feetTilePos[0] + radius) {
// search up
var searchUpCounter = 0
while (true) {
val tile = Terrarum.ingame.world.getTileFromTerrain(x, feetTilePos[1] - searchUpCounter) ?: Tile.STONE
if (!TileCodex[tile].isSolid || searchUpCounter >= searchUpLimit) {
luatable[x - feetTilePos[0]] = searchUpCounter
break
}
searchUpCounter++
}
}
return luatable
}
}
}

View File

@@ -20,11 +20,11 @@ function generateCountMax()
end
function moveToDirection(delta)
local tiles = ai.getNearbyTiles(1)
local pits = ai.getFloorsHeight(2)
local ledges = ai.getLedgesHeight(1)
if moveMode == "left" then
if bit32.band(bit32.bor(tiles[0][-1], tiles[-1][-1]), 1) == 1 then
if pits[-1] == 1 then
ai.moveLeft(0.8)
if ledges[-1] <= jumpheight then -- no futile jumps
ai.jump()
@@ -33,7 +33,7 @@ function moveToDirection(delta)
ai.moveLeft(0.5)
end
elseif moveMode == "right" then
if bit32.band(bit32.bor(tiles[0][1], tiles[-1][1]), 1) == 1 then
if pits[1] == 1 then
ai.moveRight(0.8)
if ledges[1] <= jumpheight then -- no futile jumps
ai.jump()

View File

@@ -2,7 +2,7 @@ package net.torvald.terrarum.gameactors.physicssolver
import com.jme3.math.FastMath
import net.torvald.terrarum.Terrarum
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.ActorWithSprite
import java.util.*
/**
@@ -20,9 +20,9 @@ object CollisionSolver {
private val collListX = ArrayList<CollisionMarkings>(COLL_LIST_SIZE)
private val collListY = ArrayList<CollisionMarkings>(COLL_LIST_SIZE)
private val collCandidateX = ArrayList<Pair<ActorWithBody, ActorWithBody>>(COLL_CANDIDATES_SIZE)
private val collCandidateY = ArrayList<Pair<ActorWithBody, ActorWithBody>>(COLL_CANDIDATES_SIZE)
private var collCandidates = ArrayList<Pair<ActorWithBody, ActorWithBody>>(COLL_FINAL_CANDIDATES_SIZE)
private val collCandidateX = ArrayList<Pair<ActorWithSprite, ActorWithSprite>>(COLL_CANDIDATES_SIZE)
private val collCandidateY = ArrayList<Pair<ActorWithSprite, ActorWithSprite>>(COLL_CANDIDATES_SIZE)
private var collCandidates = ArrayList<Pair<ActorWithSprite, ActorWithSprite>>(COLL_FINAL_CANDIDATES_SIZE)
private val collCandidateStack = Stack<CollisionMarkings>()
@@ -40,7 +40,7 @@ object CollisionSolver {
// mark list x
Terrarum.ingame.actorContainer.forEach { it ->
if (it is ActorWithBody) {
if (it is ActorWithSprite) {
collListX.add(CollisionMarkings(it.hitbox.hitboxStart.x, STARTPOINT, it))
collListX.add(CollisionMarkings(it.hitbox.hitboxEnd.x, ENDPOINT, it))
}
@@ -73,7 +73,7 @@ object CollisionSolver {
// mark list y
Terrarum.ingame.actorContainer.forEach { it ->
if (it is ActorWithBody) {
if (it is ActorWithSprite) {
collListY.add(CollisionMarkings(it.hitbox.hitboxStart.y, STARTPOINT, it))
collListY.add(CollisionMarkings(it.hitbox.hitboxEnd.y, ENDPOINT, it))
}
@@ -89,7 +89,7 @@ object CollisionSolver {
else if (it.kind == ENDPOINT) {
val mark_this = it
val mark_other = collCandidateStack.pop()
val collCandidate: Pair<ActorWithBody, ActorWithBody>
val collCandidate: Pair<ActorWithSprite, ActorWithSprite>
// make sure actor with lower ID comes first
if (mark_this.actor < mark_other.actor)
collCandidate = Pair(mark_this.actor, mark_other.actor)
@@ -137,7 +137,7 @@ object CollisionSolver {
return indexOfEqFn(this, other) >= 0
}
private fun solveCollision(a: ActorWithBody, b: ActorWithBody) {
private fun solveCollision(a: ActorWithSprite, b: ActorWithSprite) {
// some of the Pair(a, b) are either duplicates or erroneously reported.
// e.g. (A, B), (B, C) and then (A, C);
// in some situation (A, C) will not making any contact with each other
@@ -170,11 +170,11 @@ object CollisionSolver {
}
}
private infix fun ActorWithBody.makesCollisionWith(other: ActorWithBody) =
this.collisionType != ActorWithBody.COLLISION_NOCOLLIDE &&
other.collisionType != ActorWithBody.COLLISION_NOCOLLIDE
private infix fun ActorWithSprite.makesCollisionWith(other: ActorWithSprite) =
this.collisionType != ActorWithSprite.COLLISION_NOCOLLIDE &&
other.collisionType != ActorWithSprite.COLLISION_NOCOLLIDE
private infix fun ActorWithBody.isCollidingWith(other: ActorWithBody): Boolean {
private infix fun ActorWithSprite.isCollidingWith(other: ActorWithSprite): Boolean {
val ax = this.hitbox.centeredX
val ay = this.hitbox.centeredY
val bx = other.hitbox.centeredX
@@ -205,7 +205,7 @@ object CollisionSolver {
data class CollisionMarkings(
val pos: Double,
val kind: Int,
val actor: ActorWithBody
val actor: ActorWithSprite
)
/**

View File

@@ -1,6 +1,6 @@
package net.torvald.terrarum.gameactors.physicssolver
import net.torvald.terrarum.gameactors.ActorWithBody
import net.torvald.terrarum.gameactors.ActorWithSprite
/**
* Created by minjaesong on 16-05-01.
@@ -11,7 +11,7 @@ object VelocitySolver {
}
private fun applyGravity(actor: ActorWithBody) {
private fun applyGravity(actor: ActorWithSprite) {
}