mirror of
https://github.com/TheRavenwoodArts/LunaLightXMG.git
synced 2026-07-30 22:55:03 -07:00
Initil Sprite Animation with the player class. (#4)
* Added RoSpriteSheet and defined animation states. * Added methods o handle sprite animation states. * Figured out how to flip sprites when moving left. * Bug Fix: Ready state wasn't animating, now it is ;) --------- Co-authored-by: jme9 <jme9@pdx.edu>
This commit is contained in:
@@ -1,20 +1,26 @@
|
||||
using System;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Transactions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
using MonoGame.Extended.Animations;
|
||||
using MonoGame.Extended.Graphics;
|
||||
|
||||
namespace LunaLightXMG
|
||||
{
|
||||
public class Player
|
||||
{
|
||||
private float hsp; // Horizontal speed
|
||||
public float hsp; // Horizontal speed
|
||||
public float vsp; // Vertical speed
|
||||
private float hsp_frac; // Hold fractional position data
|
||||
private float vsp_frac; // Hold fractional position data
|
||||
private float wallJumpDelay; // Delay for wall jumping
|
||||
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.
|
||||
public bool walled; // Is the player wall sliding
|
||||
public bool stopped; // animation control for when player has stopped moving.
|
||||
private bool spriteFacingLeft;
|
||||
private bool wasWalled; // Remember if the player was on a wall or ground.
|
||||
private float hspAcc; // Horizontal acceleration
|
||||
private float hspFrictionGround; // Ground friction
|
||||
private float hspFrictionAir; // Air friction
|
||||
@@ -24,11 +30,32 @@ namespace LunaLightXMG
|
||||
private float grvWall; // Gravity when wall sliding
|
||||
private float vspMaxWall; // Maximum vertical speed when wall sliding
|
||||
private float vspJump; // Jump speed
|
||||
private Texture2D texture;
|
||||
public Vector2 position;
|
||||
public BoundingBox boundingBox { get; private set; }
|
||||
public CollisionManager.CollisionSide collisionSide { get; private set; }
|
||||
private CollisionManager collisionManager;
|
||||
|
||||
// Sprites
|
||||
private Sprite wallSlide;
|
||||
private AnimatedSprite animatedSprite;
|
||||
|
||||
public enum PlayerState
|
||||
{
|
||||
Idle,
|
||||
Run,
|
||||
Jump,
|
||||
WallSlide,
|
||||
Climb,
|
||||
ClimbLedge,
|
||||
Edge,
|
||||
Stop,
|
||||
Ready,
|
||||
Attack1,
|
||||
Attack2,
|
||||
Attack3
|
||||
}
|
||||
|
||||
public PlayerState currentState; // make private before release ;)
|
||||
|
||||
|
||||
|
||||
@@ -42,10 +69,12 @@ namespace LunaLightXMG
|
||||
grounded = false;
|
||||
walled = false;
|
||||
wasWalled = false;
|
||||
spriteFacingLeft = false;
|
||||
stopped = true;
|
||||
hspAcc = 0.2f;
|
||||
hspFrictionGround = 0.3f;
|
||||
hspFrictionAir = 0.3f;
|
||||
hspWalk = 3f;
|
||||
hspWalk = 2.5f;
|
||||
grv = 0.2f;
|
||||
vspMax = 10f;
|
||||
grvWall = 0.1f;
|
||||
@@ -58,30 +87,240 @@ namespace LunaLightXMG
|
||||
|
||||
public void LoadContent(ContentManager content)
|
||||
{
|
||||
texture = content.Load<Texture2D>("player");
|
||||
}
|
||||
// Load Player SpriteSheet
|
||||
Texture2D texture2D = content.Load<Texture2D>("Ro_Sprites/RoSpriteSheet");
|
||||
Texture2DAtlas atlas = Texture2DAtlas.Create("Atlas/RoSpriteSheet", texture2D, 18, 18);
|
||||
SpriteSheet spriteSheet = new SpriteSheet("SpriteSheet/RoSpriteSheet", atlas);
|
||||
|
||||
// Single Sprites
|
||||
wallSlide = atlas.CreateSprite(regionIndex: 47);
|
||||
|
||||
// Animated Sprites
|
||||
spriteSheet.DefineAnimation("climbLedge", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(regionIndex: 0, duration: TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(1, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(2, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(3, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(4, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(5, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(6, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(7, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("edge", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(8, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(9, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(10, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(11, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(12, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(13, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(14, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(15, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("jump", builder =>
|
||||
{
|
||||
builder.IsLooping(false)
|
||||
.AddFrame(16, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(17, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(18, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(19, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(20, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(21, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(22, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(23, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("run", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(24, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(25, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(26, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(27, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(28, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(29, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(30, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(31, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(32, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(33, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(34, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(35, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("stop", builder =>
|
||||
{
|
||||
builder.IsLooping(false)
|
||||
.AddFrame(36, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(37, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(38, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(39, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("ready", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(40, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(41, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(42, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(43, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(44, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(45, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(46, TimeSpan.FromSeconds(0.2));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("climb", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(48, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(49, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(50, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(51, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(52, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(53, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(54, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(55, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(56, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(57, TimeSpan.FromSeconds(0.2));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("idle", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(58, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(59, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(60, TimeSpan.FromSeconds(0.2))
|
||||
.AddFrame(61, TimeSpan.FromSeconds(0.2));
|
||||
});
|
||||
|
||||
animatedSprite = new AnimatedSprite(spriteSheet, "idle");
|
||||
}
|
||||
|
||||
public void Update(GameTime gameTime, PlayerInput input, Platform[] platforms)
|
||||
{
|
||||
animatedSprite.Update(gameTime);
|
||||
Movement(input);
|
||||
boundingBox.Update(position, boundingBox.Bounds.Width, boundingBox.Bounds.Height);
|
||||
DumpFractions();
|
||||
CollisionChecks(platforms);
|
||||
UpdateAnimation();
|
||||
}
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
// Adjust sprite draw position to align with bounding box
|
||||
Vector2 drawOffset = new Vector2(-5, -1);
|
||||
|
||||
// Snap position to integer values
|
||||
Vector2 drawPosition = new Vector2((int)position.X, (int)position.Y);
|
||||
spriteBatch.Draw(texture, drawPosition, Color.White);
|
||||
Vector2 drawPosition = new Vector2((int)position.X, (int)position.Y) + drawOffset;
|
||||
|
||||
// Flip sprites when moving left.
|
||||
SpriteEffects flipEffect = spriteFacingLeft ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
|
||||
|
||||
// Draw sprite
|
||||
if (currentState == PlayerState.WallSlide)
|
||||
{
|
||||
spriteBatch.Draw(wallSlide.TextureRegion.Texture,
|
||||
drawPosition,
|
||||
wallSlide.TextureRegion.Bounds,
|
||||
Color.White,
|
||||
0f,
|
||||
Vector2.Zero,
|
||||
1f,
|
||||
flipEffect,
|
||||
0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
animatedSprite.Effect = flipEffect;
|
||||
spriteBatch.Draw(animatedSprite, drawPosition);
|
||||
}
|
||||
}
|
||||
|
||||
// Method Implementation -------------------------------------------------------------------------------
|
||||
|
||||
public void Reset(Vector2 initialPosition)
|
||||
{
|
||||
position = initialPosition;
|
||||
// Reset other player-specific states later
|
||||
}
|
||||
|
||||
private void UpdateAnimation()
|
||||
{
|
||||
if (walled && !grounded)
|
||||
{
|
||||
currentState = PlayerState.WallSlide;
|
||||
stopped = false;
|
||||
}
|
||||
else if (grounded)
|
||||
{
|
||||
if (hsp == 0.0f)
|
||||
{
|
||||
if (!stopped)
|
||||
{
|
||||
stopped = true;
|
||||
HandleSetAnimation(PlayerState.Stop);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleSetAnimation(PlayerState.Run);
|
||||
stopped = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleSetAnimation(PlayerState.Jump);
|
||||
stopped = false;
|
||||
}
|
||||
|
||||
// TODO: Need logic for climbing, climgLedge, edge, attacks
|
||||
|
||||
// TODO: Need timer to track idle time, then move to idle state after some amount of time
|
||||
}
|
||||
|
||||
private void HandleSetAnimation(PlayerState newState)
|
||||
{
|
||||
if (currentState == newState) return;
|
||||
|
||||
currentState = newState;
|
||||
|
||||
switch (currentState)
|
||||
{
|
||||
case PlayerState.Idle:
|
||||
animatedSprite.SetAnimation("idle");
|
||||
break;
|
||||
case PlayerState.Run:
|
||||
animatedSprite.SetAnimation("run");
|
||||
break;
|
||||
case PlayerState.Jump:
|
||||
animatedSprite.SetAnimation("jump");
|
||||
break;
|
||||
case PlayerState.Stop:
|
||||
animatedSprite.SetAnimation("stop").OnAnimationEvent += (sender, trigger) =>
|
||||
{
|
||||
if (trigger == AnimationEventTrigger.AnimationCompleted)
|
||||
{
|
||||
HandleSetAnimation(PlayerState.Ready);
|
||||
}
|
||||
};
|
||||
break;
|
||||
case PlayerState.Ready:
|
||||
animatedSprite.SetAnimation("ready");
|
||||
break;
|
||||
case PlayerState.WallSlide:
|
||||
// not sure yet
|
||||
break;
|
||||
case PlayerState.Climb:
|
||||
animatedSprite.SetAnimation("climb");
|
||||
break;
|
||||
case PlayerState.ClimbLedge:
|
||||
animatedSprite.SetAnimation("climbLedge");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void Movement(PlayerInput input)
|
||||
{
|
||||
@@ -89,10 +328,10 @@ namespace LunaLightXMG
|
||||
{
|
||||
vsp = vspJump;
|
||||
}
|
||||
|
||||
|
||||
// Horizontal movement with acceleration + wall jump delay
|
||||
wallJumpDelay = Math.Max(wallJumpDelay - 1, 0); // counts down every frame
|
||||
|
||||
|
||||
if (wallJumpDelay == 0) // no left-right control until delay is 0, prevents rapid wall climb
|
||||
{
|
||||
float moveH = input.KeyRight - input.KeyLeft;
|
||||
@@ -103,14 +342,22 @@ namespace LunaLightXMG
|
||||
float hspFrictionFinal = grounded ? hspFrictionGround : hspFrictionAir;
|
||||
hsp = Approach(hsp, 0, hspFrictionFinal);
|
||||
}
|
||||
|
||||
|
||||
hsp = MathHelper.Clamp(hsp, -hspWalk, hspWalk);
|
||||
if (hsp < 0)
|
||||
{
|
||||
spriteFacingLeft = true;
|
||||
}
|
||||
else if (hsp > 0)
|
||||
{
|
||||
spriteFacingLeft = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate vertical movement
|
||||
float grvFinal = grv;
|
||||
float vspMaxFinal = vspMax;
|
||||
|
||||
|
||||
if (walled && vsp > 0)
|
||||
{
|
||||
grvFinal = grvWall;
|
||||
@@ -156,8 +403,10 @@ namespace LunaLightXMG
|
||||
|
||||
collisionSide = CollisionManager.GetCollisionSide(position, boundingBox, platforms);
|
||||
}
|
||||
|
||||
|
||||
private float Approach(float start, float end, float shift)
|
||||
// TODO: Move below to utilities class
|
||||
private static float Approach(float start, float end, float shift)
|
||||
{
|
||||
if (start < end)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user