{"id":13460142,"url":"https://github.com/madebypixel02/so_long","last_synced_at":"2025-04-11T17:22:48.571Z","repository":{"id":80577874,"uuid":"388483228","full_name":"madebypixel02/so_long","owner":"madebypixel02","description":"[42 Madrid] And thanks for all the fish!","archived":false,"fork":false,"pushed_at":"2023-04-05T12:45:23.000Z","size":4794,"stargazers_count":88,"open_issues_count":0,"forks_count":4,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T13:21:03.986Z","etag":null,"topics":["42","42-cursus","42born2code","42madrid","42school","born2code","game","peer2peer","so-long"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/madebypixel02.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-07-22T14:03:43.000Z","updated_at":"2025-03-23T20:30:22.000Z","dependencies_parsed_at":"2023-05-16T17:45:36.899Z","dependency_job_id":null,"html_url":"https://github.com/madebypixel02/so_long","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebypixel02%2Fso_long","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebypixel02%2Fso_long/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebypixel02%2Fso_long/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madebypixel02%2Fso_long/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/madebypixel02","download_url":"https://codeload.github.com/madebypixel02/so_long/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248448038,"owners_count":21105223,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["42","42-cursus","42born2code","42madrid","42school","born2code","game","peer2peer","so-long"],"created_at":"2024-07-31T10:00:36.276Z","updated_at":"2025-04-11T17:22:48.546Z","avatar_url":"https://github.com/madebypixel02.png","language":"C","funding_links":[],"categories":["WELCOME"],"sub_categories":["**So_long**"],"readme":"# so_long | 42 Madrid\r\n\r\n*And thanks for all the fish! 🐟*\r\n\r\n\u003cdiv align=\"center\"\u003e\r\n  \u003cimg src=https://user-images.githubusercontent.com/40824677/149228578-cf688aea-1e68-4d94-ba29-763ed2c1758b.png /\u003e\r\n\u003c/div\u003e\r\n\r\n### Table of Contents\r\n\r\n* [Introduction](#introduction)\r\n* [How it Works](#how-it-works)\r\n* [Extras](#extras)\r\n* [Gameplay](#gameplay)\r\n* [Other Maps](#other-maps)\r\n* [Installation](#installation)\r\n* [Technical Issues](#technical-issues)\r\n* [Summary](#summary)\r\n\r\n## Introduction\r\nIn this project, we'll code a simple 2D game to get familiar with the mlx library and UI in general. In my case, it will be Pac-Man.\r\n\r\n### Game Rules\r\nThe game we choose must follow a set of rules. The executable ``so_long`` will receive a map as the only argument, and this map will have a ``.ber`` filetype.\r\n\r\nThe file also must follow these rules:\r\n- Only ``P`` *(pacman)*, ``1`` *(wall)*, ``0`` *(empty)*, ``C`` *(collectible)*, and ``E`` *(exit)* will be accepted characters in our map (except if you add enemies as bonus)\r\n- The map must be rectangular, i.e. all rows must have the same length\r\n- There must be at least one exit, one player, and one collectible on the map\r\n- The map must be closed, i.e. surrounded by walls\r\n\r\nIf any of these checks fail, the game must end with ``Error\\n`` followed by a custom message.\r\n\r\nThe goal is for the player(s) to collect all the collectibles on the map before going to an exit in the least possible number of steps\r\n\r\n## How it Works\r\nFor the graphics part of the project we used a library called ``minilibx``. It's fairly basic and somewhat limited, but was still fun to use in the project.\r\n\r\n\r\n\r\n### Part 1: reading the map\r\n\r\nIn this part of the code I checked that the given map was properly opened, that it had a ``.ber`` filetype, and then continued by reading the file one line at a time with [get_next_line](https://gitlab.com/madebypixel02/get_next_line).\r\nOnce that was done I filled a struct ``t_lay`` with some basic map attributes like number of players, exits, collectibles, number of rows and columns, etc. During the reading process I also created a string containing the entire map, whcih was later useful when creating a matrix with ``ft_split`` with ``\\n`` as the separator.\r\n\r\n\r\n\r\n### Part 2: starting the game\r\n\r\nFor this part I took the ``t_lay`` and my map matrix to build my main ``t_game`` struct. This struct includes more detailed information about my game state, such a list of pacmans, a list of ghosts, the number of loop repetitions (frames), and other info. From here I initialized a window with the mlx function and started drawing the static elements of the map (walls, spaces and collectibles) on the window. The mlx library, as other graphic libraries, has an infinite loop where the game events happen. From here I check the state of the game to re-print certain elements of the map or to manage special events, such as when Pacman dies or when ghosts are in panic mode.\r\nThe ``mlx`` library has hooks, which essentially link certain events on the computer (keypresses, mouse clicks, etc) with functions we implement. In my case I 'hooked' the end of the game function to pressing the ``x`` button to close the window. Also, I used a key hook to link keypresses with pacman's movements.\r\n\r\n\r\n### Part 3: game mechanics\r\n\r\nWhen the ``ESC``/``Q`` key is pressed, the game ends. If the arrow keys or the ``W``. ``A``, ``S``, ``D`` keys are pressed, every pacman on the map changes its direction and tries to move in that direction. Also, every so often all pacmans will all try to move in the same direction they're headed. This way the arrow/WASD keys just change pacmans' directions to make them move forward till they hit a wall.\r\nGhosts behave similarly (they're the first bonus: enemies), but instead of responding the keypress, they use a basic algorithm to find the closest pacman and try to catch it. Whenever a pacman is caught by a ghost, the attribute ``pac_dying`` is set to 1 in the ``t_game`` struct and all pacmans die with a short animation.\r\nGhosts load in seven different colors, and each new ghost will have a different color. To do this, I had to load every sprite of every color with the mlx library and assign a new color to every new ghost with ``ghost_number % number_of_colors``, thus rotating through the list of colors when there are more ghosts than available colors.\r\n\r\nLastly, if a pacman reaches an exit and there are no collectibles left, it will be deleted from the list of players. If all pacmans reach the exit, the game ends and the final score is displayed.\r\n\r\n\r\n### Part 4: animations\r\n\r\nThere are several animations throughout the game (it's the other bonus in the project), from pacman's gobbling animation or ghosts' panic mode to pacman's death animation. They are all animated in a similar way: with linked lists. Every node in the list corresponds to an image of the animation. Every so often a function is called which will move to the next image, and if the last one is found, the node resets to the top of the linked list.\r\n\r\nPacman and ghosts move on the map matrix, which is much smaller than the mlx window. For this reason and to make movement smooth it is interesting to keep a position in the matrix (``pos``) and a position on the window (``win_pos``) for every pacman/ghost, and update the position on the window one pixel at a time until ``pos * sprite_size == win_pos``.\r\n\r\n\r\n## Extras\r\n\r\nThe pacman game I designed has a few extras we weren't asked to implement, but I thought would make the overall game experience better. Here's a list of the most relevant additions:\r\n\r\n- Add custom (simple) chasing algorithm using euclidean distances.\r\n- Ability to restart the game by pressing the ``R`` key\r\n- Ability to exit the game by pressing the ``Q`` key\r\n- Ghosts enter panic mode when there's less than a third of the pacdots remaining. During this time the players will be faster and ghosts will flash for the sake of distraction\r\n- The score is displayed in the classic pacman fonts, instead of the (ugly) builtin fonts from ``mlx_string_put()``\r\n- Arrow keys also move the player\r\n- Add decorating pacman logo centered at the bottom\r\n- Add support for both ``linux`` and ``MacOS``\r\n- Implement several players in a single map\r\n- Ability to save a direction for when it's available\r\n- Added 30 test maps (most of them playable)\r\n- Restrict ending or resetting the game while pacman is dying\r\n\r\n## Gameplay\r\n\r\nThere are a total of 30 maps available. See [MAPS.md](./tests/MAPS.md)\r\n\r\nHere are a few sample gameplays from my favorite maps:\r\n\r\n![test](https://user-images.githubusercontent.com/40824677/144236348-16d25b18-083b-4b3d-8e68-1c5a750aadbd.gif)\r\n\r\n![run](https://user-images.githubusercontent.com/40824677/144236512-ef823d58-a669-422b-b28d-aa619cf38b09.gif)\r\n\r\n![island](https://user-images.githubusercontent.com/40824677/144236536-cf60d7de-06b6-40ef-99f8-6a5e459c7051.gif)\r\n\r\n![classic](https://user-images.githubusercontent.com/40824677/144236580-afefb02c-8d9e-4fb4-8003-fc2770fe45dc.gif)\r\n\r\n\r\n## Other Maps\r\nThere are 20+ maps (ported from [Machine-Learning-Pacman](https://gitlab.com/madebypixel02/Machine-Learning-Pacman/tree/main/layouts)) to try your skill/luck.\r\n\r\nSee [Other Maps](./tests/MAPS.md#other-maps)\r\n\r\n## Installation\r\n\r\n### Cloning the repositories\r\n```shell\r\ngit clone https://gitlab.com/madebypixel02/so_long.git\r\ncd so_long\r\nmake\r\n```\r\n\r\n### Installing the MLX library\r\n\r\n* ``Linux``\r\n\r\nIf you're not using a MacOS computer from 42, you'll need to install the libraries manually. Please refer to the [official github](https://github.com/42Paris/minilibx-linux) for more details. To install it, do the following (requires root access):\r\n\r\n```shell\r\ngit clone https://github.com/42Paris/minilibx-linux.git\r\ncd minilibx-linux/\r\nmake\r\nsudo cp mlx.h /usr/include\r\nsudo cp libmlx.a /usr/lib\r\n```\r\n\r\n* ``MacOS``\r\n\r\nTo install the library, you will need to first install a package manager like homebrew (check [here](https://brew.sh/)) to then install the X11 package with ``brew install Xquartz``. After that you must extract the minilibx file called ``minilibx_opengl.tgz``. Then install it to your system with the following commands (requires sudo as well):\r\n\r\n```shell\r\ncd minilibx_opengl\r\nmake\r\nsudo cp mlx.h /usr/local/include\r\nsudo cp libmlx.a /usr/local/lib\r\nsudo reboot\r\n```\r\nNote: A reboot is necessary to ensure that the ``Xquartz`` is working properly. You can test if it is by running a test example with the command ``xeyes``.\r\n\r\n### Installing the manuals\r\n\r\nIf you want quick access to the mlx manuals, it is recommended that you copy the files from the ``man`` folder in [minilibx-linux](https://github.com/42Paris/minilibx-linux) to your system manuals:\r\n\r\n* ``Linux``\r\n```shell\r\nsudo cp man/man3/* /usr/share/man/man3/\r\n```\r\nNote: Depending on your Linux configuration, to get the manuals working (e.g. ``man mlx``) you will need to individually gzip all the manual files you just copied, e.g. ``sudo gzip /usr/share/man/man3/mlx.3``.\r\n\r\n* ``MacOS``\r\n```shell\r\nsudo cp man/man3/* /usr/X11/share/man/man3\r\n```\r\n\r\n### Usage\r\n\r\n```\r\nmake                        compiles so_long executable\r\nmake test MAP={path_to_map} compiles and executes so_long with the specified map\r\nmake play                   compiles and executes a small set of maps sequentially\r\nmake play2                  compiles and executes a much larger set of maps sequentially\r\nmake git                    adds and commits everything, then pushes to upstream branch\r\nmake norminette             runs norminette for all files in the project that need to pass it\r\n```\r\nNote: we were not allowed to use multiple threads, thus it is pretty hard to time the speeds of the game. I found that using valgrind on ``linux`` helps slow the game down so it is more similar to the performance in MacOS. Depending on your computer's performance the speed of the game may vary. I hope to learn ways to improve that for future projects. For ``linux``, try always using valgrind as follows: ``valgrind ./so_long \u003cmap.ber\u003e``\r\n\r\n## Technical Issues\r\n\r\nThroughout the project, there have been a few roadblocks that needed to be worked around, here's some of them:\r\n\r\n- Timing: getting the timing for animations and other stuff right was quite challenging. I ended up just using the number of loop repetitions from ``mlx_loop_hook`` and fiddling with different rates, which also varied a lot between MacOS and Linux.\r\n- Sprites: The minilibx in Linux doesn't handle transparency in sprites the same way MacOS' minilibx does. On Linux the sprites will just have black pixels in the transparent area. I found ways to work this around but it was too much of a hussle.\r\n- Leaks: Minilibx has some leaks that are only detected by ``valgrind``. Using the function ``mlx_destroy_display`` solves that leak, but apparently that function isn't a part of the minilibx in MacOS. For this reason I decided to split the file where that function was called, so that the file compiled in Linux had that extra line for valgrind to be happy.\r\n- Keycodes: yet another difference between MacOS and Linux. The keycodes (``WASD``, ``ESC``, etc) are completely different. I defined those variables straight from the makefile to correct this issue.\r\n\r\n## Summary\r\nThis has been my favorite project so far, coding my own pacman clone was so much fun, regargless how flawed it might be :)\r\n\r\nAugust 14th, 2021\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadebypixel02%2Fso_long","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmadebypixel02%2Fso_long","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadebypixel02%2Fso_long/lists"}