Advertisement
  1. Code
  2. Coding Fundamentals
  3. Game Development

Desarrolla un juego inspirado en Monkey Ball con Unity

Scroll to top
Read Time: 20 min

() translation by (you can also view the original English article)

Final product imageFinal product imageFinal product image
What You'll Be Creating

Introducción

En este tutorial, aprenderás cómo crear un juego 3D para móviles usando C# y Unity. El objetivo del juego es usar el acelerómetro para mover la bola y alcanzar el portal.

Aprenderás los siguientes aspectos del desarrollo de juegos en Unity en este tutorial:

  • Primitivas 3D
  • control del acelerómetro
  • movimiento de cámara
  • física
  • Texturas GUI

1. Crea un nuevo proyecto Unity

Abre Unity y selecciona New Project en el menú File para abrir el diálogo de proyecto nuevo. Díle a Unity dónde quieres guardar el proyecto y configura el menu de Set up defaults for: a 3D.


2. Configuración de desarrollo

En el siguiente paso, se presenta la interfaz de usuario de Unity. En el siguiente paso, se te ofrece la interfaz de usuario de Unity. Configura el proyecto para desarrollo en entornos móviles eligiendo Build Settings en el menú File y seleccionando la plataforma que elijas.


3. Dispositivos

Antes que nada, necesitamos seleccionar la plataforma de destino para elegir el tamaño de las ilustraciones que usaremos en el juego. Esto nos ayudará a seleccionar un tamaño adecuado para las texturas 3D y 2D en el GUI y así evitar que la ilustración aparezca borrosa o utilizar texturas que sean demasiado grandes para el dispositivo de destino. Por ejemplo, las ilustraciones necesitan tener una resolución mayor si vas a desarrollar para un iPad con pantalla retina que si lo haces para un Lumia 520.

iOS

  • iPad sin Retina: 1024px x 768px
  • iPad con Retina: 2048px x 1536px
  • iPhone/iPod Touch de 3,5" sin Retina: 320px x 480px
  • iPhone/iPod de 3.5" sin Retina: 960px x 640px
  • iPhone/iPod Touch de 4": 1136px x 640px

Android

Como Android es una plataforma abierta, hay un amplio rango de dispositivos, resoluciones de pantalla y densidad de píxeles. Aquí tenéis una lista de los que pueden ser los más comunes:

  • Asus Nexus 7 Tablet: 800px x 1280px, 216 ppi
  • Motorola Droid X: 854px x 480px, 228 ppi
  • Samsung Galaxy SIII: 720px x 1280px, 306 ppi

Windows Phone y BlackBerry

  • Blackberry Z10: 720px x 1280px, 355 ppi
  • Nokia Lumia 520: 400px x 800px, 233 ppi
  • Nokia Lumia 1520: 1080px x 1920px, 367 ppi

Daos cuenta de que el código que usemos en este tutorial puede utilizarse para cualquiera de estas plataformas.


4. Exportar gráficos

Dependiendo de los dispositivos para los que estés desarrollando, puede que necesites convertir la ilustración al tamaño y la densidad de píxeles recomendada . Puedes hacerlo en tu editor de imágenes favorito. Yo he usado la función Ajustar tamaño en el menú Herramientas de la aplicación Vista Previa de OS X.


5. La interfaz de usuario de Unity

Puedes modificar la resolución que se va a usar en el panel Game.


6. Interfaz del juego

La interfaz de nuestro juego será bastante sencilla. La captura de pantalla que está aquí arriba te dará una idea de las ilustraciones que vamos a usar y el aspecto que terminará teniendo la interfaz del juego. Puedes encontrar las ilustraciones y los recursos adicionales en los archivos del tutorial en GitHub.


7. Lenguaje de programación

Puedes usar uno de estos tres lenguajes de programación cuando uses Unity: C#, UnityScript, una variante de JavaScript, y Boo. Cada lenguaje tiene sus pros y sus contras, y eres tú el que tiene que decidir cuál prefieres. Mi preferencia personal se la lleva C#, así que ese es el lenguaje que voy a usar en este tutorial.

Si decides usar otro lenguaje de programación, asegúrate de echar un vistazo al Unity's Script Reference para consultar los ejemplos.


8. Efectos de sonido

