/// <summary> /// (перемещает этот объект в выбранном направлении) /// </summary> /// <param name="speed">(скорость перемещения)</param> /// <param name="typeX">(<see cref="SideX"/> направление по оси X)</param> /// <param name="typeY">(<see cref="SideY"/> направление по оси X)</param> public static void MoveAside(this ObjectSingle objectToMove, float speed, SideX typeX = SideX.middle, SideY typeY = SideY.middle) { int kX = 0; int kY = 0; switch (typeX) { case SideX.left: kX = -1; break; case SideX.middle: kX = 0; break; case SideX.right: kX = 1; break; } switch (typeY) { case SideY.up: kY = -1; break; case SideY.middle: kY = 0; break; case SideY.down: kY = 1; break; } Move(objectToMove, speed, kX.GridToX(), kY.GridToY()); }
/// <summary> /// (перемещает этот объект в направлении целевой позиции) /// </summary> /// <param name="speed">(скорость перемещения)</param> /// <param name="targetObject">(целевая позиция)</param> public static void MoveTowards(this ObjectSingle objectToMove, float speed, Vector targetPosition) { int kX = (int)targetPosition.X - (int)objectToMove.Position.X; int kY = (int)targetPosition.Y - (int)objectToMove.Position.Y; Move(objectToMove, speed, kX, kY); }
//========= protected void Initialize(ObjectSingle parentObject) { for (int i = 0; i < tempArray.Length; i++) { tempArray[i] = new List <Object>(); } ParentObject = parentObject; StartThread(Monitoring); }
/// <summary> /// Writes this string to position inside object. For <see cref="ALBGame.Update"/> method only. (Вписывает эту строку на позиции внутри объекта. Только для <see cref="ALBGame.Update"/> метода.) /// </summary> /// <param name="objectTarget">target object (целевой объект)</param> /// <param name="positionX">object-dependent X-axis position coordinate (координата позиции по оси X относительно центра объекта)</param> /// <param name="positionY">object-dependent Y-axis position coordinate (координата позиции по оси Y относительно центра объекта)</param> /// <param name="stringColor">string color (цвет строки)</param> public static void WriteTo(this string str, ObjectSingle objectTarget, int positionX = 0, int positionY = 0, ConsoleColor stringColor = ConsoleColor.Black) { if (objectTarget.Position.PrevX == (int)objectTarget.Position.X && objectTarget.Position.PrevY == (int)objectTarget.Position.Y) { str.WriteTo((int)(objectTarget.Position.X + positionX), (int)(objectTarget.Position.Y + positionY), objectTarget.Color, stringColor); } if (!objectTarget.IsTextured) { objectTarget.IsTextured = true; } }
/// <summary> gets called on startup only (выполняется только при запуске) </summary> public override void Start() { //==== instantiating ==== Console.Title = "Straight Racing"; //background plane = new ObjectSingle(Preset.plane, ConsoleColor.DarkGreen); road = new ObjectSingle(Preset.plane, ConsoleColor.DarkGray, null, 0.04f, null, null, (int)(plane.Size.X / 2)); border = new ObjectSingle(Preset.plane, ConsoleColor.DarkYellow, null, 0.02f, null, null, road.Size.X + 4); linesSizeY = (int)(road.Size.Y / ZeroCheck(linesQuantY * 2)); firstLine = new ObjectGroup(null, ConsoleColor.Gray, null, 0.06f, road.Position.X, road.Position.Y - road.Size.Y, Math.Max((int)(linesSizeY / 5), 1), linesSizeY, (int)(road.Size.X / 3), linesSizeY, 2, linesQuantY); secondLine = new ObjectGroup(null, firstLine.Color, null, 0.06f, firstLine.Position.X, road.Position.Y, firstLine.Size.X, firstLine.Size.Y, firstLine.Gap.X, firstLine.Gap.Y, firstLine.Quant.X, firstLine.Quant.Y); secondLine.Position.MaxY = firstLine.Position.MaxY = road.Position.Y + road.Size.Y; //text textA = new ObjectSingle(Preset.boxXL, ConsoleColor.White, null, 10f, null, null, null, 7); textB = new ObjectSingle(Preset.boxXL, ConsoleColor.Black, null, textA.Layer - 0.01f, textA.Position.X + 1, textA.Position.Y + 1, null, textA.Size.Y); textA.ChildList.Add(textB); textPoint = new Vector(0, plane.Position.Y + (int)(textA.Size.Y / 1.5f) - (int)(plane.Size.Y / 2)); //cars carPosX = new Random().Next(0, 2) > 0 ? road.Position.X - (int)(road.Size.X / 3) : road.Position.X + (int)(road.Size.X / 3); car = new ObjectSingle(Preset.boxL, ConsoleColor.Blue, null, 1f, carPosX, road.Position.Y - (int)(road.Size.Y * 0.75f), (int)(road.Size.X / 6), (int)(road.Size.Y / 4)); windows = new ObjectGroup(null, ConsoleColor.Cyan, null, car.Layer + 0.5f, car.Position.X, car.Position.Y + 1, car.Size.X - 2, Math.Max((int)(car.Size.Y / 8), 1), null, (int)(car.Size.Y / 4) + 1, 1, 2); wheels = new ObjectGroup(null, ConsoleColor.Black, null, car.Layer - 0.5f, car.Position.X, car.Position.Y, 1, (int)(car.Size.Y / 4), car.Size.X, (int)(car.Size.Y / 3), 2, 2); car.ChildList.Add(windows); car.ChildList.Add(wheels); heroCar = car.CopyThis(); heroCar.Position.MinX = road.Position.X + (int)(heroCar.Size.X / 2) - (int)(road.Size.X / 2); heroCar.Position.MinY = road.Position.Y + (int)(heroCar.Size.Y / 2) - (int)(road.Size.Y / 2); heroCar.Position.MaxX = road.Position.X - (int)(heroCar.Size.X / 2) + (int)(road.Size.X / 2); heroCar.Position.MaxY = road.Position.Y - (int)(heroCar.Size.Y / 2) + (int)(road.Size.Y / 2); heroCar.AlignWithSide(SideX.middle, SideY.down); heroCar.Color = ConsoleColor.Red; heroCar.Layer = car.Layer + 1; heroCar.ChildList[0].Layer = heroCar.Layer + 0.5f; heroStep = (heroCar.Size.X * 2.1f).XToGrid(); AddEnemy(); //environment house = new ObjectSingle(Preset.boxL, ConsoleColor.Gray, "house", 3f, plane.Position.X - (int)(plane.Size.X / 2), plane.Position.Y, (int)(plane.Size.X / 3), (int)(plane.Size.Y / 2)); houseB = new ObjectGroup(Preset.boxL, windows.Color, null, house.Layer + 0.5f, house.Position.X, house.Position.Y, (int)(house.Size.X / 1.2f), (int)(house.Size.Y / 4), null, (int)(house.Size.Y / 6), 1, 2); houseC = new ObjectSingle(Preset.boxL, ConsoleColor.Black, null, house.Layer + 1.0f, house.Position.X, house.Position.Y, (int)(house.Size.X / 2f), (int)(house.Size.Y * 1.2f)); house.Position.MaxY = road.Position.Y + (int)(houseC.Size.Y / 2) + (int)(plane.Size.Y / 2); house.ChildList.Add(houseB); house.ChildList.Add(houseC); tree = new ObjectSingle(Preset.boxL, ConsoleColor.DarkYellow, "tree", 4f, house.Position.X, house.Position.Y, (int)(plane.Size.X / 2.5f), (int)(plane.Size.Y / 20)); treeB = new ObjectGroup(Preset.boxL, ConsoleColor.Green, null, tree.Layer + 0.5f, tree.Position.X, tree.Position.Y, (int)(tree.Size.X / 4), tree.Size.Y * 5, (int)(tree.Size.X / 8), null, 2, 1); treeC = new ObjectSingle(Preset.boxL, treeB.Color, null, tree.Layer + 1.0f, tree.Position.X, tree.Position.Y, (int)(tree.Size.X / 1.3f), tree.Size.Y * 3); tree.Position.MaxY = road.Position.Y + (int)(treeB.Size.Y / 2) + (int)(plane.Size.Y / 2); tree.ChildList.Add(treeB); tree.ChildList.Add(treeC); tree.Position.X = plane.Position.X + plane.Size.X / 2; environs.Add(tree); environs.Add(house); environsPosY = road.Position.Y - (int)(houseC.Size.Y / 2) - (int)(plane.Size.Y / 2); }
//================ /// <summary> /// entry point of a application (точка входа приложения) /// </summary> static void Main() { void MainMethod() { MainTimer.Start(); view.MainInitialize(); view.StartSum(); Thread.Sleep(SleepTime); int currentTime; while (true) { currentTime = (int)MainTimer.ElapsedMilliseconds; view.UpdateSum(); SleepTime = (FixedTimeMs - ((int)MainTimer.ElapsedMilliseconds - currentTime)).Range(0, FixedTimeMs); DeltaTime = (float)Math.Max(FixedTimeMs, (int)MainTimer.ElapsedMilliseconds - currentTime) / 1000; Thread.Sleep(SleepTime); } } if (!DoExceptionView) { MainMethod(); } else { try { MainMethod(); } catch (Exception Ex) { string message = Ex.Source + " error! " + Ex.Message; try { ObjectSingle plane = new ObjectSingle(Preset.plane, ConsoleColor.White); while (true) { message.WriteTo(plane); } } catch { Console.WriteLine(message); Console.ReadKey(); } } } }
//---private--- /// <summary> /// (перемещает объект в направлении целевого вектора) /// </summary> /// <param name="speed">(скорость перемещения)</param> /// <param name="targetX">(целевой вектор X)</param> /// <param name="targetY">(целевой вектор Y)</param> static void Move(ObjectSingle objectToMove, float speed, int targetX, int targetY) { objectToMove.Position.PrevX = (int)objectToMove.Position.X; objectToMove.Position.PrevY = (int)objectToMove.Position.Y; if (targetX != 0 || targetY != 0) { float gX = targetX.XToGrid(); float gY = targetY.YToGrid(); double atang = Math.Atan2(gY, gX); float velocityX = (float)Math.Cos(atang) * speed * Model.DeltaTime; float velocityY = (float)Math.Sin(atang) * speed * Model.DeltaTime; objectToMove.Position.X += Math.Sign(gX) * Math.Min(Math.Abs(targetX), Math.Abs(velocityX).GridToX()); objectToMove.Position.Y += Math.Sign(gY) * Math.Min(Math.Abs(targetY), Math.Abs(velocityY).GridToY()); } }
//====== /// <summary> /// (перемещает этот объект в направлении нажатой клавиши-стрелки или WASD) /// </summary> /// <param name="speed">(скорость перемещения)</param> /// <param name="stopDistance">(Дистанция до остановки. В случае null остановки нет.)</param> public static void MoveByWASD(this ObjectSingle objectToMove, float speed, float?stopDistance = null) { if (!getKeyIsOn) { Model.StartThread(GetKey); getKeyIsOn = true; } if (stopDistance != null) { stopGap = (float)stopDistance; ObjectToMove = objectToMove; if (LastKey != null && LastKey != ConsoleKey.Enter) { MoveTowards(objectToMove, speed, new Vector(posX, posY)); } } else { Move(objectToMove, speed, keyX.GridToX(), keyY.GridToY()); } }
//========= public Inspector(ObjectSingle parentObject) { Initialize(parentObject); }
/// <summary> gets called every frame (выполняется для каждого кадра) </summary> public override void Update() { //==== game loop ==== if (!isEnd) { currentSpeed = windowMult * (float)Math.Sqrt(Math.Pow(startSpeed, 2) + 0.02f * MainTimer.ElapsedMilliseconds); //background firstLine.MoveAside(currentSpeed, SideX.middle, SideY.down); secondLine.MoveAside(currentSpeed, SideX.middle, SideY.down); if (firstLine.Position.Y >= firstLine.Position.MaxY) { firstLine.Position.Y = secondLine.Position.Y - road.Size.Y; } if (secondLine.Position.Y >= secondLine.Position.MaxY) { secondLine.Position.Y = firstLine.Position.Y - road.Size.Y; } //text if (messageOn) { messageA = "Press arrow keys or WASD to move."; //message.WriteTo(textA); if (Controller.LastKey != null) { //textA.IsDrawn = false; messageOn = false; } } else { charCounter = (int)Math.Max(Math.Floor(currentSpeed * mphMult / 10) - 5, 0); messageA = String.Format("Current speed: {0} mph {1}", (int)(currentSpeed * mphMult), new string('!', charCounter)); textA.MoveTowards(textSpeed * 4, textPoint); } messageA.WriteTo(textA); //cars for (int i = 0; i < enemies.Count; i++) { enemies[i].MoveAside(currentSpeed - startSpeed * 2, SideX.middle, SideY.down); int prev = i - 1 < 0 ? enemies.Count - 1 : i - 1; if (enemies[i].Position.Y >= enemies[i].Position.MaxY) { enemies[i].Position.X = new Random().Next((int)heroCar.Position.MinX, (int)heroCar.Position.MaxX); enemies[i].Position.Y = Math.Min(car.Position.Y - new Random().Next(0, (int)currentSpeed.GridToY()), enemies[prev].Position.Y - road.Size.Y / ZeroCheck(enemies.Count)); enemies[i].Color = RandomColor(ConsoleColor.Black, ConsoleColor.DarkRed, windows.Color, heroCar.Color, road.Color, firstLine.Color); if (!enemies[i].IsDrawn) { enemies[i].IsDrawn = true; } } } heroCar.MoveByWASD(currentSpeed, heroStep); if (heroCar.TriggerEnter(out other, enemyTag)) { restartCar = other[0]; heroCar.ChildList[0].Color = ConsoleColor.DarkRed; restartCar.ChildList[0].Color = ConsoleColor.DarkRed; Console.Beep(); isEnd = true; } //environment for (int i = 0; i < environs.Count; i++) { environs[i].MoveAside(currentSpeed, SideX.middle, SideY.down); int prev = i - 1 < 0 ? environs.Count - 1 : i - 1; if (environs[i].Position.Y >= environs[i].Position.MaxY) { environs[i].Position.X = new Random().Next(0, 2) > 0 ? plane.Position.X - plane.Size.X / 2 : plane.Position.X + plane.Size.X / 2; environs[i].Position.Y = Math.Min(environsPosY - new Random().Next(0, (int)currentSpeed.GridToY()), environs[prev].Position.Y - houseC.Size.Y * 1.5f); if (environs[i].Tag == house.Tag) { environs[i].Color = RandomColor(ConsoleColor.Black, ConsoleColor.Red, ConsoleColor.DarkRed, windows.Color, heroCar.Color, road.Color, plane.Color); } } } } else { //text messageA = currentSpeed > 30 ? String.Format(" You drove at a speed of {0} mph!", (int)(currentSpeed * mphMult)): ""; messageB = String.Format("Game over!{0}", messageA); messageC = "Press Enter to restart."; messageB.WriteTo(textA, 0, -1); messageC.WriteTo(textA, 0, 1); textA.MoveTowards(textSpeed, heroCar); if (Controller.LastKey == ConsoleKey.Enter) { //System.Diagnostics.Process.Start(Assembly.GetExecutingAssembly().Location); //Environment.Exit(0); currentSpeed = startSpeed; heroCar.AlignWithSide(SideX.middle, SideY.down); heroCar.ChildList[0].Color = windows.Color; restartCar.ChildList[0].Color = windows.Color; restartCar.Position.Y = (int)restartCar.Position.MaxY; MainTimer.Restart(); //SleepTime = FixedTimeMs; isEnd = false; } } }
//======== /// <summary> /// provides game object rendering (Oбеспечивает рендеринг игрового объекта. Вызывается автоматически при изменении соответствующих параметров объекта.) /// </summary> public static void DrawObject(List <dynamic>[] tempArray, bool[] actionToggle, ObjectSingle parentObject, bool isParentGroup) { BoxBuilder builder = new BoxBuilder(); List <int[]> boxes; bool isLast; ConsoleColor locol; ConsoleColor col = (ConsoleColor)tempArray[(int)Param.color][tempArray[(int)Param.color].Count - 1]; float lay = (float)tempArray[(int)Param.layer][tempArray[(int)Param.layer].Count - 1]; //current fixed values(текущие фиксированные значения) int sx = (int)tempArray[(int)Param.sizeX][tempArray[(int)Param.sizeX].Count - 1]; int sy = (int)tempArray[(int)Param.sizeY][tempArray[(int)Param.sizeY].Count - 1]; int px = (int)tempArray[(int)Param.positionX][tempArray[(int)Param.positionX].Count - 1] + (int)WindowSize.X / 2 - sx / 2; int py = (int)tempArray[(int)Param.positionY][tempArray[(int)Param.positionY].Count - 1] + (int)WindowSize.Y / 2 - sy / 2; int sumX; int sumY; //previous values(предыдущие значения) int _sx = (int)tempArray[(int)Param.sizeX][0]; int _sy = (int)tempArray[(int)Param.sizeY][0]; int _px = (int)tempArray[(int)Param.positionX][0] + (int)WindowSize.X / 2 - _sx / 2; int _py = (int)tempArray[(int)Param.positionY][0] + (int)WindowSize.Y / 2 - _sy / 2; int _sumX; int _sumY; //--- if (isParentGroup) { if (actionToggle[(int)Draw.destroy]) { RedrawGroup(false, true); } else { if (actionToggle[(int)Draw.vector]) { RedrawGroup(true, true); if (!actionToggle[(int)Draw.color]) { RedrawGroup(true, false); } } if (actionToggle[(int)Draw.color]) { RedrawGroup(false, false); } } for (int i = 0; i < actionToggle.Length; i++) { actionToggle[i] = false; } } else { if (actionToggle[(int)Draw.destroy]) { RedrawSingle(false, true); } else { if (actionToggle[(int)Draw.vector]) { RedrawSingle(true, true); if (!actionToggle[(int)Draw.color]) { RedrawSingle(true, false); } } if (actionToggle[(int)Draw.color]) { RedrawSingle(false, false); } } for (int i = 0; i < actionToggle.Length; i++) { actionToggle[i] = false; } } //---- /// <summary> /// Создание (отрисовка) объекта либо его удаление. /// </summary> void RedrawSingle(bool isPartial, bool isRemove) { if (isRemove) { ArrayBlocker.WaitOne(); for (int j = 0; j < _sy; j++) { for (int i = 0; i < _sx; i++) { isLast = (j + 1 == _sy && i + 1 == _sx) ? true : false; _sumX = _px + i; _sumY = _py + j; sumX = px; sumY = py; Remove(_sumX, _sumY, sumX, sumY, isPartial, isLast); } } ArrayBlocker.ReleaseMutex(); } else { ArrayBlocker.WaitOne(); for (int j = 0; j < sy; j++) { for (int i = 0; i < sx; i++) { isLast = (j + 1 == sy && i + 1 == sx) ? true : false; sumX = px + i; sumY = py + j; _sumX = _px; _sumY = _py; Redraw(sumX, sumY, _sumX, _sumY, isPartial, isLast); } } ArrayBlocker.ReleaseMutex(); } } //---- /// <summary> /// Создание (отрисовка) группы объектов либо ее удаление. /// </summary> void RedrawGroup(bool isPartial, bool isRemove) { //current fixed values(текущие фиксированные значения) int gx = (int)tempArray[(int)Param.gapX][tempArray[(int)Param.gapX].Count - 1] + sx; int gy = (int)tempArray[(int)Param.gapY][tempArray[(int)Param.gapY].Count - 1] + sy; int qx = (int)tempArray[(int)Param.quantX][tempArray[(int)Param.quantX].Count - 1]; int qy = (int)tempArray[(int)Param.quantY][tempArray[(int)Param.quantY].Count - 1]; int hx = (sx + gx * (qx - 1)) / 2; int hy = (sy + gy * (qy - 1)) / 2; px = (int)tempArray[(int)Param.positionX][tempArray[(int)Param.positionX].Count - 1] + (int)WindowSize.X / 2 - hx; py = (int)tempArray[(int)Param.positionY][tempArray[(int)Param.positionY].Count - 1] + (int)WindowSize.Y / 2 - hy; //previous values(предыдущие значения) int _gx = (int)tempArray[(int)Param.gapX][0] + _sx; int _gy = (int)tempArray[(int)Param.gapY][0] + _sy; int _qx = (int)tempArray[(int)Param.quantX][0]; int _qy = (int)tempArray[(int)Param.quantY][0]; int _hx = (_sx + _gx * (_qx - 1)) / 2; int _hy = (_sy + _gy * (_qy - 1)) / 2; _px = (int)tempArray[(int)Param.positionX][0] + (int)WindowSize.X / 2 - _hx; _py = (int)tempArray[(int)Param.positionY][0] + (int)WindowSize.Y / 2 - _hy; if (isRemove) { ArrayBlocker.WaitOne(); for (int l = 0; l < _qy; l++) { for (int k = 0; k < _qx; k++) { for (int j = 0; j < _sy; j++) { for (int i = 0; i < _sx; i++) { isLast = (l + 1 == _qy && k + 1 == _qx && j + 1 == _sy && i + 1 == _sx) ? true : false; _sumX = _px + i + _gx * k; _sumY = _py + j + _gy * l; sumX = px + gx * k; sumY = py + gy * l; Remove(_sumX, _sumY, sumX, sumY, isPartial, isLast); } } } } ArrayBlocker.ReleaseMutex(); } else { ArrayBlocker.WaitOne(); for (int l = 0; l < qy; l++) { for (int k = 0; k < qx; k++) { for (int j = 0; j < sy; j++) { for (int i = 0; i < sx; i++) { isLast = (l + 1 == qy && k + 1 == qx && j + 1 == sy && i + 1 == sx) ? true : false; sumX = px + i + gx * k; sumY = py + j + gy * l; _sumX = _px + _gx * k; _sumY = _py + _gy * l; Redraw(sumX, sumY, _sumX, _sumY, isPartial, isLast); } } } } ArrayBlocker.ReleaseMutex(); } } //---- void Redraw(int x, int y, int _x, int _y, bool isPartial, bool isItLast) { if (CheckPrint(x, y)) { if (!isPartial || !((x >= _x && x < _x + _sx) && (y >= _y && y < _y + _sy))) { if (WindowArray[x, y].Count == 0 || lay >= WindowArray[x, y][0][1]) { DrawBox(col, x, y); } if (actionToggle[(int)Draw.color]) { WindowArray[x, y].RemoveAll(obj => obj[2].Equals(parentObject.GetHashCode())); } if (!WindowArray[x, y].Exists(obj => obj[2].Equals(parentObject.GetHashCode()))) { if (WindowArray[x, y].Count == 0) { WindowArray[x, y].Add(new float[] { (int)col, lay, parentObject.GetHashCode() }); } else { for (int n = 0; n < WindowArray[x, y].Count; n++) { if (lay >= WindowArray[x, y][n][1]) { WindowArray[x, y].Insert(n, new float[] { (int)col, lay, parentObject.GetHashCode() }); break; } else if (n == WindowArray[x, y].Count - 1) { WindowArray[x, y].Add(new float[] { (int)col, lay, parentObject.GetHashCode() }); } } } } } } if (isItLast) { DrawBoxLast(); } } //---- void Remove(int _x, int _y, int x, int y, bool isPartial, bool isItLast) { if (CheckPrint(_x, _y)) { if (!isPartial || !((_x >= x && _x < x + sx) && (_y >= y && _y < y + sy))) { WindowArray[_x, _y].RemoveAll(obj => obj[2].Equals(parentObject.GetHashCode())); locol = WindowArray[_x, _y].Count == 0 ? DefaultColor : (ConsoleColor)(int)WindowArray[_x, _y][0][0]; DrawBox(locol, _x, _y); } } if (isItLast) { DrawBoxLast(); } } //---- /// <summary> /// draws box at last point (отрисовывает квадратный элемент в последней точке) /// </summary> void DrawBoxLast() { boxes = builder.LastPixel(); if (boxes != null) { for (int i = 0; i < boxes.Count; i++) { DrawPixel((ConsoleColor)boxes[i][0], boxes[i][1], boxes[i][2], boxes[i][3], boxes[i][4]); } } } //---- /// <summary> /// draws box at point (отрисовывает квадратный элемент в точке) /// </summary> /// <param name="color">color to draw (цвет для отрисовки)</param> /// <param name="x">point X coordinate (координата точки по оси X)</param> /// <param name="y">point Y coordinate (координата точки по оси Y)</param> void DrawBox(ConsoleColor color, int x, int y) { boxes = builder.AddPixel(color, x, y); if (boxes != null) { for (int i = 0; i < boxes.Count; i++) { DrawPixel((ConsoleColor)boxes[i][0], boxes[i][1], boxes[i][2], boxes[i][3], boxes[i][4]); } } } }