Top Banner
three a simple 2D game engine: input handling and collision detection
43

Three a simple 2D game engine: input handling and collision detection.

Dec 28, 2015

Download

Documents

Ross Lynch
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Three a simple 2D game engine: input handling and collision detection.

three

a simple 2D game engine: input handling and collision detection

Page 2: Three a simple 2D game engine: input handling and collision detection.

Getting input from the user

We want to keep track of Where the mouse is Whether a mouse button has

been pressed What keys have been pressed

We’ll do this by storing the information in global variables

For mouse position and state And a list of states (up/down)

for each key

[define mouse-location [point 0 0]]

[define mouse-in-window? false]

[define mouse-pressed? false]

[define key-states [Array.CreateInstance Boolean 256]]

[define key-pressed?[keyvalue →

[get key-states keyvalue]]]

Page 3: Three a simple 2D game engine: input handling and collision detection.

Event handling

The operating system tells you what the user is doing by signaling events KeyDown/KeyUp

A key went down/up on the keyboard MouseDown/MouseUp

A button went up/down on the mouse MouseMove

The mouse moved inside the window MouseEnter/MouseLeave

The user dragged the mouse into/out of the window

So we need to set up handlers for them

Page 4: Three a simple 2D game engine: input handling and collision detection.

Setting up input handling

First, we initialize all those global variables Set all the elements of

the list of key states to false (i.e. not pressed)

Assume the mouse buttons are up

Assume the mouse is out of the window

[define initialize-input [form →

[up-to 256

[i → [[get key-states i] ← false]]]

[mouse-location ← [point 0 0]]

[mouse-down? ← false]

[mouse-in-window? ← false] … ]]

Page 5: Three a simple 2D game engine: input handling and collision detection.

Setting up event handlers

When the MouseEnter event happens Set mouse-in-window? to

be true When MouseLead

happens Set it to be false