Voy a usar unos cuantos efectos de sonido para mejorar la experiencia auditiva del juego. He conseguido los efectos de sonido que uso en este tutorial de playonloop.com y Freesound.


9. Modelos 3D

Para crear nuestro juego, primero necesitamos conseguir nuestros modelos 3D. Yo recomiendo 3docean para modelos de alta calidad, texturas y más, pero si sólo estás probando o aprendiendo puedes usar si quieres los modelos gratis. Los modelos para este tutorial se bajaron de SketchUp 3D Warehouse, donde puedes encontrar una buena variedad de modelos de todas las clases.

Ahora, ya que Unity no reconoce el formato de archivo de SketchUp, necesitamos convertirlo a algo que Unity pueda importar. Lo primero que haremos es bajarnos la versión gratuita de SketchUp, que se llama SketchUp Make.

Abre tu modelo 3D en SketchUp Make, selecciona Exportar > Modelo 3D del menú Archivo, y elige Collada (*.dae).

Elige un nombre y un destino y haz clic en el botón de guardar. Esto creará un archivo y una carpeta para el modelo 3D. Este fichero contiene los datos del objeto 3D y la carpeta guarda los mapas de textura. Ya puedes importar el modelo a Unity como se explica en el siguiente paso.


10. Importar elementos

Antes de empezar a escribir código, tenemos que incorporar nuestros elementos al proyecto de Unity. Puedes hacerlo de una de estas formas:

  • seleccionar Import Asset en el menú Assets
  • añadir los elementos a la carpeta de elementos de tu proyecto
  • arrastrar y colocar los elementos en la ventana del proyecto

Después de completar este paso, tendrías que ver tus elementos en la carpeta Assets del proyecto, dentro del panel Project.


11. Crear la escena

Estamos listos para crear la escena de nuestro juego arrastrando los objetos a unos de estos dos paneles: Hierarchy o Scene. También usaremos las primitivas 3D nativas de Unity para crear el nivel, tal como se muestra en los siguientes pasos.

12. Configurar la cámara

En primer lugar vamos a posicionar nuestra Main Camera (cámara principal) un poco más arriba para conseguir la vista que queremos. Selecciónala en el panel Hierarchy y ajusta los valores Transform en el Inspector para que coincidan con los que se indican abajo.

No te preocupes si no ves ningún cambio. Todavía no hemos creado nada que pueda ver la cámara. Luego, usa el Inspector para cambiar el color del Background a RGB: 0, 139, 252.

13. Fondo (Background)

Nuestra plataforma de nivel estará flotando sobre un fondo, que será la representación de un mar. Se creará con las primitivas de Unity, un simple Plano al que aplicaremos una textura.

Si bien Unity puede trabajar con objetos 3D de cualquier tipo creados por otros programas, a veces es más fácil y / o más conveniente usar primitivas para prototipos.

Para crear el mar, por ejemplo, selecciona Create Other > Plane en el menú GameObject y ajusta los valores Transform en el Inspector para que coincidan con los que se muestran en la imagen.

Debe un cuadrado en el panel Scene. Lo usaremos para detectar cuándo el jugador se cae de la plataforma y termina el juego.

Vale la pena mencionar que estos objetos primitivos ya tienen un Mesh Collider adjunto, lo que significa que detectarán automáticamente colisiones o desencadenarán eventos cuando entren en contacto con un RigidBody.

14. Material de textura

Para aplicar una textura al plano marino, necesitamos crear un Material. Un Material se usa para definir cómo se ve GameObject y es esencial agregar una textura a GameObject.

Seleccione Create > Material en el menú Assets para crear uno, encuéntrelo en el panel Assets y use el Inspector para seleccionar la textura que desea usar como su mar. Estas son las configuraciones que he usado:

Notarás un mensaje en la sección de material que indica que se recomienda usar Mobile / Diffuse como sombreador, porque el color blanco predeterminado no hace nada. Cambiarlo a Mobile / Diffuse también ayudará con el rendimiento.


15. Agregando Luz

Puede que hayas notado que el mar es un poco más oscuro de lo que debería ser. Para solucionar esto, necesitamos agregar una Luz Light a nuestra escena. Seleccione Create Other en el menú GameObject y seleccione Directional Light. Esto creará un objeto que produce un haz de luz. Cambie sus valores de Transform como se muestra en la siguiente captura de pantalla para que ilumine el mar.

