Сущности-предметы!
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.client.StarboundClient
|
||||||
import ru.dbotthepony.kstarbound.io.*
|
import ru.dbotthepony.kstarbound.io.*
|
||||||
import ru.dbotthepony.kstarbound.world.ChunkPos
|
import ru.dbotthepony.kstarbound.world.ChunkPos
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
import ru.dbotthepony.kstarbound.world.entities.PlayerEntity
|
||||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
||||||
import java.io.ByteArrayInputStream
|
import java.io.ByteArrayInputStream
|
||||||
@ -160,6 +161,13 @@ fun main() {
|
|||||||
println("$find $set $parse")
|
println("$find $set $parse")
|
||||||
|
|
||||||
//client.world!!.parallax = Starbound.parallaxAccess["garden"]
|
//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)
|
//ent.position += Vector2d(y = 14.0, x = -10.0)
|
||||||
|
@ -494,7 +494,9 @@ class GLStateTracker {
|
|||||||
return@computeIfAbsent named2DTextures[missingTexturePath]!!
|
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.GLStateTracker
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
import ru.dbotthepony.kstarbound.client.gl.vertex.QuadTransformers
|
||||||
import ru.dbotthepony.kstarbound.client.gl.vertex.quadRotatedZ
|
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.Entity
|
||||||
|
import ru.dbotthepony.kstarbound.world.entities.ItemEntity
|
||||||
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
import ru.dbotthepony.kstarbound.world.entities.projectile.Projectile
|
||||||
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
import ru.dbotthepony.kvector.matrix.Matrix4fStack
|
||||||
import ru.dbotthepony.kvector.vector.ndouble.Vector2d
|
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 {
|
fun getRender(state: GLStateTracker, entity: Entity, chunk: ClientChunk? = null): EntityRenderer {
|
||||||
return when (entity) {
|
return when (entity) {
|
||||||
is Projectile -> ProjectileRenderer(state, entity, chunk)
|
is Projectile -> ProjectileRenderer(state, entity, chunk)
|
||||||
|
is ItemEntity -> ItemRenderer(state, entity, chunk)
|
||||||
else -> EntityRenderer(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 texture = state.loadNamedTextureSafe(def.image.texture)
|
||||||
private val animator = FrameSetAnimator(def.image, def.animationCycle, entity.def.animationLoops)
|
private val animator = FrameSetAnimator(def.image, def.animationCycle, entity.def.animationLoops)
|
||||||
|
|
||||||
init {
|
|
||||||
texture.textureMagFilter = GL_NEAREST
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun render(stack: Matrix4fStack) {
|
override fun render(stack: Matrix4fStack) {
|
||||||
state.shaderVertexTexture.use()
|
state.shaderVertexTexture.use()
|
||||||
state.shaderVertexTexture.transform.set(stack.last)
|
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) {
|
if (chunk == null) {
|
||||||
world.orphanedEntities.add(this)
|
world.orphanedEntities.add(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
movement.onSpawnedInWorld()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun remove() {
|
override fun remove() {
|
||||||
@ -178,8 +180,15 @@ abstract class Entity(override val world: World<*, *>) : IEntity {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Контроллер перемещения данной сущности
|
* Контроллер перемещения данной сущности
|
||||||
|
*
|
||||||
|
* Контроллер перемещения реализует физические интерфейсы для KBox2D и отвечает за
|
||||||
|
* физику сущности в мире.
|
||||||
*/
|
*/
|
||||||
abstract override val movement: MovementController<*>
|
abstract override val movement: MovementController<*>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Внутренний блок "раздумья" сущности, вызывается на каждом тике мира
|
||||||
|
*/
|
||||||
protected abstract fun thinkAI(delta: Double)
|
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 position by entity::position
|
||||||
open var angle by entity::angle
|
open var angle by entity::angle
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Уничтожает данный movement controller.
|
||||||
|
*
|
||||||
|
* Вызывается изнутри [Entity.remove]
|
||||||
|
*/
|
||||||
open fun destroy() {
|
open fun destroy() {
|
||||||
body.world.destroyBody(body)
|
body.world.destroyBody(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val body by lazy {
|
private val bodyInit = lazy {
|
||||||
world.physics.createBody(BodyDef(
|
world.physics.createBody(BodyDef(
|
||||||
position = position,
|
position = position,
|
||||||
angle = angle,
|
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
|
open val velocity get() = body.linearVelocity
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whenever are we contacting something below us
|
* Проверяет, находится ли что-либо под нами
|
||||||
*/
|
*/
|
||||||
open val onGround: Boolean get() {
|
open val onGround: Boolean get() {
|
||||||
for (contact in body.contactEdgeIterator) {
|
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) {
|
class BouncyPhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractProjectileMovementController(entity, def) {
|
||||||
init {
|
override fun onSpawnedInWorld() {
|
||||||
|
super.onSpawnedInWorld()
|
||||||
|
|
||||||
body.createFixture(FixtureDef(
|
body.createFixture(FixtureDef(
|
||||||
shape = PolygonShape().also { it.setAsBox(0.5, 0.2) },
|
shape = PolygonShape().also { it.setAsBox(0.5, 0.2) },
|
||||||
restitution = 0.9,
|
restitution = 0.9,
|
||||||
@ -88,7 +90,9 @@ class BouncyPhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractPro
|
|||||||
}
|
}
|
||||||
|
|
||||||
class FlamePhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractProjectileMovementController(entity, def) {
|
class FlamePhysics(entity: Projectile, def: ConfiguredProjectile) : AbstractProjectileMovementController(entity, def) {
|
||||||
init {
|
override fun onSpawnedInWorld() {
|
||||||
|
super.onSpawnedInWorld()
|
||||||
|
|
||||||
body.createFixture(FixtureDef(
|
body.createFixture(FixtureDef(
|
||||||
shape = PolygonShape().also { it.setAsBox(0.2, 0.2) },
|
shape = PolygonShape().also { it.setAsBox(0.2, 0.2) },
|
||||||
restitution = 0.0,
|
restitution = 0.0,
|
||||||
|
Loading…
Reference in New Issue
Block a user