Add project files.

This commit is contained in:
maxwes08
2025-10-21 10:47:45 +02:00
parent a21be65109
commit f4deaadb57
8 changed files with 305 additions and 0 deletions

39
Pillar.cs Normal file
View File

@@ -0,0 +1,39 @@
using SFML.Graphics;
class Pillar
{
public Sprite Top;
public Sprite Bottom;
public float X;
public Pillar(Texture topTex, Texture bottomTex, float startX, float gapY, float gapHeight)
{
X = startX;
Top = new Sprite(topTex) { Scale = new SFML.System.Vector2f(2f, 2f) };
Bottom = new Sprite(bottomTex) { Scale = new SFML.System.Vector2f(2f, 2f) };
Top.Position = new SFML.System.Vector2f(X, gapY - gapHeight / 2f - topTex.Size.Y * Top.Scale.Y);
Bottom.Position = new SFML.System.Vector2f(X, gapY + gapHeight / 2f);
}
public void Update(float deltaTime, float speed)
{
X -= speed * deltaTime;
Top.Position = new SFML.System.Vector2f(X, Top.Position.Y);
Bottom.Position = new SFML.System.Vector2f(X, Bottom.Position.Y);
}
public void Draw(RenderWindow window)
{
window.Draw(Top);
window.Draw(Bottom);
}
public bool IsOffscreen(float screenWidth)
{
// Rightmost point of the pillar
float pillarRightEdge = X + Top.Texture.Size.X * Top.Scale.X;
return pillarRightEdge < 0;
}
}

211
Program.cs Normal file
View File