Esto se ve mucho mejor.

16. Creando Plataformas

Las plataformas pertecen a nuestro nivel y el jugador las usa para mover la bola al portal del otro lado del mar.

Cree un Plane como lo hizo para el mar y ajuste los valores de Transform en el Inspector como se muestra a continuación. Esto creará y pondrá la primera plataforma en su lugar.

Ahora podemos usar las herramientas Move y Rotation de Unity para crear las otras plataformas. Todos son del mismo tamaño, por lo que podemos usarlos vertical u horizontalmente duplicándolos usando Command + D en OS X y Control + D en Windows.


17. Textura de la plataforma

Cree un nuevo Material como hicimos en el paso 14 y aplíquele la textura. El mío se parece a esto:

Ajusta los mosaicos x e y hasta que estés satisfecho con el resultado.


18. Cilindros bordes

Necesitamos crear un borde para evitar que nuestro jugador se caiga con demasiada facilidad. Para hacer esto, usaremos un nuevo tipo de primitiva, un Cilindro Cylinder.

Seleccione Create Other > Cylinder en el menú GameObject y ajuste los valores de Transform en el Inspector como se muestra a continuación.

Esto agregará un borde pequeño al borde de la primera plataforma. Cree un nuevo Material y cambie su color en el Inspector a RGB: 255, 69, 0.

El resultado debería verse así:

Use Comando + D (Control + D en Windows) para duplicar el borde y la herramienta Scale para cambiar su tamaño. Posiciona los duplicados en los bordes de las plataformas usando las herramientas de Unity.


19. Portal

El portal es la meta final del juego. El jugador usará el acelerómetro para controlar la bola y llevarla hasta este punto mientras recoge los objetos y evita que se caiga de la plataforma. El portal es un modelo 3D, el cual ya hemos importado en el Paso 10. El portal es un modelo 3D, que importamos en el Paso 10.

Arrástrelo y suéltelo en el panel Scene o Hierarchy y cambie sus valores de Transform a lo siguiente:

Esto lo posicionará al final de las plataformas.


20. Portal Collider

Debido a que los modelos 3D importados no tienen un colisionador de forma predeterminada, debemos adjuntar uno. Como solo necesitamos evaluar si la pelota golpea el área azul del portal, le colocaremos el colisionador.

Eche un vistazo al modelo de portal en la vista Hierarchy y verá un pequeño triángulo a la izquierda de su nombre. Haga clic en el triángulo para expandir el grupo del portal y seleccione el primer elemento. He agregado el sufijo -Collider para aclararme.

Haga clic en el botón Add Component en el Inspector y seleccione Physics > Mesh Collider. Esto agregará un colisionador usando la forma del área seleccionada del modelo.


22. La fuente de sonido del Portal

Para ofrecerle feedback al jugador, reproduciremos un efecto de sonido cuando la bola toque el colisionador del portal. Como activaremos el evento usando el colisionador que hemos creado previamente, necesitamos añadir una fuente de sonido a ese mismo objeto.

Selecciónalo en el panel Hierarchy, haz clic en el botón Add Component del panel Inspector y selecciona Audio Source en la sección Audio.

Quita el check de la casilla Play on Awake y haz clic en el puntito que está a la derecha, bajo el icono del engranaje, para seleccionar el sonido que quieres reproducir.

22. Agregar islas

Las islas no son más que elementos decorativos para hacer que el nivel esté menos vacío. He usado un modelo 3D importado y un Cylinder para hacerlos. No entraré en detalles para crear las islas, ya que no son esenciales para el juego. Con lo que has aprendido hasta ahora, deberías ser capaz de crearlos tú mismo.


23. Agregando Plátanos

Al igual que en Monkey Ball, el jugador podrá recoger plátanos durante el juego. Comience arrastrando el modelo desde el panel Assets a Scene. No se preocupe por su ubicación todavía, porque la convertiremos a Prefab más adelante, ya que la reutilizaremos varias veces.

24. Banana Mesh Collider

