Giter Site home page Giter Site logo

presente's Introduction

presente

Low budget game for LP

(ノ*ФωФ)ノ

 /\_/\
( o.o )
 > ^ <

<(0w0)>

               .               ,.
              T."-._..---.._,-"/|
              l|"-.  _.v._   (" |
              [l /.'_ \; _~"-.`-t
              Y " _(o} _{o)._ ^.|
              j  T  ,-<v>-.  T  ]
              \  l ( /-^-\ ) !  !
               \. \.  "~"  ./  /c-..,__
                 ^r- .._ .- .-"  `- .  ~"--.
                  > \.                      \
                  ]   ^.                     \
                  3  .  ">            .       Y  -Row
     ,.__.--._   _j   \ ~   .         ;       |
    (    ~"-._~"^._\   ^.    ^._      I     . l
     "-._ ___ ~"-,_7    .Z-._   7"   Y      ;  \        _
        /"   "~-(r r  _/_--._~-/    /      /,.--^-._   / Y
        "-._    '"~~~>-._~]>--^---./____,.^~        ^.^  !
            ~--._    '   Y---.                        \./
                 ~~--._  l_   )                        \
                       ~-._~~~---._,____..---           \
                           ~----"~       \
                                          \

presente's People

Contributors

autopawn avatar brojasrojas avatar inkhemi avatar ivanpizarroq avatar nfsdn avatar pestay avatar sofimartinez avatar

Stargazers

 avatar

Watchers

 avatar  avatar  avatar  avatar

presente's Issues

Muros destruibles y portales

Se debe modificar el código para permitir la destrucción de muros, es decir, estos deben poseer HP, el cuál debe reducirse al recibir impactos de balas.

Para lograr esto, se puede modificar level para que las celdas pasen a estar conformadas por una struct más compleja en vez de un char. De la misma manera level_get() se puede modificar para entregar '.' si el muro ha sido destruído y '#' si no.

Adicionalmente se deben programar celdas de teletransportación, que almacenen una posición del mapa a la que el jugador debe ser teletransportado en caso de que se encuentre sobre ella.

Agregue líneas a state_populate_random() para que aparezcan algunos teletransportadores al momento de crear un nivel al azar.

Para implementar varios de los efectos señalados deberá modificar state_update().

Power-ups

Se deben implementar power-ups para el jugador.

Estos power-ups solo afectan al jugador, son aplicados automaticamente al ser recogidos por el jugador y tras esto desaparecen.

Se recomienda que le de un identificador de un solo caracter, por ejemplo D para un power-up que aumenta el daño de las balas del jugador, para que los pueda colocar en el mapa y que quede de la forma:

# # # # # . . . # #
. . . . . . . . . .
p . . # . . D . . .
. . . # . . . . . .
# . . . . . D D . #

En el ejemplo anterior # son los muros, p es el jugador, D es el power-up y . indica terreno transitable sin características especiales.

De ser implementado así se puede hacer que la función entity_physics() retorne un valor especial dependiendo del power-up y que su efecto se vea implementado en state_update() en state.c

Se requiere que haya al menos dos power-ups y que uno sea para aumentar el HP del jugador.

Enemigos capaces de disparar

Se requiere crear un nuevo tipo de enemigo que tenga la capacidad de disparar al jugador.

Las balas disparadas por enemigos no deben dañar a otros enemigos, solo al jugador. Para esto se puede agregar un campo al struct bullet en state.h y utilizarlo para comprobar si la bala está colisionando con un enemigo o con el jugador en la función update que se encuentra en state.c.

Se recomienda basarse en las mecánicas de disparo del jugador para programar el disparo de este nuevo tipo de enemigo.

Para la dirección de disparo se puede elegir que sea aleatoria o que se aproveche del conocimiento de la posición del jugador, incluso se pueden programar ambos tipos como enemigos diferentes.

Enemigos que explotan al morir

Se necesita un nuevo tipo de enemigo que hace daño a su alrededor cuando su HP llega a 0. El daño provocado por este enemigo afecta tanto al jugador como a otros enemigos.

Las definiciones de los enemigos están en state.h y los comportamientos al morir están en state.c en la función state_update().

Se debe definir el area de daño de la explosión y la cantidad de daño causado (puede ser daño fijo o cambiar según la distancia al centro de la explosión) .

Notar que comprobar los daños no es trivial.

Inteligencia de los enemigos

Se requiere que los enemigos se acerquen al jugador una vez que este está lo suficientemente cerca.

Se debe definir desde que distancia los enemigos "ven" al jugador. Una vez avistado, los enemigos se dirigen hacia él.