[define initialize-input [form → … [form.MouseEnter.Add

[ignore ignore → [mouse-in-window? ← true]]] [form.MouseLeave.Add …] [form.MouseMove.Add

[ignore e → [update-mouse e]]] [form.MouseDown.Add

[ignore e → [mouse-down? ← true] [update-mouse e]]] [form.MouseUp.Add …]]

Page 6: Three a simple 2D game engine: input handling and collision detection.

Setting up event handlers

When MouseMove happens The OS passes a

MouseEventArgs object This object contains the

current coordinates of the mouse

So call update-mouse to read the coordinates out of the object and update the mouse-location variable

[define initialize-input [form → … [form.MouseEnter.Add

[ignore ignore → [mouse-in-window? ← true]]] [form.MouseLeave.Add …] [form.MouseMove.Add

[ignore e → [update-mouse e]]] [form.MouseDown.Add

[ignore e → [mouse-down? ← true] [update-mouse e]]] [form.MouseUp.Add …]]

Page 7: Three a simple 2D game engine: input handling and collision detection.

update-mouse

The .X and .Y fields of the MouseEventArgs object give the location of the mouse

Make a point out of them and update mouse-location

[define update-mouse [e →

[mouse-location ← [point e.X e.Y]]]]

Page 8: Three a simple 2D game engine: input handling and collision detection.

Setting up event handlers

MouseDown/MouseUp events are the same way The MouseEventArgs

object also has a field called Button that tells which button was pressed

For simplicity, we’ll ignore that

Update the mouse-down? Variable

Call update-mouse to update mouse-location

[define initialize-input

[form → … [form.MouseDown.Add

[ignore e → [mouse-down? ← true] [update-mouse e]]] [form.MouseUp.Add …]]

Page 9: Three a simple 2D game engine: input handling and collision detection.

Setting up the keyboard handlers

The OS passes a KeyEventArgs object to keyboard handlers It’s KeyValue field has

a number corresponding to the key that was pressed

[define initialize-input [form →

[form.KeyDown.Add [ignore e → [set-key-state e.KeyValue true]]]

[form.KeyUp.Add [ignore e → [set-key-state e.KeyValue false]]] …]]

Page 10: Three a simple 2D game engine: input handling and collision detection.

Implementing set-key-state

Basically, we Take the key number

(keyvalue) And set the corresponding

element of key-states to state (true or false)

However, we need to do the bitwise-and thingy to “fix” the number We’ll explain this later For now, trust me

[define set-key-state[keyvalue state →

[[get key-states

[bitwise-and keyvalue 255]]

← state]]]

Page 11: Three a simple 2D game engine: input handling and collision detection.

Getting the magic key numbers

There’s an object called Keys It has fields with all the key

numbers They’re represented as a

funny kind of object So you need to do the

Convert.ToInt32 thing to make them “real” numbers

You can get any keyboard key you want this way (e.g. using Keys.A for the A key)

[define up-arrow[System.Convert.ToInt32 Keys.Up]]

[define down-arrow[System.Convert.ToInt32 Keys.Down]]

[define left-arrow[System.Convert.ToInt32 Keys.Left]]

[define right-arrow[System.Convert.ToInt32 Keys.Right]]

Page 12: Three a simple 2D game engine: input handling and collision detection.

Example: controlling a car

A simple car that you can steer with the arrow keys Up – go forward Down – go back Left, right - steer

Page 13: Three a simple 2D game engine: input handling and collision detection.

Example: controlling a car tank

A simple car that you can steer with the arrow keys

Unfortunately, it’s hard to tell which way the car is facing

So we’ll use a tank

Page 14: Three a simple 2D game engine: input handling and collision detection.

The Tank class

Basically like the Obstacle class, but a slightly different draw method

[define Tank [class [Tank position]

GameObject]]

[define-method [draw [Tank t] g]

[g.DrawRectangle black-pen −12 −10 24 20]

[g.DrawRectangle black-pen 12 −2 10 4]]

Page 15: Three a simple 2D game engine: input handling and collision detection.

Controlling speed

Simple version: If they hold down the

up-arrow key Move right at 10 pixels

per second

[define-method [tick [Tank t] Δt]

[t.velocity ←

[if [key-pressed? up-arrow]

[point 10 0]

[point 0 0]]]]]

Page 16: Three a simple 2D game engine: input handling and collision detection.

Controlling speed

Simple version: If they hold down the

up-arrow key Move right at 10 pixels

per second Slightly fancier

Let them move backward

[define-method [tick [Tank t] Δt]

[t.velocity ←

[if [key-pressed? up-arrow]

[point 10 0]

[if [key-pressed? down-arrow] [point -10 0]

[point 0 0]]]]]

Page 17: Three a simple 2D game engine: input handling and collision detection.

Controlling speed

Simple version: If they hold down the

up-arrow key Move right at 10 pixels

per second Slightly fancier

Let them move backward

Oh, yea. Let them steer.

[define-method [tick [Tank t] Δt]

[t.velocity ← [rotate-vector-degrees

[if [key-pressed? up-arrow] [point 10 0] [if [key-pressed? down-arrow]

[point -10 0] [point 0 0]]]

t.orientation]]]

Page 18: Three a simple 2D game engine: input handling and collision detection.

Controlling speed

Writing it this way makes it easier to change the speed if we want to Only one number to

change

[define-method [tick [Tank t] Δt]

[t.velocity ← [× 10

[if [key-pressed? up-arrow]

1

[if [key-pressed? down-arrow]

-1

0]]

[rotate-vector-degrees [point 1 0]

t.orientation]]]]

Page 19: Three a simple 2D game engine: input handling and collision detection.

Steering

To steer Just do the same trick

with the angular velocity

Only, remember it’s a number, not a vector

[define-method [tick [Tank t] Δt]

[t.velocity ← ...]

[t.angular-velocity ← [× 30

[if [key-pressed? left-arrow]

-1

[if [key-pressed? right-arrow]

1

0]]]]

Page 20: Three a simple 2D game engine: input handling and collision detection.

Sticking to the mouse

We can force an object to follow the mouse by just setting its position to the mouse position

[define dragger [class [dragger position]

GameObject]]

[define-method [draw [dragger o] g]

[g.DrawEllipse black-pen −20 −20 40 40]]

[define-method [tick [dragger o] Δt]

[o.position ← mouse-location]]

Page 21: Three a simple 2D game engine: input handling and collision detection.

Following the mouse

We can make the object follow the mouse by setting its speed to

always be some fraction of the vector between the object and the mouse

[define Mouser [class [Mouser position]

GameObject]]

[define-method [draw [Mouser o] g]

[g.DrawEllipse black-pen −20 −20 40 40]]

[define-method [tick [Mouser o] Δt]

[o.velocity ← [× [− mouse-location

o.position]

0.5]]]

Page 22: Three a simple 2D game engine: input handling and collision detection.

Making it more interesting

We can complicate the dynamics of the ball by: Accelerating it toward

the mouse

[define SpringMouser[class [SpringMouser position]

GameObject]]

[define-method [tick [SpringMouser o] Δt]

[o.velocity ← [+ o.velocity

[× [− mouse-location

o.position]

0.1]

[× −0.001 o.velocity]]]]

Page 23: Three a simple 2D game engine: input handling and collision detection.

Making it more interesting

We can complicate the dynamics of the ball by: Accelerating it toward

the mouse Rather than moving

straight toward it

[define SpringMouser[class [SpringMouser position]

GameObject]]

[define-method [tick [SpringMouser o] Δt]

[o.velocity ← [+ o.velocity

[× [− mouse-location

o.position]

0.1]

[× −0.001 o.velocity]]]]

Page 24: Three a simple 2D game engine: input handling and collision detection.

Making it more interesting

We can complicate the dynamics of the ball by: Accelerating it toward

the mouse Rather than moving

straight toward it And adding some

damping to slow it down

[define SpringMouser[class [SpringMouser position]

GameObject]]

[define-method [tick [SpringMouser o] Δt]

[o.velocity ← [+ o.velocity

[× [− mouse-location

o.position]

0.1]

[× −0.001 o.velocity]]]]

Page 25: Three a simple 2D game engine: input handling and collision detection.

Changing the appearance slightly

We can make a filled circle rather than a normal circle

By substituting FillEllipse

For DrawEllipse

And a Brush object For a Pen

[define green-brush [new SolidBrush [color “green”]]]

[define-method [draw [SpringMouser o] g]

[g.FillEllipse green-brush

−20 −20 40 40]]

Page 26: Three a simple 2D game engine: input handling and collision detection.

Collision handling

Many games need to notice when two objects collide This is an expensive

operation It’s an on-going area

of research We’ll just talk about

the absolute dumbest version of it

[define update-objects[form →

[with* current-time = DateTime.Now Δt = [current-time.Subtract

last-time].TotalSeconds [for-all-game-objects [o → [tick o Δt]]] [for-all-game-objects

[o → [o.position ← [+ o.position [× o.velocity Δt]]] [o.orientation ← [+ o.orientation [× o.angular-

velocity Δt]]]]]

[check-collisions] [last-time ← current-time] [form.Invalidate]]]]

Page 27: Three a simple 2D game engine: input handling and collision detection.

Naïve algorithm

Compare every object to every object

Check if they’ve collided Deal with it if they have

Notes: We haven’t said how to

check whether two objects have collided

Or what to do about it

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 28: Three a simple 2D game engine: input handling and collision detection.

Computational complexity

Suppose there are n objects in the game

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 29: Three a simple 2D game engine: input handling and collision detection.

Computational complexity

Suppose there are n objects in the game Then this procedure

runs n times

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 30: Three a simple 2D game engine: input handling and collision detection.

Computational complexity

Suppose there are n objects in the game Then this procedure

runs n times But each time it runs,

this procedure runs n times!

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 31: Three a simple 2D game engine: input handling and collision detection.

Computational complexity

Suppose there are n objects in the game Then this procedure

runs n times But each time it runs,

this procedure runs n times!

So that means we do n2 collision checks

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 32: Three a simple 2D game engine: input handling and collision detection.

Computational complexity

Suppose there are n objects in the game Then this procedure

runs n times But each time it runs,

this procedure runs n times!

So that means we do n2 collision checks

Very expensive

[define check-collisions [→ [for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2] ]]]]]]]

