From a0705472f8a8f244ab24aa046a6cc81329d6910e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 30 Dec 2022 12:27:18 +0700 Subject: [PATCH] =?UTF-8?q?=D0=A1=D1=83=D1=89=D0=BD=D0=BE=D1=81=D1=82?= =?UTF-8?q?=D0=B8-=D0=BF=D1=80=D0=B5=D0=B4=D0=BC=D0=B5=D1=82=D1=8B!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/ru/dbotthepony/kstarbound/Main.kt | 8 +++ .../kstarbound/client/gl/GLStateTracker.kt | 4 +- .../client/render/EntityRenderer.kt | 7 ++- .../client/render/entity/ItemRenderer.kt | 39 ++++++++++++++ .../kstarbound/world/entities/Entity.kt | 9 ++++ .../kstarbound/world/entities/ItemEntity.kt | 54 +++++++++++++++++++ .../world/entities/MovementController.kt | 35 +++++++++++- .../world/entities/projectile/Physics.kt | 8 ++- 8 files changed, 155 insertions(+), 9 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt create mode 100644 src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ItemEntity.kt diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt index 59329406..66aff778 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/Main.kt @@ -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) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/GLStateTracker.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/GLStateTracker.kt index bb396e73..07bd97fe 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/GLStateTracker.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/gl/GLStateTracker.kt @@ -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 + } } } diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/EntityRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/EntityRenderer.kt index ab428a46..eb751da1 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/EntityRenderer.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/EntityRenderer.kt @@ -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) diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt new file mode 100644 index 00000000..84c84e19 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/client/render/entity/ItemRenderer.kt @@ -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() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/Entity.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/Entity.kt index 78022ce7..2cfea599 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/Entity.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/Entity.kt @@ -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) /** diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ItemEntity.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ItemEntity.kt new file mode 100644 index 00000000..e337e4c3 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/ItemEntity.kt @@ -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(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: деспавнинг? + // просто, как бы, предметы не должны уж так сильно нагружать процессор + } +} diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/MovementController.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/MovementController.kt index 8cc43ffe..3a877417 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/MovementController.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/MovementController.kt @@ -17,11 +17,16 @@ abstract class MovementController(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(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) { diff --git a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/projectile/Physics.kt b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/projectile/Physics.kt index 1f2b6f0c..d57ee39c 100644 --- a/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/projectile/Physics.kt +++ b/src/main/kotlin/ru/dbotthepony/kstarbound/world/entities/projectile/Physics.kt @@ -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,