Hoorcollege 13 Animatie, game physics. De speler Wordt aangestuurd via toetsenbord Kent verschillende soorten bewegingen Rennen Stilstaan Springen Doodgaan.

Slides:



Advertisements
Verwante presentaties
HM-ES-th1 Les 9 Hardware/Software Codesign with SystemC.
Advertisements

Conditional Clauses If-zinnen.
Vervolg C Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 Onderwerpen voor vandaag Gelinkte lijsten Finite State.
MagentaPurpleTeal PinkOrangeBlue LimeBrown RedGreen Introductie C# /.NET
OOS Object geOrienteerd Software-ontwerp - 4 Codeerperikelen Singleton Specificeren Scheiding GUI en Domein Facade.
Omgevingen zijn dan geïmplementeerd als Symbol Tables. Symbol Table mapt een symbool met een Binding Meerdere noties van binding –Meerdere manieren te.
Computervaardigheden en Programmatie Universiteit AntwerpenObjecten 4.1 Computervaardigheden en Programmatie 1rste BAC Toegepaste Biologische Wetenschappen.
Modula vs Java MODULE Show; CONST PI = ; TYPE PointRc = RECORD x,y : INTEGER; speed : REAL; angle : REAL; END; VAR a,b : PointRc; BEGIN.
Server side scripting 1 Webtechnologie Lennart Herlaar.
Algoritmiek Arrays: wat zijn dat en wat kun je ermee? Loops: hoe hou je ze in bedwang? Hoorcollege 6 - Ma. 9 okt L.M. Bosveld-de Smet.
Algoritmen en Datastructuren (ALDAT) EVMINX4 Dagdeel 2.
Real-Time Systems (RTSYST) Week IPC inter process communication Shared variabele based (H5) Message based (H6) Kan ook gebruikt worden in systemen.
District 1550 Werkdag 6 oktober 2012 Vanaf I juli 2013 geen “Future Vision” meer  The New Foundation ? Vóor 1 Juli 2013:  District Qualification  Club.
Spatial classificatie
Opgave 1a: afronden int n=5; double a, b, c, d; a = n * 1.5; b = n * 3 / 2; c = n / 2 * 3; d = 3 / 2 * n; a b c d
Flocking using Global Roadmaps Niels Gorisse Motion Planning 26 februari 2003 University Utrecht.
Array nDeclaratie nCreatie nOpvragen nWijzigen nLengte String [ ] a; a = new String[10]; ……a[5]…… a[5] = ……; …a.Length… …is eigenlijk overbodig! List a;
Hoorcollege 8 Game object structuren. Arrays in games Grid-gebaseerd speelveld (zoals Tetris) Lijst van spelers Lijst van inventory items Lijst van alle.
Eerste deeltoets Uitwerking. Resultaten Gemiddeld: 6,01 Tips voor de volgende keer: – Werk in klad uit, schrijf duidelijk – Oefenen met loops en tellertjes.
Hoorcollege 14 Vijanden, excepties. Wat zit allemaal in een level? Startpositie van de speler Waterdruppels Tiles Vijanden Einde van het level Achtergronden.
Hoorcollege 7 Collections, arrays. Programma ‘Snowflakes’ Sneeuwvlok object.
Methods of Development #3: Objecten. * Staat op USAT weblog.
#3Objecten. Schrijf in LOGO de pseudocode voor een figuur naar keuze (met iig een lus of conditie). Maak tevens een screenshot van het resultaat.
Hibernate Object relational mapping
JAVA1 H 22. COLLECTIONS FRAMEWORK. 1. INLEIDING. Collections framework Is een verzameling van data structuren, interfaces en algoritmen Meest voorkomende.
Hoorcollege 12 Afronding Penguin Pairs & overzicht Tick Tick.
Hoofdstuk 2 Java. Soorten Java-programma’s nJava Applet programma “leeft” op een WWW-pagina nJava Application programma heeft een eigen window nJavascript.
Hoofdstuk 9 Objecten en klassen.
Hoorcollege 9 Jewel Jam The revenge. Hierarchie van game objecten Game object (lijst) Game object (grid) Game object (lijst) Game object.
Internetapplicaties - IV Collecties 1 Internetapplicaties Deel 4: Java hulpklassen: Collecties.
Herhaling Java-programmatie en geautomatiseerd testen (vervolg)
Deel XIV Eerste echte e-commerce applicatie Implementatie (vervolg) 1 Internetapplicaties Deel 15: Herhaling Java-programmatie en geautomatiseerd testen.
Hoofdstuk 10.1 Toepassing: Bitmap-editor. nKlik punten op scherm nPlaatje verschuiven left, right, up, down nPlaatje bewerken clear, invert, bold, outline.
Hoofdstuk 5 Interactie. Controls Form Label Button Label TextBox.
Hoorcollege 5 Herhaling, game object interactie. Ball class class Ball { Texture2D colorRed, colorGreen, colorBlue; Texture2D currentColor; Vector2 position,
C++ C++ als een verbetering van C Abstracte datatypen met classes Constructoren en destructoren Subklassen binding van functies 1.
The beast has been released! 4 arcade-style games Interviews with famous people in the game industry Develop browsers games for any device (phone, tablet,
Computertechniek Hogeschool van Utrecht / Institute for Computer, Communication and Media Technology 1 C programmeren voor niet-C programmeurs les 2 definitie.
Algoritmiek Class Hierarchies, Inheritance. Hoorcollege 12 - Ma. 20 nov L.M. Bosveld-de Smet.
Enums. Enum Houd een state bij 'Uitgebreide boolean';  ipv 2 states (True, false) meerdere states Enum UnitState { IDLE, DEFENSIVE, AGRESSIVE} Public.
Hoorcollege 14 Vijanden, excepties. Overzicht programmaconstructies Opdrachten Toekenning Aanroep void-methode return-opdracht while-opdracht for(each)-opdracht.
Hoorcollege 4 Objecten en methoden. Eigen methode toevoegen class Painter : Game { public void HandleInput() { … } protected override void Update(GameTime.
Hoorcollege 3 Game assets, Invoer verwerken. Tutorlunch GroepTutorStutorZaal UPaul BergervoetBob BestBBG 001 VMarries van de HoefSander VerkuilBBG 731.
Programma opdrachten methoden klasse variabelen en Geheugen objecten klasse zijn gegroepeerd in hebben als type veranderen bewerken.
Na de praktijk, de theorie.. Zoals een gehaktmolen 1.Je stopt er iets in. 2.Je hoeft niet te weten wat er binnenin gebeurt. 3.Het resultaat verschijnt.
Animatie & Game Physics
Partial Classes, Enemies, Exceptions
Game Object Structuren
Gameprogrammeren: Objecten en geheugen
Gameprogrammeren: Overerving
Gameprogrammeren: Animatie
Gameprogrammeren: Methoden
Arjan Egges & Paul Bergervoet
Gameprogrammeren: Overerving in Painter
Gameprogrammeren: Player input in Painter
Gameprogrammeren: Tiles in Tick Tick
Gameprogrammeren: Willekeurigheid (Randomness)
Arjan Egges & Paul Bergervoet
Gameprogrammeren: Game Basics
Voortborduren op eerder gedaan werk
Libraries, Platform Games
Willekeurigheid en Herhaling
Gameprogrammeren: Tiles en File I/O in Tick Tick
Game: omgaan met tijd (Jewel-Jam)
Gameprogrammeren: Klassen en objecten
Arjan Egges & Paul Bergervoet
Object Communication (Jewel Jam)
Gameprogrammeren: Enemies in Tick Tick
Gameprogrammeren: Sprite sheets
Gameprogrammeren: Arrays
Transcript van de presentatie:

Hoorcollege 13 Animatie, game physics

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

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

AnimatedCharacter Geanimeerde sprite

Overzicht Animation 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 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; } } … }

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 SpriteSheet

public class AnimatedGameObject : SpriteGameObject { protected Dictionary animations; public AnimatedGameObject(int layer = 0, string id = "") : base(layer, id) { animations = new Dictionary (); } public Animation Current { get { return sprite as Animation; } } … } 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); } AnimatedGameObject

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

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(); } …

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) this.PlayAnimation("idle"); else this.PlayAnimation("run"); else if (velocity.Y < 0) this.PlayAnimation("jump"); DoPhysics(); } Speler begint op een bepaalde positie. startconfiguratie “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(); } Willen we springen? Kies de juiste beweegrichting

