Add project files.
This commit is contained in:
39
Pillar.cs
Normal file
39
Pillar.cs
Normal 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
211
Program.cs
Normal 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
30
SFML Flappy Bird.csproj
Normal 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
25
SFML Flappy Bird.sln
Normal 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
BIN
background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.5 KiB |
BIN
pillar-down.png
Normal file
BIN
pillar-down.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 546 B |
BIN
pillar-up.png
Normal file
BIN
pillar-up.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 540 B |
Reference in New Issue
Block a user