MANUAL DE CHIVO-8

Comandos, teclas, funciones para programar y lecciones paso a paso · versión 0.9.2

🚀 Para empezar

Chivo-8 es una consola de videojuegos de fantasía: dibujas los personajes, armas el nivel, haces los sonidos, programas el juego y lo juegas, todo en una pantalla de 128x128 pixeles con 16 colores (o 240x136, inspirada en TIC-80).

  1. Al abrir ves la línea de comandos: escribe HELP para ver los comandos.
  2. Escribe APRENDE para ver las lecciones y APRENDE 1 para empezar la primera.
  3. ¿Prefieres partir de un juego que ya funciona? NUEVO SALTO, NUEVO NAVE, NUEVO ATRAPA, NUEVO LABERINTO o NUEVO CARRERA: arriba del código dice «CAMBIA AQUÍ».
  4. Si algo falla, la pantalla del juego te dice en español qué pasó y en qué línea.
  5. Con Esc vas a los editores; con F6 juegas.
  6. Tu trabajo se guarda solo en este equipo; con SAVE NOMBRE le pones nombre y con GOOGLE + SUBIR lo llevas a la nube.

Un juego tiene tres partes que la consola llama sola:

function _init()   -- una vez, al empezar
end
function _update() -- 30 veces por segundo: mover, chocar, contar
end
function _draw()   -- después de cada _update: dibujar
  cls(1)
  print('HOLA', 52, 60, 7)
end

🧩 Plantillas: empieza con un juego hecho

En vez de empezar en blanco, escribe NUEVO y el nombre de una plantilla: es un juego corto que ya funciona, hecho con figuras (no necesitas dibujar antes). Arriba del código hay un bloque «CAMBIA AQUÍ» con los números que deciden cómo se siente: velocidad, salto, colores, dificultad.

NUEVO SALTOPlataformas: caminas, saltas y juntas monedas.
NUEVO NAVEUna nave que dispara a lo que baja. Cambia CADA para hacerlo más difícil.
NUEVO ATRAPAAtrapa lo que cae con una canasta; cada vez cae más rápido.
NUEVO LABERINTOLaberinto visto desde arriba. Agrega paredes en la tabla paredes.
NUEVO CARRERAEsquiva los coches cambiando de carril.

Al final del código de cada plantilla hay 3 retos para seguir practicando.

Ideas para seguir: dibuja tu personaje en Sprites y cambia rectfill(x, y, 8, 8, ...) por spr(1, x, y) (lección 16); ponle sonidos de la biblioteca (SONIDOS); súmale enemigos con la lección 9.

⌨️ Teclas y atajos

F1 … F5Editores: Código, Sprites, Mapa, Efectos y Música.
F6Jugar (Play) en la Game Boy, con la biblioteca de juegos.
EscVolver a la línea de comandos (o al editor de la lección).
Ctrl+RCorrer el juego desde el editor de código.
Ctrl+Z · Ctrl+YDeshacer · rehacer.
Ctrl+F · Ctrl+G · Ctrl+OCódigo: buscar · ir a una línea · lista de funciones.
TabMapa: ver el mundo completo.
F7 · F8 · F9En Play: foto · GIF · video del juego.
Flechas + Z / XControles del jugador 1 (también WASD y N / M). Jugador 2: J L I K + U / O.

Teclado en pantalla (celular)

Se abre con el botón ⌨ y se cierra con ▼. Los números están en la tercera fila (1 … 0 y ⌫), abajo de la de símbolos y arriba de Q W E R T Y.

🖌️ Los editores

Con Esc vas y vienes entre la línea de comandos y el último editor. Las teclas F cambian de editor.

F2 · Sprites

F3 · Mapa

F4 · Efectos y F5 · Música

Los dos editores son iguales: 16 pasos con su nota, volumen, octava y comando. Está explicado completo en Sonido y música.

F1 · Código

F6 · Play

🎨 Los 16 colores

Los colores se usan por número: cls(1) pinta el fondo azul oscuro y print('HOLA', 2, 2, 7) escribe en blanco. Estos son los de la paleta de siempre (PICO-8); con PALETA eliges otra de las 12 y los números se quedan igual, solo cambia el tono.

0negro
1azul oscuro
2morado oscuro
3verde oscuro
4café
5gris oscuro
6gris claro
7blanco
8rojo
9naranja
10amarillo
11verde
12azul
13índigo
14rosa
15durazno

🔊 Sonido y música

Hay dos tipos de sonido: efectos (cortos: salto, moneda, explosión) y música (melodías que se repiten).

Efectos (F4)

Música (F5)

Cómo se hace un sonido

Los sonidos, la música y las ondas se guardan con tu cartucho: si compartes el juego, sus sonidos van con él.

Biblioteca: SONIDOS y CANCION

SONIDOS PONER copia 20 efectos listos a tu cartucho (del 5 al 24) y SONIDOS 5 te deja escucharlos. CANCION ALEGRE, CANCION AVENTURA o CANCION MISTERIO cargan una canción corta (patrones 10 a 18) que suena con track(). Después los puedes cambiar en los editores.

sfx(5)Láser
sfx(6)Disparo
sfx(7)Vida extra
sfx(8)Perder
sfx(9)Menú
sfx(10)Aceptar
sfx(11)Cancelar
sfx(12)Paso
sfx(13)Puerta
sfx(14)Recoger
sfx(15)Daño
sfx(16)Explosión grande
sfx(17)Boing
sfx(18)Campana
sfx(19)Alarma
sfx(20)Teletransporte
sfx(21)Zumbido
sfx(22)Moneda doble
sfx(23)Burbuja
sfx(24)Ganar

💬 Comandos de la consola

Se escriben en la línea de comandos (mayúsculas o minúsculas). Lo que va entre < > es obligatorio; entre [ ], opcional. HELP COMANDO explica uno.