Page 33: Three a simple 2D game engine: input handling and collision detection.

Computational complexity

The time complexity of a program is The rate at which the running time

increases With the size of its input

A linear algorithm increases about as fast as n

We then say the algorithm is O(n) A quadratic algorithm increases as

fast as n2

We then say it’s O(n2) An exponential time algorithm

increases exponentially with n Exponential algorithms are useless

unless n is very small

0

10

20

30

40

50

60

70

80

90

100

1 2 3 4 5 6 7 8 9 10

2 n̂

n 3̂

n 2̂

n

Page 34: Three a simple 2D game engine: input handling and collision detection.

Problems with the algorithm

This actually has some bugs

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 35: Three a simple 2D game engine: input handling and collision detection.

Problem 1

This will check whether each object has collided with itself It probably has …

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 36: Three a simple 2D game engine: input handling and collision detection.

Problem 1

For any two objects, x and y, it will call both [collided? x y], and [collided? y x]

[define check-collisions [→

[for-all-game-objects

[o1 → [for-all-game-objects

[o2 → [if [collided? o1 o2]

[handle-collision o1 o2]

]]]]]]]

Page 37: Three a simple 2D game engine: input handling and collision detection.

Fancy version

This version only compares objects Against objects that are later

in the list of game objects So we only compare each