Los enemigos tipo BRUTE simplemente caminan en linea recta al jugador a velocidad constante.
Los enemigos tipo MINION modifican su velocidad para dirigirse al jugador, es decir aumentan sus componentes de velocidad dependiendo de la posición del jugador.

Los enemigos deben detenerse si el jugador sale de su campo de visión.

Se recomienda ver como se modifica la velocidad del jugador en la función state_update() en state.c

Se sugiere definir una velocidad límite para los enemigos.

Marcador de puntaje y música

Se requiere un contador de puntaje que se muestre en pantalla. Cada vez que un enemigo muera, se debe ganar puntaje dependiendo del tipo de enemigo.

Adicionalmente se debe tener registrado en un archivo hiscore.txt el mejor puntaje alcanzado hasta la fecha. Este valor debe mostrarse en pantalla y por lo tanto el archivo se debe leer a la hora de comenzar el juego.

En caso de que el jugador haya alcanzado un puntaje mayor al hi-score; una vez este muere (vale decír, el hp de su entity es <=0), el archivo hiscore.txt debe actualizarse.

Es recomendable que se utilize state_update() en state.c para actualizar el puntaje y crear los archivos files.h y files.c para definir los comportamientos de manejo de archivos del juego.

Adicionalmente se necesita agregar música de fondo al juego y añadir un tono característico al acabar una partida.

Se recomienda ver el siguiente ejemplo para manejar audio con raylib: https://www.raylib.com/examples/web/audio/loader.html?name=audio_music_stream

Enemigo tipo BOSS que persiga al jugador

Programar un enemigo tipo BOSS que sea mucho más complicado de vencer; y que sea capaz de navegar por los muros para encontrar al jugador.

Para eso debe implementar un algoritmo de pathfinding como A* para computar una trayectoria; almacenarla en el enemy; y hacer que se actualice cada cierto tiempo.

Puede utilizar esta implementación:
https://github.com/felselva/uastar

En caso de usar otra implementación debe indicar la referencia utilizada.

Haga que state_populate_random() coloque al menos un BOSS.

Sprites de enemigos y jugador

Se debe agregar sprites a los enemigos y al jugador para que se utilicen estos en vez de los círculos que se están dibujando.

Los requisitos son:

  • Que cada tipo de enemigo tenga un sprite diferente.
  • Que los sprites se escalen dependiendo del tamaño de la entity que representa.
  • Que la animación avance si la entity se está moviendo, que se mantenga estática en caso contrario.
  • Que el sprite se refleje dependiendo de si la velocidad horizontal de la entity es positiva o negativa.

Puede utilizar los sprites idle que se encuentran en el pack de assets:
https://pixel-poem.itch.io/dungeon-assetpuck

En caso de utilizar otros sprites recuerde indicar de donde los obtuvo.

Diferentes tipos de armas

Se requiere implementar nuevos tipos de armas, para ello es necesario definir un botón de cambio de arma e implementar el comportamiento de cada arma.

Para poder añadir un botón se debe modificar N_BUTTONS en state.h, además de añadir un parametro al jugador para saber que arma está siendo utilizada.

En state.c, en la función state_update() se debe definir el comportamiento de las nuevas armas y asegurarse de elegir el comportamiento correcto según el arma seleccionada.

Para controlar el nuevo botón, se debe definir que botón se usará, lo cual se hace en main.c

Las armas a crear deben tener comportamientos distintos al arma por defecto, sea creativo.

Algunas ideas: disparos en múltiples direcciones, arma cuerpo a cuerpo, balas con tiempo limitado de vida.

Generación procedimental de niveles

Se debe mejorar el algoritmo con el que se inicializa la matriz de celdas de level para crear niveles más interesantes.

Para esto se debe hacer una función similar a level_fill_random en level.c y level.h que implemente un algoritmo de dungeon generation.

Puede implementar uno basado en autómatas celulares, como:
https://gamedevelopment.tutsplus.com/tutorials/generate-random-cave-levels-using-cellular-automata--gamedev-9664
o uno basado en habitaciones, como:
https://github.com/mizipzor/roguelike-dungeon-generator

En caso de implementar otro algoritmo debe indicar la referencia utilizada o, si quiere aventurarse a crear uno propio, debe crear un documento explicándolo (con dibujos).

Sistema de colisiones

Se debe implementar un sistema de colisiones extendiendo la funcionalidad de la función entity_physics() de manera que los muros del nivel efectivamente detengan a la entidad de manera correcta.
Esto significa que:

  • No se sume directamente (vx,vy) a la posición de la entidad si eso resulta que esta termine total o parcialmente atrapada en un muro. La entidad debe quedar tocando el muro pero no introducirse en él.
  • Al momento de chocar con un muro, la componente perpendicular al lado del muro con que se está chocando de la velocidad (vx,vy) sea sustraída. Esto significa que si una entidad se está moviendo en diagonal y choca con el lado vertical de un muro, pase a moverse sólo verticalmente (¡Que no quede incrustada!).

