Rocket Game

This commit is contained in:
Simon Lübeß
2022-02-13 15:22:45 +01:00
parent e61c53400f
commit d9e34b27a3
6 changed files with 616 additions and 2 deletions
+201
View File
@@ -0,0 +1,201 @@
using System;
using GlitchyEngine;
using GlitchyEngine.Events;
using System.Diagnostics;
using GlitchLog;
using GlitchyEngine.ImGui;
using ImGui;
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using GlitchyEngine.World;
using GlitchyEngine.Renderer.Text;
using System.IO;
using msdfgen;
using System.Collections;
using System.Diagnostics;
namespace Sandbox
{
class GameLayer : Layer
{
GraphicsContext _context ~ _?.ReleaseRef();
BlendState _alphaBlendState ~ _?.ReleaseRef();
Font _font ~ _.ReleaseRef();
DepthStencilState _depthStencilState ~ _.ReleaseRef();
Rocket _rocket ~ delete _;
OrthographicCamera _camera ~ delete _;
List<Obstacle> _obstacles = new List<Obstacle>() ~ DeleteContainerAndItems!(_);
[AllowAppend]
public this() : base("Example")
{
Application.Get().Window.IsVSync = false;
_context = Application.Get().Window.Context..AddRef();
BlendStateDescription blendDesc = .();
blendDesc.RenderTarget[0] = .(true, .SourceAlpha, .InvertedSourceAlpha, .Add, .SourceAlpha, .InvertedSourceAlpha, .Add, .All);
_alphaBlendState = new BlendState(blendDesc);
_font = new Font("C:\\Windows\\Fonts\\arial.ttf", 64, true, 'A', 16);
_camera = new .()
{
NearPlane = -10,
FarPlane = 10,
Height = 5,
Width = 5 * _context.SwapChain.AspectRatio
}..Update();
DepthStencilStateDescription dssDesc = .()
{
DepthEnabled = false
};
_depthStencilState = new DepthStencilState(dssDesc);
InitGame();
}
private void InitGame()
{
_rocket = new Rocket();
_rocket.Obstacles = _obstacles;
InitStarField();
}
Vector4[] points = new Vector4[1000] ~ delete _;
Random startRandom = new .() ~ delete _;
private void InitStarField()
{
for (int i < points.Count)
{
Vector4 v = .();
v.X = startRandom.Next(-1000, 1000) / 2000f * _camera.Width;
v.Y = startRandom.Next(-1000, 1000) / 2000f * _camera.Height;
v.Z = startRandom.Next(0, 999) / 1000.0f;
v.W = startRandom.Next(1000, 3000) / 1000.0f;
points[i] = v;
}
}
private float lastObstacle = 0.0f;
public override void Update(GameTime gameTime)
{
float screenWidth = _camera.Width;
Obstacle.ScreenWidth = screenWidth / 2.0f;
lastObstacle += Obstacle.Speed * gameTime.DeltaTime;
if (lastObstacle <= -Obstacle.ScreenWidth)
{
_obstacles.Add(new Obstacle());
lastObstacle += 2.5f;
_obstacles.Back.Position.X = Obstacle.ScreenWidth + 1.0f;
_obstacles.Back.Position.Y = Obstacle.random.Next(-1000, 1000) / 1000f;
}
for (int i < _obstacles.Count)
{
_obstacles[i].Update(gameTime);
if (_obstacles[i].Dead)
{
delete _obstacles[i];
_obstacles.RemoveAt(i);
i--;
}
}
_rocket.Update(gameTime);
Obstacle.Speed = -_rocket.FlightSpeed;
RenderCommand.Clear(null, .Black);
// Draw test geometry
RenderCommand.SetRenderTarget(null);
RenderCommand.BindRenderTargets();
RenderCommand.SetViewport(_context.SwapChain.BackbufferViewport);
RenderCommand.SetBlendState(_alphaBlendState);
RenderCommand.SetDepthStencilState(_depthStencilState);
Renderer2D.BeginScene(_camera, .BackToFront);
DrawStartField(gameTime);
Renderer2D.EndScene();
Renderer2D.BeginScene(_camera, .BackToFront);
Renderer2D.DrawQuad(Vector3(0, 2.75f, 1), Vector2(screenWidth, 1), 0, .White);
Renderer2D.DrawQuad(Vector3(0, -2.75f, 1), Vector2(screenWidth, 1), 0, .White);
for (Obstacle obs in _obstacles)
{
obs.Draw();
}
Renderer.BeginScene(_camera);
_rocket.Draw();
FontRenderer.DrawText(_font, scope $"{_rocket.Score}", 0, 1.5f, 1, .Black);
FontRenderer.DrawText(_font, scope $"{_rocket.Score}", 0.1f, 1.6f, 1, .(230, 230, 230));
Renderer.EndScene();
Renderer2D.EndScene();
}
private void DrawStartField(GameTime gameTime)
{
for (int i < points.Count)
{
points[i].X -= _rocket.FlightSpeed * gameTime.DeltaTime * points[i].Z;
if (points[i].X < _camera.Left)
{
points[i].X = _camera.Right + startRandom.Next(500, 1500) / 1000.0f;
}
Renderer2D.DrawCircle(Vector3(points[i].XY, 5), .(0.01f * points[i].W), Color.White);
}
}
public override void OnEvent(Event event)
{
EventDispatcher dispatcher = EventDispatcher(event);
dispatcher.Dispatch<ImGuiRenderEvent>(scope (e) => OnImGuiRender(e));
dispatcher.Dispatch<WindowResizeEvent>(scope (e) => OnWindowResize(e));
}
private bool OnImGuiRender(ImGuiRenderEvent e)
{
return false;
}
private bool OnWindowResize(WindowResizeEvent e)
{
_camera.Width = _camera.Height * e.Width / (float)e.Height;
_camera.Update();
return false;
}
}
}
+213
View File
@@ -0,0 +1,213 @@
using System;
using GlitchyEngine.Math;
namespace Sandbox
{
struct Line2D
{
public Vector2 Start;
public Vector2 End;
public this(Vector2 start, Vector2 end)
{
Start = start;
End = end;
}
/// Returns true if the given point lies on the line.
public bool OnLine(Vector2 point)
{
Vector2 startToPoint = point - Start;
Vector2 startToEnd = End - Start;
float cross = cross(startToPoint, startToEnd);
if(!MathHelper.IsZero(cross))
return false;
if(Math.Abs(startToEnd.X) >= Math.Abs(startToEnd.Y))
{
return (startToEnd.X > 0.0f) ?
(Start.X <= point.X && point.X <= End.X) :
(End.X <= point.X && point.X <= Start.X);
}
else
{
return (startToEnd.Y > 0.0f) ?
(Start.Y <= point.Y && point.Y <= End.Y) :
(End.Y <= point.Y && point.Y <= Start.Y);
}
}
[Inline]
private float cross(Vector2 v, Vector2 w)
{
return v.X * w.Y - v.Y * w.X;
}
public enum LineIntersection
{
case Collinear(Line2D IntersectionLine);
case CollinearNoIntersect;
case Parallel;
case Intersection(Vector2 Point);
case None;
}
private Result<(float Start, float End)> IntervalIntersection(float startA, float endA, float startB, float endB)
{
if(startB > endA || startA > endB)
return .Err;
else
{
float start = Math.Max(startA, startB);
float end = Math.Min(endA, endB);
return .Ok((start, end));
}
}
public LineIntersection Intersects(Line2D line)
{
Vector2 A = this.Start;
Vector2 B = this.End;
Vector2 C = line.Start;
Vector2 D = line.End;
float numR = ((A.Y-C.Y) * (D.X-C.X) - (A.X-C.X) * (D.Y-C.Y));
float den = ((B.X-A.X) * (D.Y-C.Y)-(B.Y-A.Y) * (D.X-C.X));
float r = numR / den;
float s = ((A.Y-C.Y) * (B.X-A.X) - (A.X-C.X) * (B.Y-A.Y)) / den;
if((0 <= r && r <= 1) && (0 <= s && s <= 1))
{
Vector2 P = A + r * (B - A);
return .Intersection(P);
}
else if(MathHelper.IsZero(den))
{
if(MathHelper.IsZero(numR))
{
Vector2 AtoB = B - A;
Vector2 CtoD = D - C;
float r_dot_r = Vector2.Dot(AtoB, AtoB);
// t0 = (q p) · r / (r · r)
float t0 = Vector2.Dot((C - A), AtoB) / r_dot_r;
// t1 = (q + s p) · r / (r · r) = t0 + s · r / (r · r)
float t1 = t0 + Vector2.Dot(CtoD, AtoB) / r_dot_r;
// do interval intersection
if(Vector2.Dot(CtoD, AtoB) < 0)
{
Swap!(t0, t1);
}
if(IntervalIntersection(t0, t1, 0, 1) case .Ok(let intersection))
{
return .Collinear(Line2D(A + intersection.Start * AtoB, A + intersection.End * AtoB));
}
else
{
return .CollinearNoIntersect;
}
}
else
{
return .Parallel;
}
}
return .None;
}
public static void TestIntersects()
{
{
Line2D line = .(.(0, 0), .(4, 0));
Line2D intersecting = .(.(2, 2), .(2, -2));
var result = line.Intersects(intersecting);
Vector2 intersection;
Runtime.Assert(result case .Intersection(out intersection));
Runtime.Assert(intersection == .(2, 0));
}
{
Line2D line = .(.(0, -1), .(5, 2));
Line2D intersecting = .(.(1, 3), .(4, -2));
var result = line.Intersects(intersecting);
Vector2 intersection;
Runtime.Assert(result case .Intersection(out intersection));
Runtime.Assert(intersection == .(2.5f, 0.5f));
}
{
Line2D line = .(.(-1, 0), .(1, 0));
Line2D collinear = .(.(2, 0), .( 4, 0));
var result = line.Intersects(collinear);
Runtime.Assert(result case .CollinearNoIntersect);
}
{
Line2D line = .(.(-1, 0), .(2, 0));
Line2D collinear = .(.(1, 0), .( 4, 0));
var result = line.Intersects(collinear);
Line2D intersection;
Runtime.Assert(result case .Collinear(out intersection));
Runtime.Assert(intersection.Start == .(1, 0));
Runtime.Assert(intersection.End == .(2, 0));
}
{
Line2D line = .(.(-1, 5), .(2, 5));
Line2D collinear = .(.(4, 5), .(1, 5));
var result = line.Intersects(collinear);
Line2D intersection;
Runtime.Assert(result case .Collinear(out intersection));
Runtime.Assert(intersection.Start == .(1, 5));
Runtime.Assert(intersection.End == .(2, 5));
}
}
/*
public bool Intersects(Line2D line)
{
float x1 = Start.X;
float x2 = End.X;
float x3 = line.Start.X;
float x4 = line.End.X;
float y1 = Start.Y;
float y2 = End.Y;
float y3 = line.Start.Y;
float y4 = line.End.Y;
float t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
float u = ((x1 - x3) * (y1 - y2) - (y1 - y3) * (x1 - x2)) / ((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4));
return (0.0f <= t && t <= 1.0f && 0.0f <= u && u <= 1.0f);
}
*/
}
}
+46
View File
@@ -0,0 +1,46 @@
using GlitchyEngine;
using GlitchyEngine.Math;
using GlitchyEngine.Renderer;
using System;
namespace Sandbox
{
class Obstacle
{
public Vector2 Position;
public float HoleSize = 4.5f;
public static float Speed = -2.0f;
public static float ScreenWidth;
public static Random random = new .() ~ delete _;
public bool Dead;
public void Update(GameTime gameTime)
{
Position.X += Speed * gameTime.DeltaTime;
if (Position.X < -ScreenWidth - 1)
{
Dead = true;
}
}
static Matrix mat = Matrix.Scaling(2.5f, 5, 1) * Matrix.RotationZ(MathHelper.PiOverFour);
public void Draw()
{
Matrix matty = mat;
matty.Translation.X = Position.X;
matty.Translation.Y = Position.Y - HoleSize;
Renderer2D.DrawQuad(matty, Color.White);
matty.Translation.Y = Position.Y + HoleSize;
Renderer2D.DrawQuad(matty, Color.White);
}
}
}
+153
View File
@@ -0,0 +1,153 @@
using GlitchyEngine.Renderer;
using GlitchyEngine.Math;
using GlitchyEngine;
using System;
using System.Collections;
namespace Sandbox
{
class Rocket
{
Texture2D _rocketTexture ~ _?.ReleaseRef();
private Vector2 _gravity = .(0, -9.81f);
public float Power = 50;
public float FlightSpeed = 2;
private Vector2 _acceleration = .(0, 0);
private Vector2 _speed;
private Vector2 _position;
private float _rotation;
private bool _dead;
private bool _started = false;
public List<Obstacle> Obstacles;
public int Score = 0;
public this()
{
_rocketTexture = new Texture2D("content/RocketGame/Rocket.dds");
_rocketTexture.SamplerState = SamplerStateManager.PointClamp;
}
public void Update(GameTime gameTime)
{
FlightSpeed = _dead ? 0.0f : 2.0f;
if (!_started)
{
_position = .Zero;
if (Input.IsKeyPressed(Key.Space))
_started = true;
else
return;
}
UpdatePosition(gameTime);
CheckDead();
}
public void Draw()
{
Renderer2D.DrawQuad(_position, .One, _rotation, _rocketTexture, .White);
CheckObstacles();
}
Line2D rocketLine;
private void UpdatePosition(GameTime gameTime)
{
_acceleration.Y = 0;
if (!_dead && Input.IsKeyPressed(Key.Space))
{
_acceleration.Y += Power;
}
Vector2 newSpeed = _speed + (_acceleration + _gravity) * gameTime.DeltaTime;
Vector2 newPosition = _position + newSpeed * gameTime.DeltaTime;
_speed = newSpeed;
_position = newPosition;
float ang = Math.Atan2(_speed.Y, 10) - MathHelper.PiOverTwo;
_rotation = ang;
Vector2 dir = Vector2.Normalize(_speed + .(10, 0));
rocketLine = .(_position - dir / 2.8f, _position + dir / 2.4f);
}
const float worldBorder = 2.1f;
private void CheckDead()
{
if (Math.Abs(_position.Y) >= worldBorder)
{
_dead = true;
_speed.Y *= -0.8f;
_position.Y = Math.Clamp(_position.Y, -worldBorder, worldBorder);
}
}
private int scoreLine = -1;
private void CheckObstacles()
{
for (Obstacle obs in Obstacles)
{
const float f = Vector2.One.Magnitude();
Vector2 center = obs.Position;
Vector2 topCenter = center + .(0, obs.HoleSize);
Vector2 topTip = topCenter - .(0, 2.5f * f);
Vector2 topRight = topCenter - .(f, 0);
Vector2 topLeft = topCenter + .(f, 0);
Vector2 bottomCenter = center - .(0, obs.HoleSize);
Vector2 bottomTip = bottomCenter + .(0, 2.5f * f);
Vector2 bottomRight = bottomCenter - .(f, 0);
Vector2 bottomLeft = bottomCenter + .(f, 0);
Line2D bottomR = .(bottomTip, bottomRight);
Line2D bottomL = .(bottomTip, bottomLeft);
Line2D topR = .(topTip, topRight);
Line2D topL = .(topTip, topLeft);
if ((bottomR.Intersects(rocketLine) case .Intersection) ||
(bottomL.Intersects(rocketLine) case .Intersection) ||
(topR.Intersects(rocketLine) case .Intersection) ||
(topL.Intersects(rocketLine) case .Intersection))
{
_dead = true;
}
if (!_dead)
{
if (Line2D(bottomTip, topTip).Intersects(rocketLine) case .Intersection)
{
scoreLine = @obs.Index;
}
else if (scoreLine == @obs.Index)
{
Score++;
scoreLine = -1;
}
}
}
}
}
}
+3 -2
View File
@@ -18,13 +18,14 @@ namespace Sandbox
{
public this()
{
#if GAMMA_TEST
/*#if GAMMA_TEST
PushLayer(new GammaTestLayer());
#elif SANDBOX_2D
PushLayer(new ExampleLayer2D());
#else
PushLayer(new ExampleLayer());
#endif
#endif*/
PushLayer(new GameLayer());
}
[Export, LinkName("CreateApplication")]