pair once

However, it turns out it still has some issues, so the version we hand out may be different

[define check-collisions[→

[if collision-detection-enabled?

[with i = 0

[while [< i [length all-game-objects]]

[with o1 = [get all-game-objects i]

j = [+ i 1]

[while [< j [length all-game-objects]]

[with o2 = [get all-game-objects j]

[if [collided? o1 o2]

[handle-collision o1 o2]]

[j ← [+ j 1]]]]]

[i ← [+ i 1]]]]]]]

Page 38: Three a simple 2D game engine: input handling and collision detection.

Adding collision handling to the SpringBall example

Two balls have collided if

[define collided? [o1 o2 →

[< [magnitude [− o1.position

o2.position]]

10]]]]

[define-method [handle-collision [SpringBall o1] [SpringBall o2]]

[destroy o1]

[destroy o2]]

Page 39: Three a simple 2D game engine: input handling and collision detection.

Adding collision handling to the SpringBall example

Two balls have collided if The length

[define collided? [o1 o2 →

[< [magnitude [− o1.position

o2.position]]

10]]]]

[define-method [handle-collision [SpringBall o1] [SpringBall o2]]

[destroy o1]

[destroy o2]]

Page 40: Three a simple 2D game engine: input handling and collision detection.

Adding collision handling to the SpringBall example

Two balls have collided if The length Of the space between

them

[define collided? [o1 o2 →

[< [magnitude [− o1.position

o2.position]]

10]]]]

[define-method [handle-collision [SpringBall o1] [SpringBall o2]]

[destroy o1]

[destroy o2]]

Page 41: Three a simple 2D game engine: input handling and collision detection.

Adding collision handling to the SpringBall example

Two balls have collided if The length Of the space between

them Is less than 10 pixels

[define collided? [o1 o2 →

[< [magnitude [− o1.position

o2.position]]

10]]]]

[define-method [handle-collision [SpringBall o1] [SpringBall o2]]

[destroy o1]

[destroy o2]]

Page 42: Three a simple 2D game engine: input handling and collision detection.

Adding collision handling to the SpringBall example

When two ball collide [define collided? [o1 o2 →

[< [magnitude [− o1.position

o2.position]]

10]]]]

[define-method [handle-collision [SpringBall o1] [SpringBall o2]]

[destroy o1]

[destroy o2]]

Page 43: Three a simple 2D game engine: input handling and collision detection.

Adding collision handling to the SpringBall example

When two ball collide Blow the little buggers

away

[define collided? [o1 o2 →

[< [magnitude [− o1.position

o2.position]]

10]]]]

[define-method [handle-collision [SpringBall o1] [SpringBall o2]]

[destroy o1]

[destroy o2]]