52
M1205 Interactivity Topic 07: Interactivity for Games Spring 2011 SCM-CityU 1

SM1205 Interactivity Topic 07: Interactivity for Games Spring 2011SCM-CityU1

  • View
    230

  • Download
    3

Embed Size (px)

Citation preview

SM1205 Interactivity

Topic 07: Interactivity for Games

Spring 2011 SCM-CityU 1

Overview• Techniques – Timer and its events – Collision detection and response– for loop and Array (review)

• Main example: Air Raid – AirRaid.swf in W drive

• Release Assignment 2– See Assignment.02 folder

Spring 2011 SCM-CityU 2

Skeleton Program• AirRaid_skeleton.fla

Spring 2011 SCM-CityU 3Based on an example in book: ActionScript 3.0 Game Programming University, 2nd EditionBased on an example in book: ActionScript 3.0 Game Programming University, 2nd Edition

Frame 1

Spring 2011 SCM-CityU 4

stop();

startButton.addEventListener(MouseEvent.CLICK,clickStart); function clickStart(event:MouseEvent) {

startButton.removeEventListener(MouseEvent.CLICK,clickStart); gotoAndStop(2); // go to frame for main game

}

stop();

startButton.addEventListener(MouseEvent.CLICK,clickStart); function clickStart(event:MouseEvent) {

startButton.removeEventListener(MouseEvent.CLICK,clickStart); gotoAndStop(2); // go to frame for main game

}

Name: startButton Name: startButton

Frame 2

Spring 2011 SCM-CityU 5

Name: timeLeftTxtName: timeLeftTxt

// control the movement of the gun stage.addEventListener(MouseEvent.MOUSE_MOVE, onGunMove); function onGunMove(e:MouseEvent): void {

gun.x = e.stageX; // use mouse to control gun’s translation }

// score board initialization var shotsHit:int = 0; var timeLeft:int = 10; updateGameScore();

function updateGameScore(): void { shotsHitTxt.text = String("Score: " + shotsHit); timeLeftTxt.text = String("Time Left: " + timeLeft);

}

// control the movement of the gun stage.addEventListener(MouseEvent.MOUSE_MOVE, onGunMove); function onGunMove(e:MouseEvent): void {

gun.x = e.stageX; // use mouse to control gun’s translation }

// score board initialization var shotsHit:int = 0; var timeLeft:int = 10; updateGameScore();

function updateGameScore(): void { shotsHitTxt.text = String("Score: " + shotsHit); timeLeftTxt.text = String("Time Left: " + timeLeft);

}

Name: shotsHitTxtName: shotsHitTxt Name: gunName: gun

Frame 3

Spring 2011 SCM-CityU 6

Name: playAgainButton

Name: playAgainButton

playAgainButton.addEventListener(MouseEvent.CLICK,clickPlayAgain);

