ã¢ã¡ãªã«ã®æã
2002幎ã«ãAmazing BlocksãšåŒã°ããé¢çœãããã¡ããç§ã®ã³ã³ãã¥ãŒã¿ãŒã«åœãããŸããã èšããŸã§ããªãããããªã¹ã¯ã©ã¹ã®ã²ãŒã ïŒã²ãŒã ãã¬ã€ã®è©³çŽ°ãªèª¬æã¯ä»¥äžã«ç€ºããŸãïŒã 圌女ã¯ãã®ã²ãŒã ãäœæéããã¬ã€ããŠãããç§ã®æ¯èŠªããšãŠã奜ãã§ããã ããããæ®å¿µãªæ¬ ç¹ããããŸããïŒ10ã®éå§åŸãã²ãŒã ã«ã¯ç»é²ãå¿ èŠã«ãªãå§ããŸããããé©ãã¹ãããšã«ãç¡æã§ããããã€ã³ã¿ãŒããããä»ããŠããã¡ãããç§ãã¡ã®éšåã«ã€ã³ã¿ãŒãããããªãã£ãã®ã§ãä¹ãè¶ããããªãé害ã§ããã圌ãã¯ãã®ãããªããšããããšèãããã åžžã«åã€ã³ã¹ããŒã«ããå¿ èŠããããŸããã
3幎åŸãã€ã³ã¿ãŒãããããã§ã«å®æããã²ãŒã ãã·ã§ã¢ãŠã§ã¢ã«ãªããç»é²ã®ããã®ãéãèŠæ±ãå§ãããšããç§ã¯ãããç»é²ããããšããŸãããããã®æç¹ã§ã¡ãŒã«ãŒã®ãŠã§ããµã€ãã¯çããŠãããããæ»ãã§ããå¯èœæ§ãé«ããæããã«ããã§ãä»æ¥ãŸã§ã ã²ãŒã ã®ã·ã§ã¢ãŠã§ã¢ããŒãžã§ã³ã¯ã€ã³ã¿ãŒãããäžã§ç°¡åã«èŠã€ããããšãã§ããŸããå€ãã®å Žåãå®éã«ã¯ããã€ã®æšéŠ¬ã§ããkeygensãšããèšèã¯æããããŸããããŸããæ¯èŠªãå®å šã«ç°ãªãã³ã³ãã¥ãŒã¿ãŒã§ãã¬ã€ã§ããããã«ã²ãŒã ãç»é²ããæ©äŒã¯1ã€ã§ã¯ãããŸããã ããæç¹ã§ãç§ã¯åããããªã²ãŒã ãèªåã§äœã£ãŠãã€ãŒã¿ã®åé¡ã解決ããŠã¿ãŸãããïŒ åæã«ãããçš®ã®ãããŒã¯ãŒã«ãã¯ãçŸä»£ã®ç¶æ³ã§ã·ã³ãã«ãªPCã²ãŒã ãéçºããããšããçãŸãããããããŸããããããèªè ã®æ³šæãåèµ·ããŸãã
ããã§ã¯ãã©ã®ãããªã²ãŒã ãããã®ã§ããããïŒ ãã€ã³ãã¯ããã§ãã 7Ã13ã®é·æ¹åœ¢ã®ã¬ã©ã¹ã§ã¯ã3è²ã®ãããã¯ã§æ§æãããæ°Žå¹³ã¹ãã£ãã¯ãèœäžããŸãïŒåèš5è²ãããŸãïŒã 移åäžã¯ãå·Šå³ã«ç§»åããããå転äžã®ãããã¯ãå³ããå·Šã«å ¥ãæ¿ãããããããšãã§ããŸãïŒèµ€ãç·ãéâç·ãéãèµ€ïŒã ã¹ãã£ãã¯ãã¬ã©ã¹ã®åºãŸãã¯ã¬ã©ã¹ã®åºå®ãããã¯ã«è§Šãããšãã¹ãã£ãã¯ã¯å¶åŸ¡ã§ããªããªããŸãã ã¹ãã£ãã¯ãæ§æãããããã¯ã¯ãåºå®ãããã¯ãŸãã¯ã¬ã©ã¹ã®ååã«ãªããŸã§å¥ã ã«èœäžãç¶ããŸãã ãã®åŸãåãè²ã®3ã€ä»¥äžã®ãããã¯ã®æ°Žå¹³ç·ãåçŽç·ããŸãã¯å¯Ÿè§ç·ãã¬ã©ã¹ã«ãããã©ããã確èªããŸãã ãã®ãããªè¡ã¯ç Žæ£ãããŸãã ç Žå£ãããã©ã€ã³ã®äžã«ãããã¯ããã£ãå Žåããããã¯åœ¢æããã空ãã¹ããŒã¹ãŸã§æ»ãèœã¡ããã®åŸã圢æãããã©ã€ã³ã¯åã³ç Žå£ãããŸãã ãã¹ãŠãèœã¡çããšãæ°ããã¹ãã£ãã¯ãäžããèœã¡å§ããŸãã ç Žå£ãããã©ã€ã³ãæ§ç¯ããããã«ããã¬ã€ã€ãŒã¯ãã€ã³ããåãåããŸãã ã¬ã©ã¹ããã£ã±ãã«ãªããšã²ãŒã ã¯çµäºããŸãã
ãã¯ãããžãŒã CïŒïŒç§ã¯é·ãéãããäœã§ããããèŠããã£ãïŒãOpenGLïŒDirectXã¯Windowsã§ã®ã¿åäœããLinuxã奜ãã§ãïŒãMercurialã§ããŒãžã§ã³ç®¡çãè¡ããŸãïŒVCSãªãã§ã³ãŒããæžãããšã¯èªåã«ç¡ç€Œã§ãïŒã
ã²ãŒã ã¯å°è±¡çãªãœãªãããšåŒã°ããŸãã
ã€ã³ã»ãã·ã§ã³
Windowsçšã®éçºã¯ã Microsoft Visual CïŒ2010 Express ïŒç¡æé åžïŒã§è¡ãããŸã ã MercurialããŒãžã§ã³ç®¡çã·ã¹ãã ã®Windowsã¯ã©ã€ã¢ã³ãã§ããTortoiseHgãå¿ èŠã§ãã LinuxããŒã¹ã®ã·ã¹ãã ã§ã¯ãMonoDevelopãšã³ã³ãœãŒã«hgã䜿çšããŸãã
OpenGLãæ¥ç¶ããã«ã¯ããã€ã³ãã£ã³ã°OpenTKã䜿çšããŸãã ææ°ã®ãã€ããªãŒãã«ã ïŒå·çæç¹ïŒ2011-12-03ïŒãããŠã³ããŒãããå¿ èŠããããŸãã
ImpressiveSolidsãšåŒã°ããæ°ãã空ã®ãããžã§ã¯ããVisual CïŒExpressã§äœæããŸãã ä¿åããŸãã 次ã«ããããžã§ã¯ããã£ã¬ã¯ããªãéãããã®ã³ã³ããã¹ãã¡ãã¥ãŒãåŒã³åºããŠãTortoiseHgâããã«ãªããžããªãäœæãéžæããŸãã .hgignoreãã¡ã€ã«ãäœæããåæååŸã«ã¯ãŒã¯ãã³ããéããã€ã³ããããŒã¯ããŸãã
Visual CïŒExpressã§.hgignoreãã¡ã€ã«ãéãã次ã®è¡ãæžã蟌ã¿ãŸãã ããã¯ãããŒãžã§ã³ç®¡çã·ã¹ãã ãäžèŠãªãã€ããªãã¡ã€ã«ãèæ ®ããªãããã«å¿ èŠã§ãã
syntax: glob *.suo *.pidb ImpressiveSolids/bin/* ImpressiveSolids/obj/*
ãœãªã¥ãŒã·ã§ã³ãã£ã¬ã¯ããªïŒãããžã§ã¯ãã§ã¯ãªãã.hgignoreãååšããå ŽæïŒå ã§ãOpenTKãµããã£ã¬ã¯ããªãäœæããOpenTKã¢ãŒã«ã€ãå ã®opentk \ Binaries \ OpenTK \ Release \ãã£ã¬ã¯ããªããOpenTK * .dllããã³OpenTK * .dll.configãã¡ã€ã«ãã³ããŒããŸãã
Visual CïŒExpressã§ã¯ãã³ã³ããã¹ãã¡ãã¥ãŒ[åç §]â[åç §ã®è¿œå ]â[åç §]ã ../OpenTK/OpenTK.dllãéžæããŸãã ããã«ã.NETã¿ãããSystem.Drawingãžã®åç §ãè¿œå ããå¿ èŠããããŸãã
æ°ãã
Game
ã¯ã©ã¹ãäœæããŸãã ããã¯ããã°ã©ã ã®ã¡ã€ã³ã¯ã©ã¹ã§ããããšã³ããªãã€ã³ããå«ã¿ã
OpenTK.GameWindow
ã®ç¶æ¿è ã§ãããã²ãŒã ã®ç¶æ ã®æŽæ°ïŒ
OnUpdateFrame
ïŒãšåæç»ïŒ
OnRenderFrame
ïŒãæ åœããŸãã ããã§ãé»ããŠã£ã³ããŠã«ãªããŸãã
using System; using OpenTK; using OpenTK.Graphics; using OpenTK.Graphics.OpenGL; namespace ImpressiveSolids { class Game : GameWindow { [STAThread] static void Main() { using (var Game = new Game()) { Game.Run(30); } } public Game() : base(700, 500, GraphicsMode.Default, "Impressive Solids") { VSync = VSyncMode.On; } protected override void OnLoad(EventArgs E) { base.OnLoad(E); } protected override void OnResize(EventArgs E) { base.OnResize(E); GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height); } protected override void OnUpdateFrame(FrameEventArgs E) { base.OnUpdateFrame(E); } protected override void OnRenderFrame(FrameEventArgs E) { base.OnRenderFrame(E); GL.ClearColor(Color4.Black); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); SwapBuffers(); } } }
ãããžã§ã¯ãããããã£ïŒ[ãããžã§ã¯ã]â[ImpressiveSolidsããããã£]ïŒã«ç§»åããã¿ãŒã²ãããã¬ãŒã ã¯ãŒã¯ãæå®ããŸãã åºåã¿ã€ãïŒWindowsã¢ããªã±ãŒã·ã§ã³ã ã¹ã¿ãŒãã¢ãããªããžã§ã¯ãïŒImpressiveSolids.Gameã
ä¿åããŠå®è¡ãããšããµã€ãºã700Ã500ã§ããå°è±¡çãªåºäœããšããã¿ã€ãã«ã®é»ããŠã£ã³ããŠã衚瀺ãããŸãã
ãã¹ãŠãé 調ã«é²ãã å Žåã¯ãTortoiseHg Workbenchã«ç§»åãããInitial game windowãããŒã¯ã§ãã¹ãŠãã³ãããããŸãã
ç§
ã¹ãã£ãã¯ã®å¶åŸ¡ãããèœäžãå®çŸããŸãã ãããè¡ãã«ã¯ãæåã«ã¹ãã£ãã¯ã®çŸåšã®ç¶æ ã®ã¢ãã«ãèšå®ããå¿ èŠããããŸãã ãŸããäœçœ®ã ããã©ã«ãã§ã¯ãã¬ã©ã¹ã®äžããäžå€®ãŸã§ã ïŒ0; 0ïŒã¯ã¬ã©ã¹ã®å·Šäžé ã«å¯Ÿå¿ãããšä»®å®ããŸãã
MapWidth
ãã®å¯žæ³
MapWidth
ã
MapHeight
ãèšå®ããå¿ èŠããããŸãã ã¹ãã£ãã¯ãæ§æãããããã¯ã®è²ã¯ãæŽæ°ã®é åãšããŠä¿åãããŸãã å¯èœãª
ColorsCount
è²ã®æ°ãèšå®ããè²ã
0
ãã
ColorsCount â 1
ãŸã§ã®æŽæ°å€ã§ç€ºãããããšã«åæããŸãã
Newã¡ãœãããGameã¯ã©ã¹ã«è¿œå ããOnLoadããåŒã³åºããŸãã ãã®æ¹æ³ã§ã¯ãã©ã³ãã ãªè²ã®ãããã¯ããã¹ãã£ãã¯ã®æ§ç¯ãå®è£ ããŸãã
private Random Rand; private const int MapWidth = 7; private const int MapHeight = 13; private const int StickLength = 3; private int[] StickColors; private Vector2 StickPosition; private const int ColorsCount = 5; protected override void OnLoad(EventArgs E) { base.OnLoad(E); New(); } private void New() { Rand = new Random(); StickColors = new int[StickLength]; for (var i = 0; i < StickLength; i++) { StickColors[i] = Rand.Next(ColorsCount); } StickPosition.X = (float)Math.Floor((MapWidth - StickLength) / 2d); StickPosition.Y = 0; }
æãåå§çãªããŒãžã§ã³ã§ã¯ãã¹ãã£ãã¯ãç»é¢ã«è¡šç€ºããŠã¿ãŸãããïŒè²ä»ãã®é·æ¹åœ¢ã§ãããã¯ãæç»ãããŠã£ã³ããŠã®å·Šäžé ã§ã¬ã©ã¹ãéå§ããŸãïŒã ã³ãŒãã«ããã€ãã®å€æŽãå ããŸãã
private const int NominalWidth = 700; private const int NominalHeight = 500; private float ProjectionWidth; private float ProjectionHeight; private const int SolidSize = 35; private Color4[] Colors = {Color4.PaleVioletRed, Color4.LightSeaGreen, Color4.CornflowerBlue, Color4.RosyBrown, Color4.LightGoldenrodYellow}; public Game() : base(NominalWidth, NominalHeight, GraphicsMode.Default, "Impressive Solids") { VSync = VSyncMode.On; } protected override void OnResize(EventArgs E) { base.OnResize(E); GL.Viewport(ClientRectangle.X, ClientRectangle.Y, ClientRectangle.Width, ClientRectangle.Height); ProjectionWidth = NominalWidth; ProjectionHeight = (float)ClientRectangle.Height / (float)ClientRectangle.Width * ProjectionWidth; if (ProjectionHeight < NominalHeight) { ProjectionHeight = NominalHeight; ProjectionWidth = (float)ClientRectangle.Width / (float)ClientRectangle.Height * ProjectionHeight; } } protected override void OnRenderFrame(FrameEventArgs E) { base.OnRenderFrame(E); GL.ClearColor(Color4.Black); GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit); var Projection = Matrix4.CreateOrthographic(-ProjectionWidth, -ProjectionHeight, -1, 1); GL.MatrixMode(MatrixMode.Projection); GL.LoadMatrix(ref Projection); GL.Translate(ProjectionWidth / 2, -ProjectionHeight / 2, 0); var Modelview = Matrix4.LookAt(Vector3.Zero, Vector3.UnitZ, Vector3.UnitY); GL.MatrixMode(MatrixMode.Modelview); GL.LoadMatrix(ref Modelview); GL.Begin(BeginMode.Quads); for (var i = 0; i < StickLength; i++) { RenderSolid(StickPosition.X + i, StickPosition.Y, StickColors[i]); } GL.End(); SwapBuffers(); } private void RenderSolid(float X, float Y, int Color) { GL.Color4(Colors[Color]); GL.Vertex2(X * SolidSize, Y * SolidSize); GL.Vertex2((X + 1) * SolidSize, Y * SolidSize); GL.Vertex2((X + 1) * SolidSize, (Y + 1) * SolidSize); GL.Vertex2(X * SolidSize, (Y + 1) * SolidSize); }
ãŠã£ã³ããŠã®ãµã€ãºãå€æŽããããšãã«ç»åãæ¡å€§çž®å°ããããã«ã
Nominal/Projection Width/Height
ããªãã¯
Nominal/Projection Width/Height
å¿ èŠã§ããããåæã«ãæ¯çã¯æªããããŸããã§ããã
æåŸã«ã¹ãã£ãã¯ãåããŠãâãâãâããŒãæ©èœãããŸãïŒè²ã®å転ïŒã
public Game() : base(NominalWidth, NominalHeight, GraphicsMode.Default, "Impressive Solids") { VSync = VSyncMode.On; Keyboard.KeyDown += new EventHandler<KeyboardKeyEventArgs>(OnKeyDown); } protected override void OnUpdateFrame(FrameEventArgs E) { base.OnUpdateFrame(E); StickPosition.Y += 0.02f; } protected void OnKeyDown(object Sender, KeyboardKeyEventArgs E) { if (Key.Left == E.Key) { --StickPosition.X; } else if (Key.Right == E.Key) { ++StickPosition.X; } else if (Key.Up == E.Key) { var T = StickColors[0]; for (var i = 0; i < StickLength - 1; i++) { StickColors[i] = StickColors[i + 1]; } StickColors[StickLength - 1] = T; } }
ãã¹ãŠã®å€æŽãã³ãããããŸãïŒãã¹ãã£ãã¯ãèœäžããã³å¶åŸ¡å¯èœãã
ã芧ã®ããã«ãã¬ã©ã¹ã®å¢çãè¶ããããã®ãã§ãã¯ã¯ãããŸããã ä»åŸããã®çç¥ãä¿®æ£ããŸãã
äžçã®å°å³
ã¹ãã£ãã¯ãåºã«èœã¡ããšãããŸãã¯ã¬ã©ã¹ã«ãã§ã«ãããããã¯ã«èœã¡ããšãã®ç¶æ³ã«å¯ŸåŠããŸãããã å¶åŸ¡äžèœãªãããã¯ã®èœäžãšã©ã€ã³ã®ç Žå£ã«å¯ŸåŠãããŸã§ãã¹ãã£ãã¯ãæ§æãããããã¯ãæå®ã®äœçœ®ã§åçµããïŒç©ºäžã«ã¶ãäžãã£ãŠããŠãïŒã次ã®ã¹ãã£ãã¯ãèœäžãå§ããŸãã
æŽæ°ã®2次å é åã®åœ¢ã§ã¬ã©ã¹ã®ç¶æ ãã·ãã¥ã¬ãŒãããŸãã 座æšã¯ã¬ã©ã¹ã®åžæŸæš¡æ§ã®ã°ãªããã«å¯Ÿå¿ããå€ã¯æå®ãããã»ã«å ã®ãããã¯ã®è²ã«ãªããŸã-ã»ã«ã空ã®å Žåã¯è² ã®æ°ã«ãªããŸãã
ããã§ã¯ãã¹ãã£ãã¯ãã¬ã©ã¹ãè¶ããããã®ãã§ãã¯ãå°å ¥ããå¿ èŠããããŸããããããªããšãååšããªãã€ã³ããã¯ã¹ã«ãã£ãŠé åã«ã¢ã¯ã»ã¹ã§ããŸãã
private int[,] Map; private void New() { Rand = new Random(); Map = new int[MapWidth, MapHeight]; for (var X = 0; X < MapWidth; X++) { for (var Y = 0; Y < MapHeight; Y++) { Map[X, Y] = -1; } } StickColors = new int[StickLength]; GenerateNextStick(); } private void GenerateNextStick() { for (var i = 0; i < StickLength; i++) { StickColors[i] = Rand.Next(ColorsCount); } StickPosition.X = (float)Math.Floor((MapWidth - StickLength) / 2d); StickPosition.Y = 0; } protected override void OnUpdateFrame(FrameEventArgs E) { base.OnUpdateFrame(E); StickPosition.Y += 0.02f; var FellOnFloor = (StickPosition.Y >= MapHeight - 1); var FellOnBlock = false; if (!FellOnFloor) { var Y = (int)Math.Floor(StickPosition.Y + 1); for (var i = 0; i < StickLength; i++) { var X = (int)StickPosition.X + i; if (Map[X, Y] >= 0) { FellOnBlock = true; break; } } } if (FellOnFloor || FellOnBlock) { var Y = (int)Math.Floor(StickPosition.Y); for (var i = 0; i < StickLength; i++) { var X = (int)StickPosition.X + i; Map[X, Y] = StickColors[i]; } GenerateNextStick(); } } protected void OnKeyDown(object Sender, KeyboardKeyEventArgs E) { if ((Key.Left == E.Key) && (StickPosition.X > 0)) { --StickPosition.X; } else if ((Key.Right == E.Key) && (StickPosition.X + StickLength < MapWidth)) { ++StickPosition.X; } else if (Key.Up == E.Key) { // . . . } } protected override void OnRenderFrame(FrameEventArgs E) { // . . . GL.Begin(BeginMode.Quads); for (var X = 0; X < MapWidth; X++) { for (var Y = 0; Y < MapHeight; Y++) { if (Map[X, Y] >= 0) { RenderSolid(X, Y, Map[X, Y]); } } } for (var i = 0; i < StickLength; i++) { RenderSolid(StickPosition.X + i, StickPosition.Y, StickColors[i]); } GL.End(); SwapBuffers(); }
å€ãè¯ããããªã¹ã®ããã«ããããã¯ãäžçªäžãŸã§ãã°ããã¹ã±ããã§ããŸãã ãã¹ãã§ã¯ã
0.02f
ã
0.2f
ã«çœ®ãæããããšã§èœäžçãäžããããšãã§ããŸãããäžè¬çã«ã¯ãâããŒãæŒããŠå éã§ããããã«ããå¿ èŠããããŸãã
å€æŽãMercurialãªããžããªã«ã³ãããããããšãå¿ããªãã§ãã ããïŒãã¹ãã£ãã¯ãèœã¡ãåŸã®ãããã¯ã®ä¿®æ£ãã
ããã«ã€ã³ãã¯ã
次ã«è¡ãå¿ èŠãããã®ã¯ããããã¯ã空äžã«åãäžãããªãããã«ããããšã§ãããã ãããããã¯ãéæ¢ãããŸã§èœäžãç¶ããŸãã ãã®æéäžãç»é¢ã«ã¯ã¹ãã£ãã¯ããããŸãããäœãå¶åŸ¡ã§ããŸããã ãã®ç¹ã§ãç¶æ ã®æŠå¿µãã²ãŒã ã«å°å ¥ããŸãã
ã²ãŒã ã¯åžžã«æ¬¡ã®ããããã®ç¶æ ã«ãããŸãã
- å¥ã®ã¹ãã£ãã¯ãèœã¡ãŠãããããã¯å¶åŸ¡ããããšãã§ããŸãã æ°ããã²ãŒã ãéå§ããããšããã®ç¶æ ããªã³ã«ãªããŸãã
- å¶åŸ¡ãããŠããªãèœäžãããã¯ãè£æã¡ãããã©ã€ã³ã®ç Žå£ã ãã®ç¶æ ã¯ãã¹ãã£ãã¯ããããã¯ã«è§ŠããåŸã«ãªã³ã«ãªããŸãã ãã¹ãŠã®ãããã¯ãåãããç Žå£ãããã©ã€ã³ããªããªããšçµäºããŸãã ã¬ã©ã¹ã®äžçªäžã®è¡å šäœã空ããŠããå Žåãã²ãŒã ã¯ç¶æ 1ã§ç¶è¡ããŸãã ãã以å€ã®å Žåãã²ãŒã ã¯çµäºããŸãïŒç¶æ 3ïŒã
- ã²ãŒã ãªãŒããŒã§ããäœãèµ·ãããŸããã ãã¬ãŒã€ãŒã¯æ°ããã²ãŒã ãéå§ã§ããŸãïŒãã¿ã³ãæŒããªã©ïŒã
ã³ãŒãå ã§å¯Ÿå¿ãã宣èšãäœæããŸãã
private enum GameStateEnum { Fall, Impact, GameOver } private GameStateEnum GameState; private void New() { // . . . GenerateNextStick(); GameState = GameStateEnum.Fall; } protected override void OnUpdateFrame(FrameEventArgs E) { base.OnUpdateFrame(E); if (GameStateEnum.Fall == GameState) { StickPosition.Y += 0.2f; // . . . if (FellOnFloor || FellOnBlock) { var Y = (int)Math.Floor(StickPosition.Y); for (var i = 0; i < StickLength; i++) { var X = (int)StickPosition.X + i; Map[X, Y] = StickColors[i]; } GameState = GameStateEnum.Impact; } } else if (GameStateEnum.Impact == GameState) { var Stabilized = true; // TODO if (Stabilized) { GenerateNextStick(); GameState = GameStateEnum.Fall; } } }
ãããã¯ã®æ»ãããªèœäžãæåããã¬ã©ã¹ã®ã¢ãã«ïŒ
Map
ïŒãè€éã«ããªãããã«ãããªãã¯ã«é ŒããŸãã ã»ã«ïŒX; YïŒããã»ã«ïŒX; Y + 1ïŒã«èœã¡ããããã¯ãèš±å¯ããŸã-ãããŠã圌ã¯ã©ãã«èœã¡ãã¹ãã§ããïŒ -ã»ã«ïŒX; YïŒã«ãªã¹ããããäžã®ã»ã«ã®æåŸã®ãããã®ç¬éãŸã§ã ããã«ããããã¯ã®åçŽæ¹åã®ããããªå€äœãä¿åããŸããããã¯ããŠããã£ãè¶ ãããŸã§åŸã ã«å¢å ããŸãã ã€ãŸãããããã¯ã®å®éã®åº§æšã¯ïŒX; YïŒã§ã¯ãªãïŒX; Y +ÎïŒã§ãããããã¯
OnRenderFrame
èæ ®ããå¿ èŠããããŸãã
private const float FallSpeed = 0.2f; private float[,] ImpactFallOffset; private void New() { // . . . ImpactFallOffset = new float[MapWidth, MapHeight]; } protected override void OnUpdateFrame(FrameEventArgs E) { base.OnUpdateFrame(E); if (GameStateEnum.Fall == GameState) { StickPosition.Y += FallSpeed; // . . . } else if (GameStateEnum.Impact == GameState) { var Stabilized = true; for (var X = 0; X < MapWidth; X++) { for (var Y = MapHeight - 2; Y >= 0; Y--) { if ((Map[X, Y] >= 0) && ((Map[X, Y + 1] < 0) || (ImpactFallOffset[X, Y + 1] > 0))) { Stabilized = false; ImpactFallOffset[X, Y] += FallSpeed; if (ImpactFallOffset[X, Y] >= 1) { Map[X, Y + 1] = Map[X, Y]; Map[X, Y] = -1; ImpactFallOffset[X, Y] = 0; } } } } if (Stabilized) { GenerateNextStick(); GameState = GameStateEnum.Fall; } } } protected override void OnRenderFrame(FrameEventArgs E) { // . . . GL.Begin(BeginMode.Quads); for (var X = 0; X < MapWidth; X++) { for (var Y = 0; Y < MapHeight; Y++) { if (Map[X, Y] >= 0) { RenderSolid(X, Y + ImpactFallOffset[X, Y], Map[X, Y]); } } } if (GameStateEnum.Fall == GameState) { for (var i = 0; i < StickLength; i++) { RenderSolid(StickPosition.X + i, StickPosition.Y, StickColors[i]); } } GL.End(); SwapBuffers(); }
ããŒã«ãèœäžããå¯èœæ§ã®ãããããã¯ããåå šäœãèœäžãããã«ã¯ããããã»ã«ãäžããäžã«äžŠã¹ïŒäžã®ãããã¯ãäžã«ç§»åããŸãïŒãã»ã«ã®ãã€ãã ãã§ãªã
ImpactFallOffset
ã¹ããŒã¿ã¹ã
ImpactFallOffset
ãŸãïŒæ£ã®æ°ã¯ãã®ãããã¯ãèœäžããããšãæå³ããããïŒ ïŒ
ã³ãããã«ã¯ãããããã¯ãå®å®ãããŸã§åœ±é¿ãåããŸãããšããããŒã¯ãä»ããããŠããŸãã
倧éç Žå£å µåš
ã²ãŒã ãã¬ã€ã®äž»ãªèŠçŽ ã§ãããåãè²ã®ç·ã®ç Žå£ãæçµçã«å¯ŸåŠããæãæ¥ãŸããã æå°è¡é·ãèšå®ããŸãã ãããã¯ãååšãããã¹ãŠã®ã»ã«ãééãããããããã4ã€ã®å¯èœãªæ¹åïŒæ°Žå¹³ãåçŽã2ã€ã®å¯Ÿè§ç·ïŒã®ããããã§ç·ãäœæããããšããŸãã ååãªé·ãã®1è²ã®ã©ã€ã³ãæ€åºããããšãåã³ã³ããŒãã³ããããã¯ãã¹ã¿ãã¯ã«ããã·ã¥ãããŸãã ã«ãŒãå šäœããã§ãã¯ããåŸãã¹ã¿ãã¯äžã®ãã¹ãŠã®ãããã¯ãç Žå£ããäœçœ®ãäžå®å®ãšããŠããŒã¯ããŸãã
private const int DestroyableLength = 3; private Stack<Vector2> Destroyables = new Stack<Vector2>(); protected override void OnUpdateFrame(FrameEventArgs E) { // . . . } else if (GameStateEnum.Impact == GameState) { // . . . if (Stabilized) { Destroyables.Clear(); for (var X = 0; X < MapWidth; X++) { for (var Y = 0; Y < MapHeight; Y++) { CheckDestroyableLine(X, Y, 1, 0); CheckDestroyableLine(X, Y, 0, 1); CheckDestroyableLine(X, Y, 1, 1); CheckDestroyableLine(X, Y, 1, -1); } } if (Destroyables.Count > 0) { foreach (var Coords in Destroyables) { Map[(int)Coords.X, (int)Coords.Y] = -1; } Stabilized = false; } } if (Stabilized) { GenerateNextStick(); GameState = GameStateEnum.Fall; } } } private void CheckDestroyableLine(int X1, int Y1, int DeltaX, int DeltaY) { if (Map[X1, Y1] < 0) { return; } int X2 = X1, Y2 = Y1; var LineLength = 0; while ((X2 >= 0) && (Y2 >= 0) && (X2 < MapWidth) && (Y2 < MapHeight) && (Map[X2, Y2] == Map[X1, Y1])) { ++LineLength; X2 += DeltaX; Y2 += DeltaY; } if (LineLength >= DestroyableLength) { for (var i = 0; i < LineLength; i++) { Destroyables.Push(new Vector2(X1 + i * DeltaX, Y1 + i * DeltaY)); } } }
ãªããžããªã§ããåãè²ã®ç·ãç Žå£ããããšããŒã¯ããŸãã
ã²ãŒã ãªãŒããŒ
ã°ã©ã¹ã®äžéšã«å°éãããšãã²ãŒã ã®é¢çœãåäœã«ããããæ°ã¥ããã§ããããäžéšã§ç°ãªãè²ã§ç¹æ» ãéå§ããäºãã«äº€æããç¡éã«çŸããŠããã«ã¹ãã£ãã¯ãåºããŸãã è² ããç¶æ³ãåŠçããŸãããïŒãŠãŒã¶ãŒãEnterããŒãæŒããŸã§äœãèµ·ãããŸããã
ããã§ã¯ãã¹ãŠãç°¡åã§ãã
protected override void OnUpdateFrame(FrameEventArgs E) { // . . . } else if (GameStateEnum.Impact == GameState) { // . . . if (Stabilized) { var GameOver = false; for (var X = 0; X < MapWidth; X++) { if (Map[X, 0] >= 0) { GameOver = true; break; } } if (GameOver) { GameState = GameStateEnum.GameOver; } else { GenerateNextStick(); GameState = GameStateEnum.Fall; } } } } protected void OnKeyDown(object Sender, KeyboardKeyEventArgs E) { if (GameStateEnum.Fall == GameState) { if ((Key.Left == E.Key) && (StickPosition.X > 0)) { --StickPosition.X; } else if ((Key.Right == E.Key) && (StickPosition.X + StickLength < MapWidth)) { ++StickPosition.X; } else if (Key.Up == E.Key) { var T = StickColors[0]; for (var i = 0; i < StickLength - 1; i++) { StickColors[i] = StickColors[i + 1]; } StickColors[StickLength - 1] = T; } } else if (GameStateEnum.GameOver == GameState) { if ((Key.Enter == E.Key) || (Key.KeypadEnter == E.Key)) { New(); } } }
ãã²ãŒã ãªãŒããŒãã«çœ²åããããšã§ãèŠåŽããã«ã³ãããããŸãã
ããã§ãéçºã®æåã®éšåãå®äºããŸããã ç§ãã¡ã®æã«ã¯ãä»ãããã¬ã€ã§ããå®å šã«æ©èœããã²ãŒã ããããŸãã 第äºéšã§ã¯ãèšèšã«åŸäºããŸãã ãã¯ã¹ãã£ã課ããçŸåšã®ã¹ã³ã¢ãã¬ã³ãŒãã¹ã³ã¢ã衚瀺ããŸãã 次ã«èœã¡ãæ£ã æåŸã«ãã¬ã©ã¹ã®ç»åãã²ãŒã ãŠã£ã³ããŠã®äžå€®ã«é 眮ããå¢çç·ãæç»ããŸãã äžè¬çã«ããã¹ãŠãæãæµ®ãã¹ãŸãã
ãã®ãããžã§ã¯ãã¯