API
Criaturas
Una criatura propia usa el cuerpo de una criatura del juego (su modelo, sus animaciones, su tamaño y su forma de moverse) con tu textura pintada encima, tus estadísticas, tu comportamiento y tu botín. Se declara como el resto del contenido: una lista de propiedades.
Declarar una criatura
creature "ghost" {
body: "minecraft:zombie"
texture: "entity/ghost"
health: 40
speed: 0.3
attack: 4
behaviour: ["swim", "melee_attack", { wander: 0.8 }, { look_at_players: 10 }, "look_around"]
targets: ["hurt_by", "minecraft:pig"]
loot: [ { item: "ghostmod:ecto", count: [1, 2] } ]
}| Propiedad | Valores | Por defecto |
|---|---|---|
body |
id de una criatura del juego: minecraft:zombie, minecraft:wolf, minecraft:cow… |
obligatoria |
texture |
ruta de la textura, pintada sobre el modelo del cuerpo: entity/ghost es textures/entity/ghost.png del mod |
el aspecto del cuerpo |
model |
tu propio modelo 3D: entity/robot es models/entity/robot.json del mod (abajo) |
el modelo del cuerpo |
size |
[width, height] en bloques: con qué colisiona y dónde se le hace clic (abajo) |
el del cuerpo |
health |
puntos de vida | los del cuerpo |
speed |
velocidad al andar (un zombi va a 0.23, un lobo a 0.3) | la del cuerpo |
attack |
daño de su ataque cuerpo a cuerpo | el del cuerpo |
follow_range |
a cuántos bloques detecta a sus objetivos | el del cuerpo |
behaviour |
lista de comportamientos, del más importante al menos (abajo) | el comportamiento del cuerpo |
targets |
a quién ataca, en orden de prioridad (abajo) | a nadie |
loot |
[{ item, count, chance }, …], como en los bloques: cada objeto se sortea por separado |
nada |
spawns |
biomas donde aparece sola, con peso y tamaño de grupo (abajo) | no aparece sola |
breed_item |
objeto que hace que dos se reproduzcan (abajo) | no se reproduce |
tame_item |
objeto que la doma (abajo) | no se puede domar |
rideable |
true permite montarla (abajo) |
false |
Comportamientos
La lista es la prioridad: cuando dos quieren actuar a la vez, gana el que va antes. Cada uno se escribe como un nombre, como { nombre: número } para su ajuste principal, o como un mapa con todos sus ajustes.
| Comportamiento | Qué hace | Ajustes |
|---|---|---|
"swim" |
Se mantiene a flote en el agua. | |
"look_around" |
Mira a su alrededor cuando no hace nada. | |
"wander", { wander: 0.8 } |
Pasea. | speed, por defecto 1 |
"look_at_players", { look_at_players: 10 } |
Mira a los jugadores cercanos. | range en bloques, por defecto 8 |
"melee_attack", { melee_attack: 1.2 } |
Persigue y golpea a su objetivo. | speed, por defecto 1 |
"panic", { panic: 1.5 } |
Huye cuando recibe daño. | speed, por defecto 1.25 |
{ avoid: "minecraft:wolf", distance: 8, speed: 1.2 } |
Se aleja de esa criatura. | distance en bloques, speed |
{ follow: "minecraft:wheat", speed: 1 } |
Sigue a quien lleve ese ítem en la mano. | speed |
{ ranged_attack: "minecraft:snowball", interval: 20, range: 14, damage: 3 } |
Dispara un proyectil a su objetivo (abajo). | projectile, interval, range, speed, power, damage |
"breed", { breed: 1 } |
Se reproduce con otra de su especie cuando la han alimentado. | speed |
"follow_parent", { follow_parent: 1.1 } |
Una cría se queda cerca de su progenitor. | speed |
{ follow_owner: 1.2, distance: 8 } |
Una criatura domada sigue a su dueño. | speed, distance en bloques |
{ fly_around: 1 } |
Vuela de un lado a otro; para cuerpos voladores (loro, abeja, allay). | speed |
{ can_start: …, tick: … } |
Tu propio código (abajo). | can_start, tick, keep_going, moves |
Los números de velocidad multiplican la velocidad base de la criatura: { wander: 0.8 } pasea un poco más despacio de lo que anda.
Objetivos
targets dice a quién ataca, del más prioritario al menos. "hurt_by" es quien le haga daño; un id de entidad es el más cercano de esa clase ("minecraft:player" para los jugadores, "minecraft:pig" para los cerdos). Para que el ataque ocurra, la criatura necesita un comportamiento que lo ejecute, como "melee_attack".
Hacerla aparecer
command haunt requires "ghostmod.haunt" describe "Summon a ghost where you stand" {
if player == null { return "Players only" }
world().spawn("ghostmod:ghost", player.location)
return "&7A ghost appears…"
}El id es el de tu mod: ghostmod:ghost. También sirve el comando del juego /summon ghostmod:ghost.
Que aparezcan solas
Añade spawns y la criatura aparece sola en el mundo, como las criaturas del propio juego.
creature "ghost" {
body: "minecraft:zombie"
spawns: [ { biomes: ["minecraft:dark_forest", "#minecraft:is_forest"], weight: 20, group: [1, 2] } ]
}Cada entrada indica los biomes donde aparece (un id, o una #etiqueta para todo un grupo de biomas), un weight (peso: con qué frecuencia, comparado con las demás criaturas de ese bioma; una vaca tiene 8, un zombi 95) y un rango de tamaño de group (grupo).
Sigue las reglas de aparición de su cuerpo: con cuerpo de zombi aparece en la oscuridad, con cuerpo de vaca sobre la hierba y con luz. Vale tanto al generarse el mundo como después.
Huevo generador. Cada criatura recibe además un huevo generador, su id más _spawn_egg (ghost_spawn_egg), en la pestaña creativa de huevos generadores. Su textura es textures/item/ghost_spawn_egg.png del mod, si existe; si no, se ve como el huevo de su cuerpo.
En Kotlin:
content.creature("ghost") {
body = "minecraft:zombie"
spawn("minecraft:dark_forest", "#minecraft:is_forest", weight = 20, group = 1..2)
}Dirigir una criatura desde el código
Las criaturas que declaras, y cualquier otro mob, son una Creature. Desde un evento, un comando o un temporizador puedes darles órdenes:
| Miembro | Qué hace |
|---|---|
target |
A quién ataca. Se puede leer y asignar. |
moveTo(location, speed), move_to |
Camina hasta una ubicación. La velocidad multiplica su velocidad normal. |
stop() |
Deja de caminar. |
isMoving, is_moving |
Si está yendo a algún sitio. |
lookAt(location), look_at |
Se gira para mirar una ubicación. |
canSee(entity), can_see |
Si tiene línea de visión directa hacia esa entidad. |
isBaby |
Si es una cría. |
ownerId |
El id de su dueño, una vez domada. |
tame(player) |
Hace que ese jugador sea su dueño. |
isSitting |
Si está sentada. |
playAnimation(name), play_animation |
Reproduce una de las animaciones de su modelo (ver abajo). |
Toda entidad tiene una velocity, un Vector en bloques por tick. Léela o asígnala para empujar a la entidad: entity.velocity = vector(0, 0.6, 0) la lanza hacia arriba.
En CraftScript, un let con tipo reduce una entidad a criatura. Se comprueba al ejecutarse:
command pup requires "dogmod.pup" describe "Get a pet dog" {
if player == null { return "Players only" }
let dog: Creature = world().spawn("dogmod:dog", player.location)
dog.tame(player)
dog.look_at(player.location)
dog.velocity = vector(0, 0.6, 0) // a little hop
return "&7Good dog!"
}Comportamientos propios
Cuando los incluidos no bastan, escribe uno con tu propio código. Va en la lista behaviour como cualquier otro, así que su posición es su prioridad.
creature "herder" {
body: "minecraft:wolf"
targets: ["minecraft:pig"]
behaviour: [
"swim",
{
can_start: fun(c) { return c.target != null && c.can_see(c.target) },
tick: fun(c) {
if c.target != null {
c.look_at(c.target.location)
if !c.is_moving { c.move_to(c.target.location, 1.2) }
}
}
},
{ wander: 1 }
]
}can_start: se consulta cada pocos ticks; devuelve si debe empezar.tick: se ejecuta cada tick mientras el comportamiento está activo.keep_going: indica si debe seguir. Si se omite, es igual quecan_start.moves:truepor defecto. Un comportamiento que se mueve no corre a la vez que otro que también se mueve; gana el que va antes en la lista. Usafalsepara los que solo miran o reaccionan.
En Kotlin: Behaviour.Custom(canStart = { … }, tick = { … }, keepGoing = …, moves = true)
Animales: criar, domar, montar y volar
Unas pocas propiedades y comportamientos convierten una criatura en un animal. Esta se cría con manzanas, se doma con un hueso y se puede montar:
creature "mooble" {
body: "minecraft:cow"
tame_item: "minecraft:bone"
breed_item: "minecraft:apple"
rideable: true
behaviour: ["swim", { breed: 1 }, { follow_parent: 1.1 }, { follow_owner: 1.2, distance: 8 }, { wander: 0.8 }]
}- Criar.
breed_itemmás el comportamiento"breed": alimentadas con ese objeto, dos de la misma especie tienen una cría de esa especie. Necesita un cuerpo de animal (vaca, lobo, gallina…). Las crías usan"follow_parent"para no alejarse de sus progenitores. - Domar.
tame_item: cada intento funciona una vez de cada tres. Se recuerda al dueño, y una criatura domada nunca ataca a su dueño. Agáchate y usa con la mano vacía para que se siente o se levante.{ follow_owner: 1.2, distance: 8 }hace que siga a su dueño. - Montar.
rideable: true: usa con la mano vacía para subirte (una vez domada, solo su dueño). Se dirige con las teclas de movimiento y el ratón; agáchate para bajar. - Volar.
{ fly_around: 1 }para cuerpos voladores (loro, abeja, allay). Una criaturarideablecon cuerpo volador sube cuando su jinete mira hacia arriba y baja en picado cuando mira hacia abajo.
En Kotlin: breedItem = …, tameItem = …, rideable = true y los comportamientos Behaviour.Breed(), Behaviour.FollowParent(), Behaviour.FollowOwner(speed, distance) y Behaviour.FlyAround().
Proyectiles propios
Además de los proyectiles del juego, un mod puede declarar los suyos. Tiene su propio daño, su gravedad y lo que ocurre al caer:
projectile "frost_bolt" {
damage: 4
gravity: false
on_hit: fun(e) {
let at = e.entity?.location ?? e.block?.location
if at != null { e.projectile.world.spawn_particle("minecraft:snowflake", at.add(0.5, 1, 0.5), 12, 0.4, 0.02) }
}
}damage: daño que causa a lo que golpea.gravity:falsehace que vuele en línea recta.on_hit:fun(e), se llama al caer, con el mismoeque el eventohit:e.projectile,e.shooterye.entityoe.block.texture: el proyectil vuela con el aspecto de su objeto, así que por defecto usatextures/item/<id>.png; contextureusas otra.
Úsalo como cualquier otro proyectil: world.shoot("mymod:frost_bolt", from, velocity, shooter), o en una criatura, { ranged_attack: "mymod:frost_bolt" }. En Kotlin:
content.projectile("frost_bolt") {
damage = 4.0
gravity = false
onHit = { e -> /* … */ }
}Ataques a distancia y proyectiles
El comportamiento ranged_attack hace que una criatura dispare. Se acerca hasta que su objetivo está a tiro y a la vista, y entonces dispara.
creature "frost_spirit" {
body: "minecraft:snow_golem"
behaviour: [{ ranged_attack: "minecraft:snowball", interval: 20, range: 14, damage: 3 }, { wander: 0.6 }]
targets: ["minecraft:zombie", "hurt_by"]
}
on hit(e) {
if e.shooter?.type == "frostmod:frost_spirit" && e.entity != null {
e.entity.velocity = vector(0, 0.2, 0) // knocked up
}
}| Ajuste | Significado |
|---|---|
ranged_attack |
ranged_attack: el proyectil (minecraft:arrow, minecraft:snowball, minecraft:small_fireball, minecraft:wind_charge…). |
interval |
interval: ticks entre disparos. |
range |
range: distancia en bloques desde la que dispara. |
speed |
speed: velocidad al caminar mientras se acerca. |
power |
power: la velocidad a la que vuela el proyectil. |
damage |
damage: daño extra cuando acierta. |
Para disparar desde el código, con criaturas o con la habilidad de un jugador, usa world().shoot(projectile, from, velocity, shooter, damage).
En Kotlin:
creature("frost_spirit") {
body = "minecraft:snow_golem"
behaviour(Behaviour.RangedAttack(Identifier.parse("minecraft:snowball"), interval = 20, range = 14.0, damage = 3.0))
target(TargetRule.Nearest(Identifier.parse("minecraft:zombie")))
}
// From code, e.g. a player's ability:
world.shoot(Identifier.parse("minecraft:small_fireball"), from, Vector(0.0, 0.0, 1.5), shooter = player, damage = 4.0)El evento hit (ProjectileHitEvent) se lanza cuando un proyectil impacta. Tiene e.projectile, e.shooter y e.entity o e.block, según lo que haya alcanzado. Cancélalo y el proyectil lo atraviesa. Ver Eventos.
Lo que conviene saber
- Cada cuerpo tiene sus límites. Algunas criaturas del juego no tienen una estadística: una vaca no tiene daño de ataque. Si la escribes, se ignora y Crafting lo avisa en el log.
- Cuerpos que no andan. Los que no pueden buscar un camino por sí mismos ignoran los comportamientos de andar (pasear, perseguir, huir, seguir, evitar); los demás funcionan.
- Sin
behaviour, la criatura se comporta como el cuerpo que usa. En cuanto escribes la lista, solo hace lo que está en ella. - El modelo solo cambia el aspecto. El movimiento y el comportamiento siempre vienen del cuerpo, y el tamaño también, salvo que pongas
size. - Una criatura propia es una entidad viva como cualquier otra: recibe los eventos
spawn,damageyentity_death, tienedatay se maneja con lo de El mundo y los jugadores.
En Kotlin
package com.example.rubies.content
object Creatures {
fun register(content: ContentBuilder) {
content.creature("ruby_golem") {
body = "minecraft:zombie"
texture = "entity/ruby_golem"
health = 60.0
speed = 0.25
attackDamage = 6.0
behaviour(Behaviour.Swim)
behaviour(Behaviour.MeleeAttack())
behaviour(Behaviour.Wander(0.6))
behaviour(Behaviour.LookAtPlayers(12f))
behaviour(Behaviour.LookAround)
target(TargetRule.HurtBy)
target(TargetRule.Nearest(Identifier.parse("minecraft:player")))
drop(Items.RUBY, 2..4)
}
}
}Comportamientos: Behaviour.Swim, LookAround, Wander(speed), LookAtPlayers(range), MeleeAttack(speed), Panic(speed), Avoid(entity, distance, speed), Follow(item, speed). Objetivos: TargetRule.HurtBy y TargetRule.Nearest(id). El botín se añade con drop(item, count, chance), igual que en los bloques.
Tu propio modelo 3D
Añade model y la criatura se dibuja con tu modelo en lugar del del cuerpo. El cuerpo sigue dándole su tamaño, su movimiento y su comportamiento; el modelo solo cambia cómo se ve.
creature "robot" {
body: "minecraft:pig"
model: "entity/robot"
texture: "entity/robot"
behaviour: ["swim", { wander: 0.8 }, { look_at_players: 10 }]
}El modelo es models/entity/robot.json del mod y su textura es textures/entity/robot.png. En Kotlin: creature("robot") { body = "minecraft:pig"; model = "entity/robot"; texture = "entity/robot" }. El formato es el mismo en todas las versiones del juego.
{ "texture_size": [64, 64],
"bones": [
{ "name": "body", "pivot": [0, 6, 0], "cubes": [ { "origin": [-5, 6, -3], "size": [10, 10, 6], "uv": [0, 0] } ] },
{ "name": "head", "parent": "body", "pivot": [0, 16, 0], "cubes": [ { "origin": [-4, 16, -4], "size": [8, 8, 8], "uv": [0, 16] } ] },
{ "name": "left_leg", "pivot": [2.5, 6, 0], "cubes": [ { "origin": [1, 0, -1.5], "size": [3, 6, 3], "uv": [32, 0] } ] },
{ "name": "right_leg", "pivot": [-2.5, 6, 0], "cubes": [ { "origin": [-4, 0, -1.5], "size": [3, 6, 3], "uv": [32, 16] } ] }
],
"animations": { "head": "look", "left_leg": "walk", "right_leg": "walk_opposite", "body": "idle" } }Los tamaños son en píxeles (16 es un bloque), con y apuntando hacia arriba desde los pies de la criatura.
- Hueso:
name, unparentopcional (se mueve con él),pivot(el punto alrededor del que gira) ycubes. - Cubo:
origin(su esquina más baja),sizeyuv(dónde empieza su textura en la imagen). La disposición es la habitual de las cajas: un cubo de ancho w, alto h y fondo d usa un área de 2(w+d) por (d+h) píxeles. - Las animaciones van por hueso, como un nombre o una lista de nombres:
| Animación | Qué hace |
|---|---|
look |
Gira hacia donde mira la criatura; para cabezas. |
walk, walk_opposite |
Se balancea al andar; la segunda en fase opuesta, para la otra extremidad. |
idle |
Un leve balanceo. |
spin |
Gira sin parar. |
Si un modelo no se puede dibujar, la criatura se ve como su cuerpo y el log dice por qué.
Tamaño
Una criatura es tan grande como su cuerpo. Cuando tu modelo es más pequeño o más grande, pon size: [width, height] en bloques para que aquello con lo que colisiona y el lugar donde se le hace clic coincidan con lo que ven los jugadores:
creature "drake" {
body: "minecraft:bee"
model: "entity/drake"
texture: "entity/drake"
size: [1.4, 1.1]
}En Kotlin: size = 1.4 to 1.1.
Animaciones por fotogramas clave
Para movimientos más allá de las animaciones incluidas, añade una sección clips junto a bones y animations:
{ "bones": [ … ],
"animations": { … },
"clips": {
"idle": { "length": 2.0, "bones": { "head": { "position": { "0": [0, 0, 0], "1": [0, 0.6, 0], "2": [0, 0, 0] } } } },
"walk": { "length": 1.0, "bones": { "body": { "rotation": { "0": [0, 0, -6], "0.5": [0, 0, 6], "1": [0, 0, -6] } } } },
"roar": { "length": 1.5, "bones": {
"head": { "rotation": { "0": [0, 0, 0], "0.4": [-35, 0, 0], "1.1": [-35, 0, 0], "1.5": [0, 0, 0] },
"scale": { "0": 1, "0.4": 1.35, "1.1": 1.35, "1.5": 1 } },
"body": { "position": { "0": [0, 0, 0], "0.3": [0, 4, 0], "0.6": [0, 0, 0] } } } }
} }- Cada clip tiene una
length(duración) en segundos y, por hueso, hasta tres canales:rotationen grados,positionen píxeles (y hacia arriba) yscale(un número o[x, y, z]). - Las claves son tiempos en segundos. Los valores se mezclan en línea recta entre claves; añade
"interpolation": "smooth"a un clip y pasará por sus claves en una curva. Un canal también puede ser un solo valor para todo el clip.
| Clip | Cuándo se reproduce |
|---|---|
walk |
Se repite mientras camina, al compás de sus patas. |
idle |
Se repite mientras está quieta. |
attack |
Se reproduce cuando golpea. |
| Cualquier otro nombre | Se reproduce cuando el código lo pide: c.play_animation("roar"). Los jugadores cercanos que tengan Crafting lo ven. |
"idle": { "length": 1.2, "interpolation": "smooth", "bones": {
"left_wing": { "rotation": { "0": [0, 0, -20], "0.6": [0, 0, 25], "1.2": [0, 0, -20] } } } }Un clip iniciado desde el código se reproduce sobre walk, idle y attack en vez de reemplazarlos, y se suman: una criatura puede rugir mientras camina.
Las crías de una criatura con modelo propio se dibujan a la mitad de tamaño.
Texturas
Sin modelo, la textura tiene la misma forma que la del cuerpo elegido (un zombi, un lobo…), así que puedes partir de una plantilla de ese cuerpo y pintarla. Va dentro del mod, como las de ítems y bloques:
| Mod | Dónde |
|---|---|
| CraftScript (carpeta) | mods/ghostmod/textures/entity/ghost.png |
| Kotlin o Java | src/main/resources/assets/ghostmod/textures/entity/ghost.png |