First and foremost thanks to anyone that can help me out here but Im having trouble getting my jump sprite animation to fit with the game jump speed and gravity. The animation appears to be choppy, and when i execute the animation again, it seems to start from the last frame it left off, im guessing. I want the jump/fall animation to fit perfectly with the code gravity and jump speed logic. hoping some one can help.
this is how it looks
this is how it should look
// Represents a player in the game world.
class Player extends SpriteAnimationComponent with CollisionCallbacks, KeyboardHandler{
//late ThePixelDead gameRef = GlobalGameReference.instance.gameReference;
int _hAxisInput = 0;
bool _jumpInput = false;
bool _isOnGround = false;
final double _gravity = 20;
final double _jumpSpeed = 400;
final double _moveSpeed = 64;
final Vector2 _up = Vector2(0, -1);
final Vector2 _velocity = Vector2.zero();
// Limits for clamping player.
late Vector2 _minClamp;
late Vector2 _maxClamp;
Player(
SpriteAnimation spriteAnimation, {
required Rect levelBounds,
Vector2? position,
Vector2? size,
Vector2? scale,
double? angle,
Anchor? anchor,
int? priority,
}) : super(
animation: spriteAnimation,
position: position,
size: size,
scale: scale,
angle: angle,
anchor: anchor,
priority: priority,
) {
// Since anchor point for player is at the center,
// min and max clamp limits will have to be adjusted by
// half-size of player.
final halfSize = size! / 2;
_minClamp = levelBounds.topLeft.toVector2() + halfSize;
_maxClamp = levelBounds.bottomRight.toVector2() - halfSize;
}
@override
Future<void>? onLoad() {
add(CircleHitbox());
return super.onLoad();
}
@override
void update(double dt) {
// animationLogic();
// Modify components of velocity based on
// inputs and gravity.
_velocity.x = _hAxisInput * _moveSpeed;
_velocity.y += _gravity;
// Allow jump only if jump input is pressed
// and player is already on ground.
if (_jumpInput) {
if (_isOnGround) {
AudioManager.playSfx('Jump_15.wav');
_velocity.y = -_jumpSpeed;
_isOnGround = false;
animation = gameRef.jump;
}
_jumpInput = false;
}
// Clamp velocity along y to avoid player tunneling
// through platforms at very high velocities.
_velocity.y = _velocity.y.clamp(-_jumpSpeed, 150);
// delta movement = velocity * time
position += _velocity * dt;
// Keeps player within level bounds.
position.clamp(_minClamp, _maxClamp);
// Flip player if needed.
if (_hAxisInput < 0 && scale.x > 0) {
flipHorizontallyAroundCenter();
} else if (_hAxisInput > 0 && scale.x < 0) {
flipHorizontallyAroundCenter();
}
super.update(dt);
}
@override
bool onKeyEvent(RawKeyEvent event, Set<LogicalKeyboardKey> keysPressed) {
_hAxisInput = 0;
_hAxisInput += keysPressed.contains(LogicalKeyboardKey.keyA) ? -1 : 0;
_hAxisInput += keysPressed.contains(LogicalKeyboardKey.keyD) ? 1 : 0;
_jumpInput = keysPressed.contains(LogicalKeyboardKey.space);
return true;
}
@override
void onCollision(Set<Vector2> intersectionPoints, PositionComponent other) {
if (other is Platform) {
if (intersectionPoints.length == 2) {
// Calculate the collision normal and separation distance.
final mid = (intersectionPoints.elementAt(0) +
intersectionPoints.elementAt(1)) /
2;
final collisionNormal = absoluteCenter - mid;
final separationDistance = (size.x / 2) - collisionNormal.length;
collisionNormal.normalize();
// If collision normal is almost upwards,
// player must be on ground.
if (_up.dot(collisionNormal) > 0.9) {
_isOnGround = true;
animation = gameRef.idle;
}
// Resolve collision by moving player along
// collision normal by separation distance.
position += collisionNormal.scaled(separationDistance);
}
}
super.onCollision(intersectionPoints, other);
}
// This method runs an opacity effect on player
// to make it blink.
void hit() {
add(
OpacityEffect.fadeOut(
EffectController(
alternate: true,
duration: 0.1,
repeatCount: 5,
),
),
);
}
// Makes the player jump forcefully.
void jump() {
_jumpInput = true;
_isOnGround = true;
}
}
//-------------------
// Represents the game world
class ThePixelDead extends FlameGame with HasCollisionDetection, HasKeyboardHandlerComponents, HasTappables {
final WorldData worldData;
ThePixelDead({required this.worldData}) {
globalGameReference.gameReference = this;
}
GlobalGameReference globalGameReference = Get.put(GlobalGameReference());
// Reference to common spritesheet
late Image spriteSheet;
final double stepTime = 0.2;
late SpriteSheet walkSS;
late SpriteSheet runSS;
late SpriteSheet jumpSS;
late SpriteSheet idleSS;
late SpriteAnimation walk = walkSS.createAnimation(row: 0, stepTime: stepTime, to: 7);
late SpriteAnimation run = runSS.createAnimation(row: 0, stepTime: stepTime, to: 7);
late SpriteAnimation jump = jumpSS.createAnimation(row: 0, stepTime: stepTime, to: 7, loop: false);
late SpriteAnimation idle = idleSS.createAnimation(row: 0, stepTime: stepTime, to: 7);
final playerData = PlayerDataOrig();
final textureSize = Vector2(32,32);
Size getScreenSize() {
return mat.MediaQueryData.fromWindow(mat.WidgetsBinding.instance.window).size;
}
@override
Future<void>? onLoad() async {
// Device setup
await Flame.device.fullScreen();
await Flame.device.setLandscape();
// Loads all the audio assets
await AudioManager.init();
spriteSheet = await images.load('Spritesheet.png');
idleSS = SpriteSheet(
image: Flame.images.fromCache('player/idle.png'),
srcSize: textureSize,
);
walkSS = SpriteSheet(
image: Flame.images.fromCache('player/walk.png'),
srcSize: textureSize,
);
runSS = SpriteSheet(
image: Flame.images.fromCache('player/run.png'),
srcSize: textureSize,
);
jumpSS = SpriteSheet(
image: Flame.images.fromCache('player/jump.png'),
srcSize: textureSize,
);
camera.zoom = 1.4;
//camera.viewport = FixedResolutionViewport(Vector2(640, 230),);
// camera.viewport = FixedResolutionViewport(Vector2(getScreenSize().width / 2.5, getScreenSize().height / 2.5),);
return super.onLoad();
}
}

