mirror of
https://github.com/TheRavenwoodArts/LunaLightXMG.git
synced 2026-07-30 22:05:02 -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:
+24
-12
@@ -98,6 +98,30 @@
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:player.png
|
||||
|
||||
#begin ro_emoji.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:ro_emoji.png
|
||||
|
||||
#begin Ro_Sprites/RoSpriteSheet.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:Ro_Sprites/RoSpriteSheet.png
|
||||
|
||||
#begin Sink area.png
|
||||
/importer:TextureImporter
|
||||
/processor:TextureProcessor
|
||||
@@ -146,15 +170,3 @@
|
||||
/processorParam:TextureFormat=Color
|
||||
/build:spr_Cave1_walls.png
|
||||
|
||||
#begin sprRo_Wall.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:sprRo_Wall.png
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 7.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 716 B |
Binary file not shown.
|
Before Width: | Height: | Size: 527 B |
+5
-3
@@ -222,15 +222,17 @@ namespace LunaLightXMG
|
||||
|
||||
// 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, $"Collision Side: {player.collisionSide}", new Vector2(10, 70), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"HSP: {player.hsp}", new Vector2(10, 30), Color.White);
|
||||
|
||||
spriteBatch.DrawString(debugFont, $"Grounded: {player.grounded}", new Vector2(10, 50), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"Walled: {player.walled}", new Vector2(10, 70), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"Position: {player.position}", new Vector2(10, 90), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"Camera Position: {camera2D.Position}", new Vector2(10, 110), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"Camera Rotation: {camera2D.Rotation}", new Vector2(10, 130), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"Render Target Zoom: {renderHandler.ZoomLevel}", new Vector2(10, 150), Color.White);
|
||||
|
||||
spriteBatch.DrawString(debugFont, $"Player state: {player.currentState}", new Vector2(10, 170), Color.White);
|
||||
|
||||
|
||||
spriteBatch.DrawString(debugFont, $"Camera Rotation Control - Rotate left: K, Rotate right: L", new Vector2(10, 190), Color.White);
|
||||
spriteBatch.DrawString(debugFont, $"Render Target Zoom Control - Zoom in: U, Zoom normal: I, Zoom out: O", new Vector2(10, 210), Color.White);
|
||||
|
||||
+3
-2
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RollForward>Major</RollForward>
|
||||
<PublishReadyToRun>false</PublishReadyToRun>
|
||||
<TieredCompilation>false</TieredCompilation>
|
||||
@@ -19,7 +19,8 @@
|
||||
<EmbeddedResource Include="Icon.bmp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.1.303" />
|
||||
<PackageReference Include="MonoGame.Extended" Version="4.0.4" />
|
||||
<PackageReference Include="MonoGame.Framework.DesktopGL" Version="3.8.2.1105" />
|
||||
<PackageReference Include="MonoGame.Content.Builder.Task" Version="3.8.1.303" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -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,12 +30,33 @@ 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 ;)
|
||||
|
||||
|
||||
|
||||
public Player(Vector2 initPosition)
|
||||
@@ -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,31 +87,241 @@ 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)
|
||||
{
|
||||
if (input.KeyJump && grounded)
|
||||
@@ -105,6 +344,14 @@ namespace LunaLightXMG
|
||||
}
|
||||
|
||||
hsp = MathHelper.Clamp(hsp, -hspWalk, hspWalk);
|
||||
if (hsp < 0)
|
||||
{
|
||||
spriteFacingLeft = true;
|
||||
}
|
||||
else if (hsp > 0)
|
||||
{
|
||||
spriteFacingLeft = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate vertical movement
|
||||
@@ -157,7 +404,9 @@ 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)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
## March 31st, 2025 - JME
|
||||
|
||||
**Animated Sprites**
|
||||
|
||||
We are going to use the MonoGame.Extended framework for sprite animation. I have set up the project to use the extended frmework and implemented a simple test in the player class.
|
||||
|
||||
I learned that we should be creating sprite sheets for each character that include the animations for each state of the character, e.g. "run", "jump", "attack", etc.
|
||||
The sprite sheet can be thought of as a single dimension array represented as a matrix. Each index in the array represents a frame. Lets say our run animation is 6 frames, our jump animation is 4 frames and our attack animation is 10 frames and we draw each frame in the sprite sheet whereeach frame is 18px by 18px and our sprite sheet is 90px by 72px. Then our frames can be defined as follows
|
||||
|
||||
[00][01][02][03][04]
|
||||
[05][06][07][08][09]
|
||||
[10][11][12][13][14]
|
||||
[15][16][17][18][19]
|
||||
|
||||
Where "run" is index 00 to 05, "jump" is index 06 to 09 and "attack" is index 10 to 19.
|
||||
|
||||
Then from our single sprite sheet we can define the different animations for each state.
|
||||
|
||||
Texture2D texture2D = content.Load<Texture2D>("Path/To/SpriteSheet");
|
||||
Texture2DAtlas atlas = Texture2DAtlas.Create("Atlas/SpriteSheet", texture2D, 18, 18);
|
||||
SpriteSheet spriteSheet = new SpriteSheet("SpriteSheet/SpriteSheet", atlas);
|
||||
|
||||
spriteSheet.DefineAnimation("run", 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));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("jump", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(regionIndex: 0, duration: TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(6, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(7, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(8, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(9, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
spriteSheet.DefineAnimation("attack", builder =>
|
||||
{
|
||||
builder.IsLooping(true)
|
||||
.AddFrame(regionIndex: 0, duration: 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))
|
||||
.AddFrame(16, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(17, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(18, TimeSpan.FromSeconds(0.05))
|
||||
.AddFrame(19, TimeSpan.FromSeconds(0.05));
|
||||
});
|
||||
|
||||
## April 1st, 2025 - JME
|
||||
|
||||
**More sprite animation**
|
||||
|
||||
Added RoSpriteSheet containing animations for run. jump, climbLedge, climb, wallStatic, edge and idle states.
|
||||
|
||||
Added a drawOffset to align the 18px by 18px player sprites with the 8px by 16px bounding box.
|
||||
|
||||
public void Draw(SpriteBatch spriteBatch)
|
||||
{
|
||||
// Adjust sprite draw position to align with bounding box
|
||||
Vector2 drawOffset = new Vector2(-4, -1);
|
||||
// Snap position to integer values
|
||||
Vector2 drawPosition = new Vector2((int)position.X, (int)position.Y) + drawOffset;
|
||||
//spriteBatch.Draw(texture, drawPosition, Color.White);
|
||||
spriteBatch.Draw(animatedSprite, drawPosition);
|
||||
}
|
||||
|
||||
## April 2nd, 2025 - JME
|
||||
|
||||
**Handling player states and animations**
|
||||
|
||||
Created initial sprite animation handling. We have an UpdateAnimation method that detects player states and updates the animation based on the state.
|
||||
|
||||
private void UpdateAnimation()
|
||||
{
|
||||
if (grounded)
|
||||
{
|
||||
if (Math.Abs(hsp) > 0.1f)
|
||||
{
|
||||
HandleSetAnimation(PlayerState.Run);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleSetAnimation(PlayerState.Idle);
|
||||
}
|
||||
}
|
||||
else if (vsp < 0)
|
||||
{
|
||||
HandleSetAnimation(PlayerState.Jump);
|
||||
}
|
||||
}
|
||||
|
||||
We still need logic for stop, ready, wallSlide, climbing, climgLedge, edge, attacks
|
||||
|
||||
We will need a timer to track idle time, as well as some other things probably.
|
||||
|
||||
The HandleSetAnimation method switches the animation based on state as well as other variables that might need to be set during an animation switch.
|
||||
|
||||
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");
|
||||
break;
|
||||
case PlayerState.Ready:
|
||||
animatedSprite.SetAnimation("ready");
|
||||
break;
|
||||
case PlayerState.WallSlide:
|
||||
animatedSprite.SetAnimation("wallSlide");
|
||||
break;
|
||||
case PlayerState.Climb:
|
||||
animatedSprite.SetAnimation("climb");
|
||||
break;
|
||||
case PlayerState.ClimbLedge:
|
||||
animatedSprite.SetAnimation("climbLedge");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
## April 3rd, 2025 - JME
|
||||
|
||||
Figured out how to flip our player sprites when moving left by creating a boolean **spriteFacingLeft** that ses to true when player.hsp is less than zero and false when player.hp is greater than zero.
|
||||
|
||||
Then we can create a sprite efect using SpriteEffects that changes fom FlipHorizontally to None depending on spriteFacingLeft.
|
||||
|
||||
The correct overload for a static sprite with a sprite effect was tricky to figure out, the best I could find is the following,
|
||||
|
||||
spriteBatch.Draw(wallSlide.TextureRegion.Texture,
|
||||
drawPosition,
|
||||
wallSlide.TextureRegion.Bounds,
|
||||
Color.White,
|
||||
0f,
|
||||
Vector2.Zero,
|
||||
1f,
|
||||
flipEffect,
|
||||
0f);
|
||||
|
||||
So for further static sprite effects we'll probably want to use this overload.
|
||||
|
||||
Here is the full updated draw method for the player class
|
||||
|
||||
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) + 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);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user