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