HELP [COMANDO]
también: AYUDA
La ayuda, o la de un comando
LS
también: DIR, CARTS
Tus cartuchos en este equipo
LOAD <NOMBRE>
también: CARGAR
Abrir un cartucho guardado
SAVE [NOMBRE]
también: GUARDAR
Guardar el cartucho
NEW [PLANTILLA]
también: NUEVO
Cartucho en blanco o con una plantilla de juego
DEL <NOMBRE>
también: BORRAR
Borrar un cartucho guardado
RENAME <VIEJO> <NUEVO>
también: RENOMBRAR
Cambiar el nombre
EXPORT [HTML|PNG [N]]
también: EXPORTAR, DESCARGAR
.json, html para itch.io o sprites en png
IMPORT [PNG]
también: IMPORTAR
Abrir un .json, un juego de tic-80 (.lua, .js, .fnl o .tic) o una imagen png
PANTALLA [128|240]
también: SCREEN
Tamaño de la pantalla de tu juego: 128×128 o 240×136 (la de tic-80)
APRENDE [NÚMERO]
también: LECCION, LECCIÓN
Lecciones paso a paso
SIGUE
también: SIGUIENTE, NEXT
Siguiente paso de la lección
ATRAS
también: ATRÁS, BACK
Paso anterior
PONER
también: USAR
Poner el código del paso
RUN
también: CORRER, JUGAR
Jugar el cartucho
CODE
también: CODIGO, CÓDIGO
Editor de código
SPRITESEditor de sprites
MAP
también: MAPA
Editor de mapa
SFX
también: EFECTOS
Efectos de sonido
CARCASA [COLOR]
también: GAMEBOY
Color del game boy de play
SONIDOS [PONER|N]
también: SOUNDS
Biblioteca de efectos listos para usar
CANCION [NOMBRE]
también: CANCIÓN, SONG
Canciones cortas listas para tu juego
MUSIC
también: MUSICA, MÚSICA
Música
CRT [1-5|NO]Filtro de pantalla: 1 clásico · 2 arcade · 3 tv vieja · 4 fósforo · 5 lcd
CLS
también: LIMPIAR
Limpiar la pantalla
PALETA [NÚMERO]
también: PALETTE
Ver o cambiar la paleta del cartucho
COLOR [N #RRGGBB | RESET]Cambiar un color de la paleta
BANCO [0-7]
también: BANK
Editar otro banco de sprites y mapa
MEMORIA
también: MEM
Mapa de memoria (peek/poke)
DATOS [CAMPO TEXTO]
también: INFO
Autor, descripción, versión…
VERSION
también: VERSIÓN
Versión de la consola y lo nuevo
NOVEDADES [VERSIÓN]
también: CAMBIOS, CHANGELOG
Qué cambió en cada versión
ESTUDIOAbrir el estudio clásico
ARCADEIr al arcade
MANUAL [TEMA|N]
también: GUIA, GUÍA
Manual: comandos, teclas, funciones y lecciones
TUTORIALLecciones paso a paso
PUBLICAR [NOMBRE]
también: PUBLISH
Mandar tu juego a la comunidad
DESPUBLICAR [NOMBRE]
también: OCULTAR
Quitarlo de la comunidad
COMPARTIR [NOMBRE]
también: LINK, SHARE
Enlace para jugarlo directo
PENDIENTESModerar: juegos por revisar
PROBAR <N>Moderar: jugar uno pendiente
APROBAR <N>
también: RECHAZAR
Moderar: decidir
LOGIN <CORREO>
también: ENTRAR
Entrar a tu cuenta
GOOGLEEntrar con tu cuenta de google
SIGNUP <CORREO>
también: REGISTRO
Crear una cuenta
LOGOUT
también: CERRAR
Salir de tu cuenta
WHOAMI
también: QUIEN, QUIÉN
Con qué cuenta estás
NUBE
también: CLOUD
Tus cartuchos en la nube
SUBIR [NOMBRE]
también: UPLOAD
Guardar en tu cuenta
BAJAR <NOMBRE>
también: DOWNLOAD
Abrir desde tu cuenta

💻 Programar: funciones

Los juegos se escriben en Lua (recomendado para empezar) o JavaScript. Lo básico de Lua:

local vidas = 3                  -- una variable
if vidas == 0 then ... end       -- una condición
for i = 1, 10 do ... end         -- repetir 10 veces
local function saltar() ... end  -- una función
local enemigos = {}              -- una tabla (lista)
enemigos[#enemigos + 1] = { x = 10, y = 20 }
for _, e in ipairs(enemigos) do rectfill(e.x, e.y, 8, 8, 8) end
print('PUNTOS: ' .. puntos, 2, 2, 7) -- .. pega texto

Pantalla y dibujo

cls(color)Borra la pantalla con un color (0 si no se pone).
cls(1)
pset(x, y, color)Pinta un pixel.
pset(64, 64, 8)
pget(x, y)Lee el color de un pixel.
if pget(x, y) == 8 then ... end
line(x1, y1, x2, y2, color)Línea entre dos puntos.
line(0, 0, 127, 127, 7)
rect(x, y, ancho, alto, color)Rectángulo solo con borde.
rect(10, 10, 20, 12, 7)
rectfill(x, y, ancho, alto, color)Rectángulo relleno.
rectfill(10, 10, 20, 12, 8)
circ(x, y, radio, color) · circfill(...)Círculo con borde o relleno.
circfill(64, 64, 10, 10)
elli(x, y, a, b, color) · ellib(...)Elipse rellena o solo borde (a y b son los radios).
elli(64, 64, 20, 8, 12)
tri(x1, y1, x2, y2, x3, y3, color) · trib(...)Triángulo relleno o solo borde.
tri(64, 20, 40, 60, 88, 60, 9)
print(texto, x, y, color)Escribe texto. Devuelve el ancho en pixeles (sirve para centrar).
print('HOLA', 2, 2, 7)
camera(x, y) · camera()Mueve todo lo que se dibuja (temblores, scroll). Sin números vuelve a 0, 0.
camera(cx, 0)
clip(x, y, ancho, alto) · clip()Solo dibuja dentro de ese rectángulo.
clip(0, 0, 64, 128)
pal(c1, c2) · pal()Dibuja el color c1 como c2 (cambiar colores de un sprite). pal() lo deshace.
pal(8, 12) spr(1, x, y) pal()
palt(color, true/false) · palt()Hace un color transparente (o no) al dibujar.
palt(0, true)

Sprites y mapa

spr(n, x, y, [ancho, alto, voltearX, voltearY, escala, giro])Dibuja el sprite n. Ancho y alto en sprites (2, 2 = 16x16); escala 2 = el doble; giro 1-3 = 90° cada uno.
spr(1, x, y)
spr(16, x, y, 2, 2, true)
sget(x, y) · sset(x, y, color)Lee o pinta un pixel de la hoja de sprites (128x256).
sset(8, 0, 7)
map(celdaX, celdaY, x, y, ancho, alto)Dibuja un pedazo del mapa (en celdas de 8x8).
map(0, 0, 0, 0, 16, 16)
mget(cx, cy) · mset(cx, cy, n)Lee o cambia el sprite de una celda del mapa (240x136 celdas).
if mget(x // 8, y // 8) == 2 then ... end
fget(n, bandera) · fset(n, bandera, valor)Banderas de cada sprite (0-7), por ejemplo "sólido" o "dañino".
fget(mget(cx, cy), 0)
banco(n)Cambia al banco n de sprites y mapa (0-7) mientras juegas.
banco(1)

Controles

btn(b) · btnp(b)btn: el botón está apretado. btnp: se acaba de apretar. 0 izquierda, 1 derecha, 2 arriba, 3 abajo, 4 Z, 5 X. Jugador 2: 8-13 (J L I K U O).
if btnp(4) then saltar() end
key(nombre) · keyp(nombre)Cualquier tecla: 'a', 'space', 'enter', 'up'…
if key('space') then ... end
mouse()Ratón o toque: x, y y los botones.
local mx, my, clic = mouse()

Sonido

sfx(n)Toca el efecto n (los haces en Efectos, F4).
sfx(0)
music(n) · music(-1)Repite el patrón de música n; -1 lo detiene.
music(0)
track()Toca la canción completa (los patrones de los 4 canales).
track()
tono(frecuencia, duración, onda, volumen)Un tono directo, sin editor. Onda: 0 cuadrada, 1 triangular, 2 sierra, 3 seno, 4 ruido.
tono(440, 0.2, 1, 0.4)

Guardar y memoria

cartdata(nombre)Abre una memoria de 64 casillas que no se borra al cerrar la página.
cartdata('mi_juego')
dget(i) · dset(i, valor)Lee o guarda la casilla i (récord, nivel…).
dset(0, record)
peek(dirección) · poke(dirección, valor)Lee o cambia la memoria de la consola: pantalla, sprites, mapa, banderas y paleta (comando MEMORIA).
poke(MEM_PALETA, 255)
memcpy(destino, origen, largo) · memset(destino, valor, largo)Copia o llena pedazos de memoria.
memset(MEM_PANTALLA, 0, 100)

Otras

time() · t()Segundos desde que empezó el juego.
local parpadeo = time() % 1 < 0.5
stat(7)Cuadros por segundo reales.
print(stat(7), 2, 120, 5)
trace(texto)Escribe en la consola del navegador (para buscar errores).
trace('x = ' .. x)
W · HAncho y alto de la pantalla del juego (128x128, o 240x136 con PANTALLA 240).
print("X", W - 8, H - 8, 7)

📚 Lecciones paso a paso

Las mismas lecciones están dentro de la consola: APRENDE N la empieza, SIGUE y ATRAS avanzan, PONER copia el código del paso y RUN lo juega.

Lección 1 · Tu primer sprite

  1. Mira el editor. En Sprites (F2): arriba a la izquierda está el sprite en grande, a la derecha la paleta y abajo la hoja con todos los sprites.
  2. Elige el sprite #1. En la hoja de abajo toca el cuadrito #1 (el segundo). El #0 se deja vacío: es el aire del mapa.
  3. Pinta con el lápiz. Elige un color de la paleta y pinta con el lápiz. Cada cuadro grande es un pixel. ¿Error? Ctrl+Z o el botón de deshacer.
  4. Prueba rellenar. Rellenar pinta un área de un solo color y tomar color copia uno que ya usaste. Prueba espejo y rotar para sacar variantes.
  5. Contorno y brillo. Consejo: primero el contorno oscuro, luego el relleno y al final un pixel claro de brillo. Con 3 colores alcanza.

Lección 2 · Un personaje animado

  1. 2x y bloque #16. Toca 2X: ahora editas 4 sprites juntos (16x16). En la hoja elige el bloque que empieza en el #16.
  2. Dibuja 2 cuadros. Dibuja tu personaje parado. Luego elige el bloque de al lado (#18) y dibújalo otra vez con las piernas cambiadas.
  3. Toca anim. Vuelve al #16 y toca ANIM: el lienzo repite tus cuadros como animación. Tócalo otra vez para 3 o 4 cuadros.
  4. Spr(16, x, y, 2, 2). En código, un sprite de 16x16 se dibuja con spr(16, x, y, 2, 2): los dos últimos números son ancho y alto en sprites.

Lección 3 · Arma un nivel

  1. Piso en #2 + bandera 0. En Sprites dibuja un bloque de piso en el #2. Con ese sprite elegido prende la bandera 0 (el primer cuadrito de la fila de banderas): quiere decir sólido.
  2. Pinta el piso. Ve a Mapa (F3). En la hoja de abajo toca tu bloque #2 y pinta arrastrando el dedo: haz el piso abajo.
  3. Plataformas. Agrega plataformas. Para estampar un bloque grande arrastra sobre la hoja (hasta 4x4). Borrar quita bloques.
  4. Muévete con la mano. El mapa es enorme (240x136). Muévete con la mano o las flechas; la lupa da una vista amplia. Las líneas punteadas marcan una pantalla (16x16).

Lección 4 · Un efecto de sonido

  1. Efecto 00, cuadrada. En Efectos (F4) elige el efecto 00 con < y >. Toca la onda cuadrada: suena a consola clásica.
  2. Dos notas que suben. Las barras son el tono: dibuja una a media altura en el paso 1 y otra más alta en el paso 2. Dos notas que suben = ¡ding!
  3. Probar y volumen. Toca PROBAR. Abajo de cada paso hay volumen (verde), octava y comando. Baja el volumen del último paso para que se apague suave.
  4. Efecto 01: salto. Haz otro en el 01 para el salto: notas que suben rápido, onda triangular. Para una explosión: ruido y volumen que baja.

Lección 5 · Una melodía

  1. Patrón 00, triangular. En Música (F5) elige el patrón 00. Es como un efecto más largo, hecho para repetirse. Elige la onda triangular.
  2. Notas y play. Usa pocas notas distintas y repítelas: así se pega. Toca play para oírlo; 1X cambia la velocidad.
  3. Patrón 01: bajo. Haz el patrón 01 con una línea grave (el bajo), onda cuadrada y pocas notas.
  4. Arma la canción. Toca CANC: en el canal 1, casilla 1, pon el 00; en el canal 2, casilla 1, el 01. Suenan juntos. Play toca toda la canción.

Lección 6 · Dale vida con código

  1. _init _update _draw. Todo juego tiene 3 partes: _init() al empezar, _update() la lógica (30 veces por segundo) y _draw() para dibujar.
  2. Poner, luego run. Este ejemplo mueve tu sprite #1 con las flechas sobre tu nivel.
    -- Tu sprite #1 se mueve con las flechas sobre tu nivel.
    local x, y = 20, 20
    
    function _update()
      if btn(0) then x = x - 1 end -- izquierda
      if btn(1) then x = x + 1 end -- derecha
      if btn(2) then y = y - 1 end -- arriba
      if btn(3) then y = y + 1 end -- abajo
    end
    
    function _draw()
      cls(1)                  -- fondo azul oscuro
      map(0, 0, 0, 0, 16, 16) -- tu nivel
      spr(1, x, y)            -- tu sprite #1
    end
  3. Ctrl+r o run. Escribe RUN (o Ctrl+R en Código): tu sprite se mueve con las flechas o con la cruceta de la Game Boy.
  4. Poner: con choques. Para que no atraviese paredes, revisa la bandera 0 del bloque a donde va. Este ejemplo choca, suena sfx(0) y toca tu música.
    -- Ya no atraviesa paredes: revisa la bandera 0
    -- (sólido) del bloque a donde va. Suena sfx(0) al chocar.
    local x, y = 20, 20
    
    local function solido(px, py)
      return fget(mget(px // 8, py // 8), 0)
    end
    
    local function libre(nx, ny)
      return not (solido(nx, ny) or solido(nx + 7, ny)
        or solido(nx, ny + 7) or solido(nx + 7, ny + 7))
    end
    
    local function mover(dx, dy)
      if libre(x + dx, y + dy) then x, y = x + dx, y + dy
      else sfx(0) end
    end
    
    function _init() music(0) end
    
    function _update()
      if btn(0) then mover(-1, 0) end
      if btn(1) then mover(1, 0) end
      if btn(2) then mover(0, -1) end
      if btn(3) then mover(0, 1) end
    end
    
    function _draw()
      cls(1)
      map(0, 0, 0, 0, 16, 16)
      spr(1, x, y)
      print('MI JUEGO', 2, 2, 7)
    end
  5. Sfx(0) y music(0). sfx(0) toca tu efecto 00; music(0) repite tu patrón; track() toca la canción completa. ¡Ya tienes un juego!

Lección 7 · Guarda y comparte

  1. Save nombre. Escribe SAVE y un nombre, por ejemplo SAVE MIJUEGO. Queda en este equipo con todo: sprites, mapa, sonido y código.
  2. Datos autor. Pon tus datos: DATOS AUTOR TU NOMBRE y DATOS DESC DE QUÉ TRATA.
  3. Google y subir. Entra con GOOGLE y escribe SUBIR: tu juego te sigue a cualquier dispositivo.
  4. Gif para compartir. En Play (F6) toca GIF para grabar un pedacito y compartirlo. EXPORT lo descarga como archivo.

Lección 8 · Puntos y texto

  1. Variables. Una variable guarda un dato que cambia: local puntos = 0. Con puntos = puntos + 10 le sumas.
  2. Poner: monedas. Este ejemplo hace un juego de juntar monedas con puntos.
    -- Junta monedas: cada una da 10 puntos.
    local x, y = 60, 60      -- tu personaje
    local mx, my = 20, 20    -- la moneda
    local puntos = 0
    
    local function nuevaMoneda()
      mx = math.random(8, 112)
      my = math.random(16, 112)
    end
    
    function _update()
      if btn(0) then x = x - 2 end
      if btn(1) then x = x + 2 end
      if btn(2) then y = y - 2 end
      if btn(3) then y = y + 2 end
      -- ¿la toca? (distancia menor a 8 en x y en y)
      if math.abs(x - mx) < 8 and math.abs(y - my) < 8 then
        puntos = puntos + 10
        sfx(0)
        nuevaMoneda()
      end
    end
    
    function _draw()
      cls(1)
      circfill(mx + 3, my + 3, 3, 10)  -- moneda amarilla
      rectfill(x, y, 8, 8, 11)         -- personaje verde
      print('PUNTOS: ' .. puntos, 2, 2, 7)
    end
  3. Print. print('PUNTOS: ' .. puntos, 2, 2, 7) escribe en pantalla: texto, x, y y color. Los dos puntos .. pegan texto con números.
  4. Math.random. math.random(8, 112) da un número al azar entre 8 y 112: así la moneda aparece en otro lugar. Prueba cambiar los números.

Lección 9 · Enemigos

  1. Tablas. Una tabla guarda muchas cosas juntas: enemigos[1] = { x = 10, y = 20 }. Con for _, e in ipairs(enemigos) recorres todos.
  2. Poner: enemigos. Enemigos que rebotan en las orillas. Si te tocan pierdes una vida y parpadeas un rato.
    -- Enemigos que rebotan. Si te tocan, pierdes una vida.
    local x, y = 60, 100
    local vidas, invencible = 3, 0
    local enemigos = {}
    
    function _init()
      for i = 1, 4 do
        -- cada enemigo es una tabla con posición y velocidad
        enemigos[i] = { x = math.random(0, 120), y = math.random(0, 60),
                        vx = math.random(1, 2), vy = math.random(1, 2) }
      end
    end
    
    local function choca(a, b) -- dos cuadros de 8x8 se enciman
      return math.abs(a.x - b.x) < 8 and math.abs(a.y - b.y) < 8
    end
    
    function _update()
      if vidas <= 0 then return end
      if btn(0) then x = x - 2 end
      if btn(1) then x = x + 2 end
      if btn(2) then y = y - 2 end
      if btn(3) then y = y + 2 end
      if invencible > 0 then invencible = invencible - 1 end
      for _, e in ipairs(enemigos) do
        e.x, e.y = e.x + e.vx, e.y + e.vy
        if e.x < 0 or e.x > 120 then e.vx = -e.vx end
        if e.y < 0 or e.y > 120 then e.vy = -e.vy end
        if invencible == 0 and choca(e, { x = x, y = y }) then
          vidas = vidas - 1
          invencible = 60 -- 2 segundos sin daño
        end
      end
    end
    
    function _draw()
      cls(0)
      for _, e in ipairs(enemigos) do rectfill(e.x, e.y, 8, 8, 8) end
      if invencible % 6 < 3 then rectfill(x, y, 8, 8, 12) end -- parpadea
      print('VIDAS: ' .. vidas, 2, 2, 7)
      if vidas <= 0 then print('FIN DEL JUEGO', 38, 60, 8) end
    end
  3. Choques. Dos cuadros de 8x8 chocan si están a menos de 8 pixeles en x y en y: math.abs(a.x - b.x) < 8 and math.abs(a.y - b.y) < 8.
  4. Reto. Reto: haz que cada 10 segundos aparezca un enemigo más (pista: un contador y table.insert).

Lección 10 · Gravedad y salto

  1. Velocidad. Para saltar se usa una velocidad vertical vy: cada cuadro y = y + vy, y la gravedad suma un poquito a vy.
  2. Poner: salto. Un personaje que salta entre plataformas con Z.
    -- Gravedad y salto: Z salta, flechas para moverte.
    local x, y, vy = 20, 20, 0
    local enSuelo = false
    local plataformas = {
      { x = 0,  y = 120, w = 128 }, -- el piso
      { x = 20, y = 92,  w = 30 },
      { x = 70, y = 70,  w = 30 },
      { x = 30, y = 46,  w = 24 },
    }
    
    function _update()
      if btn(0) then x = x - 2 end
      if btn(1) then x = x + 2 end
      if btnp(4) and enSuelo then vy = -5 end -- saltar
      vy = math.min(vy + 0.3, 4)                -- la gravedad jala hacia abajo
      y = y + vy
      enSuelo = false
      for _, p in ipairs(plataformas) do
        -- cae sobre una plataforma: se queda parado encima
        if vy >= 0 and x + 7 >= p.x and x <= p.x + p.w and y + 8 >= p.y and y + 8 <= p.y + 6 then
          y, vy, enSuelo = p.y - 8, 0, true
        end
      end
    end
    
    function _draw()
      cls(12)
      for _, p in ipairs(plataformas) do rectfill(p.x, p.y, p.w, 4, 4) end
      rectfill(x, y, 8, 8, 8)
      print('Z: SALTAR', 2, 2, 1)
    end
  3. Btnp vs btn. btn(4) es verdadero mientras aprietas; btnp(4) solo el instante en que lo aprietas. Para saltar se usa btnp.
  4. Ajusta el salto. Cambia vy = -5 (más negativo = salto más alto) y 0.3 (más grande = cae más rápido) hasta que se sienta bien.

Lección 11 · Título, juego y fin

  1. Estados. Un juego cambia de pantalla con una variable estado: 'titulo', 'juego' o 'fin'. _update y _draw hacen algo distinto en cada uno.
  2. Poner: pantallas. Título, 10 segundos de juego y pantalla de fin con tus puntos.
    -- Un juego tiene pantallas: título, juego y fin.
    local estado = 'titulo'
    local tiempo, puntos = 0, 0
    
    function _update()
      if estado == 'titulo' then
        if btnp(4) then estado, tiempo, puntos = 'juego', 0, 0 end
      elseif estado == 'juego' then
        tiempo = tiempo + 1
        if btnp(4) then puntos = puntos + 1 end -- aprieta Z rápido
        if tiempo >= 300 then estado = 'fin' end -- 10 segundos
      elseif estado == 'fin' then
        if btnp(5) then estado = 'titulo' end
      end
    end
    
    function _draw()
      cls(1)
      if estado == 'titulo' then
        print('MI JUEGO', 48, 50, 10)
        print('Z: EMPEZAR', 44, 70, 7)
      elseif estado == 'juego' then
        print('¡APRIETA Z!', 42, 50, 7)
        print('PUNTOS: ' .. puntos, 42, 62, 11)
        rectfill(14, 100, 100 - tiempo // 3, 4, 8) -- barra de tiempo
      else
        print('FIN', 58, 50, 8)
        print('HICISTE ' .. puntos, 46, 62, 7)
        print('X: OTRA VEZ', 42, 80, 6)
      end
    end
  3. Pásalo a tu juego. Copia la idea a tu juego: mueve tu código de juego dentro de if estado == "juego".

Lección 12 · Guarda el récord

  1. Cartdata. cartdata('mi_juego') abre una memoria con 64 casillas que no se borra al cerrar la página. Usa un nombre único para tu juego.
  2. Poner: récord. Aprieta Z lo más rápido que puedas: si superas el récord, se guarda.
    -- El récord se guarda aunque cierres la página.
    cartdata('mi_juego')      -- el nombre de tu "memoria"
    local record = dget(0)     -- casilla 0: el récord guardado
    local puntos, tiempo = 0, 300
    
    function _update()
      if tiempo > 0 then
        tiempo = tiempo - 1
        if btnp(4) then puntos = puntos + 1 end
        if tiempo == 0 and puntos > record then
          record = puntos
          dset(0, record)       -- guardarlo
        end
      elseif btnp(5) then puntos, tiempo = 0, 300 end
    end
    
    function _draw()
      cls(0)
      print('APRIETA Z RÁPIDO', 30, 40, 7)
      print('PUNTOS: ' .. puntos, 30, 56, 11)
      print('RÉCORD: ' .. math.floor(record), 30, 66, 10)
      if tiempo == 0 then print('X: OTRA VEZ', 30, 86, 6) end
    end
  3. Dget y dset. dget(0) lee la casilla 0 y dset(0, valor) la guarda. Puedes guardar nivel, vidas o monedas en otras casillas.

Lección 13 · Partículas y efectos

  1. Muchas chispas. Una partícula es un punto con posición, velocidad y vida. Se guardan en una tabla y se borran cuando se acaba su vida.
  2. Poner: explosión. Z hace una explosión de 30 chispas y la pantalla tiembla.
    -- Partículas: Z hace una explosión y la pantalla tiembla.
    local chispas, temblor = {}, 0
    
    local function explosion(x, y)
      for i = 1, 30 do
        local a, v = math.random() * 6.28, math.random() * 3
        chispas[#chispas + 1] = { x = x, y = y, vx = math.cos(a) * v,
                                  vy = math.sin(a) * v, vida = math.random(15, 30) }
      end
      temblor = 8
    end
    
    function _update()
      if btnp(4) then explosion(math.random(30, 98), math.random(30, 98)) end
      for i = #chispas, 1, -1 do -- de atrás hacia adelante para poder borrar
        local c = chispas[i]
        c.x, c.y, c.vy = c.x + c.vx, c.y + c.vy, c.vy + 0.1
        c.vida = c.vida - 1
        if c.vida <= 0 then table.remove(chispas, i) end
      end
      if temblor > 0 then temblor = temblor - 1 end
    end
    
    function _draw()
      camera(math.random(-temblor, temblor) // 2, math.random(-temblor, temblor) // 2)
      cls(0)
      for _, c in ipairs(chispas) do
        pset(c.x, c.y, c.vida > 20 and 10 or (c.vida > 10 and 9 or 8)) -- amarillo, naranja, rojo
      end
      camera()
      print('Z: EXPLOSIÓN', 2, 2, 7)
    end
  3. Camera. camera(x, y) mueve todo lo que dibujas; con números al azar la pantalla tiembla. camera() la regresa a su lugar.
  4. Úsalo. Usa explosion(x, y) cuando un enemigo muere o al juntar algo: los efectos hacen que el juego se sienta vivo.

Lección 14 · Juegos de tic-80

  1. Clásicos de tic-80. En Play (F6) abre la BIBLIOTECA: en Clásicos de TIC-80 hay juegos de la comunidad con licencia abierta. Juega uno.
  2. Poner: estilo tic-80. Chivo-8 también entiende el código de TIC-80: todo en TIC(), pantalla de 240x136 y rect relleno.
    -- title:  mi juego estilo TIC-80
    -- script: lua
    -- Así se escribe un juego de TIC-80: todo pasa en TIC(),
    -- la pantalla es de 240x136 y los botones son 0 arriba,
    -- 1 abajo, 2 izquierda, 3 derecha, 4 = Z y 5 = X.
    x, y = 116, 64
    
    function TIC()
      if btn(0) then y = y - 1 end
      if btn(1) then y = y + 1 end
      if btn(2) then x = x - 1 end
      if btn(3) then x = x + 1 end
      cls(13)
      rect(x, y, 8, 8, 2)          -- en TIC-80 rect es relleno
      print('HOLA DESDE TIC-80', 70, 20, 0)
    end
  3. Pantalla 128 o 240. Tu juego puede usar 128x128 (Chivo-8) o 240x136 (TIC-80): escribe PANTALLA 240 o PANTALLA 128. En el código, W y H dicen el tamaño.
  4. Import. IMPORT abre juegos de TIC-80 (.lua, .js, .fnl o .tic). Si los vas a publicar, revisa que el autor lo permita (su licencia).

Lección 15 · Sonido en tu juego

  1. Sonidos. Escribe SONIDOS: es una biblioteca de 20 efectos listos (láser, vida extra, puerta…). SONIDOS PONER los copia a tu cartucho, del 5 al 24.
  2. Escúchalos. SONIDOS 5 suena el láser, SONIDOS 7 la vida extra… Escucha y anota los números que quieras usar en tu juego.
  3. Cancion alegre. Escribe CANCION para ver las 3 canciones y CANCION ALEGRE para ponerla. Queda en Música (F5): ábrela y mira cómo está hecha.
  4. Poner: láser y música. Z suena el láser con sfx(5), X prende y apaga la música con track() y music(-1), y las flechas tocan notas.
    -- Sonido en tu juego: Z = láser, X = música sí/no, flechas = notas.
    -- Antes escribe SONIDOS PONER y CANCION ALEGRE en la línea de comandos.
    local musica = false
    local nota = ''
    local NOTAS = { [0] = { 'DO', 262 }, [1] = { 'MI', 330 }, [2] = { 'SOL', 392 }, [3] = { 'DO ALTO', 523 } }
    
    function _update()
      if btnp(4) then sfx(5) end              -- 5 = LÁSER de la biblioteca
      if btnp(5) then
        musica = not musica
        if musica then track() else music(-1) end
      end
      for b = 0, 3 do
        if btnp(b) then tono(NOTAS[b][2], 0.2, 1); nota = NOTAS[b][1] end  -- 1 = onda triangular
      end
    end
    
    function _draw()
      cls(1)
      print('Z: LÁSER   X: MÚSICA', 4, 4, 7)
      print('FLECHAS: NOTAS', 4, 14, 7)
      print('MÚSICA: ' .. (musica and 'SÍ' or 'NO'), 4, 30, musica and 11 or 8)
      print(nota, 50, 60, 10)
    end
  5. Tono. tono(262, 0.2, 1) toca una nota al momento: frecuencia (262 = Do), duración en segundos y onda (0 cuadrada, 1 triangular, 2 sierra, 3 seno, 4 ruido).
  6. Hazlo tuyo. Abre Efectos (F4), elige el 05 y cámbialo: otra onda, otras notas. Tu juego usará el sonido nuevo sin tocar el código.

Lección 16 · Tu personaje

  1. Nuevo salto. Empieza con NUEVO SALTO: es un juego con un cuadro rojo que salta. Vamos a cambiar ese cuadro por un personaje dibujado por ti.
  2. Dibuja en el #1. En Sprites (F2) toca el #1 de la hoja (el segundo cuadrito) y dibuja tu personaje con el lápiz. Lo que dejes en negro (color 0) será transparente.
  3. Poner: con tu sprite. Este código es la misma plantilla, pero dibuja tu sprite #1 con spr(1, x, y) en vez del cuadro rojo.
    -- Tu personaje: la plantilla SALTO con tu sprite #1 en vez del cuadro rojo.
    -- Dibuja el #1 en Sprites (F2): lo negro (color 0) no se dibuja.
    -- ── CAMBIA AQUÍ ──────────────────────────
    local VELOCIDAD = 2     -- qué tan rápido caminas
    local SALTO = -5        -- más negativo = salto más alto
    local GRAVEDAD = 0.3    -- más grande = cae más rápido
    local COLOR_CIELO = 12
    -- ─────────────────────────────────────────
    local x, y, vy, enSuelo = 10, 100, 0, false
    local mira = 1               -- 1 = derecha, -1 = izquierda
    local puntos = 0
    local plataformas = {
      { x = 0,  y = 120, w = 128 },
      { x = 20, y = 92,  w = 30 },
      { x = 70, y = 70,  w = 30 },
      { x = 30, y = 46,  w = 24 },
    }
    local monedas = {}
    
    function _init()
      for _, p in ipairs(plataformas) do
        monedas[#monedas + 1] = { x = p.x + p.w / 2, y = p.y - 8 }
      end
    end
    
    function _update()
      if btn(0) then x = x - VELOCIDAD; mira = -1 end
      if btn(1) then x = x + VELOCIDAD; mira = 1 end
      if btnp(4) and enSuelo then vy = SALTO; tono(440, 0.08) end
      vy = math.min(vy + GRAVEDAD, 4)
      y = y + vy
      enSuelo = false
      for _, p in ipairs(plataformas) do
        if vy >= 0 and x + 7 >= p.x and x <= p.x + p.w and y + 8 >= p.y and y + 8 <= p.y + 6 then
          y, vy, enSuelo = p.y - 8, 0, true
        end
      end
      for i = #monedas, 1, -1 do
        local m = monedas[i]
        if math.abs(x + 4 - m.x) < 6 and math.abs(y + 4 - m.y) < 6 then
          table.remove(monedas, i); puntos = puntos + 1; tono(880, 0.1)
        end
      end
      if y > 140 then x, y, vy = 10, 100, 0 end -- se cayó: vuelve al inicio
    end
    
    function _draw()
      cls(COLOR_CIELO)
      for _, p in ipairs(plataformas) do rectfill(p.x, p.y, p.w, 4, 4) end
      for _, m in ipairs(monedas) do circfill(m.x, m.y, 2, 10) end
      palt(0, true)                    -- el negro (color 0) se vuelve transparente
      spr(1, x, y, 1, 1, mira < 0)     -- tu sprite #1; mira < 0 lo voltea
      palt()                           -- los colores vuelven a la normalidad
      print('MONEDAS: ' .. puntos, 2, 2, 7)
      if #monedas == 0 then print('¡GANASTE!', 46, 30, 10) end
    end
  4. Palt y voltear. palt(0, true) hace transparente el negro. En spr(1, x, y, 1, 1, mira < 0) el sexto dato voltea el sprite: así mira hacia donde camina.
  5. Reto: la moneda. Dibuja una moneda en el #2 y cambia circfill(m.x, m.y, 2, 10) por spr(2, m.x - 4, m.y - 4). ¡Todo tu juego con tus dibujos!

Lección 17 · Un mundo más grande

  1. Más allá de la pantalla. La pantalla mide 128 pixeles, pero tu mundo puede ser más largo. camera(cx, 0) corre todo lo que dibujas: así la pantalla sigue al personaje.
  2. Poner: mundo largo. Un mundo de 4 pantallas con 14 plataformas y monedas. Camina a la derecha y la cámara te sigue.
    -- Un mundo más grande que la pantalla: la cámara sigue al personaje.
    local MUNDO = 512                 -- ancho del mundo en pixeles (4 pantallas)
    local x, y, vy, enSuelo = 10, 100, 0, false
    local cx = 0                      -- dónde está la cámara
    local plataformas = { { x = 0, y = 120, w = MUNDO } }
    local monedas = {}
    
    function _init()
      for i = 1, 14 do
        local p = { x = 40 + i * 32, y = 100 - (i % 3) * 18, w = 24 }
        plataformas[#plataformas + 1] = p
        monedas[#monedas + 1] = { x = p.x + 12, y = p.y - 8 }
      end
    end
    
    function _update()
      if btn(0) then x = math.max(0, x - 2) end
      if btn(1) then x = math.min(MUNDO - 8, x + 2) end
      if btnp(4) and enSuelo then vy = -5 end
      vy = math.min(vy + 0.3, 4)
      y = y + vy
      enSuelo = false
      for _, p in ipairs(plataformas) do
        if vy >= 0 and x + 7 >= p.x and x <= p.x + p.w and y + 8 >= p.y and y + 8 <= p.y + 6 then
          y, vy, enSuelo = p.y - 8, 0, true
        end
      end
      for i = #monedas, 1, -1 do
        local m = monedas[i]
        if math.abs(x + 4 - m.x) < 6 and math.abs(y + 4 - m.y) < 6 then table.remove(monedas, i); tono(880, 0.08) end
      end
      -- la cámara sigue al personaje sin salirse del mundo
      cx = math.max(0, math.min(MUNDO - 128, x - 60))
    end
    
    function _draw()
      cls(12)
      camera(cx, 0)                   -- desde aquí todo se dibuja corrido
      for _, p in ipairs(plataformas) do rectfill(p.x, p.y, p.w, 4, 4) end
      for _, m in ipairs(monedas) do circfill(m.x, m.y, 2, 10) end
      rectfill(x, y, 8, 8, 8)
      camera()                        -- lo de aquí abajo queda fijo en la pantalla
      print('FALTAN: ' .. #monedas, 2, 2, 7)
      if #monedas == 0 then print('¡LAS JUNTASTE TODAS!', 24, 30, 10) end
    end
  3. La cámara sigue. cx = x - 60 deja al personaje cerca del centro; math.max y math.min no dejan que la cámara se salga del mundo.
  4. Lo que va fijo. Después de camera() sin números, lo que dibujas se queda fijo en la pantalla: así los puntos no se van con el mundo.
  5. Con tu mapa. Si dibujaste un nivel en Mapa (F3), ponlo con map(0, 0, 0, 0, 64, 16) después de camera(cx, 0): el mapa también se mueve.

🌐 Guardar, compartir y comunidad

En este equipo

En la nube (con cuenta)

Comunidad

  1. PUBLICAR manda tu juego a revisión (hace falta cuenta).
  2. Cuando se aprueba, sale en la BIBLIOTECA de Play para todos, también sin cuenta.
  3. COMPARTIR te da un enlace para jugarlo directo (se copia solo).
  4. DESPUBLICAR lo quita. Si cambias un juego ya aprobado, vuelve a revisión.

Un juego importado de otra persona solo se publica si su licencia lo permite (MIT, GPL, CC…) o con permiso de su autor. En la biblioteca cualquiera puede reportar un juego; con 3 reportes se oculta mientras se revisa.

🆘 Errores comunes

Cuando algo falla, abajo de la pantalla del juego sale qué pasó, en qué línea y una pista. Estos son los más comunes:

LA FUNCIÓN sprr NO EXISTE · ¿QUISISTE DECIR spr?El nombre está mal escrito. Usa el que te sugiere o búscalo en Funciones.
FALTA UN end PARA EL function DE LA LÍNEA 3Cada function, if, for y while cierra con end. Cuenta que haya uno por cada uno.
SOBRA UN endHay un end de más: bórralo o revisa que no falte un if o function arriba.
FALTA then · FALTA doSe escribe if algo then ... end y for i = 1, 10 do ... end.
vidas NO TIENE VALOR (NIL)Usas una variable que nunca recibió un número. Dale un valor arriba o en _init().
e ESTÁ VACÍO (NIL)Quieres usar e.x pero e no existe (por ejemplo, un enemigo que ya borraste).
UNES TEXTO (..) CON ALGO VACÍOEn print('PUNTOS: ' .. puntos) la variable no tiene valor. Dale uno antes.
FALTA CERRAR LAS COMILLAS · FALTA CERRAR UN PARÉNTESISCada " o ' y cada ( necesita su pareja.
UNA FUNCIÓN SE LLAMA A SÍ MISMA SIN FINUna función se llama sola y nunca para. Revisa que tenga un if para detenerse.

🕹️ Juegos de TIC-80

Chivo-8 corre juegos de TIC-80 escritos en Lua, JavaScript o Fennel: traduce sus funciones (TIC(), spr con color transparente, rect relleno, btn con sus números, pmem, peek/poke…) a las de Chivo-8.

🆕 Versiones

En la consola: VERSION y NOVEDADES.

v0.9.2 · 2026-10-20 · estable

Tu personaje y mundos más grandes

  • Lección 16: tu personaje (spr, palt y voltear el sprite)
  • Lección 17: un mundo más grande que la pantalla (camera)
  • Cada plantilla trae 3 retos al final del código
  • Analítica de visitas y de uso (solo en producción)
  • El Arcade nuevo también abre cartuchos guardados (?cart=) y archivos (?archivo=)

v0.9.1 · 2026-10-20 · estable

Estilos del teclado

  • Teclado en pantalla con 4 estilos: Clásico, Rosa, Lavanda y Neón (tecla ESTILO, se recuerda en el navegador)
  • Textos: la pantalla de 240x136 es inspirada en TIC-80
  • Aviso de BETA con enlace a la versión normal; la beta no aparece en buscadores
  • 3 estilos más de teclado: Rojo, Amarillo y Verde (tonos de Game Boy)
  • Errores en español en la pantalla del juego: qué pasó, en qué línea y una pista (¿quisiste decir spr?)
  • Plantillas de juego: NUEVO SALTO, NAVE, ATRAPA, LABERINTO o CARRERA
  • Biblioteca de sonidos: SONIDOS (20 efectos listos, del 5 al 24) y CANCION (alegre, aventura y misterio)
  • Lección 15: sonido en tu juego (APRENDE 15)
  • El botón ⌨ también esconde el teclado (⌨ ▼), en Chivo-8 y en TIC-80
  • Manual más completo: plantillas, editores, los 16 colores, sonido y música, guardar y comunidad, errores comunes
  • PUBLICAR pone de autor el nombre de tu cuenta de Google si no tiene uno
  • Sonido de encendido de la consola y sonido de cartucho al empezar un juego (también en el Arcade)
  • Pantalla «TOCA LA PANTALLA O ENTER» antes del encendido, para que el sonido de arranque siempre se oiga
  • Arcade: pantalla «PRESIONA START» antes de jugar, para que suenen el arranque y la música desde el principio
  • El Arcade ahora es el mismo Game Boy del Play, solo para jugar y con PRESIONA START; los enlaces para jugar (COMPARTIR) también esperan START
  • 8 colores de carcasa para el Game Boy de Play y el Arcade: toca CHIVO-8 o escribe CARCASA

v0.9.0 · 2026-10-20 · estable

Juegos de TIC-80 y más herramientas

  • Clásicos de TIC-80 en la biblioteca: 16 juegos con licencia abierta y crédito a sus autores
  • Corre juegos de TIC-80 en Lua, JavaScript y Fennel (IMPORT acepta .lua, .js, .fnl y .tic)
  • Pantalla opcional de 240x136 inspirada en TIC-80: comando PANTALLA 128 o PANTALLA 240
  • Jugador 2 en teclado (J L I K + U O) también en los juegos de TIC-80
  • Chivotchi renovado: chivo en pixel, minijuegos, comida o dulce, 3 formas de adulto y álbum
  • Filtro CRT con 5 estilos para elegir el que más te guste: CRT 1 a CRT 5
  • Paleta editable color por color (COLOR N #RRGGBB) y bancos de sprites y mapa (BANCO N)
  • Sonido más profundo: 4 ondas que se dibujan (ED) y velocidad por efecto
  • peek, poke, memcpy y memset con mapa de memoria (MEMORIA)
  • Dibujo: elli, ellib, tri, trib y spr con escala y giro
  • Mapa: vista del mundo completo (MUNDO o Tab)
  • Código: buscar (Ctrl+F), ir a línea (Ctrl+G) y lista de funciones (Ctrl+O)
  • EXPORT PNG e IMPORT PNG de la hoja de sprites; EXPORT HTML: tu juego en un solo archivo
  • Controles físicos (gamepad) y ratón; video y GIF sin saltos
  • Arreglo: pal() y palt() sin argumentos ya restablecen los colores
  • Versiones con número: VERSION muestra lo nuevo, NOVEDADES el historial y aviso al abrir una versión nueva
  • Manual completo (comando MANUAL): comandos, teclas, funciones con ejemplos y lecciones
  • 7 lecciones nuevas (APRENDE 8 a 14): puntos, enemigos, salto, pantallas, récord, partículas y TIC-80
  • Arreglo: COLOR N #RRGGBB ya funciona

v0.8.0 · 2026-10-19 · estable

La consola es la página principal

  • La Consola pasa a ser la página principal; el Estudio queda como Estudio clásico
  • Comunidad: PUBLICAR manda tu juego a revisión y los aprobados salen en la biblioteca
  • COMPARTIR da un enlace que abre el juego directo en Play
  • Lecciones dentro de la consola: APRENDE, SIGUE, ATRAS y PONER
  • Biblioteca en Play con los juegos de Chivo-8, los guardados y los de la comunidad
  • FOTO, GIF y VIDEO del juego; paletas (PALETA) y datos del cartucho (DATOS)
  • Entrar con Google (GOOGLE) y guardar en la nube
  • Beta en /labs/chivo-8-beta/ para probar antes de publicar