Сущности-предметы!
This commit is contained in:
parent
b9b4140832
commit
a0705472f8
@ -6,6 +6,7 @@ import org.lwjgl.glfw.GLFW.glfwSetWindowShouldClose
|
||||
import ru.dbotthepony.kstarbound.client.StarboundClient
|
||||
import ru.dbotthepony.kstarbound.io.*
|
||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
import java.io.ByteArrayInputStream
|
||||
@ -160,6 +161,13 @@ fun main() {
|
||||
println("$find $set $parse")
|
||||
|
||||
//client.world!!.parallax = Starbound.parallaxAccess["garden"]
|
||||
|
||||
for (i in 0 .. 16) {
|
||||
val item = ItemEntity(client.world!!, Starbound.itemAccess["brain"]!!)
|
||||
|
||||
item.position = Vector2d(600.0 + 16.0 + i, 721.0 + 48.0)
|
||||
item.spawn()
|
||||
}
|
||||
}
|
||||
|
||||
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
||||
|
@ -494,7 +494,9 @@ class GLStateTracker {
|
||||
return@computeIfAbsent named2DTextures[missingTexturePath]!!
|
||||
}
|
||||
|
||||
return@computeIfAbsent newTexture(path).upload(Starbound.readDirect(path)).generateMips()
|
||||
return@computeIfAbsent newTexture(path).upload(Starbound.readDirect(path)).generateMips().also {
|
||||
it.textureMagFilter = GL_NEAREST
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,9 @@ import ru.dbotthepony.kstarbound.client.ClientChunk
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ
|
||||
import ru.dbotthepony.kstarbound.client.render.entity.ItemRenderer
|
||||
import ru.dbotthepony.kstarbound.world.entities.Entity
|
||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||
@ -46,6 +48,7 @@ open class EntityRenderer(val state: GLStateTracker, val entity: Entity, open va
|
||||
fun getRender(state: GLStateTracker, entity: Entity, chunk: ClientChunk? = null): EntityRenderer {
|
||||
return when (entity) {
|
||||
is Projectile -> ProjectileRenderer(state, entity, chunk)
|
||||
is ItemEntity -> ItemRenderer(state, entity, chunk)
|
||||
else -> EntityRenderer(state, entity, chunk)
|
||||
}
|
||||
}
|
||||
@ -57,10 +60,6 @@ open class ProjectileRenderer(state: GLStateTracker, entity: Projectile, chunk:
|
||||
private val texture = state.loadNamedTextureSafe(def.image.texture)
|
||||
private val animator = FrameSetAnimator(def.image, def.animationCycle, entity.def.animationLoops)
|
||||
|
||||
init {
|
||||
texture.textureMagFilter = GL_NEAREST
|
||||
}
|
||||
|
||||
override fun render(stack: Matrix4fStack) {
|
||||
state.shaderVertexTexture.use()
|
||||
state.shaderVertexTexture.transform.set(stack.last)
|
||||
|
@ -0,0 +1,39 @@
|
||||
package ru.dbotthepony.kstarbound.client.render.entity
|
||||
|
||||
import org.lwjgl.opengl.GL46
|
||||
import ru.dbotthepony.kstarbound.PIXELS_IN_STARBOUND_UNITf
|
||||
import ru.dbotthepony.kstarbound.client.ClientChunk
|
||||
import ru.dbotthepony.kstarbound.client.gl.GLStateTracker
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ
|
||||
import ru.dbotthepony.kstarbound.client.render.EntityRenderer
|
||||
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||
|
||||
class ItemRenderer(state: GLStateTracker, entity: ItemEntity, chunk: ClientChunk?) : EntityRenderer(state, entity, chunk) {
|
||||
private val def = entity.def
|
||||
private val texture = def.inventoryIcon?.let(state::loadNamedTextureSafe)
|
||||
|
||||
override fun render(stack: Matrix4fStack) {
|
||||
if (texture == null)
|
||||
return
|
||||
|
||||
state.shaderVertexTexture.use()
|
||||
state.shaderVertexTexture.transform.set(stack.last)
|
||||
state.activeTexture = 0
|
||||
state.shaderVertexTexture["_texture"] = 0
|
||||
texture.bind()
|
||||
|
||||
val builder = state.flat2DTexturedQuads.small
|
||||
|
||||
builder.begin()
|
||||
|
||||
val width = (texture.width / PIXELS_IN_STARBOUND_UNITf) / 2f
|
||||
val height = (texture.height / PIXELS_IN_STARBOUND_UNITf) / 2f
|
||||
|
||||
builder.quadRotatedZ(-width, -height, width, height, 5f, 0f, 0f, entity.movement.angle, QuadTransformers.uv(0f, 1f, 1f, 0f))
|
||||
|
||||
builder.upload()
|
||||
builder.draw()
|
||||
}
|
||||
}
|
@ -160,6 +160,8 @@ abstract class Entity(override val world: World<*, *>) : IEntity {
|
||||
if (chunk == null) {
|
||||
world.orphanedEntities.add(this)
|
||||
}
|
||||
|
||||
movement.onSpawnedInWorld()
|
||||
}
|
||||
|
||||
override fun remove() {
|
||||
@ -178,8 +180,15 @@ abstract class Entity(override val world: World<*, *>) : IEntity {
|
||||
|
||||
/**
|
||||
* Контроллер перемещения данной сущности
|
||||
*
|
||||
* Контроллер перемещения реализует физические интерфейсы для KBox2D и отвечает за
|
||||
* физику сущности в мире.
|
||||
*/
|
||||
abstract override val movement: MovementController<*>
|
||||
|
||||
/**
|
||||
* Внутренний блок "раздумья" сущности, вызывается на каждом тике мира
|
||||
*/
|
||||
protected abstract fun thinkAI(delta: Double)
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,54 @@
|
||||
package ru.dbotthepony.kstarbound.world.entities
|
||||
|
||||
import ru.dbotthepony.kbox2d.api.ContactImpulse
|
||||
import ru.dbotthepony.kbox2d.api.FixtureDef
|
||||
import ru.dbotthepony.kbox2d.api.Manifold
|
||||
import ru.dbotthepony.kbox2d.collision.shapes.PolygonShape
|
||||
import ru.dbotthepony.kbox2d.dynamics.contact.AbstractContact
|
||||
import ru.dbotthepony.kstarbound.defs.item.ItemDefinition
|
||||
import ru.dbotthepony.kstarbound.world.World
|
||||
|
||||
class ItemEntity(world: World<*, *>, val def: ItemDefinition) : Entity(world) {
|
||||
override val movement = object : MovementController<ItemEntity>(this) {
|
||||
override fun beginContact(contact: AbstractContact) {
|
||||
// тут надо код подбора предмета игроком, если мы начинаем коллизию с окружностью подбора
|
||||
}
|
||||
|
||||
override fun endContact(contact: AbstractContact) {
|
||||
|
||||
}
|
||||
|
||||
override fun postSolve(contact: AbstractContact, impulse: ContactImpulse) {
|
||||
|
||||
}
|
||||
|
||||
override fun preSolve(contact: AbstractContact, oldManifold: Manifold) {
|
||||
if (contact.fixtureA.userData is ItemEntity && contact.fixtureB.userData is ItemEntity)
|
||||
contact.isEnabled = false
|
||||
}
|
||||
|
||||
override fun onSpawnedInWorld() {
|
||||
super.onSpawnedInWorld()
|
||||
|
||||
// все предметы в мире являются коробками
|
||||
val fixture = FixtureDef(
|
||||
shape = PolygonShape().also { it.setAsBox(1.0, 1.0) },
|
||||
restitution = 0.0,
|
||||
friction = 1.0,
|
||||
density = 0.3,
|
||||
)
|
||||
|
||||
fixture.userData = this@ItemEntity
|
||||
|
||||
body.createFixture(fixture)
|
||||
|
||||
// предметы не могут поворачиваться в мире, всегда падают плашмя
|
||||
body.isFixedRotation = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun thinkAI(delta: Double) {
|
||||
// TODO: деспавнинг?
|
||||
// просто, как бы, предметы не должны уж так сильно нагружать процессор
|
||||
}
|
||||
}
|
@ -17,11 +17,16 @@ abstract class MovementController<T : IEntity>(val entity: T) : IContactListener
|
||||
open var position by entity::position
|
||||
open var angle by entity::angle
|
||||
|
||||
/**
|
||||
* Уничтожает данный movement controller.
|
||||
*
|
||||
* Вызывается изнутри [Entity.remove]
|
||||
*/
|
||||
open fun destroy() {
|
||||
body.world.destroyBody(body)
|
||||
}
|
||||
|
||||
protected val body by lazy {
|
||||
private val bodyInit = lazy {
|
||||
world.physics.createBody(BodyDef(
|
||||
position = position,
|
||||
angle = angle,
|
||||
@ -30,10 +35,36 @@ abstract class MovementController<T : IEntity>(val entity: T) : IContactListener
|
||||
))
|
||||
}
|
||||
|
||||
/**
|
||||
* Было ли создано физическое тело
|
||||
*/
|
||||
val bodyInitialized: Boolean
|
||||
get() = bodyInit.isInitialized()
|
||||
|
||||
/**
|
||||
* Физическое тело данного контроллера перемещения
|
||||
*
|
||||
* Не создаётся в мире пока к нему не обратятся
|
||||
*/
|
||||
protected val body by bodyInit
|
||||
|
||||
/**
|
||||
* Вызывается изнутри [Entity], когда оно спавнится в самом мире.
|
||||
*
|
||||
* Так как никто не запрещает нам создавать физические тела в физическом мире
|
||||
* до того, как мы появимся в самом мире, это негативно сказывается на производительности И не является корректным
|
||||
* поведением.
|
||||
*
|
||||
* Поэтому, прикреплять фигуры к физическому телу лучше всего из данной функции.
|
||||
*/
|
||||
open fun onSpawnedInWorld() {
|
||||
|
||||
}
|
||||
|
||||
open val velocity get() = body.linearVelocity
|
||||
|
||||
/**
|
||||
* Returns whenever are we contacting something below us
|
||||
* Проверяет, находится ли что-либо под нами
|
||||
*/
|
||||
open val onGround: Boolean get() {
|
||||
for (contact in body.contactEdgeIterator) {
|
||||
|
@ -77,7 +77,9 @@ abstract class AbstractProjectileMovementController(entity: Projectile, val def:
|
||||
}
|
||||
|
||||
class BouncyPhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractProjectileMovementController(entity, def) {
|
||||
init {
|
||||
override fun onSpawnedInWorld() {
|
||||
super.onSpawnedInWorld()
|
||||
|
||||
body.createFixture(FixtureDef(
|
||||
shape = PolygonShape().also { it.setAsBox(0.5, 0.2) },
|
||||
restitution = 0.9,
|
||||
@ -88,7 +90,9 @@ class BouncyPhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractPro
|
||||
}
|
||||
|
||||
class FlamePhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractProjectileMovementController(entity, def) {
|
||||
init {
|
||||
override fun onSpawnedInWorld() {
|
||||
super.onSpawnedInWorld()
|
||||
|
||||
body.createFixture(FixtureDef(
|
||||
shape = PolygonShape().also { it.setAsBox(0.2, 0.2) },
|
||||
restitution = 0.0,
|
||||
|
Loading…
Reference in New Issue
Block a user