From 02907cb4b6d1569a63d8d48776f66e9fb2590efc Mon Sep 17 00:00:00 2001 From: "J. M. Ellis" Date: Mon, 27 May 2024 21:50:09 -0700 Subject: [PATCH] Super Happy Jumping Pickle Man! --- BoundingBox.cs | 24 +++++ ClassDiagram1.cd | 2 + Content/CastleWall TS16.png | Bin 0 -> 2675 bytes Content/Content.mgcb | 43 +++++++++ Content/fonts/debugFont.spritefont | 60 ++++++++++++ Content/platform.png | Bin 0 -> 192 bytes Content/player.png | Bin 0 -> 156 bytes Game1.cs | 148 ++++++++++++++++++++++++----- Platform.cs | 23 +++++ Player.cs | 146 ++++++++++++++++++++++------ PlayerInput.cs | 5 +- 11 files changed, 396 insertions(+), 55 deletions(-) create mode 100644 BoundingBox.cs create mode 100644 ClassDiagram1.cd create mode 100644 Content/CastleWall TS16.png create mode 100644 Content/fonts/debugFont.spritefont create mode 100644 Content/platform.png create mode 100644 Content/player.png create mode 100644 Platform.cs diff --git a/BoundingBox.cs b/BoundingBox.cs new file mode 100644 index 0000000..3c2afb7 --- /dev/null +++ b/BoundingBox.cs @@ -0,0 +1,24 @@ +using Microsoft.Xna.Framework; + +namespace LunaLightXMG +{ + public class BoundingBox + { + public Rectangle Bounds { get; private set; } + + public BoundingBox(Rectangle bounds) + { + Bounds = bounds; + } + + public bool Intersects(BoundingBox other) + { + return Bounds.Intersects(other.Bounds); + } + + public void Update(Vector2 position, int width, int height) + { + Bounds = new Rectangle((int)position.X, (int)position.Y, width, height); + } + } +} \ No newline at end of file diff --git a/ClassDiagram1.cd b/ClassDiagram1.cd new file mode 100644 index 0000000..7b89419 --- /dev/null +++ b/ClassDiagram1.cd @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/Content/CastleWall TS16.png b/Content/CastleWall TS16.png new file mode 100644 index 0000000000000000000000000000000000000000..e95bbd080a8f933ec0d97b4dc3e553ed18943ca7 GIT binary patch literal 2675 zcmV-(3XJuMP)Px#L}ge>W=%~1DgXcg2mk?xX#fNO00031000^Q000001E2u_0{{R30RRC20H6W@ z1ONa40RR91FrWhf1ONa40RR91FaQ7m0NXcg3;+NL-AP12RA>dIna^)zM-j(+-u(2; zIC#CAL>yL}5F+9bp@0+#DH4JU5+{@sXA}v9_+%?GQCI2oVWt%wQmnsOZ&I~hG%~~7j_gd^5QTTJ zC8f8w1D^^8ARMUrl`HZ=f8Hu|guTR*+Z{fmPwBFu40LX|VUeBsAyCll7?#oo8GCH0 zB+sS4NG8dMjc~D8v<7D!bFR!tPv1-r7vGdL zaKn7VRz)_r`KXZ?WkenH<;c2P`;>GraGS5slb4^7Rg3RFe2~tcK6AoDui}Vfy)dzfYh3{o|z7 z=&iPXZZzB7nAfYdKh>~u1D4g$YW_OitZ%FwSe4t<>4Tqslu+uAjY}Wgbef)RM(OIU zN2xk{>T}y<#-kxWF7IaLGT{ZfvK(i!;XyY%82{@>gY?c1KP+}Sv%Ng*4^B_FGA6>|wzkHHD|Mw?e;?C{-o>_!1EYj7>m#IG*C_V9YzL$@cm<{cQG*8S?ADFXf$YLb{+64G#CtRxth>VLe6ih zZR%Z`k(M4OgMRwr%fF^$^X$194-ALKZc(GHEi%=xZ#h1)=;!c;A~qV_*a~cl@$k=P zv((#MxeNkwa&5)I^8Li-o?GUQOgEc-X!Z$~<`96*Kx2t_Uwu&}rf(d(@!eS*0@M;& zK*qaaHm2pdx@n4p6Lnsa5z*k#-K|uShJJD2Xs}H@QYb<^me=5ze^AvHp=QO@UMz0B z>O_9}z|zhWRu+RUUp6JyC-Ms!$P~Tv?9t1->=b_q3pYn0)%N=Xs{*!`_kjD*iiTEj zmwfSvUhSEk0rXo*Hc%SWH%)FsFtPonO~;rBQZfOeM(Jd^o9MOTSdqA4ogu$sq%i>* z06EVp383R#sc_hGg?$7dTi_`~^ihW4Ft9O|Tt3d!(fF9RN+ZbREb^kFl^u#J%A!4@ z$zsbsA}}$bGPCEk184XFOMr9<_Ke8zw4p0-FQ(s~`WaIW2$i;VTBVf)4kJ z?4a*3M~Dkc!&Lzwsz*=0ZF%upo~t!fNjK|%`q{^cQ~DoY{Kfgo^83hMQHBkfC--;g zB)dcFA~a{t`5w)3@zvpj_dfCna@qo%hOC0Gi1iE5&BCCGz!ifi`U={e2w)?QM(w7H zyacMqKxPyd`!1<{X)}WOg}z0+*v^z?{mV?4P;r! z_RZf3jL2xC@r)0i0}ucRWw|MHhd}pvU72;oj@9T8zvie$l;}fzItSbVO44u=?)?@K z-Q9_t@|5LP&Bq}r!9k#_Q0E1X1%=+}Z@X;Ki}KpmjhwoH4;K1$Y8;MCR!^uwmLm^UiObafme>nIAkFcCz?dgrf6s%9x*>L z$ie1t@K&%XeG7MK9G_XG58VY!#pfO4nG2>iq;i5?uF9n4<~x~6g2B3pN&$S#l^n&G z@I+qm#1@(GLkCEw@5Oxf$hOFLuX7+Wbo;m6*SmE4#{UoR&N(3AkH6RapTMhtmeV4u zXh0XQ)T}~;NGCiw&iSCTLU?Gog_15x$J@RKoX2tnT4c$1@Fj&f%rM;RKE~%6odXa@ zOG!t8xvw(wDCh~;7r-em=xRL4SK-)cLm=h*57A5 zG6D<3+W{d|lHy=6*15vCTdx(tA{|i_rlTcT>%lJSjH0t1an;mN1qmmW4}&Ysr$vx z{^U+W$MW-FxXS8nye=1Aw!ff}^R8&mYp(;5j>u!YqQ|nUo~sqT4ySkQmkDl;{8Ayu zF+|Rbo>nrPH=iHU8s>Bflf#;$<$GXj|5)VfZnfMT%=^f9a1%$u*Xhep@$55L hb85wNA6oIy{ueLvFkqqErR4ws002ovPDHLkV1i+OCLsU- literal 0 HcmV?d00001 diff --git a/Content/Content.mgcb b/Content/Content.mgcb index 5e70b96..0ff1bfd 100644 --- a/Content/Content.mgcb +++ b/Content/Content.mgcb @@ -13,6 +13,49 @@ #---------------------------------- Content ---------------------------------# +#begin CastleWall TS16.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:CastleWall TS16.png + +#begin fonts/debugFont.spritefont +/importer:FontDescriptionImporter +/processor:FontDescriptionProcessor +/processorParam:PremultiplyAlpha=True +/processorParam:TextureFormat=Compressed +/build:fonts/debugFont.spritefont + +#begin platform.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:platform.png + +#begin player.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:player.png + #begin spr_cave1_background.png /importer:TextureImporter /processor:TextureProcessor diff --git a/Content/fonts/debugFont.spritefont b/Content/fonts/debugFont.spritefont new file mode 100644 index 0000000..bd33ecf --- /dev/null +++ b/Content/fonts/debugFont.spritefont @@ -0,0 +1,60 @@ + + + + + + + Arial + + + 12 + + + 0 + + + true + + + + + + + + + + + + ~ + + + + diff --git a/Content/platform.png b/Content/platform.png new file mode 100644 index 0000000000000000000000000000000000000000..34c5c3ea971ebc8eac142c2cb31454a31425bd9e GIT binary patch literal 192 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|Dm+~rLoEE0 zLmsdAecpjFp+!>R!}(5?WIKbm%&Xa@87}b%DO?kn5hcKD&X6Ky*ru@hph3d~#TQ}; zrVP^+Z^X1;W+-tksN`MGXyEK%vhKjrwTv$o_MR2p!s$|z*_dDwG-X1^MV`|-5}uOr oArDU_YRv3hlGCwFf?>BP@XyFnGH9xvX("sprRo_Wall"); - sprCave1Background = Content.Load("spr_cave1_background"); - sprCave1Foreground = Content.Load("spr_Cave1_foreground"); - sprCave1Walls = Content.Load("spr_Cave1_walls"); + //sprCave1Background = Content.Load("spr_cave1_background"); + //sprCave1Foreground = Content.Load("spr_Cave1_foreground"); + //sprCave1Walls = Content.Load("spr_Cave1_walls"); + // Test platform + platformTexture = Content.Load("platform"); + + // load player sprite + player.LoadContent(Content); // player sprite is now handled in player.cs // Test Render Target renderTarget = new RenderTarget2D(GraphicsDevice, retroWidth, retroHeight); + + // Debugging + debugFont = Content.Load("fonts/debugFont"); } protected override void Update(GameTime gameTime) @@ -106,7 +185,7 @@ namespace LunaLightXMG // Test player input and movement with abstracted player class playerInput.Update(); - player.Update(gameTime, playerInput); + player.Update(gameTime, playerInput, platforms); base.Update(gameTime); } @@ -121,13 +200,19 @@ namespace LunaLightXMG // Test Sprite spriteBatch.Begin(samplerState: SamplerState.PointClamp); // Draw sprites here - spriteBatch.Draw(sprCave1Background,new Vector2(0,0),Color.White); + //spriteBatch.Draw(sprCave1Background,new Vector2(0,0),Color.White); + + // Test draw tiles + foreach (var platform in platforms) + { + platform.Draw(spriteBatch, platformTexture); // Assuming all tiles use the same texture for now + } // Test player input and movement with abstracted player class - player.Draw(spriteBatch, sprRo); + player.Draw(spriteBatch); - spriteBatch.Draw(sprCave1Walls, new Vector2(0, 0), Color.White); - spriteBatch.Draw(sprCave1Foreground, new Vector2(0, 0), Color.White); + //spriteBatch.Draw(sprCave1Walls, new Vector2(0, 0), Color.White); + //spriteBatch.Draw(sprCave1Foreground, new Vector2(0, 0), Color.White); spriteBatch.End(); @@ -137,7 +222,24 @@ namespace LunaLightXMG spriteBatch.Draw(renderTarget, renderDestination, Color.White); spriteBatch.End(); + // Debugging + DrawDebugInfo(); + base.Draw(gameTime); } + + // Debugging + private void DrawDebugInfo() + { + spriteBatch.Begin(); + + // Draw debug messages + spriteBatch.DrawString(debugFont, $"VSP: {player.vsp}", new Vector2(10, 10), Color.White); + spriteBatch.DrawString(debugFont, $"Grounded: {player.grounded}", new Vector2(10, 30), Color.White); + spriteBatch.DrawString(debugFont, $"Walled: {player.walled}", new Vector2(10, 50), Color.White); + spriteBatch.DrawString(debugFont, $"Position: {player.position}", new Vector2(10, 70), Color.White); + + spriteBatch.End(); + } } } diff --git a/Platform.cs b/Platform.cs new file mode 100644 index 0000000..9f1b657 --- /dev/null +++ b/Platform.cs @@ -0,0 +1,23 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace LunaLightXMG +{ + public class Platform + { + public Vector2 Position { get; private set; } + public BoundingBox BoundingBox { get; private set; } + + public Platform(Vector2 position, int width, int height) + { + Position = position; + BoundingBox = new BoundingBox(new Rectangle((int)position.X, (int)position.Y, width, height)); + } + + public void Draw(SpriteBatch spriteBatch, Texture2D texture) + { + spriteBatch.Draw(texture, Position, Color.White); + } + } +} + diff --git a/Player.cs b/Player.cs index ac2f26d..e5e83ed 100644 --- a/Player.cs +++ b/Player.cs @@ -1,5 +1,6 @@ using System; using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; using Microsoft.Xna.Framework.Graphics; namespace LunaLightXMG @@ -8,25 +9,28 @@ namespace LunaLightXMG { // Declare variables private float hsp; // Horizontal speed - private float vsp; // Vertical speed + public float vsp; // Vertical speed private float wallJumpDelay; // Delay for wall jumping - private bool grounded; // Is the player grounded? - private bool walled; // Is the player wall sliding? - private float hspAcc; // Horizontal acceleration - private float hspFrictionGround; // Ground friction - private float hspFrictionAir; // Air friction - private float hspWalk; // Maximum horizontal speed + public bool grounded; // Is the player grounded? + public bool walled; // Is the player wall sliding? + private bool wasWalled; // Remember is the player was on a wall or ground. + private float hspAcc; // Horizontal acceleration + private float hspFrictionGround; // Ground friction + private float hspFrictionAir; // Air friction + private float hspWalk; // Maximum horizontal speed private float grv; // Gravity - private float vspMax; // Maximum vertical speed - private float grvWall; // Gravity when wall sliding - private float vspMaxWall; // Maximum vertical speed when wall sliding - private float vspJump; // Jump speed + private float vspMax; // Maximum vertical speed + private float grvWall; // Gravity when wall sliding + private float vspMaxWall; // Maximum vertical speed when wall sliding + private float vspJump; // Jump speed - // Player position + // Player initilization + private Texture2D texture; public Vector2 position; - + public BoundingBox BoundingBox { get; private set; } + // Constructor to initialize variables - public Player() + public Player(Vector2 initPosition) { // Initialize your variables here hsp = 0; @@ -34,32 +38,46 @@ namespace LunaLightXMG wallJumpDelay = 0; grounded = false; walled = false; - hspAcc = 0.5f; - hspFrictionGround = 0.2f; - hspFrictionAir = 0.1f; - hspWalk = 4f; - //grv = 0.5f; - grv = 0.0f; // No grav until we have walls, bounding boxes, etc.. + wasWalled = false; + hspAcc = 0.2f; + hspFrictionGround = 0.3f; + hspFrictionAir = 0.3f; + hspWalk = 3f; + grv = 0.2f; vspMax = 10f; grvWall = 0.1f; vspMaxWall = 5f; - vspJump = -10f; + vspJump = -4f; - position = new Vector2(163, 63); // Initialize player position + position = initPosition; + BoundingBox = new BoundingBox(new Rectangle((int)position.X, (int)position.Y, 8, 16)); + } + public void LoadContent(ContentManager content) + { + texture = content.Load("player"); } // Update method to handle movement logic - public void Update(GameTime gameTime, PlayerInput input) + public void Update(GameTime gameTime, PlayerInput input, Platform[] platforms) { + // Update player position Movement(input); - // Update player position based on speed - position.X += hsp; - position.Y += vsp; + // Update the player's bounding box + BoundingBox.Update(position, 8, 16); + + CollisionChecks(platforms); } private void Movement(PlayerInput input) { + // Handle jumping + if (input.KeyJump && grounded) + { + grounded = false; + vsp = vspJump; + } + // Horizontal movement with acceleration + wall jump delay wallJumpDelay = Math.Max(wallJumpDelay - 1, 0); // counts down every frame @@ -86,7 +104,6 @@ namespace LunaLightXMG grvFinal = grvWall; vspMaxFinal = vspMaxWall; } - vsp += (vsp == 0 ? grvFinal * 2 : grvFinal); vsp = MathHelper.Clamp(vsp, vspJump, vspMaxFinal); } @@ -109,12 +126,83 @@ namespace LunaLightXMG return start; } - public void Draw(SpriteBatch spriteBatch, Texture2D texture) + // Collision Checks - maybe abstract to a class --------------------------------------------------------------- + private void CollisionChecks(Platform[] platforms) + { + // Horizontal collision prediction + float onePixh = Math.Sign(hsp); + if (IsColliding(position + new Vector2(hsp, 0), platforms)) + { + while (!IsColliding(position + new Vector2(onePixh, 0), platforms)) + { + position.X += onePixh; + } + hsp = 0; + } + position.X += hsp; // Horizontal move + + // Vertical collision prediction + float onePixv = Math.Sign(vsp); + if (IsColliding(position + new Vector2(0, vsp), platforms)) + { + while (!IsColliding(position + new Vector2(0, onePixv), platforms)) + { + position.Y += onePixv; + } + vsp = 0; + } + position.Y += vsp; // Vertical move + + // Grounded? + grounded = IsColliding(position + new Vector2(0, 1), platforms); + + // Walled? + walled = WallCheck(platforms); + if (walled) + wasWalled = walled; + } + + private bool IsColliding(Vector2 newPosition, Platform[] platforms) + { + Rectangle newBounds = new Rectangle((int)newPosition.X, (int)newPosition.Y, BoundingBox.Bounds.Width, BoundingBox.Bounds.Height); + foreach (var platform in platforms) + { + if (newBounds.Intersects(platform.BoundingBox.Bounds)) + { + return true; + } + } + return false; + } + + private Platform GetCollidingPlatform(Vector2 newPosition, Platform[] platforms) + { + Rectangle newBounds = new Rectangle((int)newPosition.X, (int)newPosition.Y, BoundingBox.Bounds.Width, BoundingBox.Bounds.Height); + foreach (var platform in platforms) + { + if (newBounds.Intersects(platform.BoundingBox.Bounds)) + { + return platform; + } + } + return null; + } + + private bool WallCheck(Platform[] platforms) + { + if (IsColliding(position + new Vector2(1, 0), platforms) || IsColliding(position + new Vector2(-1, 0), platforms)) + { + return true; + } + return false; + } + // Collision checks end --------------------------------------------------------------------------------------------------------- + + public void Draw(SpriteBatch spriteBatch) { // Snap position to integer values Vector2 drawPosition = new Vector2((int)position.X, (int)position.Y); spriteBatch.Draw(texture, drawPosition, Color.White); } } - } diff --git a/PlayerInput.cs b/PlayerInput.cs index f853ab9..6e3169e 100644 --- a/PlayerInput.cs +++ b/PlayerInput.cs @@ -27,7 +27,7 @@ namespace LunaLightXMG // If using controller, switch to keyboard by pressing any key if (Keyboard.GetState().GetPressedKeys().Length > 0) { - // Insert your logic to create the objMouseJoyStick instance + // TODO: Insert logic to create the objMouseJoyStick instance Controller = false; } @@ -67,7 +67,7 @@ namespace LunaLightXMG GamePadState gamepadState = GamePad.GetState(PlayerIndex.One); if (gamepadState.IsConnected && gamepadState.Buttons.Start == ButtonState.Pressed) { - // Insert your logic to destroy the objMouseJoyStick instance + // TODO: Insert logic to destroy the objMouseJoyStick instance Controller = true; } @@ -111,5 +111,4 @@ namespace LunaLightXMG } } } - }