[first slide]

Introduction to Object Oriented Programming

Timothy A. Budd

Chapter 7

Case Study: A Billiards Game

Outline

  1. Purpose of Chapter
  2. Picture of Billiards Table
  3. Graphical Object Class
  4. Objects must be initialized
  5. Graphical Objects can Draw themselves
  6. Objects can be Hit
  7. Balls move when updated
  8. Reaction to Mouse Down Events
  9. Using Inheritance
Source Code

Other Material

Intro OOP, Chapter 7, Slide 1


Purpose of Chapter

The purpose of this chapter is to once again illustrate the design of a program as a universe of interacting agents working together to produce the desired outcome.

Intro OOP, Chapter 7, Slide 1


Picture of Billiards Table


picture of billiards table
Not pool, not really billiards, but a bunch of balls bouncing around.
Intro OOP, Chapter 7, Slide 2


Graphical Object Class

Every graphical object has a link field and a region of space.

Wall = object 
	link : Wall;        (* data fields *)
	region : Rect;
		(* factor used to reflect striking balls *)
	convertFactor : real;

	procedure initialize  (* initialization function *)
		(left, top, right, bottom : integer; cf : real);

	procedure draw;	 (* draw wall *)

		(* notify wall that a ball has struck *)
	procedure hitBy (aBall : Ball);
end;
Intro OOP, Chapter 7, Slide 3


Objects must be initialized

procedure Wall.initialize 
	(left, top, right, bottom : integer; cf : real);
begin
		(* initialize conversion factor *)
	convertFactor := cf;
	link := nil;
	
		(* set up region for wall *)
	SetRect (region, left, top, right, bottom);
end;
Intro OOP, Chapter 7, Slide 4


Graphical Objects can Draw themselves

procedure Wall.draw;
begin
	PaintRect (region);
end;

procedure hole.draw;
begin
	PaintOval (region);
end;

procedure Ball.draw;
begin
	if self = CueBall then
			(* draw an open circle *)
		FrameOval (region)
	else
			(* draw a filled circle *)
		PaintOval (region)
end;
Intro OOP, Chapter 7, Slide 5


Objects can be Hit

procedure Wall.hitBy (aBall : Ball);
begin
		(* bounce the ball off the wall *)
	aBall.setDirection(convertFactor - aBall.direction);
end;

procedure Hole.hitBy (aBall : Ball);
begin
		(* drain energy from ball, remove it *)
	aBall.energy := 0.0;
	aBall.erase;
		(* move ball *)
	if aBall = CueBall then
		aBall.setCenter(50, 100)
	else begin
		saveRack := saveRack + 1;
		aBall.setCenter (10 + saveRack * 15, 250);
	end;
	(* redraw ball *) aBall.draw;
end;

procedure Ball.hitBy (aBall : Ball);
var
	da : real;
begin
		(* cut the energy of the hitting ball in half *)
	aBall.energy := aBall.energy / 2;

		(* and add it to our own *)
	energy := energy + aBall.energy;

		(* set our new direction *)
	setDirection(hitAngle(self.x - aBall.x, self.y - aBall.y));

		(* and set the hitting balls direction *)
	da := aBall.direction - direction;
	aBall.setDirection (aBall.direction + da);
end;
Intro OOP, Chapter 7, Slide 6


Balls move when updated

procedure Ball.update;
var
	hptr : Hole;
	wptr : Wall;
	bptr : Ball;
	dx, dy : integer;
	theIntersection : Rect;
begin
	if energy > 0.5 then begin
		ballMoved := true;
			(* erase ball *)
		erase;
			(* decrease energy *)
		energy := energy - 0.05;
			(* move ball *)
		dx := trunc(5.0 * cos(direction));
		dy := trunc(5.0 * sin(direction));
		offsetRect(region, dx, dy);
			(* redraw ball *)
		draw;
			(* see if we hit a hole *)
		hptr := listOfHoles;
		while (hptr <> nil) do 
			if SectRect (region, hptr.region, 
				theIntersection) then begin
				hptr.hitBy(self);
				hptr := nil;
			end
			else
				hptr := hptr.link;

			(* see if we hit a wall *)
		wptr := listOfWalls;
		while (wptr <> nil) do 
			if SectRect (region, wptr.region, 
				theIntersection) then begin
				wptr.hitBy(self);
				wptr := nil;
			end
			else
				wptr := wptr.link;

			(* see if we hit a ball *)
		bptr := listOfBalls;
		bhit := nil;
		while (bptr <> nil) do 
			if (bptr <> self) and 
				SectRect (region, bptr.region, 
				theIntersection) then begin
				bptr.hitBy(self);
				bptr := nil;
			end
			else
				bptr := bptr.link;
	end;
end;
Intro OOP, Chapter 7, Slide 7


Reaction to Mouse Down Events

procedure mouseButtonDown (x, y : integer);
var
	bptr : Ball;
begin
		(* give the cue ball some energy *)
	CueBall.energy := 20.0;
		(* and a direction *)
	CueBall.setDirection(hitAngle (cueBall.x - x, cueBall.y - y));
		(* then update as long as any ball moves *)
	ballMoved := true;
	while ballMoved do begin
		ballMoved := false;
		bptr := listOfBalls;
		while bptr <> nil do begin
			bptr.update;
			bptr := bptr.link;
		end;
	end;
end;
Intro OOP, Chapter 7, Slide 8


Using Inheritance

The program can be greatly simplfied by making all graphical objects inherit from a common base class.

We will have much more to say about inheritance, and the power that comes from the use of inheritance, in subsequent chapters.

Intro OOP, Chapter 7, Slide 9