Speler physics public void Jump(float speed = 1100) { velocity.Y = -speed; } private void DoPhysics() { velocity.Y += 55f; HandleCollisions(); } We vallen steeds harder naar beneden. Springen = negatieve y-snelheid.

Botsingen in games

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

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

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

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 sprite.Height spritePositie (X,Y) middelpunt straal

Botsingen tussen sprites Hoe berekenen we dit? Drie mogelijkheden:

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

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

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

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

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

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 …

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

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

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

Break vs continue break – 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 39

Botsingen verwerken 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!

Botsing tussen twee sprites Y intersectiediepte X intersectiediepte

Botsing tussen twee sprites

Botsingen verwerken 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. Deze methode moeten we nog maken.

Botsingen verwerken 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? Diepte in de Y-richting is kleiner. Indien op de grond of geen platformtile… float afrondingsfouten voorkomen

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 + - =

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

Verkorte versie if-opdracht Vector2 depth = Vector2.Zero; depth.X = distance.X > 0 ? minDistance.X - distance.X; : -minDistance.X - distance.X; … 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… “if (distance.X > 0)” Dan is het resultaat “else” Alternatief resultaat Uitgebreide versie

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!

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

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; } return false; }

De volgende keer Vijanden! Be afraid…Be VERY afraid!! I’m thirsty… I hate my life 