// NAV DOMĀTS VĒRTĒŠANAI // ŠIS IR ARHĪVS using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Threading; namespace ConsoleApp1 { internal class Game { public const int CanvasWidth = 220; public const int CanvasHeight = 55; public static float CameraOffset = 15f; public static float Gravity = 60f; public static float GroundYLevel = -10; public static List RenderQueue = new List(); public static char[] RenderBuffer = new char[CanvasHeight * CanvasWidth]; // -- // // Fankšons // -- public static Vector2 Project(Vector3 point) { // Math by chat gpt float z = point.Z + CameraOffset; if (z <= 0.01f) { z = 0.01f; } float projectedX = point.X / z; float projectedY = (-point.Y) / z; Vector2 projection = new Vector2( (int)(projectedX * 7) + CanvasWidth / 2, (int)(projectedY * 7) + CanvasHeight / 2 ); return projection; } public static void Render() { StringBuilder sb = new StringBuilder( CanvasWidth * CanvasHeight + CanvasHeight ); for (int y = 0; y < CanvasHeight; y++) { for (int x = 0; x < CanvasWidth; x++) { sb.Append( RenderBuffer[(y * CanvasWidth) + x] ); } sb.Append('\n'); } Console.SetCursorPosition(0, 0); Console.Write(sb.ToString()); } public static void DrawPixelToRenderBuffer(Vector2 screenPosition, char character) { int x = (int)screenPosition.X; int y = (int)screenPosition.Y; if (x < 0 || x >= CanvasWidth || y < 0 || y >= CanvasHeight) return; int bufferIndex = (y * CanvasWidth) + x; RenderBuffer[bufferIndex] = character; } public static void DrawLine(Vector2 start, Vector2 end, char character) { int x0 = (int)start.X; int y0 = (int)start.Y; int x1 = (int)end.X; int y1 = (int)end.Y; int dx = Math.Abs(x1 - x0); int dy = Math.Abs(y1 - y0); int sx = x0 < x1 ? 1 : -1; int sy = y0 < y1 ? 1 : -1; int err = dx - dy; while (true) { DrawPixelToRenderBuffer( new Vector2(x0, y0), character ); if (x0 == x1 && y0 == y1) break; int e2 = err * 2; if (e2 > -dy) { err -= dy; x0 += sx; } if (e2 < dx) { err += dx; y0 += sy; } } } // -- // // Interfaces // -- public interface IControllable { void OnKey(ConsoleKeyInfo CKeyInfo); } // -- // // Geometry // -- public struct Vector3 { private float x; public float X { get; set; } private float y; public float Y { get; set; } private float z; public float Z { get; set; } // OVERRIDE MATH public static Vector3 operator +(Vector3 v1, Vector3 v2) { v1.X += v2.X; v1.Y += v2.Y; v1.Z += v2.Z; return v1; } public static Vector3 operator -(Vector3 v1, Vector3 v2) { v1.X -= v2.X; v1.Y -= v2.Y; v1.Z -= v2.Z; return v1; } public static Vector3 operator *(Vector3 v1, Vector3 v2) { v1.X *= v2.X; v1.Y *= v2.Y; v1.Z *= v2.Z; return v1; } public static Vector3 operator /(Vector3 v1, Vector3 v2) { v1.X /= v2.X; v1.Y /= v2.Y; v1.Z /= v2.Z; return v1; } public float Magnitude() { return (float)Math.Sqrt((this.X * this.X) + (this.Y * this.Y) + (this.Z * this.Z)); } public override string ToString() { return $"x:{this.X}|y:{this.Y}|z:{this.Z}"; } public Vector3 Unit() { float Magnitude = this.Magnitude(); Vector3 A = new Vector3( this.X / Magnitude, this.Y / Magnitude, this.Z / Magnitude ); return A; } public Vector3(float x, float y, float z) { this.x = default; this.y = default; this.z = default; this.X = x; this.Y = y; this.Z = z; } } public struct Vector2 { private float x; public float X { get; set; } private float y; public float Y { get; set; } // OVERRIDE MATH public static Vector2 operator +(Vector2 v1, Vector2 v2) { v1.X += v2.X; v1.Y += v2.Y; return v1; } public static Vector2 operator -(Vector2 v1, Vector2 v2) { v1.X -= v2.X; v1.Y -= v2.Y; return v1; } public static Vector2 operator *(Vector2 v1, Vector2 v2) { v1.X *= v2.X; v1.Y *= v2.Y; return v1; } public static Vector2 operator /(Vector2 v1, Vector2 v2) { v1.X /= v2.X; v1.Y /= v2.Y; return v1; } public float Magnitude() { return (float)Math.Sqrt((this.X * this.X) + (this.Y * this.Y)); } public override string ToString() { return $"x:{this.X}|y:{this.Y}"; } public Vector2 Unit() { float Magnitude = this.Magnitude(); Vector2 A = new Vector2( this.X / Magnitude, this.Y / Magnitude ); return A; } public Vector2(float x, float y) { this.x = default; this.y = default; this.X = x; this.Y = y; } } // public struct Line { public Vertex A; public Vertex B; public Vector3 Unit() { Vector3 Difference = B.Position - A.Position; return Difference.Unit(); } public float Magnitude() { Vector3 Difference = A.Position - B.Position; return Difference.Magnitude(); } public Line(Vertex A, Vertex B) { this.A = A; this.B = B; } } // public class Vertex { public Vector3 Position; public List Wires = new List(); public Vertex(float x = 0, float y = 0, float z = 0) { this.Position = new Vector3(x, y, z); } } // -- // // Objects // -- public abstract class Object { public List Vertecies = new List(); public bool Anchored = false; public bool HasGravity = true; public Vector3 Position; public Vector3 Force = new Vector3(0, 0, 0); public float Scale = 1f; public float Drag = 0.5f; public char DrawCharacter = '█'; public virtual void LogicUpdate(float delta_time) { } public virtual void PhysicsUpdate(float delta_time) { if (Anchored == false) { if (HasGravity) this.Force.Y -= Gravity * delta_time; this.Position += new Vector3( (this.Force.X * Drag) * delta_time, (this.Force.Y) * delta_time, (this.Force.Z * Drag) * delta_time ); } Vertex lowest_vertex = Vertecies[0]; foreach (Vertex vertecie in Vertecies) { if (vertecie.Position.Y * Scale + Position.Y < lowest_vertex.Position.Y * Scale + Position.Y) lowest_vertex = vertecie; } if (lowest_vertex.Position.Y * Scale + Position.Y < GroundYLevel) { this.Force.Y = 0; this.Position.Y += (GroundYLevel - (lowest_vertex.Position.Y * Scale + Position.Y)); } } public void Render() { for (int index = 0; index < Vertecies.Count; index++) { Vertex vertex = Vertecies[index]; foreach (Line wire in vertex.Wires) { Vector2 start = Game.Project(wire.A.Position * new Vector3(Scale, Scale, Scale) + Position); Vector2 end = Game.Project(wire.B.Position * new Vector3(Scale, Scale, Scale) + Position); Game.DrawLine(start, end, this.DrawCharacter); } } } } public class Cube : Object { public Cube(Vector3 Position) { this.Vertecies.Add(new Vertex(-6, 0, -2)); // BOTTOM BOTTOM LEFT this.Vertecies.Add(new Vertex(-6, 6, -2)); // BOTTOM TOP LEFT this.Vertecies.Add(new Vertex(6, 6, -2)); // BOTTOM TOP RIGHT this.Vertecies.Add(new Vertex(6, 0, -2)); // BOTTOM BOTTOM RIGHT this.Vertecies.Add(new Vertex(6, 0, 2)); // FRONT BOTTOM RIGHT this.Vertecies.Add(new Vertex(6, 6, 2)); // FRONT TOP RIGHT this.Vertecies.Add(new Vertex(-6, 6, 2)); // FRONT TOP LEFT this.Vertecies.Add(new Vertex(-6, 0, 2)); // FRONT BOTTOM LEFT // SETTING WIREFRAME this.Vertecies[0].Wires.Add(new Line(this.Vertecies[0], this.Vertecies[1])); // BOTTOM BOTTOM LEFT to BOTTOM TOP LEFT this.Vertecies[0].Wires.Add(new Line(this.Vertecies[0], this.Vertecies[3])); // BOTTOM BOTTOM LEFT to BOTTOM BOTTOM RIGHT this.Vertecies[0].Wires.Add(new Line(this.Vertecies[0], this.Vertecies[7])); // BOTTOM BOTTOM LEFT to FRONT BOTTOM LEFT this.Vertecies[2].Wires.Add(new Line(this.Vertecies[2], this.Vertecies[1])); // BOTTOM TOP RIGHT to BOTTOM TOP LEFT this.Vertecies[2].Wires.Add(new Line(this.Vertecies[2], this.Vertecies[3])); // BOTTOM TOP RIGHT to BOTTOM BOTTOM RIGHT this.Vertecies[2].Wires.Add(new Line(this.Vertecies[2], this.Vertecies[5])); // BOTTOM TOP RIGHT to FRONT TOP RIGHT this.Vertecies[6].Wires.Add(new Line(this.Vertecies[6], this.Vertecies[5])); // FRONT TOP LEFT to FRONT TOP RIGHT this.Vertecies[6].Wires.Add(new Line(this.Vertecies[6], this.Vertecies[7])); // FRONT TOP RIGHT to FRONT BOTTOM LEFT this.Vertecies[6].Wires.Add(new Line(this.Vertecies[6], this.Vertecies[1])); // FRONT TOP RIGHT to BOTTOM TOP LEFT this.Vertecies[4].Wires.Add(new Line(this.Vertecies[4], this.Vertecies[5])); // FRONT BOTTOM RIGHT to FRONT TOP RIGHT this.Vertecies[4].Wires.Add(new Line(this.Vertecies[4], this.Vertecies[7])); // FRONT TOP RIGHT to FRONT BOTTOM LEFT this.Vertecies[4].Wires.Add(new Line(this.Vertecies[4], this.Vertecies[3])); // FRONT TOP RIGHT to BOTTOM BOTTOM RIGHT this.Scale = 2; this.Position = Position; } public override void LogicUpdate(float delta_time) { this.Force.X = -15; } } public class Player : Object, IControllable { public Player(Vector3 Position) { this.Vertecies.Add(new Vertex(-6, 0, -1)); // BOTTOM BOTTOM LEFT this.Vertecies.Add(new Vertex(-6, 6, -1)); // BOTTOM TOP LEFT this.Vertecies.Add(new Vertex(6, 6, -1)); // BOTTOM TOP RIGHT this.Vertecies.Add(new Vertex(6, 0, -1)); // BOTTOM BOTTOM RIGHT this.Vertecies.Add(new Vertex(6, 0, 1)); // FRONT BOTTOM RIGHT this.Vertecies.Add(new Vertex(6, 6, 1)); // FRONT TOP RIGHT this.Vertecies.Add(new Vertex(-6, 6, 1)); // FRONT TOP LEFT this.Vertecies.Add(new Vertex(-6, 0, 1)); // FRONT BOTTOM LEFT // SETTING WIREFRAME this.Vertecies[0].Wires.Add(new Line(this.Vertecies[0], this.Vertecies[1])); // BOTTOM BOTTOM LEFT to BOTTOM TOP LEFT this.Vertecies[0].Wires.Add(new Line(this.Vertecies[0], this.Vertecies[3])); // BOTTOM BOTTOM LEFT to BOTTOM BOTTOM RIGHT this.Vertecies[0].Wires.Add(new Line(this.Vertecies[0], this.Vertecies[7])); // BOTTOM BOTTOM LEFT to FRONT BOTTOM LEFT this.Vertecies[2].Wires.Add(new Line(this.Vertecies[2], this.Vertecies[1])); // BOTTOM TOP RIGHT to BOTTOM TOP LEFT this.Vertecies[2].Wires.Add(new Line(this.Vertecies[2], this.Vertecies[3])); // BOTTOM TOP RIGHT to BOTTOM BOTTOM RIGHT this.Vertecies[2].Wires.Add(new Line(this.Vertecies[2], this.Vertecies[5])); // BOTTOM TOP RIGHT to FRONT TOP RIGHT this.Vertecies[6].Wires.Add(new Line(this.Vertecies[6], this.Vertecies[5])); // FRONT TOP LEFT to FRONT TOP RIGHT this.Vertecies[6].Wires.Add(new Line(this.Vertecies[6], this.Vertecies[7])); // FRONT TOP RIGHT to FRONT BOTTOM LEFT this.Vertecies[6].Wires.Add(new Line(this.Vertecies[6], this.Vertecies[1])); // FRONT TOP RIGHT to BOTTOM TOP LEFT this.Vertecies[4].Wires.Add(new Line(this.Vertecies[4], this.Vertecies[5])); // FRONT BOTTOM RIGHT to FRONT TOP RIGHT this.Vertecies[4].Wires.Add(new Line(this.Vertecies[4], this.Vertecies[7])); // FRONT TOP RIGHT to FRONT BOTTOM LEFT this.Vertecies[4].Wires.Add(new Line(this.Vertecies[4], this.Vertecies[3])); // FRONT TOP RIGHT to BOTTOM BOTTOM RIGHT this.Scale = 2; this.Position = Position; this.DrawCharacter = '▓'; } public void OnKey(ConsoleKeyInfo ckey_info) { ConsoleKey key = ckey_info.Key; switch (key) { case ConsoleKey.W: this.Position += new Vector3(0, 0, .45f); break; case ConsoleKey.A: this.Position += new Vector3(-1, 0, 0); break; case ConsoleKey.S: this.Position += new Vector3(0, 0, -.45f); break; case ConsoleKey.D: this.Position += new Vector3(1, 0, 0); break; case ConsoleKey.Spacebar: this.Force = new Vector3(0, 45, 0); break; default: break; } } public override void LogicUpdate(float DeltaTime) { } } static void Main(string[] args) { Thread.Sleep(2000); // to full screen RenderQueue.Add(new Player(new Vector3(2, 0, -5))); RenderQueue.Add(new Cube(new Vector3(100, -20, -5))); Console.CursorVisible = false; ConsoleKeyInfo? HeldKey = null; Stopwatch timer = new Stopwatch(); long previous_time = 0; long current_time = 0; float delta_time = 0; timer.Start(); while (true) { current_time = timer.ElapsedMilliseconds; delta_time = (float)((current_time - previous_time) / 1000f); previous_time = current_time; Console.Write(Math.Floor(1000 / (1000 * delta_time)) + " FPS"); if (Console.KeyAvailable) HeldKey = Console.ReadKey(true); else HeldKey = null; for (int i = 0; i < RenderBuffer.Length; i++) RenderBuffer[i] = ' '; foreach (Object obj in RenderQueue) { // User Input if (HeldKey != null) if (obj is IControllable controllable_obj) controllable_obj.OnKey((ConsoleKeyInfo)HeldKey); // Updates obj.PhysicsUpdate(delta_time); obj.LogicUpdate(delta_time); // Rendering obj.Render(); } Game.Render(); int processing_time = (int)(timer.ElapsedMilliseconds - previous_time); int yield_time = 10 - processing_time; if (yield_time < 0) yield_time = 0; Thread.Sleep(yield_time); } } } }