165 lines
6.7 KiB
C#
165 lines
6.7 KiB
C#
using System;
|
|
using Coroutine;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using Microsoft.Xna.Framework.Input;
|
|
using MLEM.Animations;
|
|
using MLEM.Extended.Extensions;
|
|
using MLEM.Extended.Tiled;
|
|
using MLEM.Extensions;
|
|
using MLEM.Input;
|
|
using MLEM.Startup;
|
|
using MLEM.Textures;
|
|
using MonoGame.Extended;
|
|
using MonoGame.Extended.Tiled;
|
|
using RectangleF = MLEM.Misc.RectangleF;
|
|
|
|
namespace GreatSpringGameJam {
|
|
public class Player : Entity {
|
|
|
|
private static readonly UniformTextureAtlas PlayerTexture = new(MlemGame.LoadContent<Texture2D>("Textures/Player"), 4, 1);
|
|
|
|
public RectangleF Bounds => new(this.Position + new Vector2(4 / 16F, 0), new Vector2(9 / 16F, 1));
|
|
|
|
private readonly SpriteAnimationGroup animations;
|
|
private bool walking;
|
|
private bool onGround;
|
|
private Vector2 velocity;
|
|
private TimeSpan jumpTime;
|
|
private bool facingRight;
|
|
private HeldItem heldItem;
|
|
private float currJumpHeight;
|
|
private bool climbingVine;
|
|
|
|
public Player(Map map, Vector2 position) : base(map, position) {
|
|
this.animations = new SpriteAnimationGroup();
|
|
this.animations.Add(new SpriteAnimation(0.15F, PlayerTexture[1], PlayerTexture[2], PlayerTexture[3], PlayerTexture[0]), () => this.walking);
|
|
this.animations.Add(new SpriteAnimation(1, PlayerTexture[0]), () => !this.walking);
|
|
this.facingRight = true;
|
|
}
|
|
|
|
public override void Update(GameTime time) {
|
|
base.Update(time);
|
|
if (!GameImpl.Instance.IsInCutscene) {
|
|
var jumpHeight = 0.15F;
|
|
var (_, tileBelow) = this.GetTileBelow();
|
|
if (tileBelow != null && tileBelow.Properties.GetBool("JumpPad"))
|
|
jumpHeight = 0.25F;
|
|
|
|
var (_, foregroundInside) = this.GetTileBelow(Vector2.Zero, "Foreground");
|
|
var (_, tileInside) = this.GetTileBelow(Vector2.Zero);
|
|
if (foregroundInside != null && foregroundInside.Properties.GetBool("Goal")) {
|
|
GameImpl.Instance.Finish();
|
|
return;
|
|
}
|
|
|
|
// input
|
|
var move = Vector2.Zero;
|
|
if (MlemGame.Input.IsAnyDown(Keys.A, Keys.Left)) {
|
|
move.X -= 0.04F;
|
|
this.facingRight = false;
|
|
}
|
|
if (MlemGame.Input.IsAnyDown(Keys.D, Keys.Right)) {
|
|
move.X += 0.04F;
|
|
this.facingRight = true;
|
|
}
|
|
|
|
// climbing
|
|
if (tileInside != null && tileInside.Properties.GetBool("Vine")) {
|
|
if (MlemGame.Input.IsAnyDown(Keys.W, Keys.Up)) {
|
|
this.climbingVine = true;
|
|
move.Y -= 0.03F;
|
|
}
|
|
if (MlemGame.Input.IsAnyDown(Keys.S, Keys.Down)) {
|
|
this.climbingVine = true;
|
|
move.Y += 0.03F;
|
|
}
|
|
} else {
|
|
this.climbingVine = false;
|
|
}
|
|
|
|
this.walking = move != Vector2.Zero;
|
|
this.velocity += move;
|
|
|
|
if (MlemGame.Input.IsDown(Keys.Space)) {
|
|
// only start jumping if we just started pressing the buttons
|
|
if ((this.onGround || this.climbingVine) && MlemGame.Input.IsPressed(Keys.Space)) {
|
|
this.jumpTime = TimeSpan.FromSeconds(0.3F);
|
|
this.currJumpHeight = jumpHeight;
|
|
this.climbingVine = false;
|
|
}
|
|
this.jumpTime -= time.ElapsedGameTime;
|
|
if (this.jumpTime > TimeSpan.Zero)
|
|
this.velocity.Y = -this.currJumpHeight;
|
|
} else {
|
|
this.jumpTime = TimeSpan.Zero;
|
|
}
|
|
|
|
// restart if we fell
|
|
if (this.Position.Y >= this.Map.Size.Y + 5)
|
|
GameImpl.Instance.RestartLevel();
|
|
}
|
|
|
|
// movement and collisions
|
|
this.Position += this.velocity;
|
|
this.Collide(() => this.Bounds.ToExtended(), ref this.velocity, ref this.onGround);
|
|
this.velocity *= new Vector2(this.onGround ? 0.5F : 0.6F, this.climbingVine ? 0.5F : 0.95F);
|
|
if (!this.climbingVine)
|
|
this.velocity.Y += 0.015F;
|
|
|
|
// item usage
|
|
var rot = this.GetHeldRotation();
|
|
var rotVec = new Vector2(MathF.Cos(rot), MathF.Sin(rot));
|
|
if (MlemGame.Input.IsDown(MouseButton.Left)) {
|
|
this.heldItem = HeldItem.SnowBlower;
|
|
Random.NextUnitVector(out var vel);
|
|
vel = vel * 0.03F + rotVec * 0.13F;
|
|
this.Map.AddEntity(new SnowBlowerWind(this.Map, this.Position + Vector2.One / 2 + rotVec * 0.75F, vel));
|
|
} else if (MlemGame.Input.IsDown(MouseButton.Right)) {
|
|
this.heldItem = HeldItem.WateringCan;
|
|
if (Random.NextSingle() <= 0.45F) {
|
|
Random.NextUnitVector(out var vel);
|
|
vel = vel * 0.015F + rotVec * 0.03F;
|
|
this.Map.AddEntity(new WaterDrop(this.Map, this.Position + Vector2.One / 2 + rotVec * 0.65F, vel));
|
|
}
|
|
}
|
|
|
|
this.animations.Update(time);
|
|
}
|
|
|
|
public override void Draw(GameTime time, SpriteBatch batch) {
|
|
base.Draw(time, batch);
|
|
|
|
// draw self
|
|
var pos = this.Position * this.Map.TileSize;
|
|
var effects = this.facingRight ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
|
|
batch.Draw(this.animations.CurrentRegion, pos, Color.White, 0, Vector2.Zero, 1, effects, 0);
|
|
|
|
// draw held item
|
|
var tex = this.heldItem switch {
|
|
HeldItem.SnowBlower => StuffTexture[0, 0],
|
|
HeldItem.WateringCan => StuffTexture[2, 0],
|
|
_ => null
|
|
};
|
|
var origin = new Vector2(tex.Width * 0.25F, tex.Height / 2);
|
|
var rot = this.GetHeldRotation();
|
|
var flip = rot >= MathHelper.PiOver2 && rot <= MathHelper.Pi * 1.5F ? SpriteEffects.FlipVertically : SpriteEffects.None;
|
|
batch.Draw(tex, pos + this.Map.TileSize / 2, Color.White, rot, origin, 1, flip, 0);
|
|
}
|
|
|
|
private float GetHeldRotation() {
|
|
var myPos = GameImpl.Instance.Camera.ToCameraPos((this.Position + Vector2.One / 2) * this.Map.TileSize);
|
|
var mousePos = MlemGame.Input.MousePosition.ToVector2();
|
|
var (x, y) = myPos - mousePos;
|
|
return MathF.Atan2(y, x) + MathHelper.Pi;
|
|
}
|
|
|
|
private enum HeldItem {
|
|
|
|
SnowBlower,
|
|
WateringCan
|
|
|
|
}
|
|
|
|
}
|
|
} |