Introducción
A través de los logros y estadísticas de Steam, tu juego puede proporcionar fácilmente a los usuarios un seguimiento de sus logros y estadísticas persistente y desde cualquier lugar. Los datos del usuario están asociados a la cuenta de Steam, y todos los logros y estadísticas de cada usuario se pueden formatear y mostrar en su perfil de la comunidad de Steam.
Utilidad
Además de ofrecer recompensas muy apreciadas por los jugadores, los logros son útiles para incentivar y recompensar el trabajo en equipo y la interacción entre los jugadores, ya que añaden más dimensiones a los objetivos del juego y premian a los usuarios por dedicarle más tiempo al juego.
Las estadísticas realizan un seguimiento de datos detallados, como el tiempo de juego, la cantidad de mejoras utilizadas, etc. También pueden usarse simplemente para hacer un seguimiento de los datos internos del juego. De esta forma, por ejemplo, podrás conceder un logro a partir de las estadísticas de varias sesiones de juego recopiladas en diferentes ordenadores y dispositivos del usuario.
Resumen de implementación
Configuración de las estadísticas y logros del juego
Los logros son específicos para cada aplicación y se configuran en la página del administrador de aplicaciones del sitio de asociados de Steamworks.
El juego puede almacenar tres tipos de estadísticas:
- INT: un valor numérico entero de 32 bits con signo (por ejemplo, la cantidad de juegos a los que jugó el usuario)
- FLOAT: un valor de punto flotante de 32 bits (por ejemplo, número de millas recorridas)
- AVGRATE: una media móvil. Consulta: Tipo de estadística AVGRATE
El sitio web de asociados de Steamworks proporciona una interfaz para establecer y actualizar las estadísticas y logros del juego. Se puede utilizar para lo siguiente:
- Establecer las estadísticas y logros iniciales.
- Añadir más estadísticas y logros.
- Actualizar los nombres, descripciones e iconos de los logros.
- Actualizar los parámetros y restricciones de las estadísticas (valores máximos y mínimos, tamaños de media móvil de ventanas, etc.).
Las estadísticas tienen las siguientes propiedades:
- ID: una identificación numérica generada automáticamente para cada estadística.
- Tipo: el tipo de esta estadística: INT, FLOAT o AVGRATE.
- Nombre de la API: la cadena utilizada para acceder a esta estadística mediante la API.
- Establecido por: establece quién puede modificar la estadística. El valor predeterminado es «Client». Para obtener más información, consulta Estadísticas del servidor de juego.
- Incrementar únicamente: si se establece, esta estadística solo puede aumentar su valor con el tiempo.
- Diferencia máxima: si se configura, establece un límite en la cantidad que el valor de la estadística puede cambiar entre una llamada a SetStat y la siguiente.
- Valor mínimo: si se establece, el valor numérico mínimo que puede tomar esta estadística. De forma predeterminada, el mínimo es el mínimo del tipo numérico subyacente (INT_MIN o -FLT_MAX).
- Valor máximo: si se establece, el valor numérico máximo que puede tomar esta estadística. De forma predeterminada, el máximo es el máximo del tipo numérico subyacente (INT_MAX o FLT_MAX).
- Valor predeterminado: si se configura, el valor predeterminado inicial de esta estadística para un nuevo usuario. Si no se establece, el valor predeterminado es 0.
- Agregado: si se establece, Steam mantendrá un total global para esta estadística. Consulta la sección sobre estadísticas globales más abajo para obtener más información.
- Nombre para mostrar: el nombre de esta estadística cuando se muestra en tu aplicación.
AVGRATE Las estadísticas tienen las siguientes propiedades adicionales:
- Ventana: tamaño de la «ventana deslizante» que se usará para hallar la media de los datos.
Steam promedia automáticamente las estadísticas
AVGRATE. Consulta la sección
AVGRATE a continuación para obtener más información.
Los logros tienen las siguientes propiedades:
- ID: una identificación numérica generada automáticamente para cada logro.
- Nombre de la API: la cadena utilizada para acceder a este logro mediante la API.
- Estadística de progreso: especifica una estadística que se usa como una barra de progreso en la comunidad para este logro. El logro se desbloqueará automáticamente cuando la estadística alcance el valor de desbloqueo.
- Nombre para mostrar: el nombre que este logro tendrá en las ventanas emergentes de notificación del cliente y en la comunidad. Se puede traducir a otros idiomas.
- Descripción: una descripción de este logro, para mostrar en la comunidad. Se puede traducir a otros idiomas.
- Establecido por: establece quién puede desbloquear el logro. El valor predeterminado es «client». Para obtener más información, consulta Estadísticas del servidor de juego.
- ¿Oculto?: si es
true
, es un logro «oculto» que no se muestra en la página de la comunidad de un usuario (en absoluto) hasta que lo hayan logrado.
- Icono de logro desbloqueado: el icono que se muestra cuando se completa un logro.
- Icono de logro bloqueado: el icono que se muestra cuando aún no se ha completado el logro.
Esta es la lista de logros de
Ejemplo de aplicación de la API de Steamworks (Spacewar!):
Consideraciones especiales
- Los iconos y nombres de los logros deben ser apropiados para todas las edades.
- De forma predeterminada, los juegos inicialmente tienen un límite de 100 logros. Podrás añadir más una vez que tu aplicación alcance el umbral para las Características del perfil.
Cómo se usan
¿Cómo acceder a los logros y estadísticas desde dentro del juego?:
- Después de iniciar la API de Steamworks, se puede empezar a usar la API de estadísticas y logros, que forma parte de la interfaz ISteamUserStats.
- Al comienzo de una sesión de juego, llama a ISteamUserStats::RequestCurrentStats para obtener las estadísticas del usuario y los datos de logros del backend de Steam. Recibirás una función callback ISteamUserStats::UserStatsReceived_t cuando los datos estén listos.
- Usa ISteamUserStats::GetStat y ISteamUserStats::GetAchievement para iterar los datos e inicializar el estado del juego.
- Si deseas mostrar los logros en tu juego, puedes usar ISteamUserStats::GetAchievementDisplayAttribute para recuperar las propiedades legibles del logro, incluidos su nombre ("nombre") y descripción ("desc"). Estas propiedades se pueden traducir en esta página del sitio web de asociados de Steamworks y los datos se devuelven en el idioma en que el usuario esté ejecutando el juego. También puede obtener el icono de un logro usando ISteamUserStats::GetAchievementIcon o la hora en que se desbloqueó cada logro con ISteamUserStats::GetAchievementAndUnlockTime.
- Siempre que cambie una estadística, especialmente antes de que se muestre cualquier cambio al usuario, llama a ISteamUserStats::SetStat o a ISteamUserStats::UpdateAvgRateStat. Estas llamadas solo modifican el estado en memoria de Steam y utilizan muy pocos recursos. Esto permite a Steam conservar los cambios entre sesiones aun en el caso de que el juego se bloquee.
- En los puntos apropiados dentro de tu juego (es decir, puntos de control, transiciones de nivel), llama a ISteamUserStats::StoreStats para cargar los cambios. Recibirás una función callback de ISteamUserStats::UserStatsStored_t cuando se haya completado.
- Para los logros que tienen barras de progreso, usa ISteamUserStats::IndicateAchievementProgress en puntos significativos para mostrar una ventana emergente con el progreso. Por ejemplo, si son necesarias 20 victorias, se puede llamar a esta función al llegar a 10 victorias para indicar al usuario que está a mitad de camino.
- Siempre que se desbloqueen uno o más logros, llama a ISteamUserStats::SetAchievement para cada logro desbloqueado y luego a ISteamUserStats::StoreStats para cargarlos inmediatamente. Tu juego verá una función callback de ISteamUserStats::UserStatsStored_t y otra de ISteamUserStats::UserAchievementStored_t por cada logro desbloqueado. La interfaz de Steam en el juego mostrará al usuario un panel de notificación.
Tipo de estadística AVGRATE
Este tipo de estadística ofrece una funcionalidad especial y muy útil, pero requiere una explicación algo más detallada.
Supongamos que queremos llevar un seguimiento de una estadística media, como «puntos ganados por hora». Un método posible sería usar dos estadísticas, una de tipo INT con «TotalPoints» y una de tipo FLOAT con «TotalPlayTimeHours», para luego dividir los puntos entre el tiempo y obtener los puntos por hora.
El inconveniente de esta implementación es que, cuando el jugador acumula una amplia cantidad de tiempo de juego, la media calculada cambia con una lentitud extrema. De hecho, cuanto más juegue el usuario, peor responderá esta media. Si el usuario ha pasado 100 horas jugando al juego, la media calculada se retrasará unas 50 horas respecto a esa cantidad. Si el usuario aumenta su habilidad, no verá el aumento en puntos por hora que espera.
La estadística AVGRATE permite utilizar un «efecto de ventana deslizante» en la media. Por ejemplo, se pueden utilizar solo las últimas horas de juego para que la estadística refleje con más precisión el nivel de habilidad actual del jugador.
Configuremos una estadística AVGRATE que calcule «puntos por hora» y en la que solo se usen las 20 horas de juego anteriores para calcular el valor. Haríamos lo siguiente:
- Ten en cuenta que, como estamos calculando la media «por horas», las unidades de tiempo de todos los parámetros asociados con esta estadística serán «horas». Esto se aplica a la propiedad del rango en la estadística en sí, y también para la "dSessionLength" parámetro pasado en
UpdateAvgRateStat
a continuación.
- Crea una estadística AVGRATE llamada «AvgPointsPerHour» y un abanico temporal de 20 (recordemos que la unidad es en «horas»).
- En los puntos apropiados durante tu juego, llama a ISteamUserStats::UpdateAvgRateStat con los siguientes parámetros:
- pchName: "AvgPointsPerHour"
- flCountThisSession: número de puntos que ha ganado el jugador desde la última llamada a UpdateAvgRateStat.
- dSessionLength: la cantidad de tiempo de juego desde la última llamada a UpdateAvgRateStat. La unidad debería ser la misma que la de la propiedad de la ventana de la estadística. En este caso, «horas».
- Por ejemplo, si el jugador obtuvo 77 puntos en la última ronda, que duró 0,225 horas (13,5 minutos), eso sería
SteamUserStats()->UpdateAvgRateStat( "AvgPointsPerHour", 77, 0.225 )
En el ejemplo anterior, Steam tomará la media de 342,2 puntos por hora (77 entre 0,225) de la ronda actual para combinarla con el valor anterior. El resultado reflejará la media total de las últimas 20 horas de juego del jugador. Si esta es la primera vez que se actualiza la estadística para el usuario actual, el valor será 342,2.
Este ejemplo usa «horas» como unidad de tiempo, pero puedes usar la unidad de tiempo que prefieras. Solo hay que tener en cuenta que esa unidad se debe usar homogéneamente como base para "dSessionLength", así como para la propiedad de la ventana.
Obtener estadísticas de otros usuarios
Puedes usar
ISteamUserStats::RequestUserStats para obtener las estadísticas de otro usuario. Luego puedes usar
ISteamUserStats::GetUserStat,
ISteamUserStats::GetUserAchievement y
ISteamUserStats::GetUserAchievementAndUnlockTime para obtener datos para el usuario. Estos datos no se actualizan automáticamente a medida que el otro usuario carga nuevas estadísticas, por lo tanto, para actualizar los datos simplemente vuelve a llamar a
ISteamUserStats::RequestUserStats.
Para no usar demasiada memoria, se mantiene una caché LRU y se descargan ocasionalmente las demás estadísticas del usuario. Cuando esto sucede, se envía automáticamente una función callback
ISteamUserStats::UserStatsUnloaded_t. Cuando se envíe esta función callback, las estadísticas del usuario especificado no estarán disponibles hasta que se vuelva a llamar a
ISteamUserStats::RequestUserStats.
Modo desconectado
Steam mantiene una caché local de los datos de estadísticas y logros, de forma que las API se puedan usar con normalidad en modo desconectado. Las estadísticas que no se puedan enviar se guardan hasta la siguiente vez que el usuario se conecta. En caso de que se hayan modificado en más de un dispositivo, Steam combinará automáticamente los logros y elegirá el conjunto de estadísticas que tenga mayor progreso. Puesto que Steam guarda los datos de estadísticas en una caché local, no es necesario que el juego mantenga también en el disco una caché local de los datos. De hacerlo, se podría producir un conflicto entre ambas cachés y al usuario le parecería que su progreso ha desaparecido, lo que resultaría frustrante.
Estadísticas del servidor de juego
En paralelo a
ISteamUserStats existe
ISteamGameServerStats para los servidores de juego. Los servidores pueden obtener estadísticas de los usuarios del mismo modo que los clientes, tal como se ha descrito antes. También pueden configurar estadísticas y conceder logros, pero solo si la opción «Establecido por» se configura como GS (servidor de juego) o como Official GS (servidor oficial). La diferencia entre servidores de juego y servidores oficiales de juego es que tú controlas estos últimos y ofertas tu servicio desde ellos. Usar los servidores oficiales de juego para establecer estadísticas aporta mayor seguridad frente a las trampas, ya que los usuarios podrían modificar sus propios servidores de juego o simular ser un servidor de juego. Para definir los servidores oficiales del juego, introduce los rangos de IP de los servidores
aquí.
Los usuarios no pueden configurar las estadísticas ni los logros que son configurables por parte de los servidores. Los servidores de juego solo pueden configurar estadísticas y logros para usuarios que estén jugando actualmente en el servidor. Si el usuario abandona el servidor, hay un breve período de gracia para establecer las estadísticas finales, pero después cualquier nueva carga de estadísticas será denegada. Esto ayuda a garantizar la consistencia y a evitar que un servidor de juego malintencionado establezca las estadísticas de alguien en cualquier momento. Dada la restricción, es importante no esperar hasta el final de una ronda para establecer las estadísticas. Han de establecerse de forma continuada, para poder almacenarlas cuando un usuario abandona el servidor.
Los clientes obtendrán actualizaciones automáticas cuando un servidor de juego cambie sus estadísticas. Sin embargo, al igual que los clientes, las estadísticas cargadas por el servidor para otros usuarios no se actualizan automáticamente y pueden quedar obsoletas.
Restablecer estadísticas
Durante el desarrollo, a menudo sucede que es preferible una eliminación completa de estadísticas y logros en una cuenta o en todas ellas con fines de testeo. Para borrar las estadísticas de una cuenta, llama a
ISteamUserStats::ResetAllStats con
bAchievementsToo
establecido en
true para borrar también los logros. Cuando termine la llamada, acuérdate de reiterar las estadísticas y logros, y restablecer el estado de juego en memoria. No hay forma de eliminar globalmente las estadísticas y los logros para todos los usuarios. Una de las razones para ello es que, incluso si se hiciese una eliminación global, las partidas en curso podrían no detectar la eliminación y reescribir los valores en memoria. Afortunadamente, hay una forma sencilla de elaborar un sistema para eliminaciones globales integrado en los juegos. Para ello:
- Define una estadística con un nombre como «Versión».
- Pon un número de versión para estadísticas codificado de forma rígida en el juego.
- Una vez que se hayan cargado las estadísticas, compara la estadística «Versión» con tu número de versión codificada.
- Si no coinciden, llama a ISteamUserStats::ResetAllStats y luego configura la estadística «Versión» con el número codificado.
De esta forma, siempre que quieras realizar una eliminación global, solo tendrás que cambiar el número de versión para las estadísticas codificadas de forma rígida. La eliminación global tendrá lugar después, a medida que los usuarios accedan a la nueva compilación.
Consistencia de estadísticas
Es una práctica recomendada considerar que las estadísticas relacionadas podrían volverse inconsistentes. Por ejemplo, puedes tener tres estadísticas «GamesWon», «GamesLost» y «GamesPlayed». A pesar de estar diseñadas con las mejores intenciones, las estadísticas pueden perder (y de hecho pierden) la sincronización entre sí. En este caso, podría producirse que las partidas ganadas y perdidas no diesen como suma el número total de partidas jugadas. Si esto se resolviera eliminando la estadística «GamesLost» y en su lugar se computara el valor como «GamesPlayed» - «GamesWon», una inconsistencia podría causar que «GamesLost» resultara en un valor negativo. En este caso, es mejor eliminar las estadísticas «GamesPlayed» y computar el valor como «GamesWon» + «GamesLost».
Estadísticas globales
Las estadísticas pueden marcarse como agregadas en la página de administración para ordenar a Steam mantener un total global de todos los valores de los usuarios para la estadística. Puede usarse para obtener datos como el total de dinero en la economía, el total de víctimas, armas y mapas favoritos, y qué equipo suele obtener mejores resultados. Por otro lado, esta opción no debería usarse para estadísticas como «MostKills», ya que la suma total de ese valor para varios usuarios no tendría sentido. Como las estadísticas están en manos de los usuarios, estos datos están sujetos a manipulación. Por lo tanto, es crucial que cuando se usen estadísticas agregadas se establezcan buenos límites para el valor mínimo, el valor máximo, solo incremental (si fuese apropiado) y la diferencia máxima. La diferencia máxima tiene un significado especial para las estadísticas agregadas. Cuando se carga un nuevo valor, el cambio en el valor global no superará el valor de la diferencia máxima. Esto limita lo rápido que un tramposo puede influenciar los totales globales.
Para acceder a los totales globales, llama a
ISteamUserStats::RequestGlobalStats y luego a
ISteamUserStats::GetGlobalStat para cada estadística global. También puedes solicitar
ISteamUserStats::RequestGlobalStats para un número específico de días de historial. El historial es la cantidad que cambió la estadística cada día. Puedes acceder a ese historial con
ISteamUserStats::GetGlobalStatHistory.
También se pueden solicitar al cliente los porcentajes de compleción de logros globales. Para hacerlo, primero llama a
ISteamUserStats::RequestGlobalAchievementPercentages. Después, muestra los logros en orden descendente según el porcentaje de completación llamando a
ISteamUserStats::GetMostAchievedAchievementInfo y
ISteamUserStats::GetNextMostAchievedAchievementInfo. También puedes obtener el porcentaje de finalización para un logro en particular llamando a
ISteamUserStats::GetAchievementAchievedPercent.
Pruebas
Hasta que no se publique tu aplicación, no podrás ver qué logros se han obtenido en la comunidad de Steam ni en la biblioteca. La aplicación necesitará una forma de presentar los logros obtenidos por el usuario.
Para borrar un logro o estadísticas sin añadir código al juego, puedes usar la consola del cliente de Steam. Ejecuta steam.exe -console y luego escribe:
- achievement_clear <appid> <achievement name>
- reset_all_stats <appid>
La comunidad de Steam
Después de que tu juego se haya lanzado, la información sobre el progreso individual y global de logros se mostrará en la comunidad de Steam. Cada jugador tendrá un enlace desde su perfil de la comunidad que lleva a una página donde se muestran sus logros ya conseguidos y cuáles quedan aún por desbloquear.
NOTA: Tus logros no se mostrarán hasta que tu aplicación sea visible para la comunidad.
Cada logro se incluye con el icono apropiado, y el nombre y la descripción tal y como se hayan establecido en el panel de control de Steamworks. Si el nombre y la descripción del logro han sido traducidos al idioma que el usuario haya elegido, se mostrarán en ese mismo idioma.
También habrá un enlace desde esta página y otro desde la página principal de Steam de tu juego para establecer un conjunto de estadísticas de logros globales para el mismo. Muestra el porcentaje de jugadores de Steam que han alcanzado cada logro, ordenados desde el logro más común al más infrecuente. Esto es algo que a los jugadores les gusta ver y también un gran recurso para los desarrolladores: ¿son los retos más especiales lo suficientemente difíciles? ¿O tal vez demasiado difíciles? (Esta información también está disponible en el sitio de informes de ventas y activaciones).
¿Tienes más preguntas?
Plantea tus preguntas en el
panel de discusión de estadísticas y logros.