Загрузка данных
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
namespace GungeonLike
{
public partial class Form1 : Form
{
// ================= MAP =================
int[,] map;
int tileSize = 32;
int mapW = 40;
int mapH = 25;
// ================= ROOMS =================
enum RoomType { Start, Fight, Boss }
class Room
{
public Rectangle rect;
public RoomType type;
public bool cleared;
}
List<Room> rooms = new List<Room>();
Room currentRoom;
// ================= PLAYER =================
float px, py;
float speed = 4f;
bool up, down, left, right;
// ================= ENEMIES =================
List<PointF> enemies = new List<PointF>();
// ================= GAME =================
Timer timer;
Random rnd = new Random();
bool roomLocked = false;
enum GameState { Menu, Playing }
GameState state = GameState.Menu;
// ================= INIT =================
public Form1()
{
InitializeComponent();
DoubleBuffered = true;
timer = new Timer();
timer.Interval = 16;
timer.Tick += UpdateGame;
timer.Start();
GenerateDungeon();
}
// ================= GENERATION =================
void GenerateDungeon()
{
map = new int[mapW, mapH];
rooms.Clear();
for (int x = 0; x < mapW; x++)
for (int y = 0; y < mapH; y++)
map[x, y] = 0;
// rooms
for (int i = 0; i < 6; i++)
{
int w = rnd.Next(6, 10);
int h = rnd.Next(6, 10);
int x = rnd.Next(1, mapW - w - 1);
int y = rnd.Next(1, mapH - h - 1);
RoomType type = RoomType.Fight;
if (i == 0) type = RoomType.Start;
if (i == 5) type = RoomType.Boss;
Room r = new Room
{
rect = new Rectangle(x, y, w, h),
type = type
};
rooms.Add(r);
for (int ix = x; ix < x + w; ix++)
for (int iy = y; iy < y + h; iy++)
map[ix, iy] = 1;
}
for (int i = 1; i < rooms.Count; i++)
{
DrawCorridor(Center(rooms[i - 1].rect), Center(rooms[i].rect));
}
SpawnPlayer();
}
void DrawCorridor(Point a, Point b)
{
for (int x = Math.Min(a.X, b.X); x <= Math.Max(a.X, b.X); x++)
for (int i = -1; i <= 1; i++)
if (InMap(x, a.Y + i))
map[x, a.Y + i] = 1;
for (int y = Math.Min(a.Y, b.Y); y <= Math.Max(a.Y, b.Y); y++)
for (int i = -1; i <= 1; i++)
if (InMap(b.X + i, y))
map[b.X + i, y] = 1;
}
Point Center(Rectangle r)
{
return new Point(r.X + r.Width / 2, r.Y + r.Height / 2);
}
bool InMap(int x, int y)
{
return x >= 0 && y >= 0 && x < mapW && y < mapH;
}
// ================= SPAWN =================
void SpawnPlayer()
{
var start = rooms[0].rect;
px = (start.X + start.Width / 2) * tileSize;
py = (start.Y + start.Height / 2) * tileSize;
EnterRoom(rooms[0]);
}
void EnterRoom(Room r)
{
currentRoom = r;
if (!r.cleared)
SpawnEnemies(r);
}
void SpawnEnemies(Room r)
{
enemies.Clear();
roomLocked = true;
int count = (r.type == RoomType.Boss) ? 6 : 3;
for (int i = 0; i < count; i++)
{
enemies.Add(new PointF(
(r.rect.X + rnd.Next(r.rect.Width)) * tileSize,
(r.rect.Y + rnd.Next(r.rect.Height)) * tileSize
));
}
}
// ================= UPDATE =================
void UpdateGame(object sender, EventArgs e)
{
if (state != GameState.Playing)
{
Invalidate();
return;
}
MovePlayer();
MoveEnemies();
CheckRoomClear();
CheckRoomTransition();
Invalidate();
}
void MovePlayer()
{
if (up) TryMove(0, -speed);
if (down) TryMove(0, speed);
if (left) TryMove(-speed, 0);
if (right) TryMove(speed, 0);
}
void MoveEnemies()
{
for (int i = 0; i < enemies.Count; i++)
{
var e = enemies[i];
e.X += Math.Sign(px - e.X) * 1.2f;
e.Y += Math.Sign(py - e.Y) * 1.2f;
enemies[i] = e;
}
}
void CheckRoomClear()
{
if (enemies.Count == 0)
{
roomLocked = false;
currentRoom.cleared = true;
}
}
void CheckRoomTransition()
{
foreach (var r in rooms)
{
if (PlayerInRoom(r.rect))
{
if (currentRoom != r)
EnterRoom(r);
}
}
}
bool PlayerInRoom(Rectangle r)
{
int tx = (int)(px / tileSize);
int ty = (int)(py / tileSize);
return r.Contains(tx, ty);
}
void TryMove(float dx, float dy)
{
float nx = px + dx;
float ny = py + dy;
if (CanMove(nx, ny))
{
px = nx;
py = ny;
}
}
bool CanMove(float x, float y)
{
if (map == null) return false;
int tx = (int)(x / tileSize);
int ty = (int)(y / tileSize);
if (!InMap(tx, ty)) return false;
if (roomLocked && currentRoom != null)
{
if (!currentRoom.rect.Contains(tx, ty))
return false;
}
return map[tx, ty] == 1;
}
// ================= INPUT =================
protected override void OnKeyDown(KeyEventArgs e)
{
if (e.KeyCode == Keys.W) up = true;
if (e.KeyCode == Keys.S) down = true;
if (e.KeyCode == Keys.A) left = true;
if (e.KeyCode == Keys.D) right = true;
if (e.KeyCode == Keys.Enter)
state = GameState.Playing;
if (e.KeyCode == Keys.R)
GenerateDungeon();
}
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.W) up = false;
if (e.KeyCode == Keys.S) down = false;
if (e.KeyCode == Keys.A) left = false;
if (e.KeyCode == Keys.D) right = false;
}
// ================= DRAW =================
protected override void OnPaint(PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(Color.Black);
if (state == GameState.Menu)
{
g.DrawString("GUNGEON CORE",
new Font("Arial", 28, FontStyle.Bold),
Brushes.White, 120, 100);
g.DrawString("ENTER - Start",
new Font("Consolas", 14),
Brushes.Gray, 150, 200);
return;
}
if (map != null)
{
for (int x = 0; x < mapW; x++)
{
for (int y = 0; y < mapH; y++)
{
Brush b = map[x, y] == 0
? Brushes.DarkSlateGray
: Brushes.Gray;
g.FillRectangle(b,
x * tileSize,
y * tileSize,
tileSize,
tileSize);
}
}
}
// rooms outline
foreach (var r in rooms)
{
g.DrawRectangle(Pens.White,
r.rect.X * tileSize,
r.rect.Y * tileSize,
r.rect.Width * tileSize,
r.rect.Height * tileSize);
}
// enemies
foreach (var e2 in enemies)
{
g.FillEllipse(Brushes.Red,
e2.X, e2.Y, 20, 20);
}
// player
g.FillEllipse(Brushes.Cyan, px, py, 25, 25);
// UI
g.DrawString($"ENEMIES: {enemies.Count}",
new Font("Consolas", 10),
Brushes.White, 10, 10);
if (roomLocked)
g.DrawString("ROOM LOCKED",
new Font("Consolas", 14),
Brushes.Red, 10, 40);
}
}
}