Nivel 7: Creemos un mini juego - desplazamiento de personaje
🎮 Creemos un mini juego - desplazamiento de personaje
En este tutorial, crearemos un juego simple pero divertido llamado "Gopher Walk" utilizando la biblioteca Ebitengine. ¡Prepárate para aprender mientras te diviertes! 🚀
📺 Video Tutorial
🧠 Conceptos que aprenderemos
- Configuración básica de un juego con Ebitengine
- Manejo de entrada del usuario
- Animación de sprites
- Escalado y transformaciones de imágenes
- Ciclo de juego (actualización y dibujado)
🛠️ Preparación del entorno
Antes de comenzar, asegúrate de tener Go instalado en tu sistema. Puedes descargarlo e instalarlo desde la página oficial de Go.
Instalación de Ebitengine
- Visita la documentación oficial de instalación de Ebitengine.
- Sigue las instrucciones específicas para tu sistema operativo (Windows, macOS, o Linux).
Inicialización del proyecto
- Crea un nuevo directorio para tu proyecto:
mkdir gopher-walk cd gopher-walk
- Inicializa un nuevo módulo Go:
go mod init gopher-walk
- Instala las dependencias necesarias:
go get "github.com/hajimehoshi/ebiten/v2" go get "github.com/hajimehoshi/ebiten/v2/ebitenutil"
💻 ¡Manos a la obra!
Vamos a escribir cada parte del código
Importaciones y Constantes
package main import ( "fmt" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" "image" "log" "math" ) const ( baseScreenWidth = 640 baseScreenHeight = 480 frameWidth = 64 frameHeight = 64 )
- Importamos los paquetes necesarios, incluyendo Ebitengine (
ebiten/v2
) y utilidades adicionales (ebitenutil
). - Definimos constantes para el tamaño de la pantalla y las dimensiones de cada frame de animación.
Estructura del Juego
type Game struct { playerImage *ebiten.Image playerX float64 playerY float64 frameIndex int direction int // 1 mira hacia la derecha, -1 mira hacia la izquierda frameCount int isMoving bool scale float64 speed float64 }
Esta estructura Game
es el corazón de nuestro juego:
playerImage
: Almacena la imagen del personaje.playerX
yplayerY
: Posición del jugador en la pantalla.frameIndex
: Índice del frame actual de la animación.direction
: Dirección del personaje (1 derecha, -1 izquierda).frameCount
: Contador para controlar la velocidad de la animación.isMoving
: Indica si el personaje está en movimiento.scale
yspeed
: Escala y velocidad del personaje.
Inicialización del Juego
func New() *Game { g := &Game{ playerX: baseScreenWidth / 2, playerY: baseScreenHeight / 2, direction: 1, frameCount: 0, isMoving: false, scale: 2.0, speed: 1.0, } //Carga la imagen del jugador img, _, err := ebitenutil.NewImageFromFile("gognition_gopher.png") if err != nil { log.Fatal(err) } g.playerImage = img return g }
Esta función crea una nueva instancia del juego:
- Inicializamos al jugador en el centro de la pantalla.
- Establecemos valores iniciales para dirección, escala y velocidad.
- Cargamos la imagen del personaje desde un archivo.
Actualización del Juego
func (g *Game) Update() error { g.isMoving = false moveSpeed := g.speed * g.scale // Movimiento de nuestro personaje if ebiten.IsKeyPressed(ebiten.KeyLeft) { g.playerX -= moveSpeed g.direction = -1 g.isMoving = true } if ebiten.IsKeyPressed(ebiten.KeyRight) { g.playerX += moveSpeed g.direction = 1 g.isMoving = true } if ebiten.IsKeyPressed(ebiten.KeyUp) { g.playerY -= moveSpeed g.isMoving = true } if ebiten.IsKeyPressed(ebiten.KeyDown) { g.playerY += moveSpeed g.isMoving = true } //Escalamiento de nuestro personaje if ebiten.IsKeyPressed(ebiten.KeyQ) { g.scale = math.Max(0.1, g.scale*0.99) } if ebiten.IsKeyPressed(ebiten.KeyE) { g.scale = math.Min(5.0, g.scale*1.01) } //Ajuste de la velocidad if ebiten.IsKeyPressed(ebiten.KeyA) { g.speed = math.Max(0.1, g.speed*0.99) } if ebiten.IsKeyPressed(ebiten.KeyD) { g.speed = math.Min(5.0, g.speed*1.01) } // Animación del personaje if g.isMoving { g.frameCount++ if g.frameCount >= 5 { g.frameIndex = (g.frameIndex + 1) % 6 //Avanzamos al siguiente frame, volviendo al 0 después del 5 g.frameCount = 0 } } else { g.frameIndex = 0 } return nil }
Esta función se llama cada frame y maneja la lógica del juego:
- Detectamos la entrada del teclado para mover al personaje.
- Ajustamos la escala y velocidad del personaje.
- Manejamos la animación del personaje cambiando los frames.
Renderizado del Juego
func (g *Game) Draw(screen *ebiten.Image) { baseScreen := ebiten.NewImage(baseScreenWidth, baseScreenHeight) op := &ebiten.DrawImageOptions{} op.GeoM.Scale(float64(g.direction)*g.scale, g.scale) if g.direction == -1 { op.GeoM.Translate(frameWidth*g.scale, 0) } //Posicionar el personaje op.GeoM.Translate(g.playerX, g.playerY) sx := g.frameIndex * frameWidth frame := g.playerImage.SubImage(image.Rect(sx, 0, sx+frameWidth, frameHeight)).(*ebiten.Image) //Dibujar el personaje en la imagen base baseScreen.DrawImage(frame, op) //Añadir información de depuración ebitenutil.DebugPrint(baseScreen, fmt.Sprintf("Escala: %.2f\nVelocidad: %.2f", g.scale, g.speed)) // Calcular la escala necesaria para ajustar el juego a la ventana actual screenScale := math.Min( float64(screen.Bounds().Dx())/float64(baseScreenWidth), float64(screen.Bounds().Dy())/float64(baseScreenHeight), ) screenOp := &ebiten.DrawImageOptions{} screenOp.GeoM.Scale(screenScale, screenScale) screenOp.GeoM.Translate( float64(screen.Bounds().Dx())/2-float64(baseScreenWidth)*screenScale/2, float64(screen.Bounds().Dy())/2-float64(baseScreenHeight)*screenScale/2, ) screen.DrawImage(baseScreen, screenOp) }
Esta función se encarga de renderizar el juego:
- Creamos una imagen base y aplicamos transformaciones al personaje.
- Seleccionamos el frame correcto de la animación.
- Dibujamos el personaje y añadimos información de depuración.
- Escalamos y centramos el juego en la pantalla.
Diseño de la Ventana
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) { return outsideWidth, outsideHeight }
Esta función maneja el diseño de la ventana, permitiendo que el juego se ajuste a diferentes tamaños de pantalla.
Función Principal
func main() { ebiten.SetWindowSize(baseScreenWidth, baseScreenHeight) ebiten.SetWindowTitle("¡Aprende haciendo con Gognition") if err := ebiten.RunGame(New()); err != nil { log.Fatal(err) } }
La función main
es el punto de entrada de nuestro programa:
- Configuramos el tamaño y título de la ventana.
- Iniciamos el juego llamando a
ebiten.RunGame(New())
.
🕹️ Cómo Jugar
- Usa las flechas del teclado para mover al personaje.
- Presiona Q para reducir el tamaño del personaje y E para aumentarlo.
- Presiona A para reducir la velocidad y D para aumentarla.
🌟 Source code
🚀 Próximos Pasos
¡Este es solo el comienzo! Puedes expandir "Gopher Walk" de muchas maneras:
- Añadir obstáculos o enemigos
- Implementar un sistema de puntuación
- Crear diferentes niveles
- Mejorar los gráficos y añadir efectos de sonido
Crear juegos es una forma divertida y práctica de aprender Go. A través de este proyecto, hemos explorado conceptos fundamentales de Go y cómo se pueden aplicar en el desarrollo de juegos.
¿Tienes preguntas o sugerencias? ¡Déjalas en los comentarios abajo! Y no olvides suscribirte a nuestro canal de YouTube para más tutoriales de Go.
Happy coding! 🐹✨
Comentarios