@@ -0,0 +1,211 @@
using SFML.Graphics;
using SFML.System;
using SFML.Window;
internal class Program
{
private static void Main()
{
// Game constants
uint gameWidth = 900;
uint gameHeight = 504;
float gravity = 800f; // px/sec^2
float jumpForce = -300f; // px/sec
float scrollSpeed = 150f; // px/sec
float scrollDecay = 500f; // px/sec^2
float maxUpAngle = -30f; // tilt up max
float maxDownAngle = 60f; // tilt down max
float maxVelocity = 500f; // velocity that corresponds to max tilt
float backgroundSpeed = 0.75f;
// Pillars
List<Pillar> pillars = new List<Pillar>();
float spawnInterval = 2.0f; // seconds between pillar spawns
float pillarTimer = spawnInterval; // triggers first pillar immediately
float spacing = 200f; // horizontal distance between pillars
// Gap limits
float minGapHeight = 110f;
float maxGapHeight = 300f;
float minGapY = 100f; // min distance from top
// Game status
bool alive = true;
Random random = new Random();
// Create window
RenderWindow window = new RenderWindow(new VideoMode(gameWidth, gameHeight), "Flappy Bird Clone");
window.Closed += (s, e) => window.Close();
window.SetFramerateLimit(60);
// Setup view for scaling
View view = new View(new FloatRect(0, 0, gameWidth, gameHeight));
window.SetView(view);
window.Resized += (s, e) =>
{
float windowRatio = (float)e.Width / e.Height;
float gameRatio = (float)gameWidth / gameHeight;
FloatRect viewport;
if (windowRatio > gameRatio)
{
float width = gameRatio / windowRatio;
viewport = new FloatRect((1 - width) / 2f, 0, width, 1);
}
else
{
float height = windowRatio / gameRatio;
viewport = new FloatRect(0, (1 - height) / 2f, 1, height);
}
view.Viewport = viewport;
window.SetView(view);
};
// Load textures
Texture backgroundTexture = new Texture("background.png") { Repeated = true };
Texture birdTexture = new Texture("bird.png");
// Background rectangle
RectangleShape backgroundRect = new RectangleShape(new Vector2f(gameWidth, gameHeight));
backgroundRect.Texture = backgroundTexture;
long backgroundOffset = 0;
// Bird sprite
Sprite bird = new Sprite(birdTexture);
bird.Scale = new Vector2f(3f, 3f); // scale as desired
bird.Position = new Vector2f(100, gameHeight / 2f);
bird.Origin = new SFML.System.Vector2f(
bird.Texture.Size.X / 2f, // horizontal center
bird.Texture.Size.Y / 2f // vertical center
);
float birdVelocity = 0f;
float hitboxWidth = bird.Texture.Size.X * bird.Scale.X * 0.6f; // 60% of sprite width
float hitboxHeight = bird.Texture.Size.Y * bird.Scale.Y * 0.8f; // 80% of sprite height
float hitboxOffsetX = bird.Texture.Size.X * bird.Scale.X * 0.2f; // offset from left
float hitboxOffsetY = bird.Texture.Size.Y * bird.Scale.Y * 0.1f; // offset from top
// Pillar textures
Texture pillarUpTexture = new Texture("pillar-up.png");
Texture pillarDownTexture = new Texture("pillar-down.png");
RectangleShape hitboxRect = new RectangleShape(new Vector2f(hitboxWidth, hitboxHeight))
{
FillColor = new Color(255, 0, 0, 100) // red with transparency
};
// Clock for deltaTime
Clock clock = new Clock();
while (window.IsOpen)
{
float deltaTime = clock.Restart().AsSeconds();
window.DispatchEvents();
FloatRect birdHitbox = new FloatRect(
bird.Position.X - hitboxWidth / 2f,
bird.Position.Y - hitboxHeight / 2f,
hitboxWidth,
hitboxHeight
);
// Check lose condition
bool collision = false;
foreach (var pillar in pillars)
{
if (birdHitbox.Intersects(pillar.Top.GetGlobalBounds()) ||
birdHitbox.Intersects(pillar.Bottom.GetGlobalBounds()))
{
collision = true;
break;
}
}
hitboxRect.Position = new Vector2f(
bird.Position.X - hitboxWidth / 2f,
bird.Position.Y - hitboxHeight / 2f
);
if (collision && alive)
{
birdVelocity = 0;
alive = false;
}
// Input
if (alive && Keyboard.IsKeyPressed(Keyboard.Key.Space))
{
birdVelocity = jumpForce;
}
// Update pillars
pillarTimer += deltaTime;
if (pillarTimer > spawnInterval)
{
pillarTimer = 0f;
// Randomize gap size
float gapHeight = minGapHeight + (float)random.NextDouble() * (maxGapHeight - minGapHeight);
float maxGapY = gameHeight - 100f - gapHeight; // adjust max Y for new gap
float gapY = minGapY + (float)random.NextDouble() * (maxGapY - minGapY);
// Add new pillar at the right edge of the screen
pillars.Add(new Pillar(pillarUpTexture, pillarDownTexture, gameWidth, gapY, gapHeight));
}
// Update existing pillars
for (int i = pillars.Count - 1; i >= 0; i--)
{
pillars[i].Update(deltaTime, scrollSpeed);
if (pillars[i].IsOffscreen(gameWidth))
pillars.RemoveAt(i);
}
// Physics
birdVelocity += gravity * deltaTime;
bird.Position += new Vector2f(0, birdVelocity * deltaTime);
// Prevent bird from falling below floor
float birdHeight = bird.Texture.Size.Y * bird.Scale.Y;
if (bird.Position.Y + birdHeight > gameHeight)
{
bird.Position = new Vector2f(bird.Position.X, gameHeight - birdHeight);
birdVelocity = 0;
}
if (!alive)
{
// Gradually reduce speed towards 0
scrollSpeed -= scrollDecay * deltaTime;
if (scrollSpeed < 0) scrollSpeed = 0;
}
// Scroll background
backgroundOffset += (long)(scrollSpeed * deltaTime * backgroundSpeed);
if (backgroundOffset > backgroundTexture.Size.X) backgroundOffset -= backgroundTexture.Size.X;
// Clear
window.Clear();
// Draw tiled scrolling background
backgroundRect.TextureRect = new IntRect((int)backgroundOffset, 0, (int)gameWidth, (int)gameHeight);
window.Draw(backgroundRect);
// Draw pillars
foreach (var pillar in pillars)
pillar.Draw(window);
// Draw bird
float targetRotation = MathF.Max(MathF.Min(birdVelocity / maxVelocity * maxDownAngle, maxDownAngle), maxUpAngle);
bird.Rotation += (targetRotation - bird.Rotation) * 0.1f; // smoothing factor
window.Draw(bird);
window.Draw(hitboxRect);
// Display
window.Display();
}
}
}

30
SFML Flappy Bird.csproj Normal file
View File

@@ -0,0 +1,30 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>SFML_Flappy_Bird</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="SFML.Net" Version="2.6.1" />
</ItemGroup>
<ItemGroup>
<None Update="bird.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="background.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="pillar-up.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="pillar-down.png">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

25
SFML Flappy Bird.sln Normal file
View File

@@ -0,0 +1,25 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.14.36414.22 d17.14
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SFML Flappy Bird", "SFML Flappy Bird.csproj", "{5B9EC870-D392-4DA4-81B4-9AAB78D9F5DB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{5B9EC870-D392-4DA4-81B4-9AAB78D9F5DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5B9EC870-D392-4DA4-81B4-9AAB78D9F5DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5B9EC870-D392-4DA4-81B4-9AAB78D9F5DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5B9EC870-D392-4DA4-81B4-9AAB78D9F5DB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {A0A9F4D4-D2BF-41DF-95F0-7BAC8195E11C}
EndGlobalSection
EndGlobal

BIN
background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
bird.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 486 B

BIN
pillar-down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

BIN
pillar-up.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 B