Como mencioné anteriormente, los modelos importados no tienen un colisionador por defecto, por lo que debemos adjuntar uno al plátano. Haga clic en el botón Add Component en Inspector y seleccione Physics > Mesh Collider. Esto agregará un colisionador usando la forma del modelo. Asegúrese de marcar la casilla Trigger, porque queremos detectar colisiones, pero no queremos que la bola reaccione con el plátano.


24. Agregar el jugador

Es hora de crear nuestro personaje del juego, que será una simple primitiva Sphere. Seleccione Create Other > Sphere en el menú GameObject para crear la primitiva y modificar los valores de Transform en el Inspector como se muestra a continuación.

Esto creará la esfera y la posicionará al comienzo de nuestro nivel.

Para hacer que la esfera sea semitransparente, debemos cambiar sus opciones de Shader. Abra el Inspector y cambie el sombreador a Transparent/Diffuse.


25. Jugador RigidBody

Para detectar una colisión con el jugador, debemos adjuntarle un RigidBody. Para agregar uno, seleccione Add Component en el panel Inspector, seguido de Physics > RigidBody. Puede dejar la configuración en sus valores predeterminados.


26. Texturas GUI

Para mostrar la interfaz de usuario del juego, usaremos las Texturas GUI de Unity. La documentación de Unity proporciona una explicación clara de las Texturas GUI:

Las Texturas GUI se muestran como imágenes planas en 2D. Están hechos especialmente para elementos de la interfaz del usuario, botones o decoraciones. Su posicionamiento y escalado se realiza solamente a lo largo de los ejes xey, y se miden en Coordenadas de pantalla, en lugar de las Coordenadas mundiales.

De forma predeterminada, las imágenes importadas a la carpeta Assets se convierten a Texturas que se pueden aplicar a objetos 3D. Necesitamos cambiar esto a Textura GUI para las imágenes que queremos usar en la interfaz de usuario del juego.

Seleccione las imágenes que desea convertir en el panel Assets y abra el Inspector, haga clic en el menú desplegable Texture Type y seleccione GUI.

Ahora puede arrastrar y soltar las imágenes a la Scene. Las imágenes siempre aparecerán frente a cada objeto en el escenario y se tratarán como elementos 2D.

27. Texto GUI

Dentro de cada elemento de la GUI, mostraremos un número que indica la cantidad de plátanos que el jugador ha recogido y el tiempo que le queda al jugador.

Seleccione Create Other > GUI Text en el menú GameObject para crear un objeto de texto, colóquelo en el centro del elemento GUI y cambie el texto en el panel Hierarchy a 0. Haga lo mismo para la hora a la derecha. Establecí el tiempo predeterminado en 30 segundos.

Puede usar una fuente personalizada para el texto agregando la fuente a la carpeta Assets y luego cambiando la propiedad Font Fuente del texto en el Inspector.

28. Agregar scripts

Es hora de escribir algún código. Con la interfaz de usuario en su lugar, podemos comenzar a escribir el código necesario para agregar funcionalidad a nuestro juego. Hacemos esto por medio de scripts. Los scripts están unidos a diferentes objetos del juego. Siga los siguientes pasos para aprender cómo agregar interacción al nivel que acabamos de crear.


29. Escena movimiento

Comenzaremos haciendo uso del acelerómetro del dispositivo. Mover al jugador usando el acelerómetro es bastante simple en Unity. No hay nada que configurar y es fácil de entender.

Seleccione la etapa, haga clic en el botón Add Component en el panel Inspector y elija New Script. Nombre el script MoveScene y no olvide cambiar el idioma a C #. Abra el archivo recién creado y agregue el siguiente fragmento de código

1
using UnityEngine;
2
using System.Collections;
3
4
public class MoveScene : MonoBehaviour
5
{
6
    void Update()
7
    {
8
        transform.rotation *= Quaternion.Euler(Input.acceleration.y/6, -Input.acceleration.x/3, 0);
9
    }
10
}

Utilizamos el método Update para solicitar datos del acelerómetro en cada cuadro utilizando la propiedad Input.acceleration, que mide el movimiento del dispositivo en un espacio tridimensional. Esto nos permite obtener los valores x, y, y z y usarlos para controlar la posición del jugador.

Luego aplicamos los valores obtenidos a la propiedad transform.rotation del nivel invocando Quaternion.Euler, que devuelve los valores de rotación. Tenga en cuenta que dividimos los valores del acelerómetro para evitar que el ugador se mueva demasiado rápido, lo que dificulta el juego.

