Gameprogrammeren: Animatie Arjan Egges Paul Bergervoet Wouter van Toll
De speler Wordt aangestuurd via toetsenbord Kent verschillende soorten bewegingen Rennen Stilstaan Springen Doodgaan Botsingen moeten afgehandeld worden We willen simpele ‘physics’ voor de speler
Animatie We hebben al simpele animaties gezien In de Painter game: bal, paintcans, … Bewegende paddles in Pong Tetrisblokjes die naar beneden vallen Enzovoorts… Maar tot nu toe verplaatsen we alleen sprites Hoe zit het met animaties?
Wat is animatie? Snelle opeenvolging van net iets andere plaatjes Als dat snel genoeg gebeurt, dan denken we dat iets beweegt “Persistence of Vision” “Persistence of Motion”
De sprite met alle frames Animatie in C# Verschillende mogelijkheden a) Iedere frame = een aparte sprite b) Een sprite bevat een aantal frames Hiervoor kunnen we mooi sprite sheets gebruiken! De sprite met alle frames 1 frame
AnimatedCharacter Geanimeerde sprite
Overzicht Animation-klasse AnimatedGameObject-klasse Uitbreiding van SpriteSheet Namelijk: sheet index aanpassen aan de verstreken tijd AnimatedGameObject-klasse Bevat een aantal Animation-objecten Kan verschillende animaties afspelen
Animation-klasse public class Animation : SpriteSheet { protected float frameTime; protected bool isLooping; protected float time; public Animation(string asset, bool isLooping, float frtime = 0.1f) : base(asset) { this.frameTime = frtime; this.isLooping = isLooping; } public int CountFrames { get { return this.NumberSheetElements; } … De tijd tussen iedere frame, oftewel: dit bepaalt de snelheid van de animatie! Handige property dat het aantal frames berekent
public float FrameTime { get { return frameTime; } } public bool IsLooping get { return isLooping; } public bool AnimationEnded get return !this.isLooping && sheetIndex >= NumberSheetElements - 1; Nog meer properties…
public override void Update(GameTime gameTime) public void Play() { this.sheetIndex = 0; this.time = 0.0f; } public override void Update(GameTime gameTime) time += (float)gameTime.ElapsedGameTime.TotalSeconds; while (time > frameTime) time -= frameTime; if (isLooping) sheetIndex = (sheetIndex + 1) % this.CountFrames; else sheetIndex = Math.Min(sheetIndex + 1, this.CountFrames - 1); Start de animatie. Bereken huidig af te beelden frame.
Spiegelen van sprites Naar links lopen of naar rechts lopen Spiegel de sprite in plaats van twee aparte sprites public class SpriteSheet { … protected bool mirror; public bool Mirror { get { return mirror; } set { mirror = value; } }
Spiegelen in SpriteSheets public void Draw(SpriteBatch s, Vector2 position, Vector2 origin) { int columnIndex = sheetIndex % sheetColumns; int rowIndex = sheetIndex / sheetColumns; Rectangle spritePart = new Rectangle(columnIndex * this.Width, rowIndex * this.Height, this.Width, this.Height); SpriteEffects spriteEffects = SpriteEffects.None; if (mirror) spriteEffects = SpriteEffects.FlipHorizontally; spriteBatch.Draw(sprite, position, spritePart, Color.White, 0.0f, origin, 1.0f, spriteEffects, 0.0f); } Sprite spiegelen
AnimatedGameObject-klasse public class AnimatedGameObject : SpriteGameObject { protected Dictionary<string, Animation> animations; public AnimatedGameObject(int layer = 0, string id = "") : base(layer, id) animations = new Dictionary<string, Animation>(); } public Animation Current get { return sprite as Animation; } …
AnimatedGameObject-klasse public void LoadAnimation(string asset, string id, bool looping, float frametime = 0.1f) { Animation anim = new Animation(assetname, looping, frametime); animations[id] = anim; } public void PlayAnimation(string id) { if (sprite == animations[id]) return; if (sprite != null) animations[id].Mirror = sprite.Mirror; animations[id].Play(); sprite = animations[id]; origin = new Vector2(sprite.Width / 2, sprite.Height);
AnimatedGameObject-klasse public override void Update(GameTime gameTime) { if (sprite == null) return; Current.Update(gameTime); base.Update(gameTime); }
Player-klasse class Player : AnimatedGameObject { public Player(Vector2 start) : base(2, "player") this.LoadAnimation("spr_idle", "idle", true); this.LoadAnimation("spr_run@13", "run", true, 0.05f); this.LoadAnimation("spr_jump@14", "jump", false, 0.05f); this.LoadAnimation("spr_celeb@14", "celebrate", false, 0.05f); this.LoadAnimation("spr_die@5", "die", false); this.LoadAnimation("spr_expl@5x5", "explode", false, 0.04f); startPosition = start; Reset(); } …
public override void Reset() { this.position = startPosition; isOnTheGround = true; this.PlayAnimation("idle"); previousYPosition = BoundingBox.Bottom; } public override void Update(GameTime gameTime) { base.Update(gameTime); if (isOnTheGround) if (velocity.X == 0) else this.PlayAnimation("run"); else if (velocity.Y < 0) this.PlayAnimation("jump"); DoPhysics(); startconfiguratie Speler begint op een bepaalde positie. “idle”-animatie positie
public override void HandleInput(InputHelper inputHelper) { float walkingSpeed = 400; if (inputHelper.IsKeyDown(Keys.Left)) velocity.X = -walkingSpeed; else if (inputHelper.IsKeyDown(Keys.Right)) velocity.X = walkingSpeed; else if (isOnTheGround) velocity.X = 0.0f; if (velocity.X != 0.0f) Mirror = velocity.X < 0; if ((inputHelper.KeyPressed(Keys.Space) || inputHelper.KeyPressed(Keys.Up)) && isOnTheGround) Jump(); } Kies de juiste beweegrichting Willen we springen?
Physics in de Player-klasse public void Jump(float speed = 1100) { velocity.Y = -speed; } private void DoPhysics() velocity.Y += 55f; HandleCollisions(); Springen = negatieve y-snelheid. We vallen steeds harder naar beneden.