function clickPlayAgain(event:MouseEvent) {

playAgainButton.removeEventListener(MouseEvent.CLICK,clickPlayAgain);

gotoAndStop(2); // go back to main frame to restart game }

playAgainButton.addEventListener(MouseEvent.CLICK,clickPlayAgain);

function clickPlayAgain(event:MouseEvent) {

playAgainButton.removeEventListener(MouseEvent.CLICK,clickPlayAgain);

gotoAndStop(2); // go back to main frame to restart game }

SM1205 Interactivity

Timer

Spring 2011 SCM-CityU 7

Timer (ref)• Usage 1: continuous updating for every user-specified

interval (e.g., for programmatic animation)– E.g., rotating second hand per second

• timer_events.swf

– Updating frequency is specifiedby you, largely independent of Flash’s FPS setting• E.g., for every 1 second

– Cf. ENTER_FRAME: animation synchronized with Flash runtime’s frame rate • E.g., Corresponding event listener will be invoked for 30 times per

second (due to FPS = 30)

Spring 2011 SCM-CityU 8

Timer (ref)• Usage 2: count down – Allowing to perform certain action after a given time period

Spring 2011 SCM-CityU 9

Creating Timers • Timer is a complex data type – Syntax of variable definition for complex data type

• Number of parameters can be zero, e.g., our SymbolDuck from last class (data type by us) – var duck:SymbolDuck = new SymbolDuck();

Spring 2011 SCM-CityU 10

var varName:ComplexType = new ComplexType(para1, …, para2);

var varName:ComplexType = new ComplexType(para1, …, para2);

Creating Timers • Timer has two parameters (ref)

– interval: in milliseconds between timer event• TimerEvent.TIMER event happens whenever a timer reaches the

specified interval – E.g., if interval = 1000, there is a TimerEvent.TIMER event for every second – An interval lower than 20 milliseconds is NOT recommended (too fast), which may

causes runtime problems

– repeatCount: total number of TimerEvent.TIMER needed• E.g., if repeatCount = 10, the timer will stop after 10

TimerEvent.TIMER events are completed;it will then trigger a TimerEvent.TIMER_COMPLETE

• If zero (by default), the timer repeats infinitely

Spring 2011 SCM-CityU 11

Timer(interval:Number, repeatCount:int = 0)Timer(interval:Number, repeatCount:int = 0)

Starting/Stopping Timers• Timer instance will not start to invoke events until you call its

start() method– If your timer doesn’t work, it is often because you forget to start the timer

(common problem)!

• To stop the timer, call its stop() method

Spring 2011 SCM-CityU 12

var timer:Timer = new Timer(1000, 2);

timer.addEventListener(TimerEvent.TIMER, onTimer);

timer.start();

var i:int = 0; function onTimer(e:TimerEvent): void {

i++; trace("number of repetitions", i);

}

var timer:Timer = new Timer(1000, 2);

timer.addEventListener(TimerEvent.TIMER, onTimer);

timer.start();

var i:int = 0; function onTimer(e:TimerEvent): void {

i++; trace("number of repetitions", i);

}

Example

Spring 2011 SCM-CityU 13

var timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER, onTimer); timer.start();

function onTimer(evt:TimerEvent):void { watch.hand.rotation +=5; }

var timer:Timer = new Timer(1000); timer.addEventListener(TimerEvent.TIMER, onTimer); timer.start();

function onTimer(evt:TimerEvent):void { watch.hand.rotation +=5; }

Class Exercise• New year countdown – Count down from 10 to 1

• Output one number per second

– Output “Happy New Year” 1 second after “1” is outputted • I.e., output “Happy New Year”

instead of “0”

– Hint: we need to output 11 messages, one per second

Spring 2011 SCM-CityU 14

for Loop vs ENTER_FRAME/Timer

• All of them allow repetitive execution of some code

• However, unlike ENTER_FRAME or Timer, for loop itself is NOT sufficient for creating animation– Because of no frame refreshing for individual (for) iterations

• E.g., NoAnimationWithForLoop.fla vs AnimationWithTimer.fla

Spring 2011 SCM-CityU 15

var speed:Number = 10; for (var i:uint = 0; i < 20; i++) {

circle.x += speed; circle.y += speed;

}

var speed:Number = 10; for (var i:uint = 0; i < 20; i++) {

circle.x += speed; circle.y += speed;

}Direct jumpingDirect jumping

Back to Main Example• Task: creating multiple planes in a random manner– Random intervals: use Timer – Random side: starting from either left or right – Random speed: random velocity; direction is dependent on

which side the plane comes from– Random altitude – Random plane shape: one out of 5 plane models

Spring 2011 SCM-CityU 16

Random Intervals • It seems easy to make timer interval random– E.g., var t:Timer = new Timer(100+100*Math.random());

• But such solution still cannot make the delay for creating individual planes random – E.g., waiting for 1 second before creating Plane 1; waiting for

0.78 second before creating Plane 2

• In fact, with such timer, every plane will be created for a fixed interval

Spring 2011 SCM-CityU 17

Random Intervals • Solution

– setTimer function below initializes a timer with random interval. This function will be repeated at random intervals

Spring 2011 SCM-CityU 18

var t:Timer; setTimer();

function setTimer(): void { t = new Timer(1000+Math.random()*1000, 1); t.addEventListener(TimerEvent.TIMER_COMPLETE, timerComplete); t.start();

}

function timerComplete(e:TimerEvent): void { // create a plane // ...

// for next timer with random interval setTimer();

}

var t:Timer; setTimer();

function setTimer(): void { t = new Timer(1000+Math.random()*1000, 1); t.addEventListener(TimerEvent.TIMER_COMPLETE, timerComplete); t.start();

}

function timerComplete(e:TimerEvent): void { // create a plane // ...

// for next timer with random interval setTimer();

}

Example• TimerWithRandomInterval.fla

Spring 2011 SCM-CityU 19

Review: Dynamically Creating Display Objects in AS

1. Create a class name for your symbol – E.g., MySymbol

2. Create a symbol instance in AS– E.g., var s:MySymbol = new MySymbol();

3. Display it to stage – addChild(s);

Spring 2011 SCM-CityU 20

Review: Instance Name vs Class Name

• Instance name: like variable name in AS– If your AS wants to directly assess some existing symbol instance on

stage, assign instance name

• Class name: like data type in AS– If your AS wants to dynamically create new symbol instances, create

class name for your symbol!• Class naming style is the same as

variable/instance naming style

Spring 2011 SCM-CityU 21

This name has no special usageThis name has

no special usage

Spring 2011 SCM-CityU 22

Scope of Variables • Local variables

– Defined in function bodies (in-between function {})– Can be used only within the function where variables are

created– Can prevent

name collision

• Global variables– Can be

accessedeverywhere

Spring 2011 SCM-CityU 23

var v01:Number = 3; // global variable

function show1() : void { var v02: Number = 4; // local variable var v03: Number = 5; // local variable trace(v01); // 3}

function show2() : void { var v02:Number = 6; // local variable trace(v02); // 6 trace(v03); // compilation error: local variable in show1}

show1();show2(); trace(v01); // 3trace(v02); // compilation error: local variable in show1/show2trace(v03); // compilation error: local variable in show1

var v01:Number = 3; // global variable

function show1() : void { var v02: Number = 4; // local variable var v03: Number = 5; // local variable trace(v01); // 3}

function show2() : void { var v02:Number = 6; // local variable trace(v02); // 6 trace(v03); // compilation error: local variable in show1}

show1();show2(); trace(v01); // 3trace(v02); // compilation error: local variable in show1/show2trace(v03); // compilation error: local variable in show1

Random Speed • Each plane has a random speed • How to store such set of random speed values?

• Solution 1: create another array to store speed values

– For plane planes[i], its corresponding speed is planeSpeedArray[i]

Spring 2011 SCM-CityU 24

var planeSpeedArray:Array = new Array();

Random Speed • Solution 2: associate speed directly with each plane

(much simpler!) – Airplane is a complex data type– For complex data type, you can create temporary properties

by assignment operator • Such temporary properties behave exactly the same as predefined

properties like x, y, alpha etc.

• You might use any valid variable name as property name, e.g.,

Spring 2011 SCM-CityU 25

p.speed = Math.random() * 8 + 3; p.speed = Math.random() * 8 + 3;

p.speedX = Math.random() * 8 + 3; p.speedX = Math.random() * 8 + 3;

Random Side• Originally planes are designed for right-to-left flight • Need to flipping shape for planes from left border – By setting scaleX = -1

• Exact transformation will depend on the location of registration point – E.g., example below has registration at top-left corner

Spring 2011 SCM-CityU 26

x

Y

x

Y

scaleX = -1

Spring 2011 SCM-CityU 27

Class Exercise • Task: fire a bullet for each mouse click

– Create an Array: name bullets– Add event listener for MouseEvent.CLICK– Inside this event listener, create a bullet and add it to stage

• In this exercise, don’t bother the movement of bulletsSpring 2011 SCM-CityU 28

Make Planes Moving

• Review: for loop structure– Starting with for keyword

– Example

Spring 2011 SCM-CityU 29

for (declare counter; condition; update counter) { // statement(s) to execute repeatedly // as long as condition is true

}

for (declare counter; condition; update counter) { // statement(s) to execute repeatedly // as long as condition is true

}

for (var i:int = 1; i <= 100; i++) { trace(i);}

for (var i:int = 1; i <= 100; i++) { trace(i);}

SCM-CityU 29

Make Planes Moving• Class exercise – Make each plane planes[i] move at speed of planes[i].speed– Hint: use for loop to access every plane in planes array

Spring 2011 SCM-CityU 30

Removing Off-Screen Planes• Since we’re keeping inserting new planes, we have to

remove planes that are off screen – Otherwise we’ll lead to many unused planes in RAM

• But how? – Question 1: how to check?

• Depending on flight direction– (p.speed < 0 && p.x < 0) || (p.speed > 0 && p.x > stage.stageWidth)

– Question 2: how to remove such planes from stage and planes array?• Removal from stage is easy. Just use removeChild(plane); • How to remove all off-screen planes from the array?

– Use Array.pop()? But this removes the last element of the array only. What if the element to be removed has an arbitrary index?

Spring 2011 SCM-CityU 31

Removing Off-Screen Planes from Array

• Solution: use Array’s splice method (ref)– splice(startIndex:int, deleteCount:uint): Array;

• startIndex: where the deletion begins • deleteCount: number of elements to be deleted • Returning an array containing the elements that were removed

Spring 2011 SCM-CityU 32

var vegetables:Array = new Array("spinach", "green pepper", "cilantro", "onion",

"avocado");

// remove 2 elements starting at index 2var spliced:Array = vegetables.splice(2, 2);

trace(vegetables); // spinach,green pepper,avocado trace(spliced); // cilantro,onion

var vegetables:Array = new Array("spinach", "green pepper", "cilantro", "onion",

"avocado");

// remove 2 elements starting at index 2var spliced:Array = vegetables.splice(2, 2);

trace(vegetables); // spinach,green pepper,avocado trace(spliced); // cilantro,onion

Removing Off-Screen Planes from Array

• How can we use splice together with for loop?• For example, how to remove all elements that are equal to 3

from an array below?

• Above solution is wrong! Why?

Spring 2011 SCM-CityU 33

var a:Array = [3, 3, 5, 6, 7, 3, 3, 5, 7, 3];

for (var i:uint = 0; i < a.length; i++) { if (a[i] == 3) {

a.splice(i, 1); trace(a);

} }

trace("final: ", a);

var a:Array = [3, 3, 5, 6, 7, 3, 3, 5, 7, 3];

for (var i:uint = 0; i < a.length; i++) { if (a[i] == 3) {

a.splice(i, 1); trace(a);

} }

trace("final: ", a);

Removing Off-Screen Planes from Array

• Some 3 cannot be removed successfully!

Spring 2011 SCM-CityU 34

3 3 5 6 7 3 3 5 7 3

i=0

3 5 6 7 3 3 5 7 3

i=1

First 3 is sliced and i++

Iteration 0

Iteration 1

Removing Off-Screen Planes from Array

• Correct solution: bottom-up iteration

Spring 2011 SCM-CityU 35

var a:Array = [3, 3, 5, 6, 7, 3, 3, 5, 7, 3];

for (var i:int = a.length -1; i >=0; i--) { if (a[i] == 3) {

a.splice(i, 1); trace(a);

} }

trace("final: ", a);

var a:Array = [3, 3, 5, 6, 7, 3, 3, 5, 7, 3];

for (var i:int = a.length -1; i >=0; i--) { if (a[i] == 3) {

a.splice(i, 1); trace(a);

} }

trace("final: ", a); 3 3 5 6 7 3 3 5 7 3

i=9

i=8

Iteration 0

Iteration 1 3 3 5 6 7 3 3 5 7

Class Exercise

• Task: making bullets moving! – You can get the ideas from movePlanes function

Spring 2011 SCM-CityU 36

Next Step

• Check if any bullet hits any plane

Spring 2011 SCM-CityU 37

SM1205 Interactivity

Collision Detection & Response

Spring 2011 SCM-CityU 38

Collision Detection (wiki)• Building block for many applications, e.g., games– Detecting if objects intersect with each other

• Detection complexity depends on shape complexity

Spring 2011 SCM-CityU 39

Collision Detection in AS• Collision against stage borders or other boundaries

Spring 2011 SCM-CityU 40

Collision Detection in AS

• Collision between complex objects

• Use DisplayObject’s hitTestObject method or hitTestPoint method

• E.g., bird.hitTestObject(wall);

Spring 2011 SCM-CityU 41

hitTestObject Method (ref)

Spring 2011 SCM-CityU 42

• Check if bounding boxes of two display objects intersect with each other– Check if two corresponding rectangles overlap or not – E.g., bird.hitTestObject(wall);– Return true if intersection detected; false otherwise.

Example • Decrease HP points when collision is detected– Start with

skeleton program in W drive

Spring 2011 SCM-CityU 43

hp

hill

wall

bird

bird.hitTestObject(wall)

hill.hitTestObject(bird)

Equivalent testing

Class Exercise • Task: detect if there is collision between bird and hill

Spring 2011 SCM-CityU 44

bird

hill

Weakness of hitTestObject Method

• It is possible that – Display objects do not intersect with each other– But their bounding boxes do intersect

Spring 2011 SCM-CityU 45

hitTestPoint Method (ref)

• obj.hitTestPoint(x, y, shapeFlag)– Detect if point (x, y) intersects with obj• If shapeFlag == true, detection is done against object

shape• If shapeFlag == false, detection is done against bounding

box of the object

– E.g., hill.hitTestPoint(mouseX, mouseY, true)

Spring 2011 SCM-CityU 46

(x,y)(x,y)

shapeFlag == trueshapeFlag == false

Collision Detection in AS• How to detect collision between objects with complex shapes? • Approximate solution

– Sample the boundary of one object into a set of points {pi}

– For every pi, check if it intersects with another shape • Using shapeA.hitTestPoint(pi.x, pi.y, true);

Spring 2011 SCM-CityU 47

p0

p1

p2

p3

p4

p5

p6

p7

p8

p9Shape A

Class Exercise

• Check if any bullet hits any plane

• Hint: use nested for loop– For every bullet b • For every plane p

– Do hit test on the pair of b and p

Spring 2011 SCM-CityU 48

Avoid Getting Hit Twice• How to avoid any plane or bullet getting hit twice?

– Simply removing bullets/planes from stage and array • Use Array’s splice method • Traverse array in bottom-up manner

• If a bullet hits any plane, it is meaningless to compare it with the other plane elements in planes array

• We need to immediatelly exit the inner loop if any hit is detected – Use break key word

Spring 2011 SCM-CityU 49

// for each bulletfor (var bi:int = bullets.length-1; bi >= 0; bi--) {

// for each planefor (var ai:int = planes.length-1; ai >= 0; ai--)

{// splicing elements below

}}

// for each bulletfor (var bi:int = bullets.length-1; bi >= 0; bi--) {

// for each planefor (var ai:int = planes.length-1; ai >= 0; ai--)

{// splicing elements below

}}

Early Exit of for Loop• Break statement causes inner-most loop to be

terminated immediately

Spring 2011 SCM-CityU 50

for (var i:int = 0; i <= 10; i++) { if (i == 8) {

break; // exit the loop

} trace (i); }

for (var i:int = 0; i <= 10; i++) { if (i == 8) {

break; // exit the loop

} trace (i); }

for (var i:int = 0; i <= 10; i++) { for (var j:int = 0; j <= 15; j++) {

if (j == 8) { break; // exit inner loop only

} trace(i, j);

} }

for (var i:int = 0; i <= 10; i++) { for (var j:int = 0; j <= 15; j++) {

if (j == 8) { break; // exit inner loop only

} trace(i, j);

} }

Plane Explosion Effect• What if we want to play some animation for plane

explosion? – We cannot immediately remove the hit plane from

stage/array

• How can we still avoid getting hit twice?– Solution

• Marking hit planes alive = false – By introducing a temporary property

• Hit test will not be done for planes with alive = false• Such hit planes will be automatically removed from stage/array

when they are off screen Spring 2011 SCM-CityU 51

Class Exercise • Add time constraint to the game

– E.g., shot as many planes as possible within 30 seconds

• Hints– Add another timer – Update timeLeftTxt text field with the time left

• Listening for TimerEvent.TIMER

– Jump to game over frame when the timer is completed • Listening for TimerEvent.TIMER_COMPLETE • Be aware to stop timers and remove event listeners at current frame

before jumping • Remove remaining planes and bullets as well

Spring 2011 SCM-CityU 52