Solo modificamos los valores x e y del nivel, porque solo necesitamos que se incline y no se mueva más cerca o más lejos de la cámara.

30. Seguimiento de Cámara

La siguiente secuencia de comandos está conectada a la Main Camera. Calcula el espacio entre la cámara y el jugador y lo mantiene mientras la bola se mueve.

1
using UnityEngine;
2
using System.Collections;
3
4
public class FollowPlayer : MonoBehaviour
5
{
6
    public GameObject player;
7
    private Vector3 playerOffset;
8
9
    // Use this for initialization

10
    void Start()
11
    {
12
        playerOffset = transform.position - player.transform.position;
13
    }
14
    
15
    // Update is called once per frame

16
    void Update()
17
    {
18
        transform.LookAt(player.transform);
19
        transform.position = player.transform.position + playerOffset;
20
    }
21
}

El script usa dos variables que vale la pena explicar:

  • player: esta es una referencia al jugador en la Scene. Puede configurar esto en el Inspector.
  • playerOffset: esta es la distancia entre la cámara y el jugador. Debido a que mantenemos la misma distancia entre la cámara y el reproductor, la cámara sigue al jugador mientras se mueve. El desplazamiento se calcula en el método Start.

Dirigimos la cámara al reproductor y establecemos su posición en la posición del jugador más el valor de playerOffset. Debido a que hacemos esto en el método Update, la posición de la cámara se calcula y actualiza en cada cuadro. El resultado es que la cámara sigue al jugador. Esta es una estrategia simple pero efectiva para crear una cámara que sigue al jugador.

31. Elegir plátanos

La siguiente secuencia de comandos se adjunta a la banana y maneja cualquier interacción con ella. Comenzamos obteniendo referencias al sonido correspondiente y al texto que muestra el número de bananas recolectadas, que necesitaremos para reproducir el sonido y aumentar el contador en la parte superior izquierda cuando el jugador colisiona con un plátano. Una vez que haya declarado las variables en la secuencia de comandos, debe establecer estas referencias en el Inspector.

1
using UnityEngine;
2
using System.Collections;
3
4
public class PickBanana : MonoBehaviour
5
{
6
    public AudioClip bananaSound;
7
    public GUIText bananaText;
8
9
    void OnTriggerEnter(Collider other)
10
    {
11
        AudioSource.PlayClipAtPoint(bananaSound, transform.position);
12
		int score = int.Parse (bananaText.text) + 1;
13
		bananaText.text = score.ToString();
14
        Destroy(gameObject);
15
    }
16
}

Luego, llamamos a un método que detecta cuando la pelota colisiona con una banana. Cuando esto sucede, reproducimos el sonido y aumentamos el contador.

Para modificar el contador, creamos una variable usando el valor del Texto GUI y usamos el método int.Parse para convertir la cadena a un número e incrementar el número en 1. Luego, establecemos el valor en el Texto GUI, primero convirtiendo el número a una cadena invocando el método toString. Finalmente, invocamos a Destroy para eliminar el objeto del juego banana.

32. Caerse de la plataforma

La siguiente clase se usa para detectar cuándo el jugador cae de la plataforma al mar. Adjunta la secuencia de comandos al objeto de juego del mar.

1
using UnityEngine;
2
using System.Collections;
3
4
public class Lose : MonoBehaviour
5
{
6
    void OnCollisionEnter()
7
    {
8
        audio.Play();
9
        Invoke("Reload", 1.59f);
10
    }
11
12
    void Reload()
13
    {
14
        Application.LoadLevel(Application.loadedLevel);
15
    }
16
}

Esta clase simple usa el método OnCollisionEnter para detectar cuándo la pelota colisiona con el mar, lo que significa que el jugador se cayó de la plataforma. Cuando esto sucede, reproducimos el sonido adjunto al mar y usamos el método Invoke para llamar al método Reload, que reinicia el juego al volver a cargar la escena actual.

El segundo parámetro del método Invoke define la demora con la que se invoca el método Reload. Esto es necesario ya que primero queremos que el sonido termine antes de comenzar un nuevo juego.

33. Tiempo de monitoreo