Es fácil hacer sistemas de colisión con errores, este hilo de SO le puede ser de ayuda para hacer colisiones círculo-rectángulo:
https://stackoverflow.com/questions/45370692/circle-rectangle-collision-response

Si se le hace muy complicado, puede considerar la entidad como un cuadrado para fines de colisiones con muros; y resolver utilizando otro método para colisiones rectángulo-rectángulo, como el que se muestra en este video:
https://www.youtube.com/watch?v=VpSWuywFlC8
o en este tutorial de pygame (con python2):
https://www.pygame.org/project-Rect+Collision+Response-1061-.html

También puede asumir que el diámetro de las entidades siempre será menor o igual al TILE_SIZE.

En caso de basarse en otra referencia recuerde indicarla en su entrega.

Arreglos dinámicos de enemigos y balas

Modificar state para que tenga arreglos de tamaño dinámico (vectores) tal que la memoria disponible para enemigos y balas se duplique cada vez que se necesita.

Se deben crear funciones para añadir un enemigo y para añadir una bala en state.c y state.h a un state. Todas las veces que se esté creando una bala o enemigo en el código actual deben reemplazarse llamadas a estas funciones.

Adicionalmente, se debe programar que cada cierto tiempo aparezcan enemigos nuevos, a una distancia prudente del jugador.

Daño de los enemigos

Se necesita programar el daño de los enemigos.

Los enemigos dañan al jugador colisionando con él.

Se debe definir el daño según el tipo de enemigo, lo cual se puede hacer en state.h, y es necesario restar HP del jugador al colisionar con un enemigo, lo cual se puede hacer en la función state_update() en state.c, notar que las colisiones entre jugador y enemigos son similares a las colisones entre el jugador y las balas.

Como se podría dar el caso en el que el jugador está rodeado de enemigos y podría morir instantaneamente, se requiere que el jugador tenga un leve periodo de inmunidad tras recibir daño. Para lograr esto, se le puede dar un nuevo parametro en su definición en state.h y modificarlo según sea necesario en la función state_update().

Tilesets dinámicos

Se necesita que en cada muro se dibuje un tile de un tileset como este:
https://pixel-poem.itch.io/dungeon-assetpuck
(en vez del cuadrado que se está dibujando ahora).

Pese a que en el nivel sólo existe un tipo de muro '#', vea que el tile a dibujar se elija correctamente dependiendo de la presencia o no de muros en las celdas adyacentes (en total hay 2^4=16 posibilidades).

Para realizar esto deberá utilizar las funciones de raylib para cargar y dibujar texturas.
Este ejemplo puede servirle:
https://www.raylib.com/examples/web/textures/loader.html?name=textures_rectangle

Features adicionales?

Además de las features señaladas en las otras issues, usted puede proponer una feature que Ud. quiera implementar. Si esta feature es aprobada por el profesor podrá entregarla.

Formato y carga de niveles

Se debe crear un formato de archivo fácil de editar que permita definir un nivel.

Por ejemplo:

10 5
# # # # # . . . # #
. . . . . . . . . .
p . . # . . b . . .
. . . # . . . . . .
# . . . . . m m . #

pudiendo utilizar p para indicar la posición inicial del jugador, b de un BRUTE y m de un MINION.

Se deben crear los archivos load.h y load.c que contengan una función para crear un state y level nuevos a partir de un archivo.

Si el juego se llama sin pasar argumentos en la línea de comandos, state y level se deben inicializar normalmente (al azar), sin embargo, si se pasa un argumento por la línea de comandos, el nivel se debe cargar a partir del archivo ubicado en esa ruta:

$ ./bin/presente nivel.txt

Si el archivo tiene un error, el programa debe terminar con exit(1) y un mensaje de error.

GUI

Para hacer que la experiencia de juego sea mejor, se requiere programar una GUI (Graphic User Interface) que muestre el HP del jugador y los enemigos.

Existen muchas formas de lograrlo, se puede mostrar el HP como números sobre el jugador y los enemigos, es posible mostrar el HP como una barra u otra forma que estime conveniente.

Para mostrar esto por pantalla se debe modificar la función draw_state() en draw.c.

Notar que para esta funcionalidad será necesario leer la documentación de raylib.

Adicionalmente se debe dibujar una mira y una guía de disparo al frente del jugador, en la dirección en que se está apuntando; y una forma de representar el cooldown del jugador.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.