De presentatie wordt gedownload. Even geduld aub

De presentatie wordt gedownload. Even geduld aub

Animatie & Game Physics

Verwante presentaties


Presentatie over: "Animatie & Game Physics"— Transcript van de presentatie:

1 Animatie & Game Physics
Arjan Egges & Paul Bergervoet

2 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

3 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?

4 Wat is animatie? Animatie is een snelle opeenvolging van net iets andere plaatjes Als dat snel genoeg gebeurt, dan denken we dat iets beweegt. “Persistence of Vision” + “Persistence of Motion”

5 De sprite met alle frames
Animatie in C# Verschillende mogelijkheden Iedere frame = een sprite Een sprite bevat een aantal frames Hiervoor kunnen we mooi sprite sheets gebruiken! De sprite met alle frames 1 frame

6 AnimatedCharacter Geanimeerde sprite

7 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

8 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

9 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…

10 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.

11 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; } }

12 SpriteSheet 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

13 AnimatedGameObject 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; }

14 AnimatedGameObject 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);

15 AnimatedGameObject public override void Update(GameTime gameTime) {
if (sprite == null) return; Current.Update(gameTime); base.Update(gameTime); }

16 De Player klasse class Player : AnimatedGameObject {
public Player(Vector2 start) : base(2, "player") this.LoadAnimation("spr_idle", "idle", true); "run", true, 0.05f); "jump", false, 0.05f); "celebrate", false, 0.05f); "die", false); "explode", false, 0.04f); startPosition = start; Reset(); }

17 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

18 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?

19 Speler physics 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.

20 Botsingen in games

21 Botsingen tussen sprites
Twee manieren: Kijk per pixel of de sprites overlappen Gebruik een vereenvoudigde voorstelling van de sprites

22 Botsingen tussen sprites
Twee veel voorkomende vormen: cirkel, rechthoek Noemen we ook wel ‘bounding box’ en ‘bounding circle’ (of ‘bounding sphere’ in 3D) Dit kunnen we ook generaliseren: Convexe polygonen met behulp van Separating Axis Theorem Wij beperken ons tot cirkels en rechthoeken

23 Botsingen tussen sprites
Berekenen van bounding cirkels en bounding boxes. Rectangle bounding = new Rectangle(spritePositie.X, spritePositie.Y, sprite.Width, sprite.Height); sprite.Width spritePositie (X,Y) sprite.Height

24 Botsingen tussen sprites
Bounding cirkel berekenen we als volgt: Vector2 middelpunt = new Vector2(spritePositie.X + sprite.Width / 2, spritePositie.Y + sprite.Height / 2); float straal = Math.Max(sprite.Width / 2, sprite.Height / 2); sprite.Width spritePositie (X,Y) straal sprite.Height middelpunt

25 Botsingen tussen sprites
Hoe berekenen we dit? Drie mogelijkheden:

26 Botsingen tussen sprites
Twee cirkels botsen met elkaar als de afstand tussen de middelpunten kleiner is dan de som van de twee stralen

27 Botsingen tussen sprites
In code: bool InBotsing(Vector2 middel1, float straal1, Vector2 middel2, float straal2) { float afstand = (middel1 – middel2).Length(); return afstand < straal1 + straal2 == true; }

28 Botsingen tussen sprites
Twee rechthoeken Is al voor ons gedaan! Rectangle box1, box2; bool botst = box1.Intersects(box2);

29 Botsingen tussen sprites
Tussen een cirkel en een rechthoek Via het dichtstbijzijnde punt op de rechthoek tot middelpunt van de cirkel

30 Botsingen tussen sprites
bool InBotsing(Vector2 middel, float straal, Rectangle box) { Vector2 dichtstbij = new Vector2( MathHelper.Clamp(middel.X, box.Left, box.Right), MathHelper.Clamp(middel.Y, box.Top, box.Bottom)); float afstand = (dichtstbij – middel).Length(); return afstand < straal; }

31 Wat te doen bij een botsing?
Snelheid omdraaien Twee biljartballen die botsen Het balletje in Pong vliegt de andere kant op Een van de sprites niet meer tekenen Als je over een ‘powerup’ vliegt Game over De speler loopt tegen een vijand aan

32 Botsingen verwerken De speler kan botsen met: Vijanden Waterdruppels
Walltiles Vijanden + waterdruppels handelen we af in de Enemy/WaterDrop-klassen (komt later) Speler + Tiles doen we in de Speler klasse

33 Botsingen met tiles Kijk voor elke tile of hij botst met de speler
Dit hoeven we alleen maar te doen voor tiles die geen achtergrondtile zijn. En alleen voor tiles die in de buurt van de speler zijn

34 Botsingen verwerken private void HandleCollisions() {
isOnTheGround = false; TileField tiles = GameWorld.Find("tiles") as TileField; int x_floor = (int)position.X / tiles.CellWidth; int y_floor = (int)position.Y / tiles.CellHeight; for (int y = y_floor - 2; y <= y_floor + 1; ++y) for (int x = x_floor - 1; x <= x_floor + 1; ++x) TileType tileType = tiles.GetTileType(x, y); if (tileType == TileType.Background) continue; // kijk of er een botsing is } ..

35 Break vs continue break continue Wat is de uiteindelijke waarde van z?
Stopt de huidige iteratie en verlaat de loop continue Stopt ook de huidige iteratie, maar gaat door met de loop! Wat is de uiteindelijke waarde van z? int i, z = 0; for (i = 0; i < 10; i++) { z++; } int i, z = 0; for (i = 0; i < 10; i++) { if (i == 3) break; z++; } int i, z = 0; for (i = 0; i < 10; i++) { if (i == 3) continue; z++; } 10 3 9

36 Botsingen verwerken De tiles bewegen niet indien er een botsing is
Rectangle tileBounds = new Rectangle(x * tiles.CellWidth, y * tiles.CellHeight, tiles.CellWidth, tiles.CellHeight); Rectangle boundingBox = this.BoundingBox; boundingBox.Height += 1; Tile currentTile = tiles.Get(x, y) as Tile; if (((currentTile != null && !currentTile.CollidesWith(this)) || currentTile == null) && !tileBounds.Intersects(boundingBox)) continue; De tiles bewegen niet indien er een botsing is Dus moeten we de spelerpositie corrigeren!

37 Botsing tussen twee sprites
Y intersectiediepte X intersectiediepte

38 Botsing tussen twee sprites

39 Botsing tussen twee sprites

40 Botsing tussen twee sprites

41 Diepte in de X-richting
Botsingen verwerken Deze methode moeten we nog maken. Vector2 depth = Collision.CalculateIntersectionDepth(boundingBox, tileBounds); if (Math.Abs(depth.X) < Math.Abs(depth.Y)) { if (tileType == TileType.Normal) position.X += depth.X; } Diepte in de X-richting is kleiner.

42 Botsingen verwerken else {
Diepte in de Y-richting is kleiner. else { if (previousYPosition <= tileBounds.Top && tileType != TileType.Background) isOnTheGround = true; velocity.Y = 0; } if (tileType == TileType.Normal || isOnTheGround) position.Y += depth.Y; position = new Vector2((float)Math.Floor(position.X), (float)Math.Floor(position.Y)); Staan we op de grond? Indien op de grond of geen platformtile… float afrondingsfouten voorkomen

43 Intersectiediepte + - =
Stap 1: bereken de maximale afstand tussen de twee middenpunten Stap 2: bereken de werkelijke afstand tussen de twee middenpunten Stap 3: bereken het verschil, dit is de intersectiediepte Het teken (+/-) geeft de volgorde van de 2 objecten aan + - =

44 Intersectiediepte berekenen
public static Vector2 CalculateIntersectionDepth(Rectangle rectA, Rectangle rectB) { Vector2 minDistance = new Vector2(rectA.Width + rectB.Width, rectA.Height + rectB.Height) / 2; Vector2 centerA = new Vector2(rectA.Center.X, rectA.Center.Y); Vector2 centerB = new Vector2(rectB.Center.X, rectB.Center.Y); Vector2 distance = centerA - centerB; Vector2 depth = Vector2.Zero; if (distance.X > 0) depth.X = minDistance.X - distance.X; else depth.X = -minDistance.X - distance.X; if (distance.Y > 0) depth.Y = minDistance.Y - distance.Y; else depth.Y = -minDistance.Y - distance.Y; return depth; }

45 Intersectiediepte berekenen
public static Vector2 CalculateIntersectionDepth(Rectangle rectA, Rectangle rectB) { Vector2 minDistance = new Vector2(rectA.Width + rectB.Width, rectA.Height + rectB.Height) / 2; Vector2 centerA = new Vector2(rectA.Center.X, rectA.Center.Y); Vector2 centerB = new Vector2(rectB.Center.X, rectB.Center.Y); Vector2 distance = centerA - centerB; Vector2 depth = Vector2.Zero; depth.X = distance.X > 0 ? minDistance.X - distance.X; : -minDistance.X - distance.X; depth.Y = distance.Y > 0 ? minDistance.Y - distance.Y; : -minDistance.Y - distance.Y; return depth; } Verkorte versie if-opdracht

46 Verkorte versie if-opdracht
Dan is het resultaat Vector2 depth = Vector2.Zero; depth.X = distance.X > 0 ? minDistance.X - distance.X; : -minDistance.X - distance.X; “if (distance.X > 0)” “else” Alternatief resultaat Vector2 depth = Vector2.Zero; if (distance.X > 0) depth.X = minDistance.X - distance.X; else depth.X = -minDistance.X - distance.X; if (distance.Y > 0) // etc… Uitgebreide versie

47 Per-pixel botsing afhandelen
De bounding boxes overlappen, maar de ‘echte’ objecten botsen niet met elkaar Enige oplossing: botsing afhandelen door per pixel te kijken. Hoeft alleen voor het overlappende stuk te gebeuren!

48 Per pixel botsing afhandelen
public static Rectangle Intersection(Rectangle rect1, Rectangle rect2) { int xmin = (int)MathHelper.Max(rect1.Left, rect2.Left); int xmax = (int)MathHelper.Min(rect1.Right, rect2.Right); int ymin = (int)MathHelper.Max(rect1.Top, rect2.Top); int ymax = (int)MathHelper.Min(rect1.Bottom, rect2.Bottom); return new Rectangle(xmin, ymin, xmax - xmin, ymax - ymin); }

49 Per pixel botsing afhandelen
public bool CollidesWith(SpriteGameObject obj) { if (!this.Visible || !obj.Visible || !BoundingBox.Intersects(obj.BoundingBox)) return false; Rectangle b = Collision.Intersection(BoundingBox, obj.BoundingBox); for (int x = 0; x < b.Width; x++) for (int y = 0; y < b.Height; y++) { int thisx = b.X - (int)(GlobalPosition.X - origin.X) + x; int thisy = b.Y - (int)(GlobalPosition.Y - origin.Y) + y; int objx = b.X - (int)(obj.GlobalPosition.X - obj.origin.X) + x; int objy = b.Y - (int)(obj.GlobalPosition.Y - obj.origin.Y) + y; if (sprite.GetPixelColor(thisx, thisy).A != 0 && obj.sprite.GetPixelColor(objx, objy).A != 0) return true; }


Download ppt "Animatie & Game Physics"

Verwante presentaties


Ads door Google