La siguiente clase, Timer, está conectada a la GUI de tiempo en la parte superior derecha. Reduce el tiempo y finaliza el juego cuando el contador llega a 0.

1
using UnityEngine;
2
using System.Collections;
3
4
public class Timer : MonoBehaviour
5
{
6
    public GUIText timeText;
7
8
    void Start()
9
    {
10
        InvokeRepeating("ReduceTime", 1, 1);
11
    }
12
13
    void ReduceTime()
14
    {
15
        int currentTime = int.Parse(timeText.text) - 1;
16
        timeText.text = currentTime.ToString();
17
18
        if (currentTime == 0)
19
        {
20
            audio.Play();
21
            Invoke("Reload", 1.59f);//waits until sound is played to reload

22
            Destroy(timeText);
23
        }
24
    }
25
26
    void Reload()
27
    {
28
        Application.LoadLevel(Application.loadedLevel);
29
    }
30
}

Mantenemos una referencia al texto en la variable timeText para facilitar la modificación de la interfaz de usuario. En el método Start, llamamos al método InvokeRepeating, que invoca repetidamente el método ReduceTime repetidamente.

Para actualizar el texto en la interfaz de usuario, creamos una variable para convertir el texto a un número, tal como lo hicimos anteriormente, y restamos un segundo y actualizamos la interfaz de usuario con el resultado.

Cuando el contador llega a 0, se reproduce el sonido apropiado y destruimos el texto del contador. Invocamos el método Reload con un retraso para reiniciar el juego cuando el sonido ha terminado de reproducirse.

34. Nivel completo

La última clase, EndLevel, se usa para detectar cuándo el jugador llega al portal. Cuando el jugador pasa a través del portal, mostramos un mensaje en la pantalla y destruimos la bola. Hacemos esto para evitar que la pelota caiga al mar.

1
using UnityEngine;
2
using System.Collections;
3
4
public class EndLevel : MonoBehaviour
5
{
6
    public GameObject complete;
7
    public GameObject player;
8
9
    void OnTriggerEnter(Collider other)
10
    {
11
        audio.Play();
12
        Invoke("Restart", 2);
13
        GameObject alert = Instantiate(complete, new Vector3(0.5f, 0.5f, 0), transform.rotation) as GameObject;
14
        Destroy(player.rigidbody);
15
    }
16
17
    void Restart()
18
    {
19
        Application.LoadLevel(Application.loadedLevel);
20
    }
21
}

El método Instantiate se utiliza para crear una instancia del mensaje que se muestra al jugador. Nos permite usar el elemento GUI de los Assets del proyecto en lugar de tenerlo en la escena. Finalmente, reiniciamos el juego con un retraso de dos segundos.

35. Prueba

Es hora de probar el juego. Presiona Comando + P para jugar el juego en Unity. Si todo funciona como se espera, entonces estás listo para los pasos finales.


36. Configuración del jugador

Cuando esté satisfecho con su juego, es hora de seleccionar Build Settings en el menú File y hacer clic en el botón Player Settings. Esto debería mostrar la Player Settings en el panel Inspector, donde puede establecer los parámetros para su aplicación.

Estas configuraciones son datos específicos de la aplicación que incluyen el creador o la compañía, resolución de la aplicación y modo de visualización, modo de renderizado (CPU, GPU), compatibilidad del sistema operativo del dispositivo, etc. Configure los ajustes según los dispositivos a los que se dirige y la tienda o mercado donde planea publicar la aplicación.


37. Iconos e imágenes Splash

Usando los gráficos que creó anteriormente, ahora puede crear un icono agradable y una imagen de bienvenida para su juego. Unity le muestra los tamaños requeridos, que dependen de la plataforma para la que está construyendo.

38. Build y juega


Una vez que tu proyecto esté configurado de la forma adecuada, es hora de revisitar los Build Settings y hacer clic en el botón Build. Eso es todo lo que tienes que hacer para compilar tu juego para pruebas y/o distribución.

Conclusión

En este tutorial hemos aprendido a usar el acelerómetro para controlar el movimiento del jugador, las texturas de la interfaz, las primitivas y otros aspectos del desarrollo de juegos en Unity. Te animo a que experimentes con el resultado y lo personalices hasta hacerlo tuyo. Espero que te haya gustado y lo hayas encontrado útil.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.