// I am a bit sad that this method turned out to be responsable for // managing the whole snake and not just moving it public bool Move() { PosChixel snakeHead = chixelList.First(); PosChixel snakeTail = chixelList.Last(); // Apply movement gotten from the controls to snake // Why is there a stack here, you ask? Well it's made so that if (between updates) the player presses // something that causes a change in direction // then follows it up by something that doesn't, the latest change causing press is applied and not caneled // this will hopefully make the controls more responsive. while (deltaDirectionStack.Count != 0) { Directions outDirection; if (!deltaDirectionStack.TryPop(out outDirection)) { continue; } if (DoesDirectionCauseTurn(outDirection)) { CurrentDirection = outDirection; break; } } deltaDirectionStack.Clear(); // Change in the position of the head. (int deltaX, int deltaY) = Utility.DirectionToXY(CurrentDirection); int newX = snakeHead.x + deltaX; // Implement looping around the screen like pacman if (newX > FrameBuffer.Instance.Width - 1) { newX = FrameBuffer.Instance.Left; } else if (newX < FrameBuffer.Instance.Left) { newX = FrameBuffer.Instance.Width - 1; } int newY = snakeHead.y + deltaY; // Implement looping around the screen like pacman if (newY > FrameBuffer.Instance.Height - 1) { newY = FrameBuffer.Instance.Top; } else if (newY < FrameBuffer.Instance.Top) { newY = FrameBuffer.Instance.Height - 1; } // Eat the Growthball if on it; if (GrowthBall.GrowthBallDict.ContainsKey((newX, newY))) { this.Grow(GrowthBall.GrowthBallDict[(newX, newY)].GrowthValue); GrowthBall.EatAt(newX, newY); }
static void Main(string[] args) { // Setting stuff up. Console.WindowHeight = 30; Console.WindowWidth = 61; Console.CursorVisible = false; GrowthBall.ANewBallsChixel = new Chixel('█', ConsoleColor.Red); // Making sure there is an instance of FrameBuffer in existance FrameBuffer frame = new FrameBuffer(0, 0, Console.WindowWidth, Console.WindowHeight); InitalizeGame(); // Them controls start here. Made it IsBackground to make sure it dies when the main thread dies Thread keylistener = CreateKeyListener(); keylistener.Start(); // Main Game loop while (!pressedEscape) { // If the snake is dead, don't do things that snakes do when they're alive like moving // I am not happy how handling death and restarts turned out. This is unreadable crap! if (!snake.Dead) { if (!snake.Move()) { snake.OnDie(); } ; if (GrowthBall.GrowthBallDict.Count < 1) { GrowthBall.Spawn(3); } } else if (IsRestarting) { FrameBuffer.Instance.Clear(); GrowthBall.GrowthBallDict.Clear(); // The stuff with the keylistener is so that it doesn't steal the Game's fist ReadKey // Which causes the game to require two key presses to unpause after restart keylistener.Abort(); InitalizeGame(); keylistener = CreateKeyListener(); keylistener.Start(); IsRestarting = false; } FrameBuffer.Instance.DrawFrame(); Thread.Sleep(frameTimeReal); } }
static void InitalizeGame() { snake = new Snake(7, new Chixel('█', ConsoleColor.White), new Chixel('█', ConsoleColor.Gray)); snake.Died += new Action <Snake>(DealWithScoring); snake.Died += new Action <Snake>(DrawGameOverScreen); FrameBuffer.Instance.DrawFrame(); // The game starts paused ControlGame(Console.ReadKey(true).Key); // Spawn a ball after the player unpauses GrowthBall.Spawn(3); }