mirror of
https://github.com/Leonmmcoset/CMLeonOS.git
synced 2026-04-21 10:53:59 +00:00
PingPong
This commit is contained in:
@@ -1 +1 @@
|
||||
2026-04-04 18:04:06
|
||||
2026-04-04 18:52:53
|
||||
@@ -1 +1 @@
|
||||
1341f10
|
||||
97f35bc
|
||||
@@ -148,6 +148,7 @@ namespace CMLeonOS.Gui
|
||||
RegisterApp(new AppMetadata("Notes", () => { return new Notes(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25)));
|
||||
RegisterApp(new AppMetadata("Sheet Editor", () => { return new SheetEditor(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25)));
|
||||
RegisterApp(new AppMetadata("Tetris", () => { return new Tetris(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25)));
|
||||
RegisterApp(new AppMetadata("Ping Pong", () => { return new PingPong(); }, Icons.Icon_Default, Color.FromArgb(25, 25, 25)));
|
||||
|
||||
Logger.Logger.Instance.Info("AppManager", $"{AppMetadatas.Count} apps were registered.");
|
||||
|
||||
|
||||
279
Gui/Apps/PingPong.cs
Normal file
279
Gui/Apps/PingPong.cs
Normal file
@@ -0,0 +1,279 @@
|
||||
using Cosmos.System;
|
||||
using CMLeonOS;
|
||||
using CMLeonOS.Gui.UILib;
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace CMLeonOS.Gui.Apps
|
||||
{
|
||||
internal class PingPong : Process
|
||||
{
|
||||
internal PingPong() : base("Ping Pong", ProcessType.Application) { }
|
||||
|
||||
private readonly WindowManager wm = ProcessManager.GetProcess<WindowManager>();
|
||||
private readonly Random random = new Random();
|
||||
|
||||
private AppWindow window;
|
||||
private Button resetButton;
|
||||
private Button pauseButton;
|
||||
|
||||
private int playerScore = 0;
|
||||
private int aiScore = 0;
|
||||
private bool paused = false;
|
||||
|
||||
private const int ArenaX = 14;
|
||||
private const int ArenaY = 28;
|
||||
private const int ArenaWidth = 620;
|
||||
private const int ArenaHeight = 320;
|
||||
|
||||
private const int PaddleWidth = 10;
|
||||
private const int PaddleHeight = 74;
|
||||
private const int BallSize = 8;
|
||||
|
||||
private int playerY;
|
||||
private int aiY;
|
||||
private float ballX;
|
||||
private float ballY;
|
||||
private float ballVx;
|
||||
private float ballVy;
|
||||
|
||||
private bool dirty = true;
|
||||
|
||||
private void ResetBall(int direction)
|
||||
{
|
||||
ballX = ArenaX + (ArenaWidth / 2f) - (BallSize / 2f);
|
||||
ballY = ArenaY + (ArenaHeight / 2f) - (BallSize / 2f);
|
||||
|
||||
float speed = 1.8f;
|
||||
ballVx = speed * direction;
|
||||
ballVy = ((float)random.NextDouble() * 2.0f - 1.0f) * 1.1f;
|
||||
if (Math.Abs(ballVy) < 0.35f)
|
||||
{
|
||||
ballVy = ballVy < 0 ? -0.35f : 0.35f;
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetGame()
|
||||
{
|
||||
playerScore = 0;
|
||||
aiScore = 0;
|
||||
playerY = ArenaY + (ArenaHeight / 2) - (PaddleHeight / 2);
|
||||
aiY = playerY;
|
||||
paused = false;
|
||||
pauseButton.Text = "Pause";
|
||||
ResetBall(random.Next(0, 2) == 0 ? -1 : 1);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void MovePlayer(int dy)
|
||||
{
|
||||
playerY += dy;
|
||||
int minY = ArenaY;
|
||||
int maxY = ArenaY + ArenaHeight - PaddleHeight;
|
||||
if (playerY < minY) playerY = minY;
|
||||
if (playerY > maxY) playerY = maxY;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void UpdateAi()
|
||||
{
|
||||
int aiCenter = aiY + (PaddleHeight / 2);
|
||||
int ballCenter = (int)ballY + (BallSize / 2);
|
||||
int diff = ballCenter - aiCenter;
|
||||
|
||||
int maxStep = 4;
|
||||
if (diff > 0) aiY += Math.Min(maxStep, diff);
|
||||
else if (diff < 0) aiY -= Math.Min(maxStep, -diff);
|
||||
|
||||
int minY = ArenaY;
|
||||
int maxY = ArenaY + ArenaHeight - PaddleHeight;
|
||||
if (aiY < minY) aiY = minY;
|
||||
if (aiY > maxY) aiY = maxY;
|
||||
}
|
||||
|
||||
private void BounceFromPaddle(int paddleY, bool fromLeft)
|
||||
{
|
||||
float paddleCenter = paddleY + (PaddleHeight / 2f);
|
||||
float ballCenter = ballY + (BallSize / 2f);
|
||||
float offset = (ballCenter - paddleCenter) / (PaddleHeight / 2f);
|
||||
if (offset < -1f) offset = -1f;
|
||||
if (offset > 1f) offset = 1f;
|
||||
|
||||
ballVy += offset * 1.6f;
|
||||
float maxVy = 3.8f;
|
||||
if (ballVy < -maxVy) ballVy = -maxVy;
|
||||
if (ballVy > maxVy) ballVy = maxVy;
|
||||
|
||||
if (fromLeft)
|
||||
{
|
||||
ballVx = Math.Abs(ballVx) + 0.05f;
|
||||
}
|
||||
else
|
||||
{
|
||||
ballVx = -Math.Abs(ballVx) - 0.05f;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateBall()
|
||||
{
|
||||
ballX += ballVx;
|
||||
ballY += ballVy;
|
||||
|
||||
if (ballY <= ArenaY)
|
||||
{
|
||||
ballY = ArenaY;
|
||||
ballVy = Math.Abs(ballVy);
|
||||
}
|
||||
else if (ballY + BallSize >= ArenaY + ArenaHeight)
|
||||
{
|
||||
ballY = ArenaY + ArenaHeight - BallSize;
|
||||
ballVy = -Math.Abs(ballVy);
|
||||
}
|
||||
|
||||
int playerX = ArenaX + 12;
|
||||
int aiX = ArenaX + ArenaWidth - 12 - PaddleWidth;
|
||||
|
||||
if (ballVx < 0
|
||||
&& ballX <= playerX + PaddleWidth
|
||||
&& ballX + BallSize >= playerX
|
||||
&& ballY + BallSize >= playerY
|
||||
&& ballY <= playerY + PaddleHeight)
|
||||
{
|
||||
ballX = playerX + PaddleWidth;
|
||||
BounceFromPaddle(playerY, fromLeft: true);
|
||||
}
|
||||
|
||||
if (ballVx > 0
|
||||
&& ballX + BallSize >= aiX
|
||||
&& ballX <= aiX + PaddleWidth
|
||||
&& ballY + BallSize >= aiY
|
||||
&& ballY <= aiY + PaddleHeight)
|
||||
{
|
||||
ballX = aiX - BallSize;
|
||||
BounceFromPaddle(aiY, fromLeft: false);
|
||||
}
|
||||
|
||||
if (ballX < ArenaX - 4)
|
||||
{
|
||||
aiScore++;
|
||||
ResetBall(direction: -1);
|
||||
}
|
||||
else if (ballX > ArenaX + ArenaWidth + 4)
|
||||
{
|
||||
playerScore++;
|
||||
ResetBall(direction: 1);
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
private void OnKeyPressed(KeyEvent key)
|
||||
{
|
||||
switch (key.Key)
|
||||
{
|
||||
case ConsoleKeyEx.W:
|
||||
case ConsoleKeyEx.UpArrow:
|
||||
MovePlayer(-20);
|
||||
break;
|
||||
case ConsoleKeyEx.S:
|
||||
case ConsoleKeyEx.DownArrow:
|
||||
MovePlayer(20);
|
||||
break;
|
||||
case ConsoleKeyEx.Spacebar:
|
||||
paused = !paused;
|
||||
pauseButton.Text = paused ? "Resume" : "Pause";
|
||||
dirty = true;
|
||||
break;
|
||||
case ConsoleKeyEx.R:
|
||||
ResetGame();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Render()
|
||||
{
|
||||
window.Clear(Color.FromArgb(18, 22, 30));
|
||||
|
||||
window.DrawFilledRectangle(ArenaX - 2, ArenaY - 2, ArenaWidth + 4, ArenaHeight + 4, Color.FromArgb(62, 74, 94));
|
||||
window.DrawFilledRectangle(ArenaX, ArenaY, ArenaWidth, ArenaHeight, Color.FromArgb(28, 33, 45));
|
||||
window.DrawRectangle(ArenaX, ArenaY, ArenaWidth, ArenaHeight, Color.FromArgb(100, 116, 142));
|
||||
|
||||
int centerX = ArenaX + (ArenaWidth / 2);
|
||||
for (int y = ArenaY + 4; y < ArenaY + ArenaHeight - 4; y += 16)
|
||||
{
|
||||
window.DrawFilledRectangle(centerX - 1, y, 2, 9, Color.FromArgb(84, 98, 122));
|
||||
}
|
||||
|
||||
int playerX = ArenaX + 12;
|
||||
int aiX = ArenaX + ArenaWidth - 12 - PaddleWidth;
|
||||
window.DrawFilledRectangle(playerX, playerY, PaddleWidth, PaddleHeight, Color.FromArgb(212, 226, 252));
|
||||
window.DrawFilledRectangle(aiX, aiY, PaddleWidth, PaddleHeight, Color.FromArgb(252, 216, 184));
|
||||
|
||||
window.DrawFilledRectangle((int)ballX, (int)ballY, BallSize, BallSize, Color.FromArgb(255, 255, 255));
|
||||
window.DrawRectangle((int)ballX, (int)ballY, BallSize, BallSize, Color.FromArgb(132, 146, 172));
|
||||
|
||||
window.DrawString("Ping Pong", Color.FromArgb(223, 233, 250), 16, 8);
|
||||
window.DrawString($"Player {playerScore} : {aiScore} AI", Color.White, ArenaX + (ArenaWidth / 2) - 76, 8);
|
||||
window.DrawString("Controls: W/S or Up/Down | Space Pause | R Reset", Color.FromArgb(180, 196, 220), 16, ArenaY + ArenaHeight + 8);
|
||||
|
||||
if (paused)
|
||||
{
|
||||
int boxW = 180;
|
||||
int boxH = 54;
|
||||
int boxX = ArenaX + (ArenaWidth / 2) - (boxW / 2);
|
||||
int boxY = ArenaY + (ArenaHeight / 2) - (boxH / 2);
|
||||
window.DrawFilledRectangle(boxX, boxY, boxW, boxH, Color.FromArgb(20, 20, 26));
|
||||
window.DrawRectangle(boxX, boxY, boxW, boxH, Color.FromArgb(112, 132, 165));
|
||||
window.DrawString("Paused", Color.FromArgb(230, 238, 255), boxX + 64, boxY + 12);
|
||||
window.DrawString("Press Space to resume", Color.FromArgb(190, 204, 232), boxX + 16, boxY + 30);
|
||||
}
|
||||
|
||||
wm.Update(window);
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
public override void Start()
|
||||
{
|
||||
base.Start();
|
||||
|
||||
window = new AppWindow(this, 120, 90, 650, 390);
|
||||
window.Title = "Ping Pong";
|
||||
window.Icon = AppManager.DefaultAppIcon;
|
||||
window.Closing = TryStop;
|
||||
window.OnKeyPressed = OnKeyPressed;
|
||||
wm.AddWindow(window);
|
||||
|
||||
resetButton = new Button(window, 456, 356, 88, 24);
|
||||
resetButton.Text = "Reset";
|
||||
resetButton.OnClick = (_, _) => ResetGame();
|
||||
wm.AddWindow(resetButton);
|
||||
|
||||
pauseButton = new Button(window, 550, 356, 88, 24);
|
||||
pauseButton.Text = "Pause";
|
||||
pauseButton.OnClick = (_, _) =>
|
||||
{
|
||||
paused = !paused;
|
||||
pauseButton.Text = paused ? "Resume" : "Pause";
|
||||
dirty = true;
|
||||
};
|
||||
wm.AddWindow(pauseButton);
|
||||
|
||||
ResetGame();
|
||||
Render();
|
||||
}
|
||||
|
||||
public override void Run()
|
||||
{
|
||||
if (!paused)
|
||||
{
|
||||
UpdateAi();
|
||||
UpdateBall();
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user