├── JustMove.png ├── README.md ├── LICENSE └── source ├── JustMove.csproj └── Program.cs /JustMove.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DosX-dev/JustMove-game/HEAD/JustMove.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JustMove 2 | A simple 2D console game for Windows where you need to jump over obstacles. Written in C# with AOT compilation. 3 | 4 | ### [Download compiled as .EXE](https://github.com/DosX-dev/JustMove-game/releases/tag/Builds) 5 | 6 | ![](JustMove.png) 7 | 8 | ## Gameplay 9 | Use `space` to jump. 10 | 11 | > Types of obstacles: 12 | > * `V` - a bird 13 | > * `X` - a cactus 14 | > 15 | > If you collide with any of them, you will die -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 DosX 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /source/JustMove.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | app 6 | net8.0 7 | enable 8 | true 9 | Exe 10 | enable 11 | 12 | false 13 | true 14 | false 15 | false 16 | false 17 | false 18 | true 19 | true 20 | true 21 | true 22 | false 23 | true 24 | false 25 | false 26 | false 27 | false 28 | none 29 | link 30 | true 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /source/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | 4 | class PlatformerGame { 5 | static GameMap? map; 6 | static Player? player; 7 | static Random random = new Random(); 8 | static bool gameRunning = true; 9 | static int score = 0; 10 | 11 | static string startText = "Press 'space' to jump."; 12 | static int startTextX; 13 | 14 | static readonly string _title = "JustMove ({0})"; 15 | static void Main(string[] args) { 16 | Console.Title = "JustMove"; 17 | Console.CursorVisible = false; 18 | 19 | SetWindowSize(); 20 | 21 | while (true) { 22 | StartGame(); 23 | 24 | while (gameRunning) { 25 | map.DrawMap(player.X, player.Y, startText, startTextX); 26 | HandleInput(); 27 | UpdateGame(); 28 | Thread.Sleep(2); 29 | } 30 | 31 | ShowGameOverScreen(); 32 | } 33 | } 34 | 35 | static void StartGame() { 36 | map = new GameMap(); 37 | player = new Player(10, 14); 38 | 39 | startTextX = GameMap.MapWidth / 2 - startText.Length / 2 + 4; 40 | map.DrawGroundLine(); 41 | gameRunning = true; 42 | score = 0; 43 | } 44 | 45 | static void SetWindowSize() { 46 | Console.SetWindowSize(GameMap.MapWidth + 2, GameMap.MapHeight + 2); 47 | Console.SetBufferSize(GameMap.MapWidth + 2, GameMap.MapHeight + 2); 48 | } 49 | 50 | static void HandleInput() { 51 | if (Console.KeyAvailable) { 52 | var key = Console.ReadKey(true).Key; 53 | if (key == ConsoleKey.Spacebar) { 54 | player.Jump(); 55 | } 56 | } 57 | } 58 | 59 | static void UpdateGame() { 60 | map.MoveObstacles(); 61 | map.GenerateObstacles(); 62 | player.ApplyGravity(); 63 | CheckCollision(); 64 | 65 | score++; 66 | Console.Title = string.Format(_title, score); 67 | 68 | startTextX--; 69 | } 70 | 71 | static void CheckCollision() { 72 | if (!map.CheckCollision(player.X, player.Y)) { 73 | return; 74 | } 75 | gameRunning = false; 76 | } 77 | 78 | static void ShowGameOverScreen() { 79 | Console.Clear(); 80 | SetWindowSize(); 81 | Console.ResetColor(); 82 | 83 | Console.BackgroundColor = ConsoleColor.DarkRed; 84 | Console.ForegroundColor = ConsoleColor.White; 85 | 86 | for (int i = 0; i < 22; i++) { 87 | if (i == 11) i = 12; 88 | 89 | if (i == 10) { 90 | Console.Write("GAME OVER!"); 91 | } else if (i % 2 == 0) { 92 | Console.BackgroundColor = ConsoleColor.White; 93 | Console.ForegroundColor = ConsoleColor.DarkRed; 94 | } else { 95 | Console.BackgroundColor = ConsoleColor.DarkRed; 96 | Console.ForegroundColor = ConsoleColor.White; 97 | } 98 | 99 | Console.Write(" "); 100 | } 101 | 102 | 103 | Console.ResetColor(); 104 | Console.Write("\n\n"); 105 | Console.Write(" Your score: "); 106 | Console.ForegroundColor = ConsoleColor.Yellow; 107 | Console.WriteLine(score); 108 | Console.ResetColor(); 109 | 110 | Console.Write("\n "); 111 | Console.ForegroundColor = ConsoleColor.White; 112 | Console.BackgroundColor = ConsoleColor.Red; 113 | Console.Write("[1]"); 114 | Console.ResetColor(); 115 | Console.Write(" Exit"); 116 | 117 | Console.Write("\n\n "); 118 | Console.ForegroundColor = ConsoleColor.Black; 119 | Console.BackgroundColor = ConsoleColor.White; 120 | Console.Write("[2]"); 121 | Console.ResetColor(); 122 | Console.Write(" Retry"); 123 | 124 | 125 | 126 | Console.ResetColor(); 127 | 128 | while (true) { 129 | ConsoleKey userAnswer = Console.ReadKey(true).Key; 130 | 131 | switch (userAnswer) { 132 | case ConsoleKey.D2: 133 | return; 134 | case ConsoleKey.D1: 135 | Environment.Exit(0); 136 | break; 137 | } 138 | } 139 | } 140 | } 141 | 142 | class GameMap { 143 | public const int MapWidth = 50; 144 | public const int MapHeight = 20; 145 | public const int GroundLevel = 19; 146 | char[,] map; 147 | static Random random = new Random(); 148 | 149 | public GameMap() { 150 | map = new char[MapWidth, MapHeight]; 151 | GenerateMap(); 152 | } 153 | 154 | void GenerateMap() { 155 | for (int x = 0; x < MapWidth; x++) { 156 | for (int y = 0; y < MapHeight; y++) { 157 | map[x, y] = ' '; 158 | } 159 | } 160 | } 161 | 162 | public void DrawGroundLine() { 163 | Console.BackgroundColor = ConsoleColor.DarkGreen; 164 | Console.SetCursorPosition(0, GroundLevel); 165 | for (int x = 0; x < 4; x++) { 166 | Console.Write(new string(' ', MapWidth) + (x != 2 ? '\n' : null)); 167 | } 168 | Console.ResetColor(); 169 | } 170 | 171 | public void DrawMap(int playerX, int playerY, string startText, int startTextX) { 172 | Console.SetCursorPosition(0, 0); 173 | for (int y = 0; y < GroundLevel; y++) { 174 | for (int x = 0; x < MapWidth; x++) { 175 | if (x == playerX && y == playerY) { 176 | Console.ForegroundColor = ConsoleColor.Blue; 177 | Console.BackgroundColor = ConsoleColor.White; 178 | Console.Write(" "); 179 | Console.ResetColor(); 180 | } else { 181 | Console.ForegroundColor = map[x, y] == 'X' ? ConsoleColor.DarkGreen : ConsoleColor.Gray; 182 | Console.Write(map[x, y]); 183 | } 184 | } 185 | Console.WriteLine(); 186 | } 187 | 188 | if (startTextX + startText.Length > 0) { 189 | Console.SetCursorPosition(Math.Max(startTextX, 0), GroundLevel - 8); 190 | Console.ResetColor(); 191 | Console.Write(startText.Substring(Math.Max(-startTextX, 0))); 192 | } 193 | } 194 | 195 | public void MoveObstacles() { 196 | for (int x = 0; x < MapWidth; x++) { 197 | for (int y = 0; y < MapHeight; y++) { 198 | if (map[x, y] != ' ') { 199 | char current = map[x, y]; 200 | map[x, y] = ' '; 201 | if (x != 0) { 202 | map[x - 1, y] = current; 203 | } 204 | } 205 | } 206 | } 207 | } 208 | 209 | public void GenerateObstacles() { 210 | 211 | int groundY = GroundLevel - 1; 212 | bool canPlaceObstacleX = map[MapWidth - 2, groundY] != 'X' && map[MapWidth - 3, groundY] != 'X'; 213 | bool canPlaceObstacleV = true; 214 | 215 | for (int i = 0; i < MapHeight; i++) { 216 | if (map[MapWidth - 2, i] == 'V' || map[MapWidth - 3, i] == 'V') { 217 | canPlaceObstacleV = false; 218 | break; 219 | } 220 | } 221 | 222 | if (random.Next(0, 100) < 3 && canPlaceObstacleX) { 223 | map[MapWidth - 1, groundY] = 'X'; 224 | } 225 | 226 | if (random.Next(0, 100) < 2 && canPlaceObstacleV) { 227 | int obstacleHeight = random.Next(2, 4); 228 | int obstaclePosition = groundY - obstacleHeight - 1; 229 | 230 | bool canPlaceTallObstacle = true; 231 | for (int i = 0; i < obstacleHeight; i++) { 232 | if (map[MapWidth - 2, obstaclePosition + i] == 'V' || map[MapWidth - 3, obstaclePosition + i] == 'V') { 233 | canPlaceTallObstacle = false; 234 | break; 235 | } 236 | } 237 | 238 | if (canPlaceTallObstacle && (map[MapWidth - 1, obstaclePosition - 1] != 'V' || map[MapWidth - 1, obstaclePosition - 1] != 'X')) { 239 | map[MapWidth - 1, obstaclePosition] = 'V'; 240 | } 241 | } 242 | } 243 | 244 | 245 | 246 | public bool CheckCollision(int playerX, int playerY) { 247 | return map[playerX, playerY] == 'X' || map[playerX, playerY] == 'V'; 248 | } 249 | } 250 | 251 | class Player { 252 | public int X { get; private set; } 253 | public int Y { get; private set; } 254 | const int JumpHeight = 3; 255 | int jumpProgress; 256 | bool isJumping; 257 | 258 | public Player(int startX, int startY) { 259 | X = startX; 260 | Y = startY; 261 | isJumping = false; 262 | jumpProgress = 0; 263 | } 264 | 265 | public void Jump() { 266 | if (Y == GameMap.GroundLevel - 1) { 267 | isJumping = true; 268 | jumpProgress = 0; 269 | } 270 | } 271 | 272 | public void ApplyGravity() { 273 | if (isJumping) { 274 | if (jumpProgress < JumpHeight) { 275 | Y--; 276 | jumpProgress++; 277 | } else { 278 | isJumping = false; 279 | } 280 | } else if (Y < GameMap.GroundLevel - 1) { 281 | Y++; 282 | } 283 | } 284 | } 285 | --------------------------------------------------------------------------------