Programming Video

Games for the

Evil Genius

Evil Genius Series

Bionics for the Evil Genius: 25 Build-it-Yourself MORE Electronic Gadgets for the Evil Genius: Projects

40 NEW Build-it-Yourself Projects

Electronic Circuits for the Evil Genius: 57 Lessons 101 Spy Gadgets for the Evil Genius

with Projects

123 PIC® Microcontroller Experiments for the Evil Electronic Gadgets for the Evil Genius:

Genius

28 Build-it-Yourself Projects

123 Robotics Experiments for the Evil Genius Electronic Games for the Evil Genius

PC Mods for the Evil Genius: 25 Custom Builds to Electronic Sensors for the Evil Genius:

Turbocharge Your Computer

54 Electrifying Projects

Programming Video Games for the Evil Genius 50 Awesome Auto Projects for the Evil Genius Solar Energy Projects for the Evil Genius

50 Model Rocket Projects for the Evil Genius 25 Home Automation Projects for the Evil Genius Fuel Cell Projects for the Evil Genius

Mechatronics for the Evil Genius:

25 Build-it-Yourself Projects

Programming Video

Games for the

Evil Genius

IAN CINNAMON

New York

Chicago

San Francisco

Lisbon

London

Madrid

Mexico City

Milan

New Delhi

San Juan

Seoul

Singapore

Sydney

Toronto

Copyright © 2008 by The McGraw-Hill Companies, Inc. All rights reserved. Manufactured in the United States of America. Except as permitted under the United States Copyright Act of 1976, no part of this publication may be reproduced or distributed in any form or by any means, or stored in a database or retrieval system, without the prior written permission of the publisher.

0-07-164353-2

The material in this eBook also appears in the print version of this title: 0-07-149752-8.

All trademarks are trademarks of their respective owners. Rather than put a trademark symbol after every occurrence of a trademarked name, we use names in an editorial fashion only, and to the benefit of the trademark owner, with no intention of infringement of the trademark. Where such designations appear in this book, they have been printed with initial caps.

McGraw-Hill eBooks are available at special quantity discounts to use as premiums and sales promotions, or for use in corporate training programs.

For more information, please contact George Hoare, Special Sales, at george_hoare@mcgraw-hill.com or (212) 904-4069.

TERMS OF USE

This is a copyrighted work and The McGraw-Hill Companies, Inc. (“McGraw-Hill”) and its licensors reserve all rights in and to the work. Use of this work is subject to these terms. Except as permitted under the Copyright Act of 1976 and the right to store and retrieve one copy of the work, you may not decompile, disassemble, reverse engineer, reproduce, modify, create derivative works based upon, transmit, distribute, disseminate, sell, publish or sublicense the work or any part of it without McGraw-Hill’s prior consent. You may use the work for your own noncommercial and personal use; any other use of the work is strictly prohibited. Your right to use the work may be terminated if you fail to comply with these terms.

THE WORK IS PROVIDED “AS IS.” McGRAW-HILL AND ITS LICENSORS MAKE NO GUARANTEES OR WARRANTIES AS TO THE

ACCURACY, ADEQUACY OR COMPLETENESS OF OR RESULTS TO BE OBTAINED FROM USING THE WORK, INCLUDING ANY INFORMATION THAT CAN BE ACCESSED THROUGH THE WORK VIA HYPERLINK OR OTHERWISE, AND EXPRESSLY DISCLAIM ANY

WARRANTY, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO IMPLIED WARRANTIES OF MERCHANTABILITY OR FIT-NESS FOR A PARTICULAR PURPOSE. McGraw-Hill and its licensors do not warrant or guarantee that the functions contained in the work will meet your requirements or that its operation will be uninterrupted or error free. Neither McGraw-Hill nor its licensors shall be liable to you or anyone else for any inaccuracy, error or omission, regardless of cause, in the work or for any damages resulting therefrom. McGraw-Hill has no responsibility for the content of any information accessed through the work. Under no circumstances shall McGraw-Hill and/or its licensors be liable for any indirect, incidental, special, punitive, consequential or similar damages that result from the use of or inability to use the work, even if any of them has been advised of the possibility of such damages. This limitation of liability shall apply to any claim or cause whatsoever whether such claim or cause arises in contract, tort or otherwise.

DOI: 10.1036/0071497528

Professional

Want to learn more?

We hope you enjoy this

McGraw-Hill eBook! If

you’d like more information about this book,

its author, or related books and websites,

please click here.

For more information about this title, click here

Contents

Foreword

vii

Project 20: Getting Smarter ...

102

Project 21: Showdown

106

Introduction

ix

Acknowledgments

xi

Tic-Tac-Toe Boxing

The Compiler

xii

Project 22: The Ring

111

Project 23: Fight!!!

115

1 Java Jumpstart

1

Project 24: Knock Out

120

This tutorial section systematically provides

Project 25: Championship

127

all basic skills necessary to program the

4

Shoot-’Em-Up Games

137

games in this book ... and beyond.

Snake Pit

Project 1: The Repeater

1

Project 26: The Arena

137

Project 2: Guess the Password

3

Project 27: Snake Bait

140

Project 3: Number Cruncher

7

Project 28: Snake Bite!

146

Project 4: Number Cruncher Extreme

10

Project 29: King Cobra

151

Project 5: Crack the Code

14

Project 6: Virtual Game Library

17

Space Destroyers

Project 7: Virtual Game Library

Project 30: The Landscape

157

Pro Edition

20

Project 31: Lasers

160

Project 8: Number Guesser

22

Project 32: Retaliation

165

Project 33: Life and Death

174

2 Racing Games

27

Radical Racing

5

Strategy Games

183

Project 9: The Track

27

Bomb Diffuser

Project 10: The Cars

32

Project 34: Bomb Squad Noob

183

Project 11: Collision!

37

Project 35: Expert Diffuser

186

Project 12: Customizing

45

Project 36: Kaboom!!!

191

Project 37: Rising Through the Ranks

197

Screen Skier

Project 13: The Slope

55

Trapper

Project 14: Practice Run

60

Project 38: Men on the Move

202

Project 15: Expert Slope

66

Project 39: Setting the Trap

206

Project 16: Bulldozer

75

Project 40: Trapped!

210

Project 17: Competition

84

Project 41: Showdown

215

3.

Board Games

95

6

Retro Games

221

Whack-an Evil Genius

Oiram

Project 18: The Lab

95

Project 42: The Platform

221

Project 19: Quick! Get ’em!

98

Project 43: Go, Oiram, Go

224

v

Project 44: Bad Guys

230

Project 51: Match Time

269

Project 45: Complicated World

237

Project 52: Beat the Clock

274

Project 53: Photo Finish

280

Java Man

Project 46: Java Man’s Universe

245

Ian Says

Project 47: Java Man Lives!

247

Project 54: Color Quad

289

Project 48: C++ Attacks

251

Project 55: Brain Drain

293

Project 49: Obituaries

257

Project 56: More Rounds,

More Frustration

300

7

Brain Busters

265

Project 57: Play Accessories

307

Memory

Project 50: Grid Design

265

Index

317

Contents

vi

Foreword

Years ago, Ian Cinnamon attended iD Tech Camps Ian, now just 15 years old, has become a luminary at our UCLA location. Ian received programming for his generation. His book, Programming Video instruction in C++ and Java. Year after year, Ian Games for the Evil Genius, offers a step-by-step continued to attend camp, and his programming

approach to programming video games—a dream

prowess grew steadily—but it became apparent

for many young kids.

that he was outpacing his peers and needed new I hear it all the time... “I wish I knew how to challenges.

program my own game,” and “I don’t know where

His instructors commented that Ian was a

to start.” My suggestion is to attend iD Tech

“sponge,” and grasped the programming

Camps and to grab a copy of Ian’s book. The

curriculum quickly—as if he would go home and

crucial steps are knowing where to go and diving study and read and solve problems on his free

in to get started. Ian is empowering his generation time. It turns out, he was doing just that.

and demystifying the code behind games. I can’t I got the opportunity to meet Ian two summers ago wait to see where Ian will be in the next five at our Stanford University location. Ian is a fine years... ten years. Just watch out.

young man with great manners, excellent social skills, and, obviously, some serious programming Pete Ingram-Cauchi

talent. He is one of the best programmers I have seen President and CEO, iD Tech Camps,

at iD Tech Camps, which is an impressive statistic internalDrive, Inc.

considering the thousands of programmers who have graduated from iD Tech Camps over the years.

vii

ABOUT THE AUTHOR

Ian Cinnamon is a 15-year old phenom who has been programming for over 7 years, and is certified in both Java and C++. He is currently a sophomore at Harvard-Westlake School in Los Angeles, California.

viii

Introduction

Board games—Mental minefields to drive you Master your gaming universe

crazy! Games and mazes that make you outthink, outwit, outmaneuver your adversaries! Frustrate What’s better than playing video games? Creating your opponents and bring them to their knees.

your own video games! Games you design, games

Think Tic-Tac-Toe on steroids.

you control ... games played by your rules.

Shoot-’em-up games—Games of lightning When you buy an off-the-shelf game at your

reflex and nerve-wracking action! Transform into a local big box store, it is often the result of months, soldier, a snake handler, an alien warrior, or a sometimes years, of effort by a small army of

stone-throwing Neanderthal as you take aim within professionals using highly complex programming the world you create.

aided by the newest, most powerful computers.

Strategy games—Trap your opponents in an But the one thing they don’t have to make the

escape-proof box or diffuse a bomb before it can perfect game is you, the Game Creator.

destroy the earth! Either way, sweat the challenge.

You are the master of your gaming universe.

Cool heads and fast thinking required.

You create the world you want. You set

Retro games—Have the classics your way!

background colors, levels of difficulty, the shape of Make variations to Mario and Pac-Man by

the game board/playing field, and cheat codes. You programming new twists and turns that make these invent the characters, you design the challenge, old games new again.

you choose how points are scored and how players win ... or lose.

Brain Buster games—Do you have a good memory? Do you perform well under pressure?

If you can think it, you can program it.

Hope so, because in these games, you live or die by what you recall. Make it as simple or as

Your personal video game arcade

complex as your courage allows.

Do you ever get bored playing the same game over and over? Not anymore. You can build an

Programming: the language of games

assortment of games with endless variations. In these pages, you’ll find the secrets to building In music, there are notes; in mathematics, there racing games, board games, shoot-’em-up games, are equations; in language, there are words; and in strategy games, retro games, and brain buster

the video game world, there are commands which games.

bring life to your games. This is called

programming. This is how you tell the computer

Racing games—Get your adrenaline what you want it to do.

pumping! Construct games in which you race

against time, an opponent, or even yourself. Speed All the games you create will be written in Java, and precision rule the road as you zoom around in the most universal of programming languages.

cars, rockets, broomsticks, skis—whatever mode What if you know absolutely nothing about

of transportation your evil genius mind can

programming? What if you have no idea how a

conjure.

computer turns your ideas into actions and images?

ix

No worry! I will lead you step by step through

Comments: Allows you to mark your code, so the basics of this very versatile language.

you know what each line is doing.

Once you have experienced Programming

Flow control: Allows you to repeat code. This is Video Games for the Evil Genius, you’ll not great when you want to retry the game.

only have a library of awesome, personalized

Variables: This is how you keep track of a games, but you’ll be a skilled game creator,

player’s score, name, level, etc.

as well.

“If” statements: Lets you test your variables with conditionals. For example, if you kill an The building blocks to game creation

enemy, your score goes up.

Programming is made up of several building

JOptionPane: Want to display a player’s score?

blocks. You’ll learn them all easily as we go

Want to get a player’s name for a high score list?

through each one step-by-step. Screen shots are This is how you get input and output.

your guide as you master these critical tools. It’s

Random numbers: The gateway to artificial fool-proof. And, like riding a bicycle, once you intelligence. If you want to make an enemy move know how, you never forget.

randomly, you’re at the right building block.

If you are new to programming, Section 1 offers

Pausing: Allows your game to refresh so that a speed-of-light review. If you have previous

your graphics remain crisp and clear.

programming experience, you may want to

Arrays and ArrayLists: Saves time by grouping proceed ahead to Section 2.

similar objects together (enemies, power-ups, etc.).

Some of the programming building blocks used

File IO (Input/Output): Allows you to save the for game creation include:

game ... handy when the boss comes in

Statements: Command central, the backbone of unexpectedly and you’ve been playing video

all games.

games instead of working.

Introduction

x

Acknowledgments

You would not be reading this book if it weren’t Judy Bass, my editor at McGraw-Hill – her

for the dedication and support from the following enthusiasm for this project and her faith in

people:

me from the very beginning will always be

My parents – their unwavering love,

valued.

encouragement, help, and even jokes have been

Pete Ingram-Cauchi, the CEO of iD Tech

vital to writing this book. They’ve always been Camps – his courses at UCLA and Stanford

there for me and I know they always will. I love ignited my enthusiasm for all things

you, Mom and Dad.

programming.

My little sister, Molly – she is my unofficial publicist, telling everyone she meets to buy this book.

xi

The Compiler

Getting your computer to listen to you

You only need three things to start making your own games—a computer (PC, Mac, or Linux), this book ...

and a compiler. This software program translates your code into a language your computer can understand. If you don’t already have a compiler, it can be downloaded FREE through the Internet.

To install Java and its compiler, go to java.sun.com and click on “Java SE” to the right under “Popular Downloads.”

Click “Get the JDK 6 with NetBeans 5.5”; JDK stands for Java Development Kit. This will allow the computer to understand the code. NetBeans is an IDE (Integrated Development Environment) which makes code writing easier.

Install NetBeans by clicking on the setup icon.

Now, the interface: Click “File”>”New Project”

xii

The Compiler

Click “Java Application”

Click “Next” and type in the Project name. It should begin with an uppercase letter and have no spaces.

xiii

Click “Finish.”

In order to create an environment in which you can write your own code, start by deleting “Main.java,”

then right click on the parent folder, and click “New” > “Empty Java File ...”

The Compiler There’s just one thing left to do ... take over the video gaming world!

xiv

Section One

Java Jumpstart

Project 1: The Repeater

Project

Variables are the same as they are in algebra

(2 x = 4), except they store more than just numbers.

Type a message, press two buttons, and the

We’ll learn more about them in the next project.

computer will repeat it.

Flow control

New building blocks

This lets you manipulate what statements to use.

Classes, Statements, Variables

More about this later (Section 1, Project 4).

When first learning Java, there are four essential Every Java program exists within a container

types of code to know: Comments, Statements,

called a Class. A class is created with the

Declarations, and Flow Control.

following code:

public class <class name>

Comments

The class name should always match the file

Comments always begin with //

name, which should always begin with a capital letter and have no spaces.

Compilers ignore comments.

To show that certain code belongs to a class, use They are only used so the programmer can

the {character after the class name and} after document the code. The documentation lets you edit the code.

the code later with ease. Once the code increases to hundreds of lines long, it is extremely difficult to Inside a class, Java will search for the main

remember the function of each line. This will help.

method. A method is a group of code that can be run multiple times. The main method is a special method—Java always calls it first (runs the code Statements

in it). This is what it looks like:

These let you do things! Like printing to the screen ...

public static void main (String[] args)

They always end in semicolons.

For now, just know that this line of code must be present for the main method. We’ll learn what each Declarations

word means later.

Within a class (outside of a method) there can Declarations use statements to create or modify only be declarations and comments. These variables.

declarations are called class variables. Within a 1

Figure 1-1

This code outputs text to the screen

class and a method, there can be declarations, Escape Sequence

Result

comments, flow control, and statements. Class

\n

Creates a new line

variables can be accessed by all methods; method

\t

Indents the line (creates a tab)

variables can only be accessed by the method in

\”

Lets you quote within a quote.

which they are created.

Here is a sample statement, which is also illustrated in Figure 1-1, that lets you print to the screen: Making the game

System.out.println(“This stuff in quotes

So ... if you want to make a program to repeat the is displayed.”);

text you have entered, you must create a class, This code is a method that Java makes for us.

write a main method, and add the

All we need to do is tell it what to display (the System.out.println() code. Whatever you put

words in quotes).

in the quotes, the computer will repeat.

Within quotes, there are escape sequences. These Try this on your own. If it works, you win!

sequences let you manipulate the text in cool ways.

Proceed to the next project.

Just add them inside the quotes:

If you need help, the completed code is below:

//create a class named S1P1

public class S1P1

{

//this is the main method

public static void main (String[] args)

{

//this prints whatever is below.

System.out.println(“Whatever you type here ... will be repeated!”);

}

}

Click “Build” > “Build Main Project” > “OK”

Figure 1-4 illustrates the output of your first game!

This compiles your game, as shown in Figure 1-2.

In the next project, you will learn how to store Click “Run” > “Run Main Project”

important information (such as the “current score”) This runs the game, as shown in Figure 1-3.

and take input from the user!

Project 1: The Repeater Figure 1-2 Compiling the project.

2

Project 2: Guess the Password

Figure 1-3

Clicking this button starts the game.

Figure 1-4

Game output.

Project 2: Guess the Password

Project

So far, you know how to create a simple

Program the computer to verify the correct

program that outputs messages to the screen.

password. In this two player exercise, one player Now, you’ll learn how to create variables,

gives hints while the other types in password

manipulate them, and test them.

guesses. The computer will let the player know when he/she is correct.

Variable creation

New building blocks

This always ends in semicolons!!!!

Here are the basic variable types that you will Variables (Creation and Use), If-statements,

use most often:

Casting, and Input

Integer (“int”)—a positive or negative whole number 3

Double (“double”)—a positive or negative This sets number equal to the sum of the variables.

number with decimals

Variable can be a number or another int/double.

Character (“char”)—a single letter

+ can be substituted for -,*, ?, or %.

String (“string”)—a bunch of characters

% finds the remainder of two numbers

Boolean (“boolean”)—either true or false For chars, you can’t add anything—just set it to another value

How to create (or declare and initialize) a variable: For Strings, you can concatenate Strings.

For “int,” “double,” or “char:”

Concatenation is the combination of two strings, int <name> = <value>;

e.g. String txt = “This is added to” +

“int” can be replaced with “double” or

“this.”

“char”

<name> is replaced with any name starting with How to test your variables

a lower case letter (no numbers or symbols)

For ints, <value> can be any number

Use “if-statements” to test variables with the (e.g. - 10, - 9999, 298)

following code:

For chars, <value> should be the letter that is if(<variable>= =<variable>){}

contained within single quotes (e.g. char

<variable> can be replaced with any variable.

letter = ‘l’;)

If the variable is a String, do not use ==. Instead, For Strings, <value> can be anything as long as do the following (pretend <String> and <String2> it is contained in quotes (e.g. String text =

are the names of two String variables)

“I am a string.”;)

if(<String>.equals(<String2>))

You can also create a variable and not set its To test if it is not equal ...

value (this is called a Declaration). To do this, just end the line early (with a semicolon):

if(!<String>.equals(<String2>))

int number;

Instead of = =, which tests for equality, you can use: Or, if you have already declared a variable and

!= means not equals (for ints/doubles/chars)

want to change (or set) its value, use the following

> means greater than (for ints/doubles)

code (this is called initialization).

< means less than (for ints/doubles)

number = 1;

>= means greater than or equal to

Or, to change the value of an int/double use the (for ints/doubles)

following:

<= means less than or equal to (for ints/doubles) number + +;

So ... “if-statements” run the code in curly

This adds one to “number”

braces when the conditional is true. What if you want some code to run when the conditional is

number− −;

false? Or what if you want to execute code when This subtracts one from “number”

the “if-statement” doesn’t run???

number+=5;

Java can do that! Here’s how:

Add 5 (or any value/variable) to “number”

if(<question>)

{

Project 2: Guess the Password number = <variable> + <variable>;

//code for true

4

Project 2: Guess the Password

}

else if (<question2>)

{

//if this is true

}

else

{

//if none of the above are true

}

Figure 2-1

Input dialog box.

You can use any of the code above (or leave

parts out) as long as the “if” is first and “else”

(if you have one) is last.

Note that input lessens the need for hard-coding.

There are only two ways to use booleans with

Hard-coding is when you actually program the value if-statements (pretend boolean b exists):

of a variable. Therefore, by getting input, you can 1: if(b)

set the variables after the code is compiled.

This means “if b has the value of true”

2: if(!b)

Casting

This means “if b has the value of false”

Casting allows you to turn one type of variable Booleans can be set like other variables:

(such as a String) into another type of variable boolean b = true;

(such as an int). To do this, use the following Or ...

commands (pretend you already have a String

named input)

boolean b = false;

int inputInIntForm = Integer.parseInt(input);

double inputInDoubleForm =

Input

Double.parseDouble(input);

You can now manipulate input!!

Now that you know how to compare values,

you need to learn how to access what the

Making the game

player is typing ... through input. First, add code to the very beginning of the program

This is a text-based game that models the final (before the class declaration). The code is below.

level of an RPG (role-playing game).

Just memorize it for now. It will be explained later.

Set a password by using a String. Ask the user for the password. If he/she gets it right, display a import javax.swing.*;

celebratory message (e.g. “Congratulations! You Now, insert the following code where you want

guessed the password”). Now, let’s get started on to ask the player for input:

the details of the game.

String input = JOptionPane.showInputDialog

First, create the class. Next, create the main (“What’s your name?”);

method. Then, create a String variable. Call it This will create a dialog with an input area that

“input.” Set “input” equal to the user’s input asks “What’s your name?” (see Figure 2-1).

(use the JOptionPane code). Test the “input”

variable against your secret password with the Input is the value that the user entered. The

following code:

value is always a string, but can be turned into other values.

if(input.equals(“secret password”))

5

Display a positive message (e.g. “You

correct password. If incorrect, display a fun insult guessed it: you are an Evil Genius!” using

(e.g. “LoSeR”).

System.out.println()) if the user guessed the

//first, allow for input getting

import javax.swing.*;

//create a class named S1P2

public class S1P2

{

//main method

public static void main (String[ ] args)

{

//this String will hold the user’s input

String input;

//get input now

input = JOptionPane.showInputDialog(“Enter the secret message.”);

//test for correctness, “Evil Genius” is my secret message!

if(input.equals(“Evil Genius”))

{

//user got it right, so tell him/her!

System.out.println(“YOU GOT THE SECRET MESSAGE!!!”);

}

//if user got it wrong ...

else

{

//tell him/her ...

System.out.println(“WRONG!!! Hahaha!”);

}

}

}

Figures 2-2 through 2-5 illustrate the game play Want to pause the game or create random

of Guess the Password.

numbers to make artificial intelligence simpler?

Just go on to the next project.

Project 2: Guess the Password Figure 2-2 Guessing the secret password.

Figure 2-3

Correct guess!

6

Project 3: Number Cruncher

Figure 2-4

Guessing a different password.

Figure 2-5

Incorrect guess.

Project 3: Number Cruncher

Project

(int) makes sure that it is int variable format Math.round() rounds it to the nearest whole

The program displays a math equation.

number

The player must solve the problem before the

computer counts down from three and displays the correct answer. Can you beat the computer?

Pausing

You can make the computer pause for a given

New building blocks

period by using a very simple command:

Random numbers, Pausing

Thread.sleep(100);

100 is the number of milliseconds you want to

sleep (this can also be an int variable).

Random numbers

Also, you must add something to the last part of All random numbers are of type double, because they the main method:

are between 0 (inclusive) and 1 (exclusive). There is After (String[] args), add “throws Exception”

a simple command to create random numbers.

The entire line should look like:

To create a random double between the value of public static void main (String[ ] args)

0 and 1, use the following code:

throws Exception

Math.random()

Making the Game

This returns a value, similar to the way

JOptionPane returns values. However, this returns OK ... you can now make a game that can be used a double instead of a String.

in math competitions around the world!

So ... if you want to create a random 1 digit

Create a math equation with two numbers

number, try the following:

using any of these operations: adding,

int rand =

subtracting, multiplying, dividing, or

(int)(Math.round(Math.random()*10));

modding.

7

Declare and initialize two empty int values with Create a new variable to hold the solution of the a random number from 0 to 9.

math problem.

Then, create a new int with a random number

Now, pause the program (to let the user answer form 0–4.

the question).

If it is 0, it will be * (times)

Display the variable that holds the solution.

If it is 1, it will be / (divided by)

If the player calculates the answer correct before If it is 2, it will be + (plus)

the computer displays it, the player wins!

If it is 3, it will be – (minus)

Here’s the code:

If it is 4, it will be % (mod)

//first, allow for input

import javax.swing.*;

//create a class named S1P3

public class S1P3

{

//main method (throws Exception) added for Thread.sleep() public static void main (String[ ] args) throws Exception

{

//random numbers for the equaton

int num1 = (int)(Math.round(Math.random()*10)); int num2 = (int)(Math.round(Math.random()*10));

//random number for the sign

int sign = (int)(Math.round(Math.random()*3));

//will store the answer

int answer;

//make stuff noticable:

System.out.println(“\n\n*****”);

if(sign= =0)

{

//tell user and calculate answer

System.out.println(num1+ “ * ”+num2);

answer = num1*num2;

}

else if(sign= =1)

{

//tell user and calculate answer

System.out.println(num1+“ / “+num2);

answer = num1/num2;

}

else if(sign= =1)

{

//tell user and calculate answer

System.out.println(num1+“ + “+num2);

answer = num1+num2;

}

else if(sign= =1)

{

//tell user and calculate answer

System.out.println(num1+” − “+num2);

answer = num1−num2;

}

else

{

Project 3: Number Cruncher

//tell user and calculate answer

8

Project 3: Number Cruncher

System.out.println(num1+“ % ”+num2);

answer = num1%num2;

}

//make it easier to read ...

System.out.println(“*****\n”);

//count down from 3

System.out.println(“3 ...”);

Thread.sleep(1000);

System.out.println(“2 ...”);

Thread.sleep(1000);

System.out.println(“1...”);

Thread.sleep(1000);

//print the answer

System.out.println(“ANSWER: “+answer);

}

}

An equation is displayed in Figure 3-1.

In the next project, you will start using loops.

This technique allows you to repeat the code that The computer counts down in Figure 3-2.

runs the game. The screen refreshes itself so that And the answer is displayed in Figure 3-3!

the images are clear and move smoothly.

Figure 3-1

Equation.

Figure 3-2

Countdown.

Figure 3-3

Answer.

9

Project 4: Number Cruncher Extreme

Project

Sample for loop:

for(int i = 0; i <10; i++) {}

This is an add-on to the previous exercise, Number Cruncher. The player can either opt to play again or Whatever is in the parentheses will execute ten change the difficulty level by increasing or

times.

decreasing the time allowed to calculate the answer.

“while” loops

New building blocks

While loops are like for loops, except they do not directly include the variable declaration and

Loops

iteration. They only include the condition.

A sample while loop:

Loops

int i = 0;

while(i<10) {i++;}

It’s time to learn some flow control techniques.

Flow control lets you repeat and execute different The process of a “while loop”: When the

parts of the code at different times, depending on a compiler encounters a while loop, the condition is condition (e.g. x= =4). There are three types of checked. If true, it will enter the loop and continue flow control, called loops:

to recheck the condition after every iteration.

If false, it stops looping.

“for” loops

“do ... while” loops

For loops allow you to execute the code within the curly brace until a given condition is satisfied.

Do ... while loops are almost identical to while loops.

Here’s the format:

Here’s the format:

for(<variable init>; <condition>;

<iterator >) {//repeated code goes here}

int i = 0;

<

do

Variable init> is a standard variable

{

declaration. (e.g. int i = 0;)

i+ +;

<

}

Condition> can be i<0 or i >0 or i>=0 or i<=0 or while(i <10);

anything else that can be inside the if statement’s parentheses.

The Process of a “do ... while loop”: Do ...

<Iterator> can be (and usually is) i+ +.

while loops are the same as while loops, except the code in braces always executes once (before The process of a “for loop”: When the JRE (Java the condition is checked).

Runtime Environment) reaches the variable

declaration, it creates the variable (which exists Special keywords

only in the for statement). If the condition is true, the code runs once. Then, the iterator code runs.

The most important keyword when working with

The condition is checked again and the process loops is “break,” which immediately exits the loop.

Project 4: Number Cruncher Extreme repeats.

Here’s an example:

10

Project 4: Number Cruncher Extreme

for(int i = 0; i <10; i+ +)

Occasionally, the program may try to divide by

{

zero, which will cause it to “throw an exception”

if(i= =1)

break;

(quit). To fix this bug, put the second number

}

random code inside a do ... while loop. If the number is zero, run it again!

Making the game

You may have realized that the answers are not always exact ... they are ints, not doubles. With Change the delay time and degree of difficulty of ints, the equation 3/ produces 1, not 0.75.

the previous exercise, Number Cruncher (1 = evil 4

genius, 10 = mathematically challenged).

Hint:

Let the user input the difficulty level and

count down from that level to zero. The higher the To make the solution value more exact, change all the level, the more time the player is given to answer.

variables of type “int” (except the random sign variable) The lower the level, the less time is given to answer.

to type “double.”

You can ask the user if he/she wants the program Here’s the code:

run again (using a do ... while loop).

//first, allow for input getting

import javax.swing.*;

//create a class named S1P3

public class S1P4

{

//main method (throws Exception) added for Thread.sleep() public static void main (String[ ] args) throws Exception

{

//this will be how many 1/

seconds the user gets

2

int difficulty;

difficulty = Integer.parseInt(JOptionPane.showInputDialog(“How good are you?\n”+

“1 = evil genius...\n”+“10 = evil, but not a genius”));

//this will tell the loop whether to continue or not: boolean cont = false;

//the contents of the main method are about to be enclosed in a do

//while loop...

do

{

//reset cont to false

cont = false;

//random numbers for the equaton

double num1 = (int)(Math.round(Math.random()*10));

//this do..while loop prevents exceptions

//num 2 must be declared outside of the do while so

//the “while” part can see it. It will still be initialized

//inside of the do part, though.

double num2;

do

{

//init num2

num2 = (int)(Math.round(Math.random()*10));

}

11

while(num2= =0.0); //if it is 0, do it again!

//random number for the sign

int sign = (int)(Math.round(Math.random()*3));

//will store the answer

double answer;

//make stuff noticable:

System.out.println(“\n\n*****”);

if(sign= =0)

{

//tell user and calculate answer

System.out.println(num1+” times “+num2);

answer = num1*num2;

}

else if(sign= =1)

{

//tell user and calculate answer

System.out.println(num1+” divided by “+num2);

answer = num1/num2;

}

else if(sign= =1)

{

//tell user and calculate answer

System.out.println(num1+” plus “+num2);

answer = num1+num2;

}

else if(sign= =1)

{

//tell user and calculate answer

System.out.println(num1+” minush “+num2);

answer = num1-num2;

}

else

{

//tell user and calculate answer

System.out.println(num1+” % “+num2);

answer = num1%num2;

}

//make it easier to read...

System.out.println(“*****\n”);

//count down from difficulty... use a for loop!!!

for(int i = difficulty; i >= 0; i− −)

{

//count down at double speed!

System.out.println(i+“...”);

//instead of waiting a second,

//this time only wait 1/2 second

//per difficulty level.

Thread.sleep(500);

}

//print the answer

System.out.println(“ANSWER: “+answer);

//ask the user if he/she wants to play again

String again;

again = JOptionPane.showInputDialog(“Play again?”);

//if the user says yes, set cont to true.

if(again.equals(“yes”))

Project 4: Number Cruncher Extreme

cont = true;

}

12

Project 4: Number Cruncher Extreme

while(cont); //keep going until continue is false

}

}

Figures 4-1 through 4-3 illustrate the game in Turn the page to learn how to save information play.

to files. This process allows you to call up a player’s progress in any game you create.

Figure 4-1

Inputting the difficulty level

Figure 4-2

Equation and count down

Figure 4-3

Play again?

13

Project 5: Crack the Code

Project

“out” is also a variable name

So far, you have designated space for a file

This is an add-on to Project 2, Guess the Password.

and prepared the computer to save it. Use the

Instead of hard-coding the password, the user can set following code to do the fun part—actually save the password through the pop-up windows. Also, the the file:

password will be permanent: it will be saved to a file.

out.println(<this text is written to the

file>);

New building blocks

“<This text is written to the file>” is

File IO (File Writing, File Reading)

usually of type String

After you have completed making the file, you

must tell the computer that you are done. Use the Creating files

following code:

Every type of file is saved the same way. The only out.flush();

difference is the extension (.doc, .txt, .avi, .jpg, etc).

out.close();

outStream.close();

Extensions exist to tell the computer what program to use to open the file. For example, when you Good job! Now you know how to write and save

store the password for this game, you’ll make a files.

.psswrd file. But, it could also be a .evilGenius or

.<anything> file.

Accessing files

First, create a File by using the following code: Once again, create a File object:

File file = new File(“password.psswrd”);

File file = new File(“password.psswrd”);

So far, this does nothing. It simply holds a space for a file named “password.psswrd.” The file is shown in Figure 5-1.

Now, you’ll learn how to actually save the above file to your computer. First, you must write the following code:

FileOutputStream outStream = new

FileOutputStream(<file name>);

“<File name>” is the name of the file from earlier (in this case, “file”)

“outStream” is the variable name; it can be

renamed anything

PrintWriter out = new

PrintWriter(outStream);

“outStream” is the name of the

Project 5: Crack the Code FileOutputStream from above Figure 5-1

Your file.

14

Project 5: Crack the Code

This time, the String (right now

buffer.close();

fr.close();

“password.psswrd”) is the name of the file you will be opening.

Remember to “throws Exception” and

Next, create a FileReader. A FileReader tells

“import java.io.*;”

the computer to open the file and prepare to

read the text.

Making the game

FileReader fr = new FileReader(file);

When the player first opens the game, two options

“file” is the File to access (from above)

will be displayed: play the game or reset the game.

“fr” is a variable name

If the player chooses to reset the game, a new Now, create a BufferedReader. A BufferedReader password must be set (which will be saved to a file).

tells the computer to read the text from the

If the player chooses to play the game,

opened file.

he/she will be allowed to try to guess the

BufferedReader buffer = new

password.

BufferedReader(fr);

To write the game, use a JOptionPane to offer

“fr” is the name of the FileReader

the player the above options.

“buffer” is a variable name

If the player wants to enter a password (reset the To access the first line of your file, use the game), use your file writing code and save the new following:

password to the file.

String line = buffer.readLine();

If the player opts to try to crack the password, Once you have finished accessing the file, you access the file and check the player’s guess with must tell the computer you are done:

the text in the File.

//first, allow for input getting

import javax.swing.*;

import java.io.*;

//create a class named S1P2

public class S1P2

{

//main method

public static void main (String[ ] args) throws Exception

{

//this String will hold the user’s input

String input;

//get input now

input = JOptionPane.showInputDialog(“1 to set password,\n”+“2 to unlock the message”);

//this is the file that will be set and opened File file = new File(“password.psswrd”);

//test for entering or setting the password

if(input.equals(“1”))

{

//setting the password ...

//get the password

String p = JOptionPane.showInputDialog(“Enter the password to set”);

//these are the two lines we learned about...

FileOutputStream outStream = new FileOutputStream(file); 15

PrintWriter out = new PrintWriter(outStream);

//set the password

out.println(p);

//close it all

out.flush();

out.close();

outStream.close();

}

//if user wants to test the password

else

{

//first, we must get the password:

FileReader fr = new FileReader(file);

BufferedReader buffer = new BufferedReader(fr);

//this is the password in the file

String password = buffer.readLine();

//get the user’s attempted password

String userPass;

userPass = JOptionPane.showInputDialog(“Enter your guess...”);

//test the password:

if(password.equals(userPass))

{

//if correct

JOptionPane.showMessageDialog(null,“CORRECT!!!!”);

}

else

{

//if incorrect:

JOptionPane.showMessageDialog(null,“WRONG =(”);

}

}

}

}

Figures 5-2 through 5-8 illustrate the game play of Crack the Code.

Figure 5-3

Enter the password.

Figure 5-2

Set or guess the password.

Project 5: Crack the Code

16

Project 6: Virtual Game Library

Figure 5-6

Congrats!

Figure 5-4

Guess the number.

Figure 5-5

Correct guess;

Figure 5-7

Replay the game.

In the next project, you will learn how to hold large amounts of similar objects. A very useful tool in game play when tracking enemies or

power ups.

Figure 5-8

Incorrect password.

Project 6: Virtual Game Library

Project

The data structure that will be covered in this project is called an “array.” An “array” lets you Keep an archive of the games you have created.

store many variables, as long as they are the same type (e.g. int, int, int or double, double, double).

New building blocks

This way, you can look up the value of a variable in the array based on its position.

Arrays

The downside of arrays? It is difficult to add Now that you know how to make some cool

new variables, which are called elements when in basic games, you need to know how to store them an array. But have no fear! A different data

for easy access. This is accomplished with data structure that allows you to easily add new

structures.

elements will be introduced in the next project.

17

If you want to set the value of the element in place Arrays

0 (remember, that’s the first element) to fifty, use the following code:

To simultaneously create and initialize an array, use the following code:

bunchOfInts[0] = 50;

int bunchOfInts[ ] = {−981,45,−6,7};

Getting values within arrays

This creates an array called “bunchOfInts” with

<variable> = [<element position to edit>]

the arbitrary values −981, 45, −6, and 7.

= <value>;

To just create an array without initializing the If you want to find the value of the element in elements, use the following code:

place 0, use the following code:

int sixInts[ ] = new int[6];

int num = bunchOfInts[0];

This will create an array that holds six ints, but right now the value of each is empty. Note: you Making the game

must always define the size of the array — in this case, six.

Create a virtual library that can store the names of To access or edit a value/element in an array, the games you have created. The Virtual Game

remember one important fact: The element count Library allows you to access the games by entering starts at zero. For example, in the array the element number.

“bunchOfInts,” the value of the first element

First, put everything in a do ... while loop so (which is located at place 0) is −981. The value of the program can be run again if the user desires.

the second element (which is located at place 1) is Then, create and initialize an array (at the same 45. And you already know the value of the element time) of type String with the values being the titles in place 2. That’s right! It’s −6.

of the previous programs/games.

Setting values within arrays

Next, use a JOptionPane to get input

(the element number).

<arrayName>[<element position to edit>] =

By using the new JOptionPane output code

<value>;

display the name of the game.

//this import stuff lets you use JOptionPane

import javax.swing.*;

public class S1P5

{

public static void main (String[ ] args)

{

//this will be used in the while part of the do...while boolean cont = false;

do

{

cont = false; //reset cont

//this is the array of Strings with the game names String names[ ] = {“Define: \”Games\””,”The Dungeon Defender”,

“Regional Math-a-thon”,”National Math-a-thon”};

//now, we’ll ask the user which name to return Project 6: Virtual Game Library

18

Project 6: Virtual Game Library

int element = Integer.parseInt(JOption Pane. showInputDialog(“Which element?”));

//this will be outputted in the output JOptionPane String output = “The Name of the Game is:\n”;

//concat! And get the element

output+=names[element];

//this is the output JOptionPane

JOptionPane.showMessageDialog(null,output);

//get input for repeating

String repeat =JOptionPane.showInput Dialog(“Again?”); if(repeat.equals(“yes”))

cont = true;

}

while(cont); //while cont is true, repeat

}

}

Figures 6-1 through 6-3 illustrate the use of

The next step is learning about ArrayLists.

arrays in Virtual Game Library.

ArrayLists are similar to arrays, except they do more and are easier to use. Continue on!

Figure 6-1

Element number of the game is entered.

Figure 6-2

Title is displayed.

Figure 6-3

Program repeats.

19

Project 7: Virtual Game Library Pro Edition

Project

Here is the code to make an ArrayList (notice

how you do not need to specify a type):

This is an add-on to Virtual Game Library. In the ArrayList structure = new ArrayList();

previous program, the games in the library had to be hard-coded in. Now you can add new games

You cannot initialize values on the same line.

without having to alter the code.

To add a value, use the following code:

structure.add(new Integer(5));

New building blocks

You can add as many elements as you like.

ArrayLists

To get a value (if you know the element (which

always begins at place 0), use the following code: Object tempObj = structure.get(0);

ArrayLists (java.util.*;

Integer tempInt = (Integer)tempObj;

must be imported)

int finalNum = tempInt.intValue();

The first line retrieves the Object from the

ArrayLists hold classes (also known as objects).

ArrayList. The second line turns the object into an Yes ... this is the same as the class you

Integer (to turn it into a Double, replace “Integer”

create when you make a program (in the

with “Double”). The last line turns the Integer code “public class”). For now, however,

into an int (if you are working with Doubles,

you’ll use premade classes. Remember

change “intValue” to “doubleValue” and “int”

when you used Integer.parseInt() and

to “double.”).

Double.parseDouble? Well, Double and

Integer are both classes that an ArrayList can Making the game

hold. To keep things simple, for now, we’ll only use these two classes.

Use the previous projects’s code. Only a few

All classes (Integer and Double) belong to a

changes are needed:

hierarchy. The highest member of every class is Ask the user to enter either 1 to add a new game called an “Object.” Therefore, an ArrayList always or 2 to access a game. Next, turn the array into an returns an “Object,” because it can be cast into the ArrayList. Then, if the user enters 2, use the specific class (Integer or Double) you originally previous project’s code to return the value.

passed in.

If the user enters 1, add the new String to the ArrayList.

//import ...

import javax.swing.*;

import java.util.*;

public class S1P6

{

public static void main (String[ ] args)

{

Project 7: Virtual Game Library Pro Edition

//the ArrayList

20

Project 7: Virtual Game Library Pro Edition ArrayList games = new ArrayList();

//this will be used in the while part of the do ... while boolean cont = false;

do

{

cont = false; //reset cont

//what do you want to do?

int choice = Integer.parseInt(JOptionPane.

showInputDialog(“Enter\n”+“1 to add a new game\n”+“2 to access games”)); if(choice= =1)

{

//get the name

String name;

name = JOptionPane.showInputDialog(“Game name?”);

//add it!

games.add(name);

}

if(choice= =2)

{

//now, we’ll ask the user which name to return int element = Integer.parseInt(JOptionPane. showInputDialog(“Which element?”));

//this will be outputted in the output JOptionPane String output = “The Name of the Game is:\n”;

//concat! And get the element

output+=((String)games.get(element));

//this is the output JOptionPane

JOptionPane.showMessageDialog(null,output);

}

//get input for repeating

String repeat =

JOptionPane.showInputDialog(“Again?”);

if(repeat.equals(“yes”))

cont = true;

}

while(cont); //while cont is true, repeat

}

}

Figures 7-1 through 7-6 illustrate the use of

ArrayLists in Virtual Game Library Pro Edition.

Proceed to the next project and create an exciting number guessing game utilizing the many skills and concepts you have learned.

Figure 7-1

Either access existing games or add

new games.

21

Figure 7-2

Add a new game.

Figure 7-5

Name of the game.

Figure 7-6

Rerun the program.

Figure 7-3

Access existing game.

Figure 7-4

Enter game number.

Project 8: Number Guesser

Project

Making the game

The computer generates a random number from

Start by generating the random number. Then, use 0 to 100 ... and you have to guess what it is! After a

each guess, the computer offers a hint—too high or do ... while loop. Get input (the user’s guess) and compare it with the correct number using

too low.

if-statements. This will provide hints for the player.

To make this program, you need to put several of The do ... while will exit if the guess is

the building tools you have learned to work:

correct.

Classes, Statements, Variables, Input, Loops,

Comments, Output, Casting, and If-Statements

Project 8: Number Guesser

22

Project 8: Number Guesser

import javax.swing.*;

public class S1WrapUp

{

public static void main (String[ ] args)

{

//this will hold the user’s guess’

int guess = -1;

//number of user guesses

int count = 0;

//create the number:

int num = (int) (Math.random()*100);

//this is the loop to ask the user:

do

{

guess = Integer.parseInt(JOptionPane. showInputDialog(“Guess a number between 0 and 100!”));

if(guess>num)

JOptionPane.showMessageDialog(null,“Too high”); if(guess>num)

JOptionPane.showMessageDialog(null,“Too low”); count+ +;

}

//keep going until the user gets the number

while(num!=guess);

JOptionPane.showMessageDialog(null,“You guessed the number − “+num+” − in “

+count+” guess(es)!!!”);

}

}

Figures 8-1 through 8-12 depict the game play

of Number Guesser.

If you have trouble writing this code, don’t

despair! Just review the previous projects to

refresh your knowledge of the concepts.

If you are able to do this on your own, consider yourself well on your way to becoming a true Evil Figure 8-2

The guess is too low.

Genius!

Figure 8-1

Guess of 50.

Figure 8-3

Guess of 75.

23

Figure 8-9

Guess of 97.

Figure 8-4

The guess is too low.

Figure 8-5

Guess of 88.

Figure 8-10

Still too low!

Figure 8-6

88 is too low.

Figure 8-11

Guess of 99.

Figure 8-7

Guess of 94.

Figure 8-12

99 is CORRECT!!!

Figure 8-8

Even 94 is too low.

Project 8: Number Guesser

24

Project 8: Number Guesser

Input is used to access the user’s name for a

Java Jumpstart quick review

high-scores list.

Comments Comments let you document code so

Random numbers Random numbers allows for

you know what each part of your game does.

artificial intelligence (make an enemy move

randomly, etc.).

Statements Statements are commands. They are

the backbone of all games.

Pausing Pausing allows the screen to refresh

so the game play graphics will be at optimum

Flow control Loops let you repeat code. This is clarity.

useful if the user wants to retry the game if he/she has lost.

Arrays Arrays keep track of the game

environment (e.g. a list of cars in a racing game, Variables Variables allow you to keep track of the a list of bullets in a shoot ‘em up).

player’s score, points, etc.

ArrayLists Arraylists are used to store players’

If-statements If-statements let you test variables.

names and scores.

For example, you can determine whether a player has any lives left ... or if he’s stone cold dead.

File IO FileIO allows for a permanent high-score list on any game.

JoptionPane JOptionPanes let you get input and output. Output is used to display a player’s score.

25

This page intentionally left blank

Section Two

Racing Games

Project 9: Radical Racing—The Track

For example, in “public class Game” the only

code inside the main method would look like this: Radical Racing

Game g = new Game();

Race cars you build around a track you design

This line of code executes the class’s constructor.

with exciting graphics and sound effects!

A constructor is similar to the main method, except it is automatically called when you create a new instance of the class (by using the code above).

Project

Therefore, all the code necessary to run your game should be in the constructor, not the main method.

Create the environment—a virtual racetrack using a Graphical User Interface (GUI).

A constructor is programmed by using the

following code:

New building blocks

public <class name>()

{

//code goes here

JFrames, Methods

}

Using the “class Game” example, the code

JFrames

would look like this:

public Game(){}

A JFrame is one of the simplest ways to create a Inside the constructor, you need to add

Graphical User Interface. It creates a pop-up box the following four lines of code so that

(similar to a JOptionPane) of a specified size. You you can create the JFrame, set the title, and set can add graphics, buttons, text fields, labels, etc.

the size:

A JFrame, before any graphics or images are

added, is shown in Figure 9-1.

super(“title goes here”);

setSize(400,400);

To create a JFrame, first add “extends JFrame”

setVisible(true);

at the end of the line “public class ...” For example, setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); if you have a class called Game, the line would Good going! You have now created your first

look like this:

GUI! And remember, a GUI is like a blank canvas: public class Game extends JFrame

you can easily add your own shapes, images,

buttons, textfields, or anything else you can

Now, change the main method so it contains

imagine! Read on to learn how to include

only one line of code:

threatening enemies, daring heroes, or even

<class name> <var name> = new <class name>(); disgusting aliens.

27

Figure 9-1

Simple JFrame.

Type the following code outside of the

Now you know how to draw a simple racetrack!

constructor, but within the class:

Hint: Eventually, you are going to need to check public void paint(Graphics g)

if the car goes out of bounds. Plan ahead and save

{

the points in an object called a Rectangle. This super.paint(g);

makes collision detection easy to program. You can

}

then draw the Rectangle by getting its values.

In this method, you can draw any shape you

To make and draw a Rectangle, use the

want — rectangles, squares, circles, arcs, or even following code:

giant letters. For now, however, we will focus on two commands: setting the color and drawing a

Rectangle r1 = new Rectangle(100, 100, 300, 400); rectangle.

g.fillRect(r1.x, r1.y, r1.width, r1.height);

To set the color, use the following code

And, if you want to re-draw the JFrame, simply (you must import java.awt.*;):

type the following code anywhere in your

program:

g.setColor(Color.<any color>);

repaint();

“<any color>” can be replaced with any color you like. In NetBeans, a list of colors to choose Remember—the “public void paint ...” code is

from will pop up when you begin typing “Color.”

always executed when the program is first run.

The list is illustrated in Figure 9-2.

To draw a Rectangle, use the following code:

Methods

g.fillRect(<x>,<y>,<width>,<height>); Methods hold code and allow it to be run

<x>, <y>, <width>, and <height> are all variables multiple times. The primary use of methods is to of type “int.”

allow the programmer to repeat code more easily.

Let’s draw a green rectangle like the one shown You can call (aka run) methods from the

Project 9: Radical Racing—The Track in Figure 9-3.

constructor. They can be called from the

28

Project 9: Radical Racing—The Track

Figure 9-2

Some of the many colors available.

constructor or from another method (but not the

“<return type>” should be “void” if the method main method). A method can take in a variable

returns nothing. If it returns an int, it should be (also known as an argument), return (send back)

“int.” If it returns an Integer, it should say a variable, do both, or do neither.

“Integer.” It can be any primitive (int, double, char To create a method, use the following code:

etc.) or object.

“<

public <return type> <name> (arguments) name>” is the name of a method. Name it

{

anything, as long as it starts with a letter.

//code

}

Figure 9-3

Simple green rectangle inside of a JFrame.

29

“arguments” are the variables that the method

To call a method (the one named “sample”), use takes in when called. They are separated by

the following code:

commas. For example, if you want a method to

sample(1, 4.563);

take in two arguments, an int and a double, you would use the following code:

This passes in the arguments “1” and “4.563.”

If “sample” returns an int, you can get the

public void sample(int i, double d){}

returned value by using the following code:

Inside of the method, “i” and “d” are the

variable names of the arguments that are passed in.

int i = sample(1, 4.563);

To return a value, use the following code:

Making the game

return <variable>;

<variable> must be the return type you specified Now, draw a virtual racetrack. The completed code when you created the method.

is below:

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

//this creates the class where you use JFrame

public class G1P1 extends JFrame

{

//this is the constand that will hold the screen size final int WIDTH = 900, HEIGHT = 650;

/*THE FOLLOWING ARE ALL OF THE RECTANGLES THAT WILL BE DRAWN*/

/*

*The following code (creating the Rectangles) may seem complicated at

*first, but it only seems that way because it creates the pieces

*based on the WIDTH and HEIGHT. In your version, you could just hard

*code values.

*/

//create rectangles that will represent the left, right, top, bottom,

//and center

Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT); Rectangle right = new Rectangle((WIDTH/9)*9,0,WIDTH/9,HEIGHT); Rectangle top = new Rectangle(0,0,WIDTH, HEIGHT/9); Rectangle bottom = new Rectangle(0,(HEIGHT/9)*9,WIDTH,HEIGHT/9); Rectangle center = new

Rectangle((int)((WIDTH/9)*2.5),(int)

((HEIGHT/9)*2.5), (int)((WIDTH/9)*5),(HEIGHT/9)*4);

//these obstacles will obstruct the path and make navigating harder Rectangle obstacle = new

Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9); Rectangle obstacle2 = new

Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle3 = new

Rectangle(2*(WIDTH/3),(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9); Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4); Project 9: Radical Racing—The Track

30

Project 9: Radical Racing—The Track

//the following rectangle is the finish line for both players Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)−HEIGHT/9, (int)((WIDTH/9)*1.5), HEIGHT/70);

//the following rectangle is the start line for the outer player Rectangle lineO = new

Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);

//the following rectangle is the start line for the inner player Rectangle lineI = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)), (HEIGHT/2)+(HEIGHT/10),

(int)((WIDTH/9)*1.5)/2, HEIGHT/140);

//the constructor:

public G1P1()

{

//the following code creates the JFrame

super(“Radical Racing”);

setSize(WIDTH,HEIGHT);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

}

//this will draw the cars and the race track

public void paint(Graphics g)

{

super.paint(g);

//draw the background for the racetrack

g.setColor(Color.DARK_GRAY);

g.fillRect(0,0,WIDTH,HEIGHT);

//when we draw, the border will be green

g.setColor(Color.GREEN);

//now, using the rectangles, draw it

g.fillRect(left.x,left.y,left.width,left.height); g.fillRect(right.x,right.y,right.width,right.height); g.fillRect(top.x,top.y,top.width,top.height);

g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height); g.fillRect(center.x,center.y,center.width,center.height); g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height); g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height); g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height); g.fillRect(obstacle4.x,obstacle4.y,obstacle3.width,obstacle4.height); g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);

//set the starting line color to white

g.setColor(Color.WHITE);

//now draw the starting line

g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height); g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);

//set the color of the finish line to yellow

g.setColor(Color.YELLOW);

//now draw the finish line

g.fillRect(finish.x,finish.y,finish.width,finish.height);

}

//this starts the program by calling the constructor: public static void main (String[ ] args)

{

new G1P1();

}

}

31

A screenshot of the completed track is displayed In the next project, you will make Radical

in Figure 9-4.

Racing come to life by creating two cars that

accelerate forward. Vroom! Vrooooom!

Figure 9-4

Radical Racing track.

Project 10: Radical Racing—The Cars

Project:

following code inside the main class but outside of any methods or constructors:

Now that you can create a GUI, you are going to public class <name> extends Thread

make it come to life. Using Threads (which let

{

}

multiple things happen at once), you will make two cars accelerate in a forward motion.

“<name>” can be anything, as long as it is different from the main class’s name.

New building blocks:

Inside of the thread, you must make a mandatory method (it must exist in order for the program to Threads/Inner Classes

compile). Use the following code:

public void run() {}

Threads/inner classes

Inside this method, we will want one of the cars to move forward. Therefore, there should be an To create a Thread, you must first program an

infinite while loop:

Project 10: Radical Racing—The Cars “inner class.” This is how you do it: type the 32

Project 10: Radical Racing—The Cars

while(true)

Move m = new Move();

{

m.start();

}

Inside the while loop, you should insert the

Making the game

following code.

try

First, draw a Rectangle to represent the car

{

(you will learn to customize your own speed-

//code

demon racers images in Project 12). Then,

}

catch(Exception e) {break;}

program a Thread (using an inner class). Insert the This code checks for errors inside the “try”

run method, add the while loop, and add the

block. If one is found, the computer executes the

“try ...” code. Next, create a global variable to code in the “catch” block. In this case, if an error keep track of the first car’s speed.

is found, “break” is called, which exits the infinite Inside of the “try ...” code, slowly increase the while loop.

speed until the car reaches its maximum velocity (use 4). Then, make the car move forward by

The controls that make the car move should be

altering the “y” value of its rectangle by adding it in place of “//code”

to the car’s speed. Finally, refresh the screen and Once you are done making your Thread, call it

add in a delay (using Thread.sleep(75);).

from the constructor using the following code

If you can get that working, try adding the

(in this example, Move is the name of your inner second car.

class):

The completed code is below.

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

//this creates the class where you use JFrame

public class G1P2 extends JFrame

{

//this is the constand that will hold the screen size final int WIDTH = 900, HEIGHT = 650;

//these will keep track of each player’s speed: double p1Speed =.5, p2Speed =.5;

//create rectangles that wil represent the left, right, top, bottom, and

//center

Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT); Rectangle right = new Rectangle((WIDTH/9)*8,0,WIDTH/9,HEIGHT); Rectangle top = new Rectangle(0,0,WIDTH,HEIGHT/9); Rectangle bottom = new Rectangle(0,(HEIGHT/9)*8,WIDTH,HEIGHT/9); Rectangle center =

newRectangle((int)((WIDTH/9) *2.5),(int)((HEIGHT/9)*2.5),(int) ((WIDTH/9)*5), (HEIGHT/9)*4);

//these obstacles will obstruct the path and make navigating harder Rectangle obstacle = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*7), WIDTH/10,HEIGHT/9);

Rectangle obstacle2 = new

Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle3 = new

33

Rectangle(2*(WIDTH/3),(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9); Rectangle obstacle5 = new Rectangle(WIDTH/2,(int) ((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4);

//the following rectangle is the finish line for both players Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)−HEIGHT/9, (int) ((WIDTH/9)*1.5),HEIGHT/70);

//this is the rectangle for player 1’s (outer) car: Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);

//this is the rectang;e for player 2’s (inner) car: Rectangle p2 =

new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+ (HEIGHT/10), WIDTH/30,WIDTH/30);

//the constructor:

public G1P2()

{

//the following code creates the JFrame

super(“Radical Racing”);

setSize(WIDTH,HEIGHT);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

//start the inner class (which works on its own, because it is a

//Thread)

Move1 m1 = new Move1();

Move2 m2 = new Move2();

m1.start();

m2.start();

}

//this will draw the cars and the race track

public void paint(Graphics g)

{

super.paint(g);

//draw the background for the racetrack

g.setColor(Color.DARK_GRAY);

g.fillRect(0,0,WIDTH,HEIGHT);

//when we draw, the border will be green

g.setColor(Color.GREEN);

//the following rectangle is the start line for the outer player Rectangle lineO = new

Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);

//the following rectangle is the start line for the inner player Rectangle lineI = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)), (HEIGHT/2)+(HEIGHT/10),(int)((WIDTH/9)*1.5)/2,HEIGHT/140);

//now, using the rectangles, draw it

g.fillRect(left.x,left.y,left.width,left.height); g.fillRect(right.x,right.y,right.width,right.height); g.fillRect(top.x,top.y,top.width,top.height);

g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height); g.fillRect(center.x,center.y,center.width,center.height); g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height); g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height); g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height); g.fillRect(obstacle4.x,obstacle4.y,obstacle3.width,obstacle4.height); g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);

//set the starting line color to white

Project 10: Radical Racing—The Cars

34

Project 10: Radical Racing—The Cars

g.setColor(Color.WHITE);

//now draw the starting line

g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height); g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);

//set the color of the finish line to yellow

g.setColor(Color.YELLOW);

//now draw the finish line

g.fillRect(finish.x,finish.y,finish.width,finish.height);

//set the color to blue for p1

g.setColor(Color.BLUE);

//now draw the actual player

g.fill3DRect(p1.x,p1.y,p1.width,p1.height,true);

//set the color to red for p2

g.setColor(Color.RED);

//now draw the actual player

g.fill3DRect(p2.x,p2.y,p2.width,p2.height,true);

}

private class Move1 extends Thread

{

public void run()

{

//now, this should all be in an infinite loop, so the process

//repeats

while(true)

{

//now, put the code in a “try” block. This will let the

//program exit

//if there is an error.

try

{

//first, refresh the screen:

repaint();

//increase speed a bit

if(p1Speed<=5)

p1Speed+=.2;

p1.y− =p1Speed;

//this delays the refresh rate:

Thread.sleep(75);

}

catch(Exception e)

{

//if there is an exception (an error), exit the loop.

break;

}

}

}

}

private class Move2 extends Thread

{

public void run()

{

//now, this should all be in an infinite loop, so the process

//repeats

while(true)

{

//now, put the code in a “try” block. This will let the 35

//program exit

//if there is an error.

try

{

//first, refresh the screen:

repaint();

//increase speed a bit

if(p2Speed<=5)

p2Speed+=.2;

p2.y−=p2Speed;

//this delays the refresh rate:

Thread.sleep(75);

}

catch(Exception e)

{

//if there is an exception (an error), exit the loop.

break;

}

}

}

}

//this starts the program by calling the constructor: public static void main (String[ ] args)

{

new G1P2();

}

}

Figures 10-1 and 10-2 illustrate the game play of Go on to the next project to learn how to add

Radical Racing.

collision detection. And that’s not all! Your keyboard will be turned into your own steering wheel.

Project 10: Radical Racing—The Cars Figure 10-1 Radial Racing.

36

Project 11: Radical Racing—Collision!

Figure 10-2

Cars accelerating forward.

Project 11: Radical Racing—Collision!

Project

Let’s say you want to check for a collision between Rectangles r1 and r2. Use the following code:

Program the cars to bounce back and slow

if(r1.intersects(r2))

down if they run into each other or the boundaries.

Plus, transform your keyboard into a steering

To check for multiple collisions, you can use the wheel by assigning specific keys to direct the

“and” or “or” keyword (in if-statements). “And” is racers.

“&&” and “or” is “||”

New building blocks

Collision detection and KeyListener

Collision detection

Collision Detection (checking to see if objects hit each other, as illustrated in Figure 11-1) is easy in Java. Because you created all of your graphics with Rectangles, we can easily check for

collisions: Rectangle has a built-in “intersects”

method.

Figure 11-1

Example of collision detection.

37

For example, to see if Rectangle r1 hit r2 or r3,

“keyTyped” is called after a key is pressed and use the following code:

released. You will be using “keyTyped” most often.

Inside of “keyTyped” you can use an if-statement if(r1.intersects(r2) || r1.intersects(r3))

to check what key was pressed. Depending on the key, you can then change the game by altering

KeyListener

such variables as the car’s direction.

To figure out what key has been pressed, use the The KeyListener lets the computer receive keyboard following line:

input from the user. This will be very useful when e.getKeyChar()

you let the players control the direction of their cars.

To use a KeyListener, you must add the following code to your “public class ...” line:

Making the game

implements KeyListener

Create global variables for the car’s direction.

This can also be added to the inner classes

Make them of type “int.” If the value is 0, the car (Threads).

travels up; if it is 1, the car heads left; etc. To keep Then, inside the constructor (or “run” method, if things simple, create final variables. For example, you are dealing with Threads), type the following initialize an int called “UP” and set its value to code:

zero. Then, if you need to see if the car is going up, compare it to “UP” instead of 0.

addKeyListener(this);

Next, use the KeyListener to change the

This line tells the keyboard to “wake up” and

direction of the player. Also, make the direction start listening for keyboard commands.

change by using if statements to test the direction Next, you must add three methods to your code: of the car and alter “x” if it is going left/right and alter “y” if it is going up/down.

public void keyPressed(KeyEvent e){}

public void keyReleased(KeyEvent e){}

Let’s check to see if the player has collided with public void keyTyped(KeyEvent e){}

a wall or the other car. If so, set the player’s speed Each of these methods are automatically called to a negative value so the car moves backwards when a key is typed. “keyPressed” is called when before picking up speed.

the key is pushed down. “keyReleased” is called The completed code is below:

when you let go of a key after pressing it.

//RADICAL RACING

//Project 11

//By Ian Cinnamon

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

//this creates the class where you use JFrame

public class G1P3 extends JFrame

{

//this is the constand that will hold the screen size final int WIDTH = 900, HEIGHT = 650;

//these will keep track of each player’s speed: Project 11: Radical Racing—Collision!

double p1Speed =.5, p2Speed =.5;

38

Project 11: Radical Racing—Collision!

//these are ints that represent directions:

final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3;

//these will keep track of the player’s directions (default = up) int p1Direction = UP;

int p2Direction = UP;

//create rectangles that wil represent the left, right, top, bottom, and center Rectangle left = new Rectangle(0,0,WIDTH/9, HEIGHT); Rectangle right = new Rectangle((WIDTH/9)*8,0,WIDTH/9,HEIGHT); Rectangle top = new Rectangle(0,0,WIDTH,HEIGHT/9); Rectangle bottom = new Rectangle(0,(HEIGHT/9)*8,WIDTH,HEIGHT/9); Rectangle center = new Rectangle((int)((WIDTH/9) *2.5),(int)((HEIGHT/9)*2.5), (int)((WIDTH/9)*5),(HEIGHT/9)*4);

//these obstacles will obstruct the path and make navigating harder Rectangle obstacle = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9); Rectangle obstacle2 = new Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle3 = new Rectangle(2*(WIDTH/3),(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9); Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5), WIDTH/30,HEIGHT/4);

//the following rectangle is the finish line for both players Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)−HEIGHT/9, (int)((WIDTH/9)*1.5),HEIGHT/70);

//this is the rectangle for player 1’s (outer) car: Rectangle p1 = newRectangle(WIDTH/9,HEIGHT/2, WIDTH/30,WIDTH/30);

//this is the rectang;e for player 2’s (inner) car: Rectangle p2 = new Rectangle(((WIDTH/9)+ ((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+

(HEIGHT/10),WIDTH/30,WIDTH/30);

//the constructor:

public G1P3()

{

//the following code creates the JFrame

super(“Radical Racing”);

setSize(WIDTH,HEIGHT);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

//start the inner class (which works on its own, because it is a Thread) Move1 m1 = new Move1();

Move2 m2 = new Move2();

m1.start();

m2.start();

}

//this will draw the cars and the race track

public void paint(Graphics g)

{

super.paint(g);

//draw the background for the racetrack

g.setColor(Color.DARK_GRAY);

g.fillRect(0,0,WIDTH,HEIGHT);

//when we draw, the border will be green

g.setColor(Color.GREEN);

//the following rectangle is the start line for the outer player Rectangle lineO = new Rectangle(WIDTH/9,HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);

//the following rectangle is the start line for the inner player Rectangle lineI = new Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)), (HEIGHT/2)+(HEIGHT/10), (int)

((WIDTH/9)*1.5)/2,HEIGHT/140);

39

//now, using the rectangles, draw it

g.fillRect(left.x,left.y,left.width,left.height); g.fillRect(right.x,right.y,right.width,right.height); g.fillRect(top.x,top.y,top.width,top.height);

g.fillRect(bottom.x,bottom.y,bottom.width,bottom.height); g.fillRect(center.x,center.y,center.width,center.height); g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height); g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height); g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height); g.fillRect(obstacle4.x,obstacle4.y,obstacle3.width,obstacle4.height); g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);

//set the starting line color to white

g.setColor(Color.WHITE);

//now draw the starting line

g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height); g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);

//set the color of the finish line to yellow

g.setColor(Color.YELLOW);

//now draw the finish line

g.fillRect(finish.x,finish.y,finish.width,finish.height);

//set the color to blue for p1

g.setColor(Color.BLUE);

//now draw the actual player

g.fill3DRect(p1.x,p1.y,p1.width,p1.height,true);

//set the color to red for p2

g.setColor(Color.RED);

//now draw the actual player

g.fill3DRect(p2.x,p2.y,p2.width,p2.height,true);

}

private class Move1 extends Thread implements KeyListener

{

public void run()

{

//add the code to make the KeyListener “wake up”

addKeyListener(this);

//now, this should all be in an infinite loop, so the process repeats while(true)

{

//now, put the code in a “try” block. This will let the program exit

//if there is an error.

try

{

//first, refresh the screen:

repaint();

//check to see if car hits the outside walls.

//If so, make it slow its speed by setting its speed

//to −4.

if(p1.intersects(left) || p1.intersects(right) ||

p1.intersects(top) || p1.intersects(bottom) ||

p1.intersects(obstacle) || p1.intersects(obstacle2)||

p1.intersects(p2) || p1.intersects(obstacle3) ||

p1.intersects(obstacle4) || p1.intersects(obstacle5))

{

p1Speed = −4;

}

//if the car hits the center, do the same as above Project 11: Radical Racing—Collision!

//but make the speed −2.5.

40

Project 11: Radical Racing—Collision!

if(p1.intersects(center))

{

p1Speed = −2.5;

}

//increase speed a bit

if(p1Speed<=5)

p1Speed+=.2;

//these will move the player based on direction if(p1Direction= =UP)

{

p1.y-=(int)p1Speed;

}

if(p1Direction= =DOWN)

{

p1.y+=(int)p1Speed;

}

if(p1Direction= =LEFT)

{

p1.x-=(int)p1Speed;

}

if(p1Direction= =RIGHT)

{

p1.x+=(int)p1Speed;

}

//this delays the refresh rate:

Thread.sleep(75);

}

catch(Exception e)

{

//if there is an exception (an error),

exit the loop.

break;

}

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event)

{

if(event.getKeyChar()= =‘a’)

{

p1Direction = LEFT;

}

if(event.getKeyChar()= =‘s’)

{

p1Direction = DOWN;

}

if(event.getKeyChar()= =‘d’)

{

p1Direction = RIGHT;

41

}

if(event.getKeyChar()= =’w’)

{

p1Direction = UP;

}

}

}

private class Move2 extends Thread implements KeyListener

{

public void run()

{

//add the code to make the KeyListener “wake up”

addKeyListener(this);

//now, this should all be in an infinite loop, so the process repeats while(true)

{

//now, put the code in a “try” block. This will let the program exit

//if there is an error.

try

{

//first, refresh the screen:

repaint();

//check to see if car hits the outside walls.

//If so, make it slow its speed by setting its speed

//to −4.

if(p2.intersects(left) || p2.intersects(right) ||

p2.intersects(top) || p2.intersects(bottom) ||

p2.intersects(obstacle) || p2.intersects(obstacle2) ||

p1.intersects(p2))

{

p2Speed = −4;

}

//if the car hits the center, do the same as above

//but make the speed −2.5.

if(p2.intersects(center))

{

p2Speed = −2.5;

}

//increase speed a bit

if(p2Speed<=5)

p2Speed+=.2;

//these will move the player based on direction if(p2Direction= =UP)

{

p2.y−=(int)p2Speed;

}

if(p2Direction= =DOWN)

{

p2.y+=(int)p2Speed;

}

if(p2Direction= =LEFT)

{

p2.x-=(int)p2Speed;

}

if(p2Direction= =RIGHT)

{

p2.x

Project 11: Radical Racing—Collision!

+=(int)p2Speed;

42

Project 11: Radical Racing—Collision!

}

//this delays the refresh rate:

Thread.sleep(75);

}

catch(Exception e)

{

//if there is an exception (an error), exit the loop.

break;

}

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event)

{

if(event.getKeyChar()= = ‘j’)

{

p2Direction = LEFT;

}

if(event.getKeyChar()= =‘k’)

{

p2Direction = DOWN;

}

if(event.getKeyChar()= =‘l’)

{

p2Direction = RIGHT;

}

if(event.getKeyChar()= =‘i’)

{

p2Direction = UP;

}

}

}

//this starts the program by calling the constructor: public static void main (String[ ] args)

{

new G1P3();

}

}

In Figures 11-2 through 11-4, the mobility

In Project 12, make the game come to life with of the cars and their collision detection are

bold graphics and sounds!

illustrated.

43

Figure 11-2

Cars are about to collide.

Figure 11-3

Cars move backwards after collision.

Project 11: Radical Racing—Collision!

44

Project 12: Radical Racing—Customizing

Figure 11-4

Cars turn and complete the track.

Project 12: Radical Racing—Customizing

Project

mode of transportation, save it to <directory of Java project>/build/classes. Figures 12-1

Add modifications to the game with images and

sounds. Create a “welcome” screen. Add a lap

tracking feature that announces the winner after three laps.

New Building Blocks

Images, Sound

Images

Want to change the graphics in your game? It’s not difficult. You can turn your racecar into a

spaceship, a boat, a plane, a cheetah, even a John Deere tractor ... anything that moves!

First, you have to draw the image yourself or

find it on the internet. Once you have chosen your Figure 12-1

Race car.

45

Figure 12-3

Airplane.

Figure 12-2

Boat.

through 12-3 represent some possible means of

URL eng = this.getClass().getResource

transportation that can be used in the game.

(“engine.wav”);

AudioClip snd = JApplet.newAudioClip(eng);

Add the following code before you draw the image: snd.loop();

“engine.wav” is the name of the sound file.

Image img = null;

try

“snd.loop()” will loop the sound file. If you

{

don’t want to loop it, you can replace that code URL url =

this.getClass().getResource (“name”);

with:

img =

Toolkit.getDefaultToolkit().getImage(url);

snd.play()

}

catch(Exception e){}

This will play the sound once.

“name” should be the name of the image you

Don’t forget to import java.applet.AudioClip;

want to use (including the extension).

The sounds used in the games in this book are

all available for free from www.mcgraw-hill.

Then, replace the code that draws the shapes

com/authors/cinnamon

with the following:

g.drawImage(img, x, y, this);

Making the game

“x” and “y” should be the x and y from the

Rectangle.

Add a “welcome” screen using a JOptionPane.

One more thing — don’t forget to import the

You can also write code to keep track of laps by following:

checking the number of collisions with the

“finish” line.

import java.io.*;

import java.net.*;

Draw images to replace the plain, rectangular

All of the images used in the games in this book cars. Make sure you orient the image to the

are available for free from www.mcgraw-hill.com/

direction the racer is traveling (when it is

authors/cinnamon

traveling right, the image should point to the right).

The completed code is below:

Sound

You can quickly add sound effects to your games with the following code:

Project 12: Radical Racing—Customizing

46

Project 12: Radical Racing—Customizing

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.net.*;

import java.applet.AudioClip;

//this creates the class where you use JFrame

public class G1P4 extends JFrame

{

//the following are all 8 images:

URL url1 = null, url2 = null, url3 = null, url4 = null, url5 = null, url6 = null, url7 = null, url8 = null; Image img1,img2,img3,img4,

img5,img6,img7,img8;

//the following URL and Image are for the center title URL URLt = null;

Image title = null;

//this is the constand that will hold the screen size final int WIDTH = 900, HEIGHT = 650;

//this will be true if someone already won

boolean winnerChosen = false;

//these will keep track of each player’s speed: double p1Speed =.5, p2Speed =.5;

//this will keep track of how may laps a player has run int p1Laps = 0, p2Laps = 0;

//these are ints that represent directions:

final int UP = 0, RIGHT = 1, DOWN = 2, LEFT = 3;

//these will keep track of the player’s directions (default = up) int p1Direction = UP;

int p2Direction = UP;

//create rectangles that will represent the left, right, top, bottom, and center Rectangle left = new Rectangle(0,0,WIDTH/9,HEIGHT); Rectangle right = new Rectangle((WIDTH/9)*8,0,WIDTH/9,HEIGHT); Rectangle top = new Rectangle(0,0,WIDTH,HEIGHT/9); Rectangle bottom = new Rectangle(0,(HEIGHT/9)*8,WIDTH,HEIGHT/9); Rectangle center = new Rectangle((int)((WIDTH/9)*2.5),(int)((HEIGHT/9)*2.5), (int) ((WIDTH/9)*5),(HEIGHT/9)*4);

//these obstacles will obstruct the path and make navigating harder Rectangle obstacle = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*7),WIDTH/10,HEIGHT/9); Rectangle obstacle2 = new Rectangle(WIDTH/3,(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle3 = new Rectangle(2*(WIDTH/3),(int)((HEIGHT/9)*5),WIDTH/10,HEIGHT/4); Rectangle obstacle4 = new Rectangle(WIDTH/3,HEIGHT/9,WIDTH/30,HEIGHT/9); Rectangle obstacle5 = new Rectangle(WIDTH/2,(int)((HEIGHT/9)*1.5),WIDTH/30,HEIGHT/4);

//the following rectangle is the finish line for both players Rectangle finish = new Rectangle(WIDTH/9,(HEIGHT/2)−HEIGHT/9, (int)((WIDTH/9)*1.5), HEIGHT/70);

//this is the rectangle for player 1’s (outer) car: Rectangle p1 = new Rectangle(WIDTH/9,HEIGHT/2,WIDTH/30,WIDTH/30);

//this is the rectangle for player 2’s (inner) car: Rectangle p2 = new

Rectangle(((WIDTH/9)+((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+(HEIGHT/10),WIDTH/3

0,WIDTH/30);

//the constructor:

public G1P4()

{

47

//the following code creates the JFrame

super(“Radical Racing”);

setSize(WIDTH,HEIGHT);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

//load the URLs

try

{

url1 = this.getClass().getResource(“G1P4Img1.jpg”); url2 = this.getClass().getResource(“G1P4Img2.jpg”); url3 = this.getClass().getResource(“G1P4Img3.jpg”); url4 = this.getClass().getResource(“G1P4Img4.jpg”); url5 = this.getClass().getResource(“G1P4Img5.jpg”); url6 = this.getClass().getResource(“G1P4Img6.jpg”); url7 = this.getClass().getResource(“G1P4Img7.jpg”); url8 = this.getClass().getResource(“G1P4Img8.jpg”); URLt = this.getClass().getResource(“title.png”);

}

catch(Exception e){}

//attach the URLs to the images

img1 = Toolkit.getDefaultToolkit().getImage(url1); img2 = Toolkit.getDefaultToolkit().getImage(url2); img3 = Toolkit.getDefaultToolkit().getImage(url3); img4 = Toolkit.getDefaultToolkit().getImage(url4); img5 = Toolkit.getDefaultToolkit().getImage(url5); img6 = Toolkit.getDefaultToolkit().getImage(url6); img7 = Toolkit.getDefaultToolkit().getImage(url7); img8 = Toolkit.getDefaultToolkit().getImage(url8); title = Toolkit.getDefaultToolkit().getImage(URLt);

//display a welcome dialog (JOptionPane) that includes the rules JOptionPane.showMessageDialog(null,“WELCOME TO RADICAL RACING!\n\n”+“Game: 2 player racing\n”+“Goal: Complete 3 full laps before your opponent!\n”+“Controls:\n”+“Player1:\n”+“(BLUE CAR) WASD directional, speed is automatic\n”+“ Player 2:\n”+“ (RED CAR) IJKL directional, speed is automatic\n”+“Also, be sure to avoid the green grass. It’s slick\n”+“and might make you spin out!\n\n”+“Click OK to start”);

//start the inner class (which works on its own, because it is a Thread) Move1 m1 = new Move1();

Move2 m2 = new Move2();

m1.start();

m2.start();

//now, play the sound:

try

{

URL eng = this.getClass().getResource (“engine.wav”); AudioClip snd = JApplet.newAudioClip(eng);

snd.loop();

}

catch(Exception e){}

}

//this will draw the cars and the race track

public void paint(Graphics g)

{

super.paint(g);

//draw the background for the racetrack

g.setColor(Color.DARK_GRAY);

Project 12: Radical Racing—Customizing

g.fillRect(0,0,WIDTH,HEIGHT);

48

Project 12: Radical Racing—Customizing

//when we draw, the border will be green

g.setColor(Color.GREEN);

//the following rectangle is the start line for the outer player Rectangle lineO = new Rectangle(WIDTH/9, HEIGHT/2,(int)((WIDTH/9)*1.5)/2,HEIGHT/140);

//the following rectangle is the start line for the inner player Rectangle lineI = new Rectangle(((WIDTH/9)+

((int)((WIDTH/9)*1.5)/2)),(HEIGHT/2)+(HEIGHT/10),(int)((WIDTH/9)*1.5)/2, HEIGHT/140);

//now, using the rectangles, draw it

g.fillRect(left.x,left.y,left.width,left.height); g.fillRect(right.x,right.y,right.width,right.height); g.fillRect(top.x,top.y,top.width,top.height);

g.fillRect(bottom.x,bottom.y,bottom.width, bottom.height); g.fillRect(center.x,center.y,center.width,center.height); g.fillRect(obstacle.x,obstacle.y,obstacle.width,obstacle.height); g.fillRect(obstacle2.x,obstacle2.y,obstacle2.width,obstacle2.height); g.fillRect(obstacle3.x,obstacle3.y,obstacle3.width,obstacle3.height); g.fillRect(obstacle4.x,obstacle4.y,obstacle3.width,obstacle4.height); g.fillRect(obstacle5.x,obstacle5.y,obstacle5.width,obstacle5.height);

//set the starting line color to white

g.setColor(Color.WHITE);

//now draw the starting line

g.fillRect(lineO.x,lineO.y,lineO.width,lineO.height); g.fillRect(lineI.x,lineI.y,lineI.width,lineI.height);

//set the color of the finish line to yellow

g.setColor(Color.YELLOW);

//now draw the finish line

g.fillRect(finish.x,finish.y,finish.width,finish.height);

//this code will draw the title image to the center of the screen: g.drawImage(title,center.x+10,center.y+80,this);

//draw the images for p1

if(p1Direction= =UP)

g.drawImage(img5,p1.x,p1.y,this);

if(p1Direction= =LEFT)

g.drawImage(img8,p1.x,p1.y,this);

if(p1Direction= =DOWN)

g.drawImage(img7,p1.x,p1.y,this);

if(p1Direction= =RIGHT)

g.drawImage(img6,p1.x,p1.y,this);

//draw the images for p2

if(p2Direction= =UP)

g.drawImage(img1,p2.x,p2.y,this);

if(p2Direction= =LEFT)

g.drawImage(img4,p2.x,p2.y,this);

if(p2Direction= =DOWN)

g.drawImage(img3,p2.x,p2.y,this);

if(p2Direction= =RIGHT)

g.drawImage(img2,p2.x,p2.y,this);

}

private class Move1 extends Thread implements KeyListener

{

public void run()

{

//add the code to make the KeyListener “wake up”

addKeyListener(this);

//now, this should all be in an infinite loop, so the process repeats while(true)

{

49

//now, put the code in a “try” block. This will let the program exit

//if there is an error.

try

{

//first, refresh the screen:

repaint();

//check to see if car hits the outside walls.

//If so, make it slow its speed by setting its speed

//to −4.

if(p1.intersects(left) || p1.intersects(right) || p1.intersects(top) ||

p1.intersects(bottom) || p1.intersects(obstacle) ||

p1.intersects(obstacle2)|| p1.intersects(p2) || p1.intersects (obstacle3) ||

p1.intersects(obstacle4) || p1.intersects(obstacle5))

{

p1Speed = −4;

}

//if the car hits the center, do the same as above

//but make the speed −2.5.

if(p1.intersects(center))

{

p1Speed = −2.5;

}

//check how many laps:

if(p1.intersects(finish)&&p1Direction= =UP)

{

p1Laps+ +;

}

//3 full laps will occur when laps is about 24.

//so, use an if statement to check it and tell the user.

//also, if winnerChosen is false, tell them they won and set it

//to true. Otherwise, tell the user they lost.

if(p1Laps>=24)

{

if(!winnerChosen)

{

winnerChosen = true;JOptionPane.showMessageDialog(null, “Player 1 (blue) Wins!!!”);

break;

}

else

{

JOptionPane.showMessageDialog(null, “Player 1 (blue): LOSER!:(\n” + “Player 2

(red): WINNER!!!:D”);

break;

}

}

//increase speed a bit

if(p1Speed<=5)

p1Speed+=.2;

//these will move the player based on direction if(p1Direction= =UP)

{

p1.y−=(int)p1Speed;

}

if(p1Direction= =DOWN)

{

p1.y+=(int)p1Speed;

Project 12: Radical Racing—Customizing

}

50

Project 12: Radical Racing—Customizing

if(p1Direction= =LEFT)

{

p1.x−=(int)p1Speed;

}

if(p1Direction= =RIGHT)

{

p1.x+=(int)p1Speed;

}

//this delays the refresh rate:

Thread.sleep(75);

}

catch(Exception e)

{

//if there is an exception (an error), exit the loop.

break;

}

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event)

{

if(event.getKeyChar()= =‘a’)

{

p1Direction = LEFT;

}

if(event.getKeyChar()= =‘s’)

{

p1Direction = DOWN;

}

if(event.getKeyChar()= =‘d’)

{

p1Direction = RIGHT;

}

if(event.getKeyChar()= =‘w’)

{

p1Direction = UP;

}

}

}

private class Move2 extends Thread implements KeyListener

{

public void run()

{

//add the code to make the KeyListener “wake up”

addKeyListener(this);

//now, this should all be in an infinite loop, so the process repeats while(true)

{

//now, put the code in a “try” block. This will let the program exit

//if there is an error.

51

try

{

//first, refresh the screen:

repaint();

//check to see if car hits the outside walls.

//If so, make it slow its speed by setting its speed

//to −4.

if(p2.intersects(left) || p2.intersects(right) ||

p2.intersects(top) || p2.intersects(bottom) ||

p2.intersects(obstacle) ||p2.intersects(obstacle2) ||

p1.intersects(p2) || p1.intersects(obstacle3) ||

p1.intersects(obstacle4) || p1.intersects(obstacle5))

{

p2Speed = −4;

}

//if the car hits the center, do the same as above

//but make the speed −2.5.

if(p2.intersects(center))

{

p2Speed = −2.5;

}

//check how many laps:

if(p2.intersects(finish)&&p2Direction= =UP)

{

p2Laps+ +;

}

//3 full laps will occur when laps is about 24.

//so, use an if statement to check it and tell the user.

//also, if winnerChosen is false, tell them they won and set it

//to true. Otherwise, tell the user they lost.

if(p2Laps>=24)

{

if(!winnerChosen)

{

winnerChosen = true;

JOptionPane.showMessageDialog(null, “Player 2 (red) Wins!!!”); break;

}

else

{

JOptionPane.showMessageDialog(null,

“Player 2 (red): LOSER!:(\n” +

“Player 1 (blue): WINNER!!!:D”);

break;

}

}

//increase speed a bit

if(p2Speed<=5)

p2Speed+=.2;

//these will move the player based on direction if(p2Direction= =UP)

{

p2.y−=(int)p2Speed;

}

if(p2Direction= =DOWN)

{

p2.y+=(int)p2Speed;

}

Project 12: Radical Racing—Customizing

if(p2Direction= =LEFT)

52

Project 12: Radical Racing—Customizing

{

p2.x-=(int)p2Speed;

}

if(p2Direction= =RIGHT)

{

p2.x+=(int)p2Speed;

}

//this delays the refresh rate:

Thread.sleep(75);

}

catch(Exception e)

{

//if there is an exception (an error), exit the loop.

break;

}

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event)

{

}

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event)

{

if(event.getKeyChar()= =‘j’)

{

p2Direction = LEFT;

}

if(event.getKeyChar()= =‘k’)

{

p2Direction = DOWN;

}

if(event.getKeyChar()= =‘l’)

{

p2Direction = RIGHT;

}

if(event.getKeyChar()= =‘i’)

{

p2Direction = UP;

}

}

}

//this starts the program by calling the constructor: public static void main (String[ ] args)

{

new G1P4();

}

}

53

Figures 12-4 through 12-6 depict the game with Experiment with different sound effects/music.

the new graphics.

Change the rules—give one player a head start

while increasing the other racer’s speed.

Customizing the game

Add a slow-motion section to the track.

Add more cars so more people can play.

Make your own track—make it round, make it

square, whatever you want!

Shape-shift: have the racers change vehicles

Add more detail/colors to both racers and the track.

after each lap.

Program hidden obstacles (potholes) in the

Reverse world: race backwards (change which

middle of the track.

keys do what).

Figure 12-4

Welcome screen.

Project 12: Radical Racing—Customizing Figure 12-5 Cars are ready to race!

54

Project 13: Screen Skier—The Slope

Figure 12-6

Blue car wins!

Project 13: Screen Skier—The Slope

computer to see where the user is clicking. In KeyListener, you had to add three methods,

Screen skier

whether or not you used all of them. You must do the same with MouseListener, except there are five It’s a slippery slope as you have exactly 45 seconds methods. They are:

to ski down the mountain on a course you create.

Fail and die or win and grab the glory!

public void mouseClicked(MouseEvent e){}

public void mouseEntered(MouseEvent e){}

public void mouseExited(MouseEvent e){}

Project

public void mousePressed(MouseEvent e){}

public void mouseReleased(MouseEvent e){}

In this project, you will create the slope-drawing In Screen Skier, you will use only the last two.

environment: is it a smooth and gentle slope, a For “mousePressed,” you will see where the

sheer drop, or a bumpy terrain of boulders and player first pressed the mouse (the first point on trees? You decide!

the slope). You will then use “mouseReleased” to see where the player ended the track.

New building blocks

Of course, the methods are useless if you

don’t know how to see the coordinates of the

MouseListener, Premade Classes

player’s click.

Here’s how:

MouseListener

To get the x coordinate, use the following code: You already know how to program the computer to e.getX();

see what the player is typing. Now, you can get the 55

To get the y coordinate, use this code:

labeled “Constructor Summary.” This will tell

you how to create the class. For a Point2D.Double, e.getY();

it says to pass in two doubles: the x and y

coordinates. Therefore, by using the

Premade classes

“mousePressed” method, you can get the first

point of the line by creating a Point2D.Double.

Java has hundreds of premade classes you can use.

You can then create a line in the “mouseReleased”

A complete list of the classes and their

method using your previous point and the point descriptions is called the Java API. It is located where the user released the mouse. You can add

here: http://java.sun.com/j2se/1.5.0/docs/api/

this line to an ArrayList.

One premade class you will use in Screen Skier If you want to know what methods you

holds the information for a single line. The class is can use with a given class, go to NetBeans and called Line2D.Double. Another class that holds a create a new instance of the class. For example, single point (the first part of the line) is called with the class Point2D.Double, do the following: Point2D.Double.

Point2D.Double pnt = new Point2D.Double

If you look in the API, it will tell you what you (23.5,563.0);

must import. In addition, you will see a table Project 13: Screen Skier—The Slope Figure 13-1 Pop-up box in NetBeans.

56

Project 13: Screen Skier—The Slope

Then, type the following:

Making the game

pnt.

When you type the period, NetBeans will create It’s time to create the first part of Screen Skier: the a list of all the methods you can use. Most are slope drawing environment. Use a mouseListener self-explanatory, but for the more complex

and Point2D.Double and Line2D.Double to draw

methods, NetBeans will make a description pop-

the ski slope. Store the lines in an ArrayList and up, as shown in Figure 13-1.

use a “for loop” to print all of the lines in the ArrayList from the paint method.

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.*;

//the actual class:

public class G2P1 extends JFrame implements MouseListener

{

//this ArrayList holds the lines:

ArrayList lines = new ArrayList();

//this will hold the first point of the line

Point2D.Double holder;

//the constructor:

public G2P1()

{

//set the title:

super(“Screen Skier — Programming Video Games for the Evil Genius”); setSize(700,700);

setVisible(true);

setDefaultCloseOperation(JFrame. EXIT_ON_CLOSE); addMouseListener(this);

}

public void paint(Graphics g)

{

super.paint(g);

//set the color to black (for the lines):

g.setColor(Color.black);

//this for loop will go thru every line in the ArrayList and draw them: for(int i = 0; i <lines.size(); i+ +)

{

//get the line in the ArrayList:

Line2D.Double temp = (Line2D.Double) lines.get(i);

//now get all the x’s and y’s

int x1 = Integer.parseInt(“”+Math.round (temp.getX1())); int y1 = Integer.parseInt(“”+Math.round (temp.getY1())); int x2 = Integer.parseInt(“”+Math.round (temp.getX2())); int y2 = Integer.parseInt(“”+Math.round (temp.getY2())); g.drawLine(x1,y1,x2,y2);

}

}

//these are the mouse listener methods:

57

public void mouseClicked(MouseEvent e){}

//these are the mouse listener methods:

public void mouseEntered(MouseEvent e){}

//these are the mouse listener methods:

public void mouseExited(MouseEvent e){}

//these are the mouse listener methods:

public void mousePressed(MouseEvent e)

{

//this code will run when the mouse is first pressed, getting the

//starting point of the line.

holder = new Point2D.Double(e.getX(),e.getY());

}

//these are the mouse listener methods:

public void mouseReleased(MouseEvent e)

{

//this code will run when the mouse is released, completing the

//line and adding it to the ArrayList.

Point2D.Double end = new Point2D.Double(e.getX(),e.getY()); lines.add(new Line2D.Double(holder,end));

//now, repinat the screen so the line is drawn: repaint();

}

public static void main (String[ ] args)

{

//begin the program:

new G2P1();

}

}

Project 13: Screen Skier—The Slope Figure 13-2 Blank canvas.

58

Project 13: Screen Skier—The Slope

Figures 13-2 through 13-4 depict the line

Let your mind go wild! In the next project,

drawing capabilities of Screen Skier.

create any kind of skier you want to glide down slopes of your design.

Figure 13-3

Single line.

Figure 13-4

Many lines connect to create the track.

59

Project 14: Screen Skier—Practice Run

Project

Create a figure to ski down the track the player has drawn.

Making the game

Start by generating the image and the Rectangle that will represent the skier.

To have the skier race down the slope, initialize a Thread that controls the player’s movements.

Inside the Thread, make a method that sets up the Figure 14-1

Starting position.

skier’s starting position (a bit to the right and above the first point of the first line), as shown in If the skier is not on the line, slowly increase Figure 14-1.

“gravity.” If the skier is on the line, find the difference between the two points of the line and Call this method from the run method before the divide by 50 for the y axis and 100 for the x axis.

while loop. In addition, create another method Add this to the respective variables, “gravity” and that takes in a boolean as its argument that can end

“velocity.” Then, apply these variables to the the while loop. Inside the while loop, check to skier’s x and y position. Don’t forget to repaint and see if the skier’s Rectangle intersects any of the delay before iterating through the loop again.

lines (use the “intersects” method).

Outside the Thread, use the KeyListener to

In order to control the skier’s x and y

see if ‘p’ (for “play”) or ‘q’ (for “quit”) is pressed.

movements, create two global doubles called

If ‘p’ is pressed, begin the loop. If ‘q’ is pressed,

“velocity” and “gravity” (discussed in Section 1).

end the loop.

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.*;

import java.io.*;

import java.net.*;

//the actual class:

public class G2P2 extends JFrame implements MouseListener, KeyListener

{

//this ArrayList holds the lines:

Project 14: Screen Skier—Practice Run

ArrayList lines = new ArrayList();

60

Project 14: Screen Skier—Practice Run

//this will hold the first point of the line

Point2D.Double holder;

//this is the Thread:

Move move;

//this will hold the character’s information:

Rectangle guy = null;

//this will tell repaint whether or not to draw the guy: boolean drawGuy = false;

//the constructor:

public G2P2()

{

//set the title:

super(“Screen Skier − Programming Video Games for the Evil Genius”); setSize(700,700);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addMouseListener(this);

addKeyListener(this);

}

public void paint(Graphics g)

{

super.paint(g);

//set the color to black (for the lines):

g.setColor(Color.black);

//this for loop will go thru every line in the ArrayList and draw them: for(int i = 0; i <lines.size(); i+ +)

{

//get the line in the ArrayList:

Line2D.Double temp = (Line2D.Double) lines.get(i);

//now get all the x’s and y’s

int x1 = Integer.parseInt(“”+Math.round (temp.getX1())); int y1 = Integer.parseInt(“”+Math.round (temp.getY1())); int x2 = Integer.parseInt(“”+Math.round (temp.getX2())); int y2 = Integer.parseInt (“”+Math.round(temp.getY2())); g.drawLine(x1,y1,x2,y2);

}

if(drawGuy)

{

try

{

//draw the guy:

URL url = this.getClass().getResource (“guy.png”); Image img = Toolkit.getDefaultToolkit().getImage(url); g.drawImage(img, guy.x, guy.y, this);

}

catch(Exception e){}

}

}

//these are the mouse listener methods:

public void mouseClicked(MouseEvent e){}

//these are the mouse listener methods:

public void mouseEntered(MouseEvent e){}

61

//these are the mouse listener methods:

public void mouseExited(MouseEvent e){}

//these are the mouse listener methods:

public void mousePressed(MouseEvent e)

{

//this code will run when the mouse is first pressed, getting the

//starting point of the line.

holder = new Point2D.Double(e.getX(),e.getY());

}

//these are the mouse listener methods:

public void mouseReleased(MouseEvent e)

{

//this code will run when the mouse is released, completing the

//line and adding it to the ArrayList.

Point2D.Double end = new Point2D.Double(e.getX(),e.getY()); lines.add(new Line2D.Double(holder,end));

//now, repinat the screen so the line is drawn: repaint();

}

//these are the key listener methods:

public void keyPressed(KeyEvent e){}

//these are the key listener methods:

public void keyReleased(KeyEvent e){}

//these are the key listener methods:

public void keyTyped(KeyEvent e)

{

//if the user presses “p” OR “P,” start the Thread if(e.getKeyChar()= =‘p’ || e.getKeyChar()= =‘P’)

{

//init the Thread:

move = new Move();

move.start();

move.action(true);

}

//if the user presses “q” OR “Q,” stop the Thread if(e.getKeyChar()= =‘q’ || e.getKeyChar()= =‘Q’)

{

move.action(false);

drawGuy = false;

move = null;

}

}

//this is the thread that will make the character move private class Move extends Thread

{

//these variables will hold the player’s speed and gravity double velocity;

double gravity;

//stops/starts the thread:

boolean go = false;

public void run()

{

if(go)

{

Project 14: Screen Skier—Practice Run

initGuy();

62

Project 14: Screen Skier—Practice Run

velocity = 0;

gravity = 1;

}

while(go)

{

try

{

//this will hold the line the guy is on (null if none) Line2D.Double lineTaken = null;

//this will say whether the character is even on a line boolean onLine = false;

//gravity needs to be reset when the guy first lands on

//the line. This will hold that info. It holds the line #

int firstOnLine = −1;

//check if he is on a line:

for(int i = lines.size()−1; i>=0; i− −)

{

//get the line:

Line2D.Double temp = (Line2D.Double) lines.get(i); if(temp.intersects(guy.x,guy.y,30,30))

{

lineTaken = temp;

onLine = true;

if(firstOnLine!=i)

{

firstOnLine = i;

gravity = 0;

}

break;

}

}

//if there is a line it is on ...

if(onLine)

{

//now, get the new gravity by subtracting the y’s and

//dividing by 20

double mGrav = (lineTaken.y2−line Taken.y1)/50;

//now, get the new velocity by subtracting the x’s and

//dividing by 20

double mVel = (lineTaken.x2−line Taken.x1)/100;

//set the maximum values

if(velocity<5)

velocity+=mVel;

if(gravity<2.5)

gravity+=mGrav;

}

else

{

gravity+=.2;

}

//alter the guy’s movements:

guy.x += velocity;

guy.y += gravity;

//delay before repainting:

Thread.sleep(75);

//repaint:

repaint();

63

}

catch(Exception e){ break; }

}

}

public void action(boolean a)

{

//stops the thread:

go = a;

}

public void initGuy()

{

/*

* This code will set up the character’s position

*/

//get the first line

Line2D.Double firstLine = (Line2D.Double) lines.get(0);

//get the first “x” and “y” of that line:

int x = Integer.parseInt(“”+Math.round (firstLine.x1)); int y = Integer.parseInt(“”+Math.round (firstLine.y1)); guy = new Rectangle(x+30,y−20,30,30);

drawGuy = true;

}

}

public static void main (String[ ] args)

{

//begin the program:

new G2P2();

}

}

Project 14: Screen Skier—Practice Run Figure 14-2 Slope comes to life.

64

Project 14: Screen Skier—Practice Run

Figure 14-3

Skiing.

Figure 14-4

More skiing.

65

Figure 14-5

Ouch! Skier falls off the end of the track.

Figures 14-2 through 14-5 depict the steps of

Want to make the game more realistic? Go on to drawing a track and letting the skier glide down the next project to learn how to make impressive the slope.

graphics.

Project 15: Screen Skier—Expert Slope

Project

Then, add this image to the program. In addition, add a 5000 by 5000 white square behind the image Create a bigger drawing environment with

(using fillRect). This will make the game appear different perspectives.

realistic if the skier goes beyond the background image, as demonstrated in Figure 15-1.

Making the game

Now, expand the drawing environment. First,

make two variables—one called “focusX” and the First, let’s add the graphics. Start by making a other called “focusY.” Set them to zero. Base

Project 15: Screen Skier—Expert Slope 1400 by 1400 pixel image to use as a background.

everything off of these variables. For example, 66

Project 15: Screen Skier—Expert Slope

Figure 15-1

Background—before and after.

when you get the x coordinate of a click, use the

“guy.y−100,” respectively. This will make the

following:

screen follow the skier. You can also add

e.getX()+focusX

keyListeners to alter focusX and focusY by 100

When you draw the skier (in the paint method), pixels so that the player can move the focus around change focusX and focusY to “guy.x−100” and

when creating the ski slope.

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.*;

import java.io.*;

import java.net.*;

//the actual class:

public class G2P3 extends JFrame implements MouseListener, KeyListener

{

//this ArrayList holds the lines:

ArrayList lines = new ArrayList();

//this will hold the first point of the line

Point2D.Double holder;

//this is the Thread:

Move move;

67

//this will hold the character’s information:

Rectangle guy = null;

//this will tell repaint whether or not to draw the guy: boolean drawGuy = false;

//this will make the screen focus on the guy:

int focusX = 0;

int focusY = 0;

//the constructor:

public G2P3()

{

//set the title:

super(“Screen Skier - Programming Video Games for the Evil Genius”); setSize(700,700);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); addMouseListener(this);

addKeyListener(this);

}

public void paint(Graphics g)

{

super.paint(g);

//draw the background:

try

{

//this is the general, plain white background: g.setColor(Color.white);

g.fillRect(−2000,−2000,5000,5000);

//this is the image background

URL url = this.getClass().getResource (“bg.png”); Image img = Toolkit.getDefaultToolkit(). getImage(url); g.drawImage(img, 0−focusX, 0−focusY, this);

}

catch(Exception e){}

//set the color to black (for the lines):

g.setColor(Color.black);

//this for loop will go tru every line in the ArrayList and draw them: for(int i = 0; i <lines.size(); i+ +)

{

//get the line in the ArrayList:

Line2D.Double temp = (Line2D.Double) lines.get(i);

//now get all the x’s and y’s

int x1 = Integer.parseInt(“”+Math.round(temp.getX1())); int y1 = Integer.parseInt(“”+Math.round (temp.getY1())); int x2 = Integer.parseInt(“”+Math.round (temp.getX2())); int y2 = Integer.parseInt(“”+Math.round (temp.getY2())); g.drawLine(x1−focusX,y1−focusY,x2−focusX,y2−focusY);

}

if(drawGuy)

{

try

{

//draw the guy:

URL url = this.getClass().getResource (“guy.png”); Image img = Toolkit.getDefaultToolkit(). getImage(url); Project 15: Screen Skier—Expert Slope

g.drawImage(img, guy.x−focusX, guy.y−focusY, this); 68

Project 15: Screen Skier—Expert Slope

}

catch(Exception e){}

//reset the focus to the guy’s position

focusX = guy.x−100;

focusY = guy.y−100;

}

}

//these are the mouse listener methods:

public void mouseClicked(MouseEvent e){}

//these are the mouse listener methods:

public void mouseEntered(MouseEvent e){}

//these are the mouse listener methods:

public void mouseExited(MouseEvent e){}

//these are the mouse listener methods:

public void mousePressed(MouseEvent e)

{

//this code will run when the mouse is first pressed, getting the

//starting point of the line.

holder = new Point2D.Double(e.getX()+ focusX,e.getY()+focusY);

}

//these are the mouse listener methods:

public void mouseReleased(MouseEvent e)

{

//this code will run when the mouse is released, completing the

//line and adding it to the ArrayList.

Point2D.Double end = new Point2D.Double(e.get X()+focusX, e.getY()+focusY); lines.add(new Line2D.Double(holder,end));

//now, repinat the screen so the line is drawn: repaint();

}

//these are the key listener methods:

public void keyPressed(KeyEvent e){}

//these are the key listener methods:

public void keyReleased(KeyEvent e){}

//these are the key listener methods:

public void keyTyped(KeyEvent e)

{

//if the user presses “p” OR “P,” start the Thread if(e.getKeyChar()= =‘p’ || e.getKeyChar()= =‘P’)

{

//init the Thread:

move = new Move();

move.start();

move.action(true);

}

//if the user presses “q” OR “Q,” stop the Thread if(e.getKeyChar()= =‘q’ || e.getKeyChar()= =‘Q’)

{

move.action(false);

drawGuy = false;

focusX = 0;

focusY = 0;

move = null;

}

//if the user presses “a” OR “A,” move the focus 69

if(e.getKeyChar()= =‘a’ || e.getKeyChar()= =‘A’)

{

focusX−=100;

repaint();

}

//if the user presses “s” OR “S,” move the focus if(e.getKeyChar()= =‘s’ || e.getKeyChar()= =‘S’)

{

focusY+=100;

repaint();

}

//if the user presses “w” OR “W,” move the focus if(e.getKeyChar()= =‘w’ || e.getKeyChar()= =‘W’)

{

focusY−=100;

repaint();

}

//if the user presses “d” OR “D,” move the focus if(e.getKeyChar()= =‘d’ || e.getKeyChar()= =‘D’)

{

focusX+=100;

repaint();

}

}

//this is the thread that will make the character move private class Move extends Thread

{

//these variables will hold the player’s speed and gravity double velocity;

double gravity;

//stops/starts the thread:

boolean go = false;

public void run()

{

if(go)

{

initGuy();

velocity = 0;

gravity = 1;

}

while(go)

{

try

{

//this will hold the line the guy is on (null if none) Line2D.Double lineTaken = null;

//this will say whether the character is even on a line boolean onLine = false;

//gravity needs to be reset when the guy first lands on

//the line. This will hold that info. It holds the line #

int firstOnLine = −1;

//check if he is on a line:

for(int i = lines.size()−1; i>=0; i− −)

{

//get the line:

Line2D.Double temp = (Line2D.Double) lines.get(i); Project 15: Screen Skier—Expert Slope

if(temp.intersects(guy.x,guy.y,30,30))

70

Project 15: Screen Skier—Expert Slope

{

lineTaken = temp;

onLine = true;

if(firstOnLine!=i)

{

firstOnLine = i;

gravity = 0;

}

break;

}

}

//if there is a line it is on ...

if(onLine)

{

//now, get the new gravity by subtracting the y’s and

//dividing by 20

double mGrav = (lineTaken.y2−lineTaken.y1)/50;

//now, get the new velocity by subtracting the x’s and

//dividing by 20

double mVel = (lineTaken.x2−lineTaken.x1)/100;

//set the maximum values

if(velocity<5)

velocity+=mVel;

if(gravity<2.5)

gravity+=mGrav;

}

else

{

gravity+=.2;

}

//alter the guy’s movements:

guy.x += velocity;

guy.y += gravity;

//delay before repainting:

Thread.sleep(75);

//repaint:

repaint();

}

catch(Exception e){ break; }

}

}

public void action(boolean a)

{

//stops the thread:

go = a;

}

public void initGuy()

{

/*

* This code will set up the character’s position

*/

//get the first line

Line2D.Double firstLine = (Line2D.Double) lines.get(0);

//get the first “x” and “y” of that line:

int x = Integer.parseInt(“”+Math.round(firstLine.x1)); int y = Integer.parseInt(“”+Math.round(firstLine.y1)); 71

guy = new Rectangle(x+30,y−20,30,30);

drawGuy = true;

}

}

public static void main (String[ ] args)

{

//begin the program:

new G2P3();

}

}

Figures 15-2 through 15-6 depict the game play With editing tools, you can make endless

of Screen Skier.

variations: add more track, undo the last piece of slope, or even bulldoze everything and start again.

Project 15: Screen Skier—Expert Slope Figure 15-2 Slope is created.

72

Project 15: Screen Skier—Expert Slope

Figure 15-3

Screen moves to expand the slope.

Figure 15-4

Skier journeys down the slope.

73

Figure 15-5

Skier continues downhill.

Project 15: Screen Skier—Expert Slope Figure 15-6 Skier ventures uphill.

74

Project 16: Screen Skier—Bulldozer

Project 16: Screen Skier—Bulldozer

Project

Change the course: delete it, add to it ... make it extreme!

Making the game

To allow the player to delete his/her last line, Figure 16-1

“confirmDialog” box.

create a new keyEvent for “z” (because “Crtl+z” is undo). When the user presses “z,” execute the

following code:

Warning: if the user accidentally presses “x,”

lines.remove(lines.size()−1);

hours of hard work will be deleted! Prevent this

“lines.remove” deletes the variable inside of the distaster by using a JOptionPane, which will

parentheses at the given element position. Because provide a safety net. Use the following code:

you are giving it the position of “lines.size()-

1,” the computer will remove the last line

int answer = JOptionPane.showConfirmDialog

(null, “Delete?”);

(remember lines.size returns the size of the

ArrayList, not the last element!).

A ConfirmDialog box is displayed in Figure 16-1.

To let the user clear the entire track, create a The variable “answer” represents one of the

keyEvent for “x.” To clear the entire ArrayList, use three options. Use the following code inside an if-the following code:

statement to check if the user pressed “OK.” Ways lines.clear();

to check for other responses can be found in the API.

answer= =JOptionPane.OK_OPTION

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.*;

import java.io.*;

import java.net.*;

import java.applet.AudioClip;

//the actual class:

public class G2P4 extends JFrame implements MouseListener, KeyListener

{

//this ArrayList holds the lines:

ArrayList lines = new ArrayList();

//this will hold the first point of the line

Point2D.Double holder;

//these are the Threads:

Move move;

75

Counter cnt;

//this will hold the character’s information:

Rectangle guy = null;

//this will tell repaint whether or not to draw the guy: boolean drawGuy = false;

//this will hold the seconds the skier has been skiing int counter = 0;

//this will make the screen focus on the guy:

int focusX = 0;

int focusY = 0;

//if the guys hits the bottom, change the icon with this boolean boolean alive = true;

//true if the sound has been played

boolean sndPlayed = false;

//the current time:

int count = 0;

//this holds the final time

int holdTime = 0;

//this says whether or not to use the “hold” value boolean useHold = false;

//the constructor:

public G2P4()

{

//set the title:

super(“Screen Skier — Programming Video Games for the Evil Genius”); setSize(700,700);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JOptionPane.showMessageDialog(null,

“SCREEN SKIER\n\n” +

“Create your own ski run! Simply\n” +

“click and drag the mouse to create\n” +

“a track. Press ‘p’ to start the\n” +

“run and ‘q’ to end it. To create\n” +

“a larger track, use the WASD keys\n” +

“to move the focus of the screen.\n” +

“All uphill slopes become ski lifts.\n” +

“If you make them too steep, however,\n” +

“they may collapse! Also, if you try\n” +

“to even the track out from a large\n” +

“decline, the skier may fall through\n” +

“the track into the snow! Also, if you\n” +

“made a mistake designing your track,\n” +

“you can erase it by pressing ‘x’.\n” +

“You can also undo the last line by\n” +

“pressing ‘z’.\n\n\n” +

“Your goal: Create a track that keeps the\n” +

“skier alive for exactly 45 seconds.\n\n” +

“Be Careful and Good Luck!”);

addMouseListener(this);

addKeyListener(this);

//set up the counter

cnt = new Counter();

cnt.go = false;

Project 16: Screen Skier—Bulldozer

cnt.start();

76

Project 16: Screen Skier—Bulldozer

}

public void paint(Graphics g)

{

super.paint(g);

//draw the background:

try

{

//this is the general, plain white background: g.setColor(Color.white);

g.fillRect(−2000,−2000,5000,5000);

//this is the image background

URL url = this.getClass().getResource (“bg.png”); Image img = Toolkit.getDefaultToolkit(). getImage(url); g.drawImage(img, 0−focusX, 0−focusY, this);

}

catch(Exception e){}

//set the color to black (for the lines):

g.setColor(Color.black);

//this for loop will go thru every line in the ArrayList and draw them: for(int i = 0; i <lines.size(); i+ +)

{

//get the line in the ArrayList:

Line2D.Double temp = (Line2D. Double) lines.get(i);

//now get all the x’s and y’s

int x1 = Integer.parseInt(“”+Math.round (temp.getX1())); int y1 = Integer.parseInt(“”+Math.round (temp.getY1())); int x2 = Integer.parseInt(“”+Math.round (temp.getX2())); int y2 = Integer.parseInt(“”+Math.round (temp.getY2())); g.drawLine(x1−focusX,y1−focusY,x2−focusX,y2−focusY);

}

if(drawGuy)

{

try

{

//draw the time:

g.setFont(new Font(“times new roman”, Font.BOLD, 16)); URL urlTime = this.getClass().getResource (“time.png”); Image imgT = Toolkit.getDefaultToolkit().getImage (urlTime); g.drawImage(imgT, −35, 10, this);

if(!useHold)

g.drawString(“Current Time: “+count, 50, 50);

else

g.drawString(“Current Time: “+holdTime, 50, 50);

//draw the guy:

if(alive)

{

URL url = this.getClass().getResource (“guy.png”); Image img = Toolkit.getDefaultToolkit().getImage(url); g.drawImage(img, guy.x−focusX, guy.y−focusY, this);

}

else

{

URL url = this.getClass().getResource (“guyDead.png”); Image img = Toolkit.getDefaultToolkit().getImage(url); g.drawImage(img, guy.x−focusX, guy.y−focusY, this);

//if the snd hasn’t been played, play it!

if(!sndPlayed)

77

{

//set up the hold time variable:

holdTime = count;

useHold = true;

//play the sound

URL snd = this.getClass().getResource(“scream.wav”); AudioClip scream = JApplet.newAudioClip(snd);

scream.play();

sndPlayed = true;

//check for a win:

checkWin();

}

}

}

catch(Exception e){}

//reset the focus to the guy’s position

focusX = guy.x−100;

focusY = guy.y−100;

}

}

//check to see if the goal is accomplished

public void checkWin()

{

if(holdTime= =45)

{

JOptionPane.showMessageDialog(null,

“Congrats!\n\n” +

“MISSION ACCOMPLISHED!”);

}

}

//these are the mouse listener methods:

public void mouseClicked(MouseEvent e){}

//these are the mouse listener methods:

public void mouseEntered(MouseEvent e){}

//these are the mouse listener methods:

public void mouseExited(MouseEvent e){}

//these are the mouse listener methods:

public void mousePressed(MouseEvent e)

{

//this code will run when the mouse is first pressed, getting the

//starting point of the line.

holder = new Point2D.Double(e.getX()+focusX,e.getY()+focusY);

}

//these are the mouse listener methods:

public void mouseReleased(MouseEvent e)

{

//this code will run when the mouse is released, completing the

//line and adding it to the ArrayList.

Point2D.Double end = new Point2D.Double(e.getX()+focusX,e.getY()+focusY); lines.add(new Line2D.Double(holder,end));

//now, repinat the screen so the line is drawn: repaint();

}

//these are the key listener methods:

public void keyPressed(KeyEvent e){}

Project 16: Screen Skier—Bulldozer

//these are the key listener methods:

78

Project 16: Screen Skier—Bulldozer

public void keyReleased(KeyEvent e){}

//these are the key listener methods:

public void keyTyped(KeyEvent e)

{

//if the user presses “p” OR “P,” start the Thread if(e.getKeyChar()= =‘p’ || e.getKeyChar()= =‘P’)

{

alive = true;

count = 0;

useHold = false;

//init the Thread:

move = new Move();

cnt.go = true;

move.start();

move.action(true);

sndPlayed = false;

}

//if the user presses “q” OR “Q,” stop the Thread if(e.getKeyChar()= =‘q’ || e.getKeyChar()= =‘Q’)

{

move.action(false);

drawGuy = false;

focusX = 0;

focusY = 0;

move = null;

cnt.go = false;

}

//if the user presses “a” OR “A,” move the focus if(e.getKeyChar()= =‘a’ || e.getKeyChar()= =‘A’)

{

focusX−=100;

repaint();

}

//if the user presses “s” OR “S,” move the focus if(e.getKeyChar()= =‘s’ || e.getKeyChar()= =‘S’)

{

focusY+=100;

repaint();

}

//if the user presses “w” OR “W,” move the focus if(e.getKeyChar()= =‘w’ || e.getKeyChar()= =‘W’)

{

focusY−=100;

repaint();

}

//if the user presses “d” OR “D,” move the focus if(e.getKeyChar()= =‘d’ || e.getKeyChar()= =’D’)

{

focusX+=100;

repaint();

}

//if the user presses “z” OR “Z,” undo the last line if(e.getKeyChar()= =‘z’ || e.getKeyChar()= =‘Z’)

{

lines.remove(lines.size()−1);

repaint();

79

}

//if the user presses “x” OR “X,” clear the track if(e.getKeyChar()= =‘x’ || e.getKeyChar()= =‘X’)

{

//double check before deleting!

int answer = JOptionPane.showConfirm Dialog(null,

“Do you really want to delete your track?”);

if(answer= =JOptionPane.OK_OPTION)

lines.clear();

repaint();

}

}

private class Counter extends Thread

{

public boolean go = true;

public void run()

{

try

{

while(true)

{

if(go)

{

Thread.sleep(1000);

count+ +;

}

}

}

catch(Exception e){}

}

}

//this is the thread that will make the character move private class Move extends Thread

{

//these variables will hold the player’s speed and gravity double velocity;

double gravity;

//stops/starts the thread:

boolean go = false;

public void run()

{

if(go)

{

initGuy();

velocity = 0;

gravity = 1;

}

while(go)

{

try

{

//this will hold the line the guy is on (null if none) Line2D.Double lineTaken = null;

//this will say whether the character is even on a line boolean onLine = false;

//gravity needs to be reset when the guy first lands on

//the line. This will hold that info. It holds the line #

Project 16: Screen Skier—Bulldozer

80

Project 16: Screen Skier—Bulldozer

int firstOnLine = −1;

//check if he is on a line:

for(int i = lines.size()−1; i>=0; i− −)

{

//get the line:

Line2D.Double temp = (Line2D.Double) lines.get(i); if(temp.intersects(guy.x,guy.y,30,30))

{

lineTaken = temp;

onLine = true;

if(firstOnLine!=i)

{

firstOnLine = i;

gravity = 0;

}

break;

}

}

//if there is a line it is on ...

if(onLine)

{

//now, get the new gravity by subtracting the y’s and

//dividing by 20

double mGrav = (lineTaken.y2−lineTaken.y1)/50;

//now, get the new velocity by subtracting the x’s and

//dividing by 20

double mVel = (lineTaken.x2−lineTaken.x1)/100;

//set the maximum values

if(velocity<5)

velocity+=mVel;

if(gravity<2.5)

gravity+=mGrav;

}

else

{

gravity+=.2;

}

//alter the guy’s movements:

guy.x += velocity;

guy.y += gravity;

//check to see if the guy died:

if(guy.y>1400)

{

alive = false;

}

//delay before repainting:

Thread.sleep(75);

//repaint:

repaint();

}

catch(Exception e){ break; }

}

}

public void action(boolean a)

{

//stops the thread:

81

go = a;

}

public void initGuy()

{

/*

* This code will set up the character’s position

*/

//get the first line

Line2D.Double firstLine = (Line2D.Double) lines.get(0);

//get the first “x” and “y” of that line:

int x = Integer.parseInt(“”+Math.round (firstLine.x1)); int y = Integer.parseInt(“”+Math.round(firstLine.y1)); guy = new Rectangle(x+30,y−20,30,30);

drawGuy = true;

}

}

public static void main (String[ ] args)

{

//begin the program:

new G2P4();

}

}

Figures 16-2 through 16-5 demonstrate

Right now, Screen Skier is a fun drawing tool.

the program’s ability to add or delete

In the next project, learn how to transform Screen track.

Skier into a high pressure “time-trial” game.

Project 16: Screen Skier—Bulldozer Figure 16-2 Pre-made slope.

82

Project 16: Screen Skier—Bulldozer

Figure 16-3

“Undoing” the last part of the slope (by pressing “Z”).

Figure 16-4

The slope is about to be cleared (by pressing “X”).

83

Figure 16-5

Slope destruction (by clicking “Okay”).

Project 17: Screen Skier—Competition

Project

Because you want the timer to run only when

the skier is in motion, go to the keyListener

It all comes together right here—the program you code that ends the skier’s run. Insert code that will created turns into an adrenaline pumping game.

end the while loop of the counter by altering a The goal? Make the skier complete his/her run in boolean in the Thread. Also, be sure to make the exactly 45 seconds. Also, add code for sound

boolean true in the keyListener code that makes effects of screams when the skier falls off the the skier begin skiing. This stops the clock when mountain.

the player passes the finish line ... or falls down the ravine.

Making the game

First, create a counter that times the skier’s run by adding a global variable called “count.” Then, initialize a new Thread called “Counter.” In the run method, insert a while loop. Inside the loop, delay for one second and increment “count” by

one. Figure 17-1 demonstrates an innovative way Project 17: Screen Skier—Competition to display the counter.

Figure 17-1

Counter.

84

Project 17: Screen Skier—Competition

To draw the text, use the method

has crashed. If you want, you can change the icon

“g.drawString(“text”,x,y)”

and add sound effects (record your own shrieks!).

You can also set the text before hand with the When the player is flat on his/her face, call a method “g.setFont(new Font()).” To specify

method that checks the time against 45 seconds.

the font, look up Font’s constructors in the API.

Dead or alive, if the slope was completed in

To check if the player has passed the finish line, exactly 45 seconds, the player wins.

create a boolean called “alive.” In the Thread Be sure to stop the counter and display the final that controls movement, check to see if the skier’s time at the end of the run. Do this by creating a y coordinate is greater than 1400 (because 1400 is variable called “holdTime.”

the bottom of the background image). If so, he/she

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.awt.geom.*;

import java.util.*;

import java.io.*;

import java.net.*;

import java.applet.AudioClip;

//the actual class:

public class G2P5 extends JFrame implements MouseListener, KeyListener

{

//this ArrayList holds the lines:

ArrayList lines = new ArrayList();

//this will hold the first point of the line

Point2D.Double holder;

//these are the Threads:

Move move;

Counter cnt;

//this will hold the character’s information:

Rectangle guy = null;

//this will tell repaint whether or not to draw the guy: boolean drawGuy = false;

//this will hold the seconds the skier has been skiing int counter = 0;

//this will make the screen focus on the guy:

int focusX = 0;

int focusY = 0;

//if the guys hits the bottom, change the icon with this boolean boolean alive = true;

//true if the sound has been played

boolean sndPlayed = false;

//the current time:

int count = 0;

//this holds the final time

int holdTime = 0;

//this says whether or not to use the “hold” value boolean useHold = false;

85

//the constructor:

public G2P5()

{

//set the title:

super(“Screen Skier − Programming Video Games for the Evil Genius”); setSize(700,700);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JOptionPane.showMessageDialog(null,

“SCREEN SKIER\n\n” +

“Create your own ski run! Simply\n” +

“click and drag the mouse to create\n” +

“a track. Press ‘p’ to start the\n” +

“run and ‘q’ to end it. To create\n” +

“a larger track, use the WASD keys\n” +

“to move the focus of the screen.\n” +

“All uphill slopes become ski lifts.\n” +

“If you make them too steep, however,\n” +

“they may collapse! Also, if you try\n” +

“to even the track out from a large\n” +

“decline, the skier may fall through\n” +

“the track into the snow! Also, if you\n” +

“made a mistake designing your track,\n” +

“you can erase it by pressing ‘x’.\n” +

“You can also undo the last line by\n” +

“pressing ‘z’.\n\n\n” +

“Your goal: Create a track that keeps the\n” +

“skiier alive for exactly 45 seconds.\n\n” +

“Be Careful and Good Luck!”);

addMouseListener(this);

addKeyListener(this);

//set up the counter

cnt = new Counter();

cnt.go = false;

cnt.start();

}

public void paint(Graphics g)

{

super.paint(g);

//draw the background:

try

{

//this is the general, plain white background: g.setColor(Color.white);

g.fillRect(−2000,−2000,5000,5000);

//this is the image background

URL url = this.getClass().getResource (“bg.png”); Image img = Toolkit.getDefaultToolkit(). getImage(url); g.drawImage(img, 0−focusX, 0−focusY, this);

}

catch(Exception e){}

//set the color to black (for the lines):

g.setColor(Color.black);

//this for loop will go thru every line in the ArrayList and draw them: for(int i = 0; i <lines.size(); i+ +)

{

Project 17: Screen Skier—Competition

86

Project 17: Screen Skier—Competition

//get the line in the ArrayList:

Line2D.Double temp = (Line2D.Double) lines.get(i);

//now get all the x’s and y’s

int x1 = Integer.parseInt(“”+Math.round (temp.getX1())); int y1 = Integer.parseInt(“”+Math.round (temp.getY1())); int x2 = Integer.parseInt(“”+Math.round (temp.getX2())); int y2 = Integer.parseInt(“”+Math.round (temp.getY2())); g.drawLine(x1−focusX,y1−focusY,x2−focusX,y2−focusY);

}

if(drawGuy)

{

try

{

//draw the time:

g.setFont(new Font(“times new roman”, Font.BOLD, 16)); URL urlTime = this.getClass().getResource (“time.png”); Image imgT = Toolkit.getDefaultToolkit(). getImage(urlTime); g.drawImage(imgT, −35, 10, this);

if(!useHold)

g.drawString(“Current Time: “+count, 50, 50);

else

g.drawString(“Current Time: “+holdTime, 50, 50);

//draw the guy:

if(alive)

{

URL url = this.getClass().getResource (“guy.png”); Image img = Toolkit.getDefaultToolkit(). getImage(url); g.drawImage(img, guy.x−focusX, guy.y−focusY, this);

}

else

{

URL url = this.getClass().getResource (“guyDead.png”); Image img = Toolkit.getDefaultToolkit().getImage(url); g.drawImage(img, guy.x−focusX, guy.y−focusY, this);

//if the snd hasn’t been played, play it!

if(!sndPlayed)

{

//set up the hold time variable:

holdTime = count;

useHold = true;

//play the sound

URL snd = this.getClass().getResource(“scream.wav”); AudioClip scream = JApplet.newAudioClip(snd);

scream.play();

sndPlayed = true;

//check for a win:

checkWin();

}

}

}

catch(Exception e){}

//reset the focus to the guy’s position

focusX = guy.x−100;

focusY = guy.y−100;

}

}

//check to see if the goal is accomplished

public void checkWin()

87

{

if(holdTime= =45)

{

JOptionPane.showMessageDialog(null,

“Congrats!\n\n” +

“MISSION ACCOMPLISHED!”);

}

}

//these are the mouse listener methods:

public void mouseClicked(MouseEvent e){}

//these are the mouse listener methods:

public void mouseEntered(MouseEvent e){}

//these are the mouse listener methods:

public void mouseExited(MouseEvent e){}

//these are the mouse listener methods:

public void mousePressed(MouseEvent e)

{

//this code will run when the mouse is first pressed, getting the

//starting point of the line.

holder = new Point2D.Double(e.getX()+ focusX,e.getY()+focusY);

}

//these are the mouse listener methods:

public void mouseReleased(MouseEvent e)

{

//this code will run when the mouse is released, completing the

//line and adding it to the ArrayList.

Point2D.Double end = new Point2D.Double(e.getX()+focusX,e.getY()+focusY); lines.add(new Line2D.Double(holder,end));

//now, repinat the screen so the line is drawn: repaint();

}

//these are the key listener methods:

public void keyPressed(KeyEvent e){}

//these are the key listener methods:

public void keyReleased(KeyEvent e){}

//these are the key listener methods:

public void keyTyped(KeyEvent e)

{

//if the user presses “p” OR “P,” start the Thread if(e.getKeyChar()= =‘p’ || e.getKeyChar()= =‘P’)

{

alive = true;

count = 0;

useHold = false;

//init the Thread:

move = new Move();

cnt.go = true;

move.start();

move.action(true);

sndPlayed = false;

}

//if the user presses “q” OR “Q,” stop the Thread if(e.getKeyChar()= =‘q’ || e.getKeyChar()= =‘Q’)

{

move.action(false);

drawGuy

Project 17: Screen Skier—Competition

= false;

88

Project 17: Screen Skier—Competition

focusX = 0;

focusY = 0;

move = null;

cnt.go = false;

}

//if the user presses “a” OR “A,” move the focus if(e.getKeyChar()= =‘a’ || e.getKeyChar()= =‘A’)

{

focusX−=100;

repaint();

}

//if the user presses “s” OR “S,” move the focus if(e.getKeyChar()= =‘s’ || e.getKeyChar()= =‘S’)

{

focusY+=100;

repaint();

}

//if the user presses “w” OR “W,” move the focus if(e.getKeyChar()= =‘w’ || e.getKeyChar()= =‘W’)

{

focusY−=100;

repaint();

}

//if the user presses “d” OR “D,” move the focus if(e.getKeyChar()= =‘d’ || e.getKeyChar()= =‘D’)

{

focusX+=100;

repaint();

}

//if the user presses “z” OR “Z,” undo the last line if(e.getKeyChar()= =‘z’ || e.getKeyChar()= =‘Z’)

{

lines.remove(lines.size()−1);

repaint();

}

//if the user presses “x” OR “X,” clear the track if(e.getKeyChar()= =’x’ || e.getKeyChar()= =’X’)

{

//double check before deleting!

int answer = JOptionPane.showConfirmDialog(null,

“Do you really want to delete your track?”);

if(answer= =JOptionPane.OK_OPTION)

lines.clear();

repaint();

}

}

private class Counter extends Thread

{

public boolean go = true;

public void run()

{

try

{

while(true)

{

if(go)

89

{

Thread.sleep(1000);

count+ +;

}

}

}

catch(Exception e){}

}

}

//this is the thread that will make the character move private class Move extends Thread

{

//these variables will hold the player’s speed and gravity double velocity;

double gravity;

//stops/starts the thread:

boolean go = false;

public void run()

{

if(go)

{

initGuy();

velocity = 0;

gravity = 1;

}

while(go)

{

try

{

//this will hold the line the guy is on (null if none) Line2D.Double lineTaken = null;

//this will say whether the character is even on a line boolean onLine = false;

//gravity needs to be reset when the guy first lands on

//the line. This will hold that info. It holds the line #

int firstOnLine = −1;

//check if he is on a line:

for(int i = lines.size()−1; i>=0; i− −)

{

//get the line:

Line2D.Double temp = (Line2D.Double) lines.get(i); if(temp.intersects(guy.x,guy.y,30,30))

{

lineTaken = temp;

onLine = true;

if(firstOnLine!=i)

{

firstOnLine = i;

gravity = 0;

}

break;

}

}

//if there is a line it is on...

if(onLine)

{

Project 17: Screen Skier—Competition

//now, get the new gravity by subtracting the y’s and 90

Project 17: Screen Skier—Competition

//dividing by 20

double mGrav = (lineTaken.y2−line Taken.y1)/50;

//now, get the new velocity by subtracting the x’s and

//dividing by 20

double mVel = (lineTaken.x2−line Taken.x1)/100;

//set the maximum values

if(velocity<5)

velocity+=mVel;

if(gravity<2.5)

gravity+=mGrav;

}

else

{

gravity+=.2;

}

//alter the guy’s movements:

guy.x += velocity;

guy.y += gravity;

//check to see if the guy died:

if(guy.y>1400)

{

alive = false;

}

//delay before repainting:

Thread.sleep(75);

//repaint:

repaint();

}

catch(Exception e){ break; }

}

}

public void action(boolean a)

{

//stops the thread:

go = a;

}

public void initGuy()

{

/*

* This code will set up the character’s position

*/

//get the first line

Line2D.Double firstLine = (Line2D.Double) lines.get(0);

//get the first “x” and “y” of that line:

int x = Integer.parseInt(“”+Math.round (firstLine.x1)); int y = Integer.parseInt(“”+Math.round(firstLine.y1)); guy = new Rectangle(x+30,y−20,30,30);

drawGuy = true;

}

}

public static void main (String[ ] args)

{

//begin the program:

new G2P5();

}

}

91

Figure 17-2

Welcome screen.

Project 17: Screen Skier—Competition Figure 17-3 Skiing.

92

Project 17: Screen Skier—Competition

Figure 17-4

End of the run.

Figures 17-2 through 17-4 illustrate the game

Turn the trees into obstacles. Run into them and play of the final version of Screen Skier.

you lose!

Change the time goal.

Customizing the game

Add a second skier racing at a different speed—

tracked by a second counter.

Look up a class called MouseMotionListener in the Make the lines automatically lock together

API. It works just like MouseListener. Utilizing the (use the previous line’s last point) to create a new class, generate a line from the first point of the continuous slope.

slope to the mouse’s current position. This lets the player preview his/her line before actually drawing it.

Record affirmations to get you through the slope (“You can do it!” “Fantastic skiing!”).

Draw your own icon for the skier.

Create your own background graphic (blacken

Create random avalanches in the middle of

the background, change the trees to stars and ski the run.

between galaxies).

Intersect with an out of control snowboarder.

When the user presses a number, the

Add cheat codes ... let the player jump into a coordinating line is deleted.

snowmobile.

93

This page intentionally left blank

Section Three

Board Games

Project 18: Whack-an Evil Genius—The Lab

After this code, you must specify how you want the components added. There are many ways to

Whack-an Evil Genius

orient them: you can place them in a grid, on the sides, one after another, etc. In this book, we will An Evil Genius is hiding in his lab waiting to focus on placing the components one after another –

unleash havoc upon the world. Because he fears a FlowLayout. This layout is the easiest to code sunshine and fresh air, he only comes out briefly.

and the easiest to understand. To set the Container When he does, your job is to whack him with a click to a FlowLayout, use the following code.

of the mouse so he goes back to his underground lab.

The problem? He keeps cloning himself.

cont.setLayout(new FlowLayout());

Now, before you start creating components,

there is just one more thing: the very last line of Project

the constructor should now say:

Begin by creating the laboratory.

setContentPane(cont);

“cont” can be replaced with the name of your

New building blocks

Container. This line makes sure the JFrame

displays every component you have added.

Components, JButtons, JLabels

JButtons

Components

A button is a clickable area. In Java, buttons are A component is a device that can be added to

called JButtons.

any Java program to increase functionality. Some A simple button is illustrated in Figure 18-1.

common components include buttons, textfields, and labels. Before you add components, however, When creating JButtons, it is best to create them you need a place to put them. That place is called globally (outside of the constructor but inside the a Container. To create a container, place the

class). This way, it will be easier to modify their following code in your constructor after the

text anywhere in the program.

JFrame is created.

To create a JButton, use the following code:

Container <varName> = getContentPane();

JButton <varName> = new JButton(“Text”);

<varName> is a variable; it can be named

<varName> can be anything; it is a variable. “Text”

anything.

is the text that is displayed on the inside of a 95

however, there is one method you should know. It is the “setEnabled()” method. It takes in a boolean.

For example, if you have a JButton named “button,”

the following code disables the button.

button.setEnabled(false);

Or, to enable the JButton, use the following code: button.setEnabled(true);

JLabels

Figure 18-1

JButton.

A JLabel is another type of component. It allows text to be displayed on the JFrame. A JLabel is JButton. If you wish to display an image instead of illustrated in Figure 18-3.

text, use the following code:

To create a JLabel, use the following code:

ImageIcon <imgName> = new ImageIcon(“path JLabel <varName> = new JLabel(“Text”);

with extension”);

JButton <varName> = new JButton(<imgName>); Like a JButton, JLabels can be added to the

<imgName> and <varName> are variable name; you JFrame using the following code (if Container is can name them whatever you want. “path with

called “cont”):

extension” should be the path of the file from the cont.add(<varName>);

location of the Java program. A button with an Now that you know how to add JLabels, it is

image is illustrated in Figure 18-2.

helpful to know how to position them. By using a To add a JButton to the container (if the

method called “setBounds(),” you can position

Container’s name is “cont” and the JButton’s

the JLabel wherever you want. “setBounds()”

name is “button”), simply use the following code: takes in an x and y coordinate as well as the width cont.add(button);

and height of the label. For example, if you want to position a label at (50,100), simply use the JButtons have many methods for disabling,

following code:

enabling, setting their icons, among other things.

A full list is available in the API. For this game, cont.setLocation(50,100,<width>,<height>); Project 18: Whack-an Evil Genius—The Lab Figure 18-2 JButton with an ImageIcon.

Figure 18-3

JLabel.

96

Project 18: Whack-an Evil Genius—The Lab

JLabels can also hold an image like JButtons.

Making the game

The code is almost identical:

Create a JFrame. Then, add a container. Next,

ImageIcon image = new ImageIcon(“path with

create a 5×5 array of JButtons, use for loops to extension”);

initialize the JButtons in the array, and add the JLabel label = new JLabel (image);

buttons to the container. Make sure to add images When using JLabels, it is often useful to update of an Evil Genius to the buttons! And don’t forget the text. To do this, use a method called

to disable all of the buttons. Lastly, create and add

“setText().” It takes in a String. For example a JLabel that holds the score (for now, just make it (if your JLabel is named “label”):

say “SCORE: ”).

label.setText(“This is the new text.”);

import javax.swing.event.*;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class Whack-an extends JFrame

{

//this array holds the 25 “evil geniuses”

JButton[ ][ ] spots = new JButton[5][5];

//these are the two icons that pop up when the “evil genius”

//comes out of his lab

ImageIcon alive = new ImageIcon(“alive.GIF”);

//the label:

JLabel score = new JLabel(“SCORE: “);

//the constructor

public Whack-an()

{

//create the JFrame

super(“Whack-an Evil Genius”);

setSize(350,325);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this holds the buttons and labels

Container cont = getContentPane();

cont.setLayout(new FlowLayout());

//this prepares the buttons for displaying

for(int i = 0; i < spots.length; i + + )

{

for(int j = 0; j < spots[0].length; j++ )

{

//create the JButton

spots[i][j] = new JButton(alive);

//add it to the JFrame

cont.add(spots[i][j]);

//make it disabled

spots[i][j].setEnabled(false);

}

}

//this makes the JLabel display the score

score.setText(“SCORE: “);

cont.add(score);

97

Figure 18-4

The game so far.

setContentPane(cont);

}

public static void main (String[ ] args)

{

//start the game

new Whack-an();

}

}

The first part of Whack-an Evil Genius is

In the next project, you will learn how to make illustrated in Figure 18-4.

Whack-an Evil Genius operational by determining if a JButton has already been pressed.

Project 19: Whack-an Evil Genius—Quick! Get ‘em!

Project

ActionListener

The game takes form. The face of the Evil Genius An ActionListener does exactly as it sounds: it appears. But have no fear, you will be able to listens for actions. In this case, actions are the whack him away by adding user interaction.

player clicking buttons. An ActionListener must be added to every button you want to listen to. In the New building blocks

case of Whack-an Evil Genius, you will want each Project 19: Whack-an Evil Genius—Quick! Get ‘em! ActionListener and every button to have an ActionListener. To add 98

Project 19: Whack-an Evil Genius—Quick! Get ‘em!

an ActionListener to a JButton called “button,” for the name of the button to see which one has been example, use the following code:

clicked.

button.addActionListener(this);

Making the game

If you are using ActionListeners, you must use

“implements ActionListener.” If you are

First, add ActionListeners to every button in the already implementing “KeyListener,” you can

array. Then, implement ActionListener and add the implement both by separating them with a comma.

mandatory method.

Remember how the KeyListener had so many

Next, create a new Thread. In its infinite while mandatory methods? Well, luckily, ActionListener loop, make the program wait a random amount of only has one mandatory method. When a button is time (between 0 and 1500 milliseconds). Then,

pressed, Java goes to that method. This is how that have a random Evil Genius pop up (by enabling

method should be created:

it). Wait 1000 milliseconds, and then disable the public void actionPerformed (ActionEvent event) button.

{

Now, go back to the actionPerformed method.

}

When a button is pressed, increment the counter To find out which button has been pressed,

that keeps track of the score, and then pause both simply put the following condition inside of an threads for a quarter of a second (this gives the if-statement:

player time to catch his or her breath).

event.getSource()= =<button name>

You can then display the score in the JLabel.

Remember how I suggested that you make your

buttons global? This is why. You need to refer to import javax.swing.event.*;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class Whack-an extends JFrame implements ActionListener

{

//this array holds the 25 “evil geniuses”

JButton[ ][ ] spots = new JButton[5][5];

//this displays the game’s status

JLabel score = new JLabel();

//the score:

double hits = 0;

//these are the two icons that pop up when the “evil genius”

//comes out of his lab

ImageIcon alive = new ImageIcon(“alive.GIF”);

//this is the thread:

T runner = null;

//the constructor

public Whack-an()

{

99

//create the JFrame

super(“Whack-an Evil Genius”);

setSize(350,325);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this holds the buttons and labels

Container cont = getContentPane();

cont.setLayout(new FlowLayout());

//this prepares the buttons for displaying

for(int i = 0; i < spots.length; i + + )

{

for(int j = 0; j < spots[0].length; j++ )

{

//create the JButton

spots[i][j] = new JButton(alive);

//add it to the JFrame

cont.add(spots[i][j]);

//make it disabled

spots[i][j].setEnabled(false);

//make it respond to clicks

spots[i][j].addActionListener(this);

}

}

cont.add(score);

setContentPane(cont);

//this starts the Thread

runner = new T();

runner.start();

setContentPane(cont);

}

//the thread:

private class T extends Thread

{

public void run()

{

//an infinite loop

while(true)

{

//create a random time delay between 0 and 1.5 seconds int timeDelay = (int)(Math.random()*1500);

try

{

//pause for the random time

Thread.sleep(timeDelay);

}

catch(Exception e)

{ }

//make a random genius pop up

int genius = (int)(Math.random()*5);

int genius2 = (int)(Math.random()*5);

//make the genius come out by enabling the button spots[genius][genius2].setEnabled(true);

try

{

//pause to let the user try to catch

//the evil genius

Thread.sleep(1000);

Project 19: Whack-an Evil Genius—Quick! Get ‘em!

}

100

Project 19: Whack-an Evil Genius—Quick! Get ‘em!

catch(Exception e)

{ }

//make the genius disappear

spots[genius][genius2].setEnabled(false);

//display the stats

score.setText(“SCORE: ”+hits);

}

}

}

//this checks to see if the button was clicked public void actionPerformed(ActionEvent e)

{

//increase the score

hits+ + ;

//pause the game for 1/2 a second

try

{

runner.sleep(500);

Thread.sleep(500);

}

catch(Exception ex)

{ }

}

public static void main (String[ ] args)

{

//start the game

new Whack-an();

}

}

Figure 19-1

Evil Geniuses are hiding ... .

101

Figure 19-2

Quick! Catch him!

Figures 19-1 and 19-2 illustrate the game play of Warning: this guy can get pretty slippery as he Whack-an Evil Genius.

learns from his mistakes ... After all, he is an Evil Move on to increasing the difficulty levels as the Genius!!!

player keeps on trying to whack the Evil Genius.

Project 20: Whack-an Evil Genius—Getting Smarter ...

Project

chances he/she wants to whack away the Evil Genius.

Then, create a variable to count the attempts. At the In this project, tension builds as the Evil Genius beginning of the Thread’s while loop, increment the appears and disappears faster and faster. Torment counter. Make a message pop up displaying the

your players as you learn how to control the levels number of hits multiplied by 10,000 and then divided of difficulty.

by the number of chances. This ends the game.

A sample dialog box is shown in Figure 20-1.

Making the game

Next, add an int called “maxDelay.” Start by

setting it at 1000. Every time an Evil Genius is When games do not increase in difficulty, they caught, subtract 100 from it. Then, create a random quickly become boring. Right now, Whack-an Evil int based off this number:

Genius is set at an intermediate level. To solve this int delay = (int)(Math.random()*maxDelay);

problem, start by asking the player how many

Project 20: Whack-an Evil Genius—Getting Smarter ...

102

Project 20: Whack-an Evil Genius—Getting Smarter .

Use this new number as the delay time (how

long the Evil Genius makes an appearance). This way, the better you do, the more difficult the game becomes.

Figure 20-1

Score is displayed; game over.

import javax.swing.event.*;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

public class Whack-an extends JFrame implements ActionListener

{

//this array holds the 25 “evil geniuses”

JButton[ ][ ] spots = new JButton[5][5];

//this displays the game’s status

JLabel score = new JLabel();

//these are the variables that keep track of the score int maxDelay = 1000;

double hits = 0;

double turns = 0;

double maxTurn = 0;

//these are the two icons that pop up when the “evil genius”

//comes out of his lab

ImageIcon alive = new ImageIcon(“alive.GIF”);

//this is the thread:

T runner = null;

//the constructor

public Whack-an()

{

//create the JFrame

super(“Whack-an Evil Genius”);

setSize(350,325);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this holds and inputs the number

//of rounds the user will play

maxTurn = Double.parseDouble

(JOptionPane.showInputDialog(“How many chances do you\n”+“want to whack an evil genius?”));

//this holds the buttons and labels

Container cont = getContentPane();

cont.setLayout(new FlowLayout());

//this prepares the buttons for displaying

.

for(int i = 0; i < spots.length; i + + )

{

.

for(int j = 0; j < spots[0].length; j++ )

103

{

//create the JButton

spots[i][j] = new JButton(alive);

//add it to the JFrame

cont.add(spots[i][j]);

//make it disabled

spots[i][j].setEnabled(false);

//make it respond to clicks

spots[i][j].addActionListener(this);

}

}

//this makes the JLabel display the score

score.setText(“Turn “+turns+”/”+maxTurn+“. Current Score:

”+((int)((hits/maxTurn)*100)));

cont.add(score);

setContentPane(cont);

//this starts the Thread

runner = new T();

runner.start();

}

//the thread:

private class T extends Thread

{

public void run()

{

//an infinite loop

while(true)

{

//check for game over

if(turns>=maxTurn)

{

//if the game is over, display the score

JOptionPane.showMessageDialog(null,

“The game is over.\n\n”+“You hit ”+

hits+“ evil geniuses in ”+turns+“ turns.\n”+“Your score is ”+

((int)(((hits*10000)/turns))),

“Game Over”,

JOptionPane.INFORMATION_MESSAGE);

break;

}

//count the number of turns

turns+ +;

//create a random time delay between 0 and 1.5 seconds int timeDelay = (int)(Math.random()*1500);

try

{

//pause for the random time

Thread.sleep(timeDelay);

}

catch(Exception e)

{ }

//make a random genius pop up

int genius = (int)(Math.random()*5);

int genius2 = (int)(Math.random()*5);

//make the genius come out by enabling the button spots[genius][genius2].setEnabled(true);

try

{

//pause to let the user try to catch

Project 20: Whack-an Evil Genius—Getting Smarter ...

//the evil genius

104

Project 20: Whack-an Evil Genius—Getting Smarter .

Thread.sleep(maxDelay);

}

catch(Exception e)

{ }

//make the genius disappear

spots[genius][genius2].setEnabled(false);

//display the stats

score.setText(“Turn “+turns+”/”+maxTurn+

“. Current Score: ”+

((int)(((hits*10000)/maxTurn))));

}

}

}

//this checks to see if the button was clicked public void actionPerformed(ActionEvent e)

{

//if an evil genius was caught,

//decrease the time each genius is shown,

//making the game harder

maxDelay−=100;

//increase the score

hits + + ;

//pause the game for 1/2 a second

try

{

runner.sleep(500);

Thread.sleep(500);

}

catch(Exception ex)

{ }

}

public static void main (String[ ] args)

{

//start the game

new Whack-an();

}

}

Figures 20-2 through 20-4 illustrate the game

Ready for special effects? In the next project, play of Whack-an Evil Genius.

explore lots of ways to add realistic and/or wild features to your game for enhanced play value.

..

Figure 20-2

Select the number of rounds.

105

Figure 20-3

Catch ‘em!!!

Figure 20-4

.

Project 21: Whack-an Evil Genius—Showdown

Project

Making the game

Music, boos, applause, crashes, thunder,

Before adding sound effects, you must decide

explosions, or any other sounds can be added for where to put them and what they should be. For more intense game play. But it doesn’t stop there.

example, when the player whacks an Evil Genius To give the game even more dimensional quality, away, he could say something scientific ...

you’ll also learn how to add images.

“E=MC2,” for example. When an Evil Genius

Project 21: Whack-an Evil Genius—Showdown

106

Project 21: Whack-an Evil Genius—Showdown

method, play the scientific sound. In the Thread, right before you disable the button, play the sound of the door slamming shut.

Lastly, create an amazing title image like the one shown in Figure 21-1. Attach it to a JLabel and add the JLabel to the container before creating any Figure 21-1

Title image.

of the buttons.

Remember, all of these sounds and images

disappears, the sound of a door slamming shut

can be downloaded for free from

could be played.

www.books.mcgraw-hill.com/authors/cinnamon

Now, after retrieving the sound file, program the sounds globally. Next, in the actionPerformed

import javax.swing.event.*;

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.net.*;

import java.applet.AudioClip;

public class Whack-an extends JFrame implements ActionListener

{

//this array holds the 25 “evil geniuses”

JButton[ ][ ] spots = new JButton[5][5];

//this displays the game’s status

JLabel score = new JLabel();

//these are the variables that keep track of the score int maxDelay = 1000;

double hits = 0;

double turns = 0;

double maxTurn = 0;

//these are the two icons that pop up when the “evil genius”

//comes out of his lab

ImageIcon alive = new ImageIcon(“alive.GIF”);

//this is the thread:

T runner = null;

URL sci = null, dr = null;

AudioClip scientific = null, door = null;

//the constructor

public Whack-an()

{

//create the JFrame

super(“Whack-an Evil Genius”);

setSize(350,475);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); try

{

sci = this.getClass().getResource(“sci.wav”);

dr = this.getClass().getResource (“door.wav”); scientific = JApplet.newAudioClip(sci);

door = JApplet.newAudioClip(dr);

107

}

catch(Exception e){ }

//this holds and inputs the number

//of rounds the user will play

maxTurn = Double.parseDouble(JOptionPane.showInputDialog(“How many chances do you\n”+

“want to whack an evil genius?”));

//this holds the buttons and labels

Container cont = getContentPane();

cont.setLayout(new FlowLayout());

//this JLabel will be the title image.

//notice how you can create a JLabel and

//add an image all on one line ...

JLabel title = new JLabel(new ImageIcon(“title.PNG”));

//now add it:

cont.add(title);

//this prepares the buttons for displaying

for(int i = 0; i < spots.length; i+ +)

{

for(int j = 0; j < spots[0].length; j++)

{

//create the JButton

spots[i][j] = new JButton(alive);

//add it to the JFrame

cont.add(spots[i][j]);

//make it disabled

spots[i][j].setEnabled(false);

//make it respond to clicks

spots[i][j].addActionListener(this);

}

}

//this makes the JLabel display the score

score.setText(“Turn “+turns+”/”+maxTurn+“. Current Score: ”+((int) ((hits/maxTurn)*100)));

cont.add(score);

setContentPane(cont);

//this starts the Thread

runner = new T();

runner.start();

}

//the thread:

public class T extends Thread

{

public void run()

{

//an infinite loop

while(true)

{

//check for game over

if(turns>=maxTurn)

{

//if the game is over, display the score

JOptionPane.showMessageDialog(null,

“The game is over.\n\n”+“You hit ”+

hits+“ evil geniuses in ”+turns+“ turns.\n”+“Your score is

”+((int)(((hits*10000)/turns))),

“Game Over”,

JOptionPane.INFORMATION_MESSAGE);

Project 21: Whack-an Evil Genius—Showdown

break;

}

108

Project 21: Whack-an Evil Genius—Showdown

//count the number of turns

turns+ +;

//create a random time delay between 0 and 1.5 seconds int timeDelay = (int)(Math.random()*1500);

try

{

//pause for the random time

Thread.sleep(timeDelay);

}

catch(Exception e)

{ }

//make a random genius pop up

int genius = (int)(Math.random()*5);

int genius2 = (int)(Math.random()*5);

//make the genius come out by enabling the button spots[genius][genius2].setEnabled(true);

try

{

door.play();

//pause to let the user try to catch

//the evil genius

Thread.sleep(maxDelay);

}

catch(Exception e)

{ }

//make the genius disappear

spots[genius][genius2].setEnabled(false);

//display the stats

score.setText(“Turn “+turns+”/”+maxTurn+“. Current Score: ”+((int)(((hits*10000)/

maxTurn))));

}

}

}

//this checks to see if the button was clicked public void actionPerformed(ActionEvent e)

{

//if an evil genius was caught,

//decrease the time each genius is shown,

//making the game harder

maxDelay−=100;

scientific.play();

//increase the score

hits+ +;

//pause the game for 1/2 a second

try

{

runner.sleep(500);

Thread.sleep(500);

}

catch(Exception ex)

{ }

}

public static void main (String[ ] args)

{

//start the game

new Whack-an();

}

}

109

Figures 21-2 and 22-3 illustrate the addictive Create your own title image.

game play of Whack-an Evil Genius.

Develop different levels (when you capture 10 Evil Geniuses, move on to the next, faster-paced level).

Customizing the game

Create a high score list using file writing and Change the dimensions of the board: you can make reading.

it anything from a simple 2×2 button setup to a Every few rounds, have your Evil Genius morph

super-complicated 100×100 buttons setup!

into a different icon. Create some “good-guy

Change the icon of the Evil Genius: use a

icons.” If you accidentally whack them, you

picture of yourself ... or your “favorite” coworker.

automatically lose!

Add background music.

Figure 21-2

30 whacks.

Project 21: Whack-an Evil Genius—Showdown Figure 21-3 Title image.

110

Project 22: Tic-Tac-Toe Boxing—The Ring

Project 22: Tic-Tac-Toe Boxing—The Ring

<component> is the variable that represents the component. The rest of the parameters are self-Tic-Tac-Toe Boxing

explanatory.

Before you create original games and add

The classic game of Tic-Tac-Toe is transformed components based on pixel location, you need to into a boxing match in which each “fighter” is know one more thing: a NullLayout is not the most represented by a different boxing glove image. By reliable layout. There is always a chance that the adding punching sounds, groans, or taunts, you will be able to challenge you opponent (or the screen will not refresh and your change will not be computer) to win, lose, or draw.

displayed. No worries, however! There is an easy fix to this problem so your changes will always register. After you add everything you need to the Project

container, type the following:

Start by creating the ring so you can touch gloves container.repaint();

and come out fighting!!!

Making the game

New building blocks

First, create an array of JButtons nine elements NullLayout

long to hold the game board. Add the buttons from the array to the container inside a loop.

NullLayout

Remember—you will be adding the components

based on pixel location. So, figure out a simple Instead of using a FlowLayout, which simply

algorithm that spaces the pieces of the ring

places components one after another, you can use correctly. Here is a suggestion: each of the images a NullLayout which allows you to specify the

used with the game are 100 by 100 pixels, so the location of the component in pixel coordinates.

boxes should be 100 pixels apart. In addition, To use a NullLayout, change the “

create two variables set to zero outside of the loop.

setLayout” line

to the following:

At each iteration, increment one of the variables by one. Then, multiply this value by 100 to get the container.setLayout(null);

correct “x” spacing. Add an if statement inside of You can still add components the same way you

your for loop. Make it check to see if the counter did with the FlowLayout. To specify the pixel

is a multiple of 3 (because the board is three pieces location of the component, use the following code long). If so, drop the other pieces down one line by only after you added the component to the

incrementing the second variable by one. Okay ...

Container:

it sounds confusing, but once you see the code, as

<

shown below, it will all make sense.

component>.setBounds(<x>, <y>, <width>,

<height>);

int newLine = 0;

111

int lineCount = 0;

Now that the board is complete, create a global for(int i = 0; i < spots.length; i+ +)

variable called “turn.” Everytime the

{

//initialize it with a blank image

“actionPerformed” method executes, “turn”

spots[i] = new JButton(blank);

should be incremented by one. Then, you will be

//this checks whether to use a new row

able to check to see whose turn it is based on if(i= =3 || i = =6)

{

“turn” being even or odd.

newLine+ +;

In “actionPerformed,” if “turn” is odd, it is

lineCount = 0;

}

player O’s turn. If it is even, player X is up.

//set the position of the button

Depending on whose turn it is, set the icons to the spots[i].setBounds(lineCount*100,newLine*

100,100,100);

correct images. After setting the icon, remember to

//add it to the container

remove the ActionListener so a player can not steal container.add(spots[i]);

his/her opponent’s position!

//and now add the action listener:

spots[i].addActionListener(this);

lineCount+ +;

}

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.net.*;

//the class with the JFrame and the ActionListner: public class TicTacToe extends JFrame implements ActionListener

{

//this is an array of the buttons (spots). We use an array, not

//an arrayList because the number of buttons is constant; it does

//not change.

JButton spots[ ] = new JButton[9];

//this will keep track of turns: even is player 1; odd is player2

//we will use mod (%) to differentiate the values: int turn = 1;

//these images represent the sides

ImageIcon red = new ImageIcon(“red.png”);

ImageIcon blue = new ImageIcon(“blue.png”);

ImageIcon blank = new ImageIcon(“blank.png”);

//the constructor

public TicTacToe()

{

super(“TicTacToe: Boxing Style”);

setSize(330,350);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this will hold the buttons:

Container container = getContentPane();

//this will tell the computer how to display the buttons: container.setLayout(null);

int newLine = 0;

int lineCount = 0;

Project 22: Tic-Tac-Toe Boxing—The Ring

for(int i = 0; i < spots.length; i+ +)

112

Project 22: Tic-Tac-Toe Boxing—The Ring

{

//initialize it with a blank image

spots[i] = new JButton(blank);

//this checks whether to use a new row

if(i= =3 || i = =6)

{

newLine+ +;

lineCount = 0;

}

//set the position of the button

spots[i].setBounds(lineCount*100,newLine*100,100,100);

//add it to the container

container.add(spots[i]);

//and now add the action listener:

spots[i].addActionListener(this);

lineCount+ +;

}

}

//the mandatory method:

public void actionPerformed(ActionEvent e)

{

//this will check the button pressed:

for(int i = 0; i < spots.length; i+ +)

{

if(e.getSource()= =spots[i])

{

//check which turn:

if(turn%2= =0)

{

//if even, player 1’s turn (X)

spots[i].setIcon(red);

}

else

{

//if odd, player 2’s turn (O)

spots[i].setIcon(blue);

}

//disable the btn so it can’t be re-pressed

spots[i].removeActionListener(this);

}

}

turn+ +;

//before letting the other player go, check whhether a player won: checkWin();

}

public void checkWin()

{

//first, we will use to go through three iterations. This allows us to

//check for both horizontal and vertical wins without using too

//much code:

for(int i = 0; i < 3; i+ +)

{

//this checks for a vertical X win

if(spots[i].getText()= =“X” &&

spots[i+3].getText()= =“X” &&

spots[i+6].getText()= =“X”)

JOptionPane.showMessageDialog(null,“X Wins”);

//this checks for a vertical O win

if(spots[i].getText()= =“O” &&

spots[i+3].getText()= =“O” &&

113

spots[i+6].getText()= =“O”)

JOptionPane.showMessageDialog(null,“O Wins”);

//this checks for a vertical X win

if(spots[i*3].getText()= =“X” &&

spots[(i*3)+1].getText()= =“X” &&

spots[(i*3)+2].getText()= =“X”)

JOptionPane.showMessageDialog(null,“X Wins”);

//this checks for a vertical X win

if(spots[i*3].getText()= =“O” &&

spots[(i*3)+1].getText()= =“O” &&

spots[(i*3)+2].getText()= =“O”)

JOptionPane.showMessageDialog(null,“O Wins”);

}

//now, this loop will check for diagnol wins

for(int i = 0; i <= 2; i+=2)

{

//this will check for diagnol X wins

if(spots[i].getText()= =“X” &&

spots[4].getText()= =“X” &&

spots[8-i].getText()= =“X”)

JOptionPane.showMessageDialog(null,“X Wins”);

//this will check for diagnol O wins

if(spots[i].getText()= =“O” &&

spots[4].getText()= =“O” &&

spots[8-i].getText()= =“O”)

JOptionPane.showMessageDialog(null,“O Wins”);

}

}

//starter (main) method:

public static void main(String[ ] args) {

TicTacToe ttt = new TicTacToe();

}

}

Figures 22-1 through 22-4 illustrate the exciting computer to determine whether Player One is the game play of Boxing Tic-Tac-Toe.

winner, Player Two is a winner, or if the boxing Fair fighting requires an impartial judge. In the match ends in a draw.

next project, you are going to program the

Project 22: Tic-Tac-Toe Boxing—The Ring Figure 22-1 Game start up.

Figure 22-2

Player One’s punch.

114

Project 23: Tic-Tac-Toe Boxing—Fight!!!

Figure 22-3

Player Two’s counter-punch.

Figure 22-4

Player Two (“O”) wins ... but the

computer cannot yet detect the result.

Project 23: Tic-Tac-Toe Boxing—Fight!!!

Project

Next, you will teach the computer how to check for knockouts. Create a method named checkWin.

Welcome to training camp. It is here where you At the end of the actionPerformed method, call will enable your two fighters to square off in the checkWin. Now that you have created the methods, ring. Add a title image to hype the fans, and

there are two techniques you can use to check for program your computer to determine who’s the

wins. The first is a heck of a lot of if-statements ...

champ and who’s the chump.

not fun! The second technique requires much less code. Because of the nature of Tic-Tac-Toe (being a square), it is easier to use if-statements inside of Making the game

for loops. This cuts down nearly 66% of the

First, start with the easier of the two objectives: code. As illustrated in Figure 23-2, you can see adding the title image. To do this, create a title that a single loop can check six different cases.

image in paint. Next, create a JLabel that will And now the difficult part: writing that pesky for display that image. Add this JLabel above the

loop. To do this, create a for loop that counts from buttons (at location 0,0). Don’t forget to change 0 to 2 (three iterations). Inside the loop, add four the loop that adds the buttons so they will not be different if-statements. One will check for a

covered by the title image. Do this by simply

vertical X win; one will check for a vertical O win; adding the height of the image to the y value of the one for a horizontal X win; and the last one, for a buttons. You can also add a set number to the

horizontal O win. Each loop determines if the icon x value of the buttons so they will be centered, as of the buttons in the appropriate position are all the shown in Figure 23-1.

same color. The actual code in the if-statements is shown below:

115

//this checks for a vertical X win

if(spots[i].getIcon().equals(red) &&

spots[i+3].getIcon().equals(red) &&

spots[i+6].getIcon().equals(red))

JOptionPane.showMessageDialog(null,“X

Wins”);

//this checks for a vertical O win

if(spots[i].getIcon().equals(blue) &&

spots[i+3].getIcon().equals(blue) &&

spots[i+6].getIcon().equals(blue))

JOptionPane.showMessageDialog(null,“O

Wins”);

//this checks for a horizontal X win

if(spots[i*3].getIcon().equals(red) && spots[(i*3)+1].getIcon().equals(red) && spots[(i*3)+2].getIcon().equals(red))

JOptionPane.showMessageDialog(null,“X

Wins”);

//this checks for a horizontal O win

if(spots[i*3].getIcon().equals(blue) && spots[(i*3)+1].getIcon().equals(blue) && spots[(i*3)+2].getIcon().equals(blue))

JOptionPane.showMessageDialog(null,“O

Wins”);

Almost there! You only need one more thing: a

second loop to check for diagonal wins. This can be accomplished the same way as checking for

horizontal and vertical wins, except the loop

should only iterate two times. The entire loop is Figure 23-1

Title image and buttons are centered.

shown below:

//now, this loop will check for diagnol wins

for(int i = 0; i <= 2; i+=2)

{

//this will check for diagnol X wins

if(spots[i].getIcon().equals(red) &&

spots[4].getIcon().equals(red) &&

spots[8−i].getIcon().equals(red))

JOptionPane.showMessageDialog(null,

“X Wins”);

//this will check for diagnol O wins

if(spots[i].getIcon().equals(blue) &&

spots[4].getIcon().equals(blue) &&

spots[8−i].getIcon().equals(blue))

JOptionPane.showMessageDialog(null,

“O Wins”);

}

Congrats! Now you have all the code necessary

to check for wins. The full code is below.

//import everything:

Figure 23-2

Single for loop checks six different

import javax.swing.*;

possible wins.

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.net.*;

Project 23: Tic-Tac-Toe Boxing—Fight!!!

//the class with the JFrame and the

116

Project 23: Tic-Tac-Toe Boxing—Fight!!!

ActionListner:

public class TicTacToe extends JFrame implements ActionListener

{

//this is an array of the buttons (spots). We use an array, not

//an arrayList because the number of buttons is constant; it does

//not change.

JButton spots[ ] = new JButton[9];

//this will keep track of turns: even is player 1; odd is player2

//we will use mod (%) to differentiate the values: int turn = 1;

//these images represent the sides

ImageIcon red = new ImageIcon(“red.png”);

ImageIcon blue = new ImageIcon(“blue.png”);

ImageIcon blank = new ImageIcon(“blank.png”);

//the title image:

JLabel title = new JLabel(new ImageIcon(“title.png”));

//the constructor

public TicTacToe()

{

super(“TicTacToe: Boxing Style”);

setSize(350,625);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this will hold the buttons:

Container container = getContentPane();

//this will tell the computer how to display the buttons: container.setLayout(null);

container.add(title);

title.setBounds(0,0,350,288);

int newLine = 0;

int lineCount = 0;

for(int i = 0; i < spots.length; i+ +)

{

//initialize it with a blank image

spots[i] = new JButton(blank);

//this checks whether to use a new row

if(i= =3 || i = =6)

{

newLine+ +;

lineCount = 0;

}

//set the position of the button

spots[i].setBounds(15+(lineCount*100),288+(newLine*100),100,100);

//add it to the container

container.add(spots[i]);

//and now add the action listener:

spots[i].addActionListener(this);

lineCount+ +;

}

//remember to refresh the screen!

container.repaint();

}

//the mandatory method:

public void actionPerformed(ActionEvent e)

{

//this will check the button pressed:

for(int i = 0; i < spots.length; i+ +)

{

if(e.getSource()= =spots[i])

{

117

//check which turn:

if(turn%2= =0)

{

//if even, player 1’s turn (X)

spots[i].setIcon(red);

}

else

{

//if odd, player 2’s turn (O)

spots[i].setIcon(blue);

}

//disable the btn so it can’t be re-pressed

spots[i].removeActionListener(this);

}

}

turn+ +;

//before letting the other player go, check whether a player won: checkWin();

}

public void checkWin()

{

//first, we will use to go through three iterations. This allows us to

//check for both horizontal and vertical wins without using too

//much code:

for(int i = 0; i < 3; i++)

{

//this checks for a vertical X win

if(spots[i].getIcon().equals(red) &&

spots[i+3].getIcon().equals(red) &&

spots[i+6].getIcon().equals(red))

JOptionPane.showMessageDialog(null,“X Wins”);

//this checks for a vertical O win

if(spots[i].getIcon().equals(blue) &&

spots[i+3].getIcon().equals(blue) &&

spots[i+6].getIcon().equals(blue))

JOptionPane.showMessageDialog(null,“O Wins”);

//this checks for a horizontal X win

if(spots[i*3].getIcon().equals(red) && spots[(i*3)+1].getIcon().equals(red) && spots[(i*3)+2].getIcon().equals(red))

JOptionPane.showMessageDialog(null,“X Wins”);

//this checks for a horizontal O win

if(spots[i*3].getIcon().equals(blue) && spots[(i*3)+1].getIcon().equals(blue) && spots[(i*3)+2].getIcon().equals(blue))

JOptionPane.showMessageDialog(null,“O Wins”);

}

//now, this loop will check for diagnol wins

for(int i = 0; i <= 2; i+=2)

{

//this will check for diagnol X wins

if(spots[i].getIcon().equals(red) &&

spots[4].getIcon().equals(red) &&

spots[8−i].getIcon().equals(red))

JOptionPane.showMessageDialog(null,“X Wins”);

//this will check for diagnol O wins

if(spots[i].getIcon().equals(blue) &&

Project 23: Tic-Tac-Toe Boxing—Fight!!!

spots[4].getIcon().equals(blue) &&

118

Project 23: Tic-Tac-Toe Boxing—Fight!!!

spots[8−i].getIcon().equals(blue))

JOptionPane.showMessageDialog(null,“O Wins”);

}

}

//starter (main) method:

public static void main(String[ ] args) {

TicTacToe ttt = new TicTacToe();

}

}

Figures 23-3 through 23-5 show Tic-Tac-Toe

Ali, Tyson, Foreman—in the next project, program Boxing’s new title image and ability to check for the ultimate boxer by adding artificial intelligence.

knockouts.

Figure 23-4

Computer recognizes Player Two (“O”)

as winner.

Figure 23-3

Player Two (“O”) is about to win!

Figure 23-5

Player One (“X”) wins next round.

119

Project 24: Tic-Tac-Toe Boxing—Knock Out

Project

can start programming the AI! First, instead of switching icons in the actionPerformed method, Forget fancy footwork, quick jabs, and thunderous simply make it display the X icon. Then, at the punches. Artificial Intelligence is the most powerful end of actionPerformed, call a method

force in the boxing ring. This project shows you named ai.

how to use AI to create an opponent that gives you In the method ai, first check the turn counter.

and your friends the ultimate challenge.

If it is the computer’s first turn, choose either the center or top left square. Next, type “return” so Making the game

the method ends and the fighter can make his/her move. If it is not the computer’s first turn, check Although you do not have to learn new code or

for two O’s in a row. If two are found, act

syntax, there is a lot of math involved in creating offensively and grab that spot, as illustrated in Artificial Intelligence (AI). Not a problem.

Figure 24-1. The computer knocks out the

Thinking the game play through before actually player!

programming the AI makes this process easier.

If two O’s in a row are not found, play

Whenever you create AI, you must analyze how

defensively and check for two X’s in a row. Block most people play the game of Tic-Tac-Toe.

that third spot so the other contender cannot win, Usually, one chooses a corner or middle spot first as illustrated in Figure 24-2.

in order to gain the upper hand. Next, he/she

To do this, create a method that takes in an Icon.

analyzes the board for the quickest victory. If a It will check for two in a row of that Icon using win is only one position away, the player takes that for loops. If one is found, take the spot and type position and defeats the opponent. If a win is

“return,” which ends the method so the computer several steps away, defensive thinking is required cannot move twice in a row.

to block the opponent.

That’s it! Begin Round 1! The completed code is Once you have taken into consideration the

below.

human thought process for securing a victory, you Figure 24-2

Play defensively and prevent the X’s

Project 24: Tic-Tac-Toe Boxing—Knock Out Figure 24-1 Act offensively and go for the win.

from winning.

120

Project 24: Tic-Tac-Toe Boxing—Knock Out

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.net.*;

//the class with the JFrame and the ActionListner: public class TicTacToe extends JFrame implements ActionListener

{

//this is an array of the buttons (spots). We use an array, not

//an arrayList because the number of buttons is constant; it does

//not change.

JButton spots[ ] = new JButton[9];

//this will keep track of turns: even is player 1; odd is player2

//we will use mod (%) to differentiate the values: int turn = 1;

//these images represent the sides

ImageIcon red = new ImageIcon(“red.png”);

ImageIcon blue = new ImageIcon(“blue.png”);

ImageIcon blank = new ImageIcon(“blank.png”);

//the title image:

JLabel title = new JLabel(new ImageIcon(“title.png”));

//the constructor

public TicTacToe()

{

super(“TicTacToe: Boxing Style”);

setSize(350,625);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this will hold the buttons:

Container container = getContentPane();

//this will tell the computer how to display the buttons: container.setLayout(null);

container.add(title);

title.setBounds(0,0,350,288);

int newLine = 0;

int lineCount = 0;

for(int i = 0; i < spots.length; i+ +)

{

//initialize it with a blank image

spots[i] = new JButton(blank);

//this checks whether to use a new row

if(i= =3 || i = =6)

{

newLine+ +;

lineCount = 0;

}

//set the position of the button

spots[i].setBounds(15+(lineCount*100),288+(newLine*100),100,100);

//add it to the container

container.add(spots[i]);

//and now add the action listener:

spots[i].addActionListener(this);

lineCount+ +;

}

//remember to refresh the screen!

container.repaint();

}

121

//the mandatory method:

public void actionPerformed(ActionEvent e)

{

//this will check the button pressed:

for(int i = 0; i < spots.length; i+ +)

{

if(e.getSource()= =spots[i])

{

//set the button to X

spots[i].setIcon(red);

//disable the btn so it can’t be re-pressed

spots[i].removeActionListener(this);

}

}

turn+ +;

//before letting the other player go, check whether a player won: checkWin();

//this method lets the computer select its turn ai();

}

public void checkWin()

{

//first, we will use to go through three iterations. This allows us to

//check for both horizontal and vertical wins without using too

//much code:

for(int i = 0; i < 3; i+ +)

{

//this checks for a vertical X win

if(spots[i].getIcon().equals(red) &&

spots[i+3].getIcon().equals(red) &&

spots[i+6].getIcon().equals(red))

{

JOptionPane.showMessageDialog(null,“You Win!”); return;

}

//this checks for a vertical O win

if(spots[i].getIcon().equals(blue) &&

spots[i+3].getIcon().equals(blue) &&

spots[i+6].getIcon().equals(blue))

{

JOptionPane.showMessageDialog(null,“YOU LOSE!”); return;

}

//this checks for a horizontal X win

if(spots[i*3].getIcon().equals(red) && spots[(i*3)+1].getIcon().equals(red) && spots[(i*3)+2].getIcon().equals(red))

{

JOptionPane.showMessageDialog(null,“You Win!”); return;

}

//this checks for a horizontal O win

if(spots[i*3].getIcon().equals(blue) && spots[(i*3)+1].getIcon().equals(blue) && spots[(i*3)+2].getIcon().equals(blue))

{

Project 24: Tic-Tac-Toe Boxing—Knock Out

122

Project 24: Tic-Tac-Toe Boxing—Knock Out

JOptionPane.showMessageDialog(null,“YOU LOSE!”); return;

}

}

//now, this loop will check for diagnol wins

for(int i = 0; i <= 2; i+=2)

{

//this will check for diagnol X wins

if(spots[i].getIcon().equals(red) &&

spots[4].getIcon().equals(red) &&

spots[8−i].getIcon().equals(red))

{

JOptionPane.showMessageDialog(null,“You Win!”); return;

}

//this will check for diagnol O wins

if(spots[i].getIcon().equals(blue) &&

spots[4].getIcon().equals(blue) &&

spots[8−i].getIcon().equals(blue))

{

JOptionPane.showMessageDialog(null,“YOU LOSE!”); return;

}

}

}

public void ai()

{

boolean movedYet;

//if this is the computer’s first turn, then try to go in the top left

//if already taken, take the middle

if(turn = = 2)

{

//if the top left is taken, take the middle

if(spots[0].getIcon().equals(red))

{

spots[4].setIcon(blue);

spots[4].removeActionListener(this);

movedYet = true;

}

//else, take the top left

else

{

spots[0].setIcon(blue);

spots[0].removeActionListener(this);

movedYet = true;

}

}

//if this is not the first turn, then check for 2 out of 3 spots

//taken. If there are none, go to a random location else

{

//callin this method checks for two in a row of the first String passed in.

//It then takes the 3rd spot with the 2nd String passed in: movedYet = twoInARow(blue);

//if the computer didn’t take an offensive spot, take a defensive

//one.

if(!movedYet)

123

{

movedYet = twoInARow(red);

//if there is no defensive move, take the next open one.

if(!movedYet)

{

//this loop finds the first untaken spot:

for(int i = 0; i < spots.length; i+ +)

{

//if empty, take it!

if(spots[i].getIcon().equals(blank))

{

spots[i].setIcon(blue);

spots[i].removeActionListener(this);

movedYet = true;

break;

}

}

}

}

}

turn+ +;

System.out.println(turn);

checkWin();

if(!movedYet)

{

//if no spot was taken, it must be a cat’s game: JOptionPane.showMessageDialog(null,“DRAW!!!”);

}

}

public boolean twoInARow(Icon a)

{

for(int i = 0; i < 3; i+ +)

{

//this checks for 2 in a row from the top

if(spots[i].getIcon().equals(a) &&

spots[i+3].getIcon().equals(a) &&

spots[i+6].getIcon().equals(blank))

{

spots[i+6].setIcon(blue);

spots[i+6].removeActionListener(this);

return true;

}

//this checks (from the top and bottom)

//for a taken spot, then a gap, then a taken one: if(spots[i].getIcon().equals(a) &&

spots[i+6].getIcon().equals(a) &&

spots[i+3].getIcon().equals(blank))

{

spots[i+3].setIcon(blue);

spots[i+3].removeActionListener(this);

return true;

}

//this checks for 2 in a row from the bottom

if(spots[i+6].getIcon().equals(a) &&

spots[i+3].getIcon().equals(a) &&

spots[i].getIcon().equals(blank))

{

Project 24: Tic-Tac-Toe Boxing—Knock Out

spots[i].setIcon(blue);

124

Project 24: Tic-Tac-Toe Boxing—Knock Out

spots[i].removeActionListener(this);

return true;

}

//this checks for 2 in a row from the left

if(spots[i*3].getIcon().equals(a) &&

spots[(i*3)+1].getIcon().equals(a) &&

spots[(i*3)+2].getIcon().equals(blank))

{

spots[(i*3)+2].setIcon(blue);

spots[(i*3)+2].removeActionListener(this);

return true;

}

//this checks (from the left and right)

//for a taken spot, then a gap, then a taken one if(spots[i*3].getIcon().equals(a) &&

spots[(i*3)+2].getIcon().equals(a) &&

spots[(i*3)+1].getIcon().equals(blank))

{

spots[(i*3)+1].setIcon(blue);

spots[(i*3)+1].removeActionListener(this);

return true;

}

//this checks for 2 in a row from the right

if(spots[(i*3)+2].getIcon().equals(a) && spots[(i*3)+1].getIcon().equals(a) &&

spots[i*3].getIcon().equals(blank))

{

spots[i*3].setIcon(blue);

spots[i*3].removeActionListener(this);

return true;

}

//now we will check for a diagnol 2 in a row:

for(int j = 0; j <= 2; j+=2)

{

//this will check for diagnol X wins

if(spots[j].getIcon()= =a &&

spots[4].getIcon()= =a &&

spots[8−j].getIcon().equals(blank))

{

spots[8−j].setIcon(blue);

spots[8−j].removeActionListener(this);

return true;

}

//this checks (from a diagnol)

//for a taken spot, then a gap, then a taken one if(spots[j].getIcon()= =a &&

spots[8-j].getIcon()= =a &&

spots[4].getIcon().equals(blank))

{

spots[4].setIcon(blue);

spots[4].removeActionListener(this);

return true;

}

if(spots[8-j].getIcon()= =a &&

spots[4].getIcon()= =a &&

spots[j].getIcon().equals(blank))

{

spots[j].setIcon(blue);

125

spots[j].removeActionListener(this);

return true;

}

}

}

return false;

}

//starter (main) method:

public static void main(String[ ] args) {

TicTacToe ttt = new TicTacToe();

}

}

Figures 24-3 through 24-6 demonstrate Tic-

make Tic-Tac-Toe Boxing worth the price of

Tac-Toe Boxing’s incredible new AI!

admission.

Blood and gore. That’s what fighting fans pay to see. Next up, you’ll add the sounds and graphics to Figure 24-4

Player takes top left, computer takes

Project 24: Tic-Tac-Toe Boxing—Knock Out Figure 24-3 Boxing begins!

middle.

126

Project 25: Tic-Tac-Toe Boxing—Championship Figure 24-5

Player takes top middle, but is blocked

Figure 24-6

Player loses

(but don’t get too cocky,

by computer.

computer, a human programmed your brain!).

Project 25: Tic-Tac-Toe Boxing—Championship

Project

the constructor. The first AudioClip should contain a punching sound. Play the punching sound in the Want to make the frenzied crowd scream for

beginning of the actionPerformed method. This

their favorite boxer or boo the opponent? Want way, every time a user throws a punch, you hear a to have great displays showing a “Win,” “Lose,”

corresponding POW! The other two AudioClips

or “Draw?” Here you add audio clips and

should contain cheering and booing sounds. If the graphic images to make the boxing match come

player wins, sound the cheers. If he/she loses, it is to life.

time to release the boos!

Instead of having to repeat code each time a

Making the game

sound is played, create a new method called win.

It has two parameters: a boolean and a String. If Begin by adding the sound effects. Declare three the boolean is false, the game is a draw. If it is AudioClips globally, but initialize them inside of true, check whether the second parameter, a String, 127

contains “win” or “lose.” The correct message and sounds will be displayed.

Now, time to add some images. Standard pop-up

boxes that display the results can be dull. To liven things up, cover the entire boxing ring with a giant JLabel that announces the outcome of the fight, as shown in Figure 25-1.

To do this, create three JLabels to hold the

images: one called win, one called lose, and the last called draw. Add them to the container and set their bounds off screen. In the win method, move the images to the center of the screen. Don’t forget to remove the buttons using a for loop so they do not cover up the JLabel! You can remove buttons by using the following code:

container.remove(<button name>);

Your training is complete. You have now

Figure 25-1

JLabel displays outcome of fight.

mastered Tic-Tac-Toe Boxing.

//import everything:

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.io.*;

import java.applet.AudioClip;

import java.net.*;

//the class with the JFrame and the ActionListner: public class TicTacToe extends JFrame implements ActionListener

{

//this is an array of the buttons (spots). We use an array, not

//an arrayList because the number of buttons is constant; it does

//not change.

JButton spots[ ] = new JButton[9];

//this will keep track of turns

int turn = 1;

//this is a JLabel: it will display the text

JLabel lbl = new JLabel(new ImageIcon(“title.png”));

//this JLabel will display whose turn it is

JLabel turnLbl = new JLabel(“X’s Turn”);

ImageIcon red = new ImageIcon(“red.png”);

ImageIcon blue = new ImageIcon(“blue.png”);

ImageIcon blank = new ImageIcon(“blank.png”);

ImageIcon loseImg = new ImageIcon(“lose.png”); ImageIcon winImg = new ImageIcon(“win.png”);

ImageIcon drawImg = new ImageIcon(“draw.png”); JLabel lose = new JLabel(loseImg);

Project 25: Tic-Tac-Toe Boxing—Championship JLabel win = new JLabel(winImg);

128

Project 25: Tic-Tac-Toe Boxing—Championship JLabel draw = new JLabel(drawImg);

URL hitURL = null, cheerURL = null, booURL = null; AudioClip hit = null, cheer = null, boo = null; Container container;

//the constructor

public TicTacToe()

{

super(“TicTacToe: Boxing Style”);

setSize(450,700);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this will hold the buttons:

container = getContentPane();

//this will tell the computer how to display the buttons: container.setLayout(null);

//we will add the winning, losing, and draw labels, butt

//move them off the screen.

container.add(lose);

lose.setBounds(−500,−500,331,438);

container.add(win);

lose.setBounds(−500,−500,331,438);

container.add(draw);

lose.setBounds(−500,−500,331,438);

//add the lbl:

container.add(lbl);

lbl.setBounds(20,0,400,288);

try

{

hitURL = this.getClass().getResource(“hit.wav”); booURL = this.getClass().getResource(“boo.wav”); cheerURL = this.getClass().getResource(“cheer.wav”); hit = JApplet.newAudioClip(hitURL);

boo = JApplet.newAudioClip(booURL);

cheer = JApplet.newAudioClip(cheerURL);

}

catch(Exception e){ }

//before we can add the buttons to the container, we must

//initialize them. Use a for loop to do it:

int newLine = 0;

int lineCount = 0;

for(int i = 0; i < spots.length; i+ +)

{

//initialize it with a blank image

spots[i] = new JButton(blank);

//this checks whether to use a new row

if(i= =3 || i = =6)

{

newLine + +;

lineCount = 0;

}

//set the position of the button

spots[i].setBounds(75+(lineCount*100),300+(newLine*100),100,100);

//add it to the container

129

container.add(spots[i]);

//and now add the action listener:

spots[i].addActionListener(this);

lineCount+ +;

}

//add the JLabel that describes the turn

container.add(turnLbl);

turnLbl.setBounds(200,630,100,30);

container.setComponentZOrder(lose,0);

container.setComponentZOrder(win,0);

container.setComponentZOrder(draw,0);

//make sure everything is displayed:

container.repaint();

}

public void reset()

{

for(int i = 0; i < spots.length; i+ +)

{

spots[i].setIcon(blank);

spots[i].addActionListener(this);

}

turn = 1;

}

//the mandatory method:

public void actionPerformed(ActionEvent e)

{

hit.play();

try

{

Thread.sleep(600);

}

catch(Exception excep){ }

//this will check the button pressed:

for(int i = 0; i < spots.length; i+ +)

{

if(e.getSource()= =spots[i])

{

//set the button to X

spots[i].setIcon(red);

//now, change the JLabel that describes the player’s turn turnLbl.setText(“X’s (Red’s) Turn”);

//disable the btn so it can’t be re-pressed

spots[i].removeActionListener(this);

}

}

turn+ +;

//before letting the other player go, check whether a player won: Project 25: Tic-Tac-Toe Boxing—Championship checkWin();

130

Project 25: Tic-Tac-Toe Boxing—Championship

//this method lets the computer select its turn ai();

}

public void ai()

{

boolean movedYet;

//if this is the computer’s first turn, then try to go in the top left

//if already taken, take the middle

if(turn = = 2)

{

//if the top left is taken, take the middle

if(spots[0].getIcon().equals(red))

{

spots[4].setIcon(blue);

spots[4].removeActionListener(this);

movedYet = true;

}

//else, take the top left

else

{

spots[0].setIcon(blue);

spots[0].removeActionListener(this);

movedYet = true;

}

}

//if this is not the first turn, then check for 2 out of 3 spots

//taken. If there are none, go to a random location else

{

//callin this method checks for two in a row of the first String passed in.

//It then takes the 3rd spot with the 2nd String passed in: movedYet = twoInARow(blue);

//if the computer didn’t take an offensive spot, take a defensive

//one.

if(!movedYet)

{

movedYet = twoInARow(red);

//if there is no defensive move, take the next open one.

if(!movedYet)

{

//this loop finds the first untaken spot:

for(int i = 0; i < spots.length; i+ +)

{

//if empty, take it!

if(spots[i].getIcon().equals(blank))

{

spots[i].setIcon(blue);

spots[i].removeActionListener

(this);

movedYet = true;

break;

}

}

}

}

131

}

turn+ +;

System.out.println(turn);

checkWin();

if(!movedYet)

{

//if no spot was taken, it must be a cat’s game: win(false,“”);

}

}

public void win(boolean notADraw,String result)

{

//remove the jbuttons:

for(int i = 0; i < spots.length; i+ +)

{

container.remove(spots[i]);

}

//checks to see if is a win or a draw

if(notADraw)

{

if(result.equals(“win”))

{

//the player won:

cheer.play();

try

{

Thread.sleep(600);

}

catch(Exception excep){ }

win.setBounds(50,50,331,438);

}

else

{

//the computer won:

boo.play();

try

{

Thread.sleep(600);

}

catch(Exception excep){ }

lose.setBounds(50,50,331,438);;

reset();

return;

}

}

else

{

//a draw:

draw.setBounds(50,50,331,438);

}

}

public boolean twoInARow(Icon a)

{

for(int i = 0; i < 3; i+ +)

{

//this checks for 2 in a row from the top

if(spots[i].getIcon().equals(a) &&

Project 25: Tic-Tac-Toe Boxing—Championship spots[i+3].getIcon().equals(a) &&

132

Project 25: Tic-Tac-Toe Boxing—Championship spots[i+6].getIcon().equals(blank))

{

spots[i+6].setIcon(blue);

spots[i+6].removeActionListener(this);

return true;

}

//this checks (from the top and bottom)

//for a taken spot, then a gap, then a taken one: if(spots[i].getIcon().equals(a) &&

spots[i+6].getIcon().equals(a) &&

spots[i+3].getIcon().equals(blank))

{

spots[i+3].setIcon(blue);

spots[i+3].removeActionListener(this);

return true;

}

//this checks for 2 in a row from the bottom

if(spots[i+6].getIcon().equals(a) &&

spots[i+3].getIcon().equals(a) &&

spots[i].getIcon().equals(blank))

{

spots[i].setIcon(blue);

spots[i].removeActionListener(this);

return true;

}

//this checks for 2 in a row from the left

if(spots[i*3].getIcon().equals(a) &&

spots[(i*3)+1].getIcon().equals(a) &&

spots[(i*3)+2].getIcon().equals(blank))

{

spots[(i*3)+2].setIcon(blue);

spots[(i*3)+2].removeActionListener(this);

return true;

}

//this checks (from the left and right)

//for a taken spot, then a gap, then a taken one if(spots[i*3].getIcon().equals(a) &&

spots[(i*3)+2].getIcon().equals(a) &&

spots[(i*3)+1].getIcon().equals(blank))

{

spots[(i*3)+1].setIcon(blue);

spots[(i*3)+1].removeActionListener(this);

return true;

}

//this checks for 2 in a row from the right

if(spots[(i*3)+2].getIcon().equals(a) && spots[(i*3)+1].getIcon().equals(a) &&

spots[i*3].getIcon().equals(blank))

{

spots[i*3].setIcon(blue);

spots[i*3].removeActionListener(this);

return true;

}

//now we will check for a diagnol 2 in a row:

for(int j = 0; j <= 2; j+=2)

{

//this will check for diagnol X wins

if(spots[j].getIcon()= =a &&

spots[4].getIcon()= =a &&

133

spots[8-j].getIcon().equals(blank))

{

spots[8−j].setIcon(blue);

spots[8−j].removeActionListener(this);

return true;

}

//this checks (from a diagnol)

//for a taken spot, then a gap, then a taken one if(spots[j].getIcon()= =a &&

spots[8−j].getIcon()= =a &&

spots[4].getIcon().equals(blank))

{

spots[4].setIcon(blue);

spots[4].removeActionListener(this);

return true;

}

if(spots[8−j].getIcon()= =a &&

spots[4].getIcon()= =a &&

spots[j].getIcon().equals(blank))

{

spots[j].setIcon(blue);

spots[j].removeActionListener(this);

return true;

}

}

}

return false;

}

public void checkWin()

{

//first, we will use to go through three iterations. This allows us to

//check for both horizontal and vertical wins without using too

//much code:

for(int i = 0; i < 3; i+ +)

{

//this checks for a vertical X win

if(spots[i].getIcon().equals(red) &&

spots[i+3].getIcon().equals(red) &&

spots[i+6].getIcon().equals(red))

{

win(true,“win”);

reset();

return;

}

//this checks for a vertical O win

if(spots[i].getIcon().equals(blue) &&

spots[i+3].getIcon().equals(blue) &&

spots[i+6].getIcon().equals(blue))

{

win(true,”lose”);

reset();

return;

}

//this checks for a horizontal X win

if(spots[i*3].getIcon().equals(red) && spots[(i*3)+1].getIcon().equals(red) && spots[(i*3)+2].getIcon().equals(red))

{

win(true,“win”);

Project 25: Tic-Tac-Toe Boxing—Championship reset();

134

Project 25: Tic-Tac-Toe Boxing—Championship return;

}

//this checks for a horizontal O win

if(spots[i*3].getIcon().equals(blue) && spots[(i*3)+1].getIcon().equals(blue) && spots[(i*3)+2].getIcon().equals(blue))

{

win(true,“lose”);

reset();

return;

}

}

//now, this loop will check for diagnol wins

for(int i = 0; i <= 2; i+=2)

{

//this will check for diagnol X wins

if(spots[i].getIcon().equals(red) &&

spots[4].getIcon().equals(red) &&

spots[8−i].getIcon().equals(red))

{

win(true,“win”);

reset();

return;

}

//this will check for diagnol O wins

if(spots[i].getIcon().equals(blue) &&

spots[4].getIcon().equals(blue) &&

spots[8−i].getIcon().equals(blue))

{

win(true,“lose”);

reset();

return;

}

}

}

//starter (main) method:

public static void main(String[ ] args) {

TicTacToe ttt = new TicTacToe();

}

}

Figures 25-2 through 25-5 shows Tic-Tac-Toe

them to simulate body blows; record your doorbell Boxing’s attention-grabbing GUI!

ringing to signal the next round.

Expand the 3 by 3 boxing ring into a 4 by

4 space requiring more complicated moves.

Customizing the game

If you really want a challenge, modify the

boxing ring into a three dimensional space with Customize the images: you can turn the gloves

multiple fighters.

into full boxing figures, growling faces ...

Allow the user to select various difficulty levels.

anything!

Play ten rounds against the computer: the

Customize the sounds: punch pillows, jump on

catch—the computer progresses in intelligence

empty plastic bottles, blow up balloons and pop after each round.

135

Figure 25-2

Although you cannot hear it, trust me, a

Figure 25-3

Player loses.

punching sound just played.

Project 25: Tic-Tac-Toe Boxing—Championship Figure 25-4 Match ends in draw!

Figure 25-5

KNOCK OUT! Player wins!

136

Section Four

Shoot ‘em up Games

Project 26: Snake Pit—The Arena

<color> can be any you choose. The option to select a color pops up after you type the period.

Snake Pit

Figure 26-1 illustrates a new background color.

You can also set the color of the text of a JLabel Two snakes. One mouse. Venom flying

by using the command:

everywhere! Snake Pit is a classic “shoot ‘em up”

lbl.setForeground(Color.<color>);

game in which you must prevent your opponent

from capturing prey as you avoid being hit by

his/her poisonous venom.

Making the game

To begin, create a JFrame that is 800 by

600 pixels. Next, set the background color of the Project

JFrame to black.

Now that you have the arena set, add the two

Create the snake pit.

snakes. Create two ImageIcons per snake—one of the basic snake (Figure 26-2); the other, of the New building blocks

snake being hit by venom (Figure 26-3).

Component Color, JLabel Font

Initialize a JLabel for the two snakes and assign the snake’s basic image to it (you will use the second ImageIcon later when you create venom).

Component color

Use the setBounds method to center each snake on the far left and far right sides of the pit. Then, use When using a Container, you can easily set the a JLabel to add the image of a mouse to the center color of the background of any component, such as of the screen. Now, create two JLabels to represent a JFrame, by using the command:

the score of each snake. Remember to set the

cont.setBackground(Color.<color>);

JLabels’ fonts to white so the scores can be seen against the dark background of the arena.

137

Figure 26-1

JFrame with black background.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SnakePit extends JFrame

{

//these variable will help to determine when the

//ball leaves the screen

int width = 800;

int height = 600;

//the two scores and the JLabels to show them: Project 26: Snake Pit—The Arena Figure 26-2 Basic snake.

Figure 26-3

Snake struck by venom.

138

Project 26: Snake Pit—The Arena

int scoreLeft = 0;

int scoreRight = 0;

JLabel left = new JLabel(“Score: “+scoreLeft); JLabel right = new JLabel(“Score: “+scoreRight);

//SNAKE ICONS:

ImageIcon snakeLeftImg = new ImageIcon(“snakeLeft.PNG”); ImageIcon snakeRightImg = new ImageIcon(“snakeRight.PNG”); ImageIcon snakeLeftHit = new ImageIcon(“snakeLeftHit.PNG”); ImageIcon snakeRightHit = new ImageIcon(“snakeRightHit.PNG”);

//these are the snake JLabels

JLabel snakeLeft = new JLabel(snakeLeftImg);

JLabel snakeRight = new JLabel(snakeRightImg); JLabel food = new JLabel(new ImageIcon(“food.PNG”)); JLabel venomRight = new JLabel(new ImageIcon(“venomRight.png”)); JLabel venomLeft = new JLabel(new ImageIcon(“venomLeft.png”));

//global container:

Container cont;

public SnakePit()

{

//create the JFrame...

super(“Snake Pit”);

setVisible(true);

setSize(width,height);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this is the container:

cont = getContentPane();

Figure 26-4

Snake Pit Arena.

139

cont.setLayout(null);

cont.setBackground(Color.BLACK);

//add the score labels:

cont.add(left);

left.setBounds(50,50,100,30);

left.setForeground(Color.WHITE);

cont.add(right);

right.setBounds(width−150,50,100,30);

right.setForeground(Color.WHITE);

//set the layout to null

cont.setLayout(null);

//add the two snakes and set their bounds to the correct positions cont.add(snakeLeft);

snakeLeft.setBounds(50,height/2,30,200);

cont.add(snakeRight);

snakeRight.setBounds(width−80,height/2,30,200);

//now, add the food (the mouse), and put it in the center cont.add(food);

food.setBounds(width/2,height/2,30,30);

}

public static void main (String[ ] args)

{

new SnakePit();

}

}

Figure 26-4 illustrates the snake pit.

You will also make the mouse flee

Slither forward, snakes! Go on to bring

for its life.

the snakes to life by adding a KeyListener.

Project 27: Snake Pit—Snake Bait

Project

Component movement

One of the key features of Snake Pit is making the Moving components is easy to do in Java.

snakes move so they can sink their fangs into their Remember that setBounds method?

bait—a bouncing mouse. You accomplish this by

Use the same method to move components.

using a KeyListener. Careful, those snakes are All you do is create a Thread and an infinite

getting hungry!

loop to set the bounds of the component during each iteration. For example, if you want a

New building blocks

component to move to the right, use the

following code, which should be inserted into

Component Movement, Component Collision

the loop:

Project 27: Snake Pit—Snake Bait Detection 140

Project 27: Snake Pit—Snake Bait

component.setBounds(component.getX()+1,

component.getY(), <width>, <height>); The getX() and getY() methods return the

component’s current X and Y positions,

respectively.

Component collision detection

Collision detection with components

can be written in one simple condition. For this example, c1 and c2 are the names of the two

components.

c1.getBounds().intersects(c2.getBounds)

Figure 27-1

Collision detection.

The above code checks for the situation

illustrated in Figure 27-1.

multiplying the y velocity by −1. If the mouse Making the game

tries to exit the arena in the x direction

(horizontally), add one point to the opposing

Create a Thread and add a KeyListener to it. Then, snake’s score (Note: scoring is based upon

create two global variables that represent the preventing your opponent from capturing prey and, velocity of the food in the x and y directions.

as you’ll soon see, striking the opposing snake Set each variable to 1. Within the thread’s infinite with venom). If one of the snakes is able to capture loop, use setBounds to move the food by the

the mouse, make the mouse bounce by multiplying velocity variables, as shown below:

the x velocity by −1.

food.setBounds(food.getX()+velX,

Now, use the thread’s KeyListener to add user

food.getY()+velY, 30, 30);

movement. When the “w” key is pressed, use the Now, use your new collision detection

setBounds method to move the left snake up.

skills to make the mouse bounce around the arena.

When “s” is pressed, move the left snake down.

If the mouse tries to exit in the y direction

The right snake will be controlled by AI, which (vertically), make the mouse ricochet by

you will program in the next project.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SnakePit extends JFrame

{

//these two arraylists will hold the labels that represent the bullets ArrayList bulletsLeft = new ArrayList();

ArrayList bulletsRight = new ArrayList();

//this array will hold both arraylists

ArrayList[ ] bullets = {bulletsLeft, bulletsRight}; 141

//these variable will help to determine when the

//ball leaves the screen

int width = 800;

int height = 600;

//the two scores and the JLabels to show them: int scoreLeft = 0;

int scoreRight = 0;

JLabel left = new JLabel(“Score: “+scoreLeft); JLabel right = new JLabel(“Score: “+scoreRight);

//SNAKE ICONS:

ImageIcon snakeLeftImg = new ImageIcon(“snakeLeft.PNG”); ImageIcon snakeRightImg = new ImageIcon(“snakeRight.PNG”); ImageIcon snakeLeftHit = new ImageIcon(“snakeLeftHit.PNG”); ImageIcon snakeRightHit = new ImageIcon(“snakeRightHit.PNG”);

//these are the snake JLabels

JLabel snakeLeft = new JLabel(snakeLeftImg);

JLabel snakeRight = new JLabel(snakeRightImg); JLabel food = new JLabel(new ImageIcon(“food.PNG”)); JLabel venomRight = new JLabel(new ImageIcon(“venomRight.png”)); JLabel venomLeft = new JLabel(new ImageIcon(“venomLeft.png”));

//these variables represent how much the food moves

//in the x and y directions:

int foodX = 1;

int foodY = 1;

//global container:

Container cont;

public SnakePit()

{

//create the JFrame...

super(“Snake Pit”);

setVisible(true);

setSize(width,height);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this is the container:

cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.black);

//add the score labels:

cont.add(left);

left.setBounds(50,50,100,30);

left.setForeground(Color.WHITE);

cont.add(right);

right.setBounds(width−150,50,100,30);

right.setForeground(Color.WHITE);

//add the two snakes and set their bounds to the correct positions cont.add(snakeLeft);

snakeLeft.setBounds(50,height/2,30,200);

cont.add(snakeRight);

snakeRight.setBounds(width−80,height/2,30,200);

//now, add the food (the mouse), and put it in the center cont.add(food);

food.setBounds(width/2,height/2,30,30);

//the thread for the snakes

SnakeThread st = new SnakeThread();

st.start();

Project 27: Snake Pit—Snake Bait

142

Project 27: Snake Pit—Snake Bait

}

//the thread:

public class SnakeThread extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(true)

{

try

{

//if the food hits the left or right sides...

if(food.getX()<0 || food.getX()>width)

{

//then reset the ball and add a point to the correct player food.setBounds(width/2,height/2,30,30);

foodX = 1;

foodY = 1;

if(food.getX()<0)

{

scoreLeft+ +;

}

else

{

scoreRight+ +;

}

left.setText(“Score: “+scoreLeft);

right.setText(“Score: “+scoreRight);

}

//if the food goes too high or low, make it bounce else if(food.getY()>height−30 || food.getY()<0)

{

foodY *= −1;

}

//if the paddle is hit

else if((food.getX()<80 && food.getY()>snakeLeft.getY() && food.getY()<snakeLeft.getY()+200) || (food.getX()>width−80 && food.getY()>snakeRight.getY() && food.getY()<snakeRight.getY()+200))

{

foodX *= −1;

}

//move the food

food.setBounds(food.getX()−foodX, food.getY()−foodY,30,30);

//the refresh delay

Thread.sleep(4);

}

catch(Exception e){ }

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

if(event.getKeyChar()==’w’)

{

snakeLeft.setBounds(snakeLeft.getX(),snakeLeft.getY()−10,30,200);

}

if(event.getKeyChar()==’s’)

{

143

snakeLeft.setBounds(snakeLeft.getX(),snakeLeft.getY()+10,30,200);

}

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event){ }

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event){ }

}

public static void main (String[ ] args)

{

new SnakePit();

}

}

Figures 27-2 through 27-4 display primary

opponent with AI. And to make things even more actions in the snake pit.

interesting, you’ll add code that allows the two You’re all alone and suddenly overcome with the snakes to spit deadly venom at one another while urge to play Snake Pit. What do you do? Create an mouse hunting.

Figure 27-2

Arena.

Project 27: Snake Pit—Snake Bait

144

Project 27: Snake Pit—Snake Bait

Figure 27-3

Snake is hungry.

Figure 27-4

One mouse gone, next mouse up!

145

Project 28: Snake Pit—Snake Bite!

Project

if-statement should check if the mouse is lower than the right snake. If so, move the right snake With AI, turn your computer into an adversary that down. Both of these if statements belong in the cannot be defeated. Also, you will implant venom infinite loop inside of the thread.

glands into the snakes that allows them to spit out Now, it’s time to add venom glands to the snake.

the deadly poison!

To do this, create two ArrayLists: each one should hold the JLabels that represent the venom from Making the game

each snake. In addition, to cut down on the

repetition of your code, add both of the ArrayLists First, you will add AI to the snake on the right side to an array. When the “q” key is pressed, add a of the arena. The AI is very simple; in fact, it can new JLabel to the container and to the ArrayList.

be programmed with only two if-statements. The Next, create another thread. This one should

first if-statement should check to see if the mouse control the AI’s firing of venom. In the infinite is higher than the right snake. If so, move the right loop, go through both ArrayLists and move the

snake up using the setBounds method. The second JLabels in the appropriate direction.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SnakePit extends JFrame

{

//these two arraylists will hold the labels that represent the bullets ArrayList bulletsLeft = new ArrayList();

ArrayList bulletsRight = new ArrayList();

//this array will hold both arraylists

ArrayList[ ] bullets = {bulletsLeft, bulletsRight};

//these variable will help to determine when the

//ball leaves the screen

int width = 800;

int height = 600;

//the two scores and the JLabels to show them: int scoreLeft = 0;

int scoreRight = 0;

JLabel left = new JLabel(“Score: “+scoreLeft); JLabel right = new JLabel(“Score: “+scoreRight);

//SNAKE ICONS:

ImageIcon snakeLeftImg = new ImageIcon(“snakeLeft.PNG”); ImageIcon snakeRightImg = new ImageIcon(“snakeRight.PNG”); ImageIcon snakeLeftHit = new ImageIcon(“snakeLeftHit.PNG”); ImageIcon snakeRightHit = new ImageIcon(“snakeRightHit.PNG”);

//these are the snake JLabels

JLabel snakeLeft = new JLabel(snakeLeftImg);

JLabel snakeRight = new JLabel(snakeRightImg); Project 28: Snake Pit—Snake Bite!

JLabel food = new JLabel(new ImageIcon(“food.PNG”)); 146

Project 28: Snake Pit—Snake Bite!

JLabel venomRight = new JLabel(new ImageIcon(“venomRight.png”)); JLabel venomLeft = new JLabel(new ImageIcon(“venomLeft.png”));

//these variables represent how much the food moves

//in the x and y directions:

int foodX = 1;

int foodY = 1;

//global container:

Container cont;

public SnakePit()

{

//create the JFrame...

super(“Snake Pit”);

setVisible(true);

setSize(width,height);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this is the container:

cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.BLACK);

//add the score labels:

cont.add(left);

left.setFont(new Font(“Times New Roman”, Font.BOLD, 20)); left.setBounds(50,50,100,30);

left.setForeground(Color.WHITE);

cont.add(right);

right.setFont(new Font(“Times New Roman”, Font.BOLD, 20)); right.setBounds(width−150,50,100,30);

right.setForeground(Color.WHITE);

//add the two snakes and set their bounds to the correct positions cont.add(snakeLeft);

snakeLeft.setBounds(50,height/2,30,200);

cont.add(snakeRight);

snakeRight.setBounds(width−80,height/2,30,200);

//now, add the food (the mouse), and put it in the center cont.add(food);

food.setBounds(width/2,height/2,30,30);

//the thread for the snakes

SnakeThread st = new SnakeThread();

st.start();

//this thread will control the intervals of the enemy’s attack Attack attack = new Attack();

attack.start();

}

public class Attack extends Thread

{

public void run()

{

while(true)

{

try

{

int interval = (int)(Math.random()*2000);

Thread.sleep(interval);

bulletsRight.add(venomRight);

cont.add(venomRight);

cont.setComponentZOrder(venomRight,0);

venomRight.setBounds(snakeRight.getX()−30,snakeRight.getY()+30,20,10); 147

}

catch(Exception e){ }

}

}

}

//the thread:

public class SnakeThread extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(true)

{

try

{

//move the bullets

//this for loop goes through the two arraylists for(int i = 0; i <bullets.length; i++)

{

int distance = 0;

if(i= =0)

distance = 1;

else

distance = −1;

for(int j = 0; j < bullets[i].size(); j+ +)

{

JLabel temp = ((JLabel)bullets [i].get(j));

((JLabel)bullets[i].get(j)).setBounds(

temp.getX()+distance,temp.getY(),20,10);

}

}

//if the food hits the left or right sides...

if(food.getX()<0 || food.getX()>width)

{

//then reset the ball and add a point to the correct player food.setBounds(width/2,height/2,30,30);

foodX = 1;

foodY = 1;

if(food.getX()<0)

{

scoreLeft+ +;

}

else

{

scoreRight+ +;

}

left.setText(“Score: “+scoreLeft);

right.setText(“Score: “+scoreRight);

}

//if the food goes too high or low, make it bounce else if(food.getY()>height−30 || food.getY()<0)

{

foodY *= −1;

}

//if the paddle is hit

else if((food.getX()<80 && food.getY()>snakeLeft.getY()

&&food.getY()<snakeLeft.getY()+200) ||(food.getX()>width−80

&&food.getY()>snakeRight.getY() &&food.getY()<snakeRight.getY()+200))

{

Project 28: Snake Pit—Snake Bite!

foodX *= −1;

148

Project 28: Snake Pit—Snake Bite!

}

//move the food

food.setBounds(food.getX()−foodX, food.getY()−foodY,30,30);

//this code controls the AI. If the food is higher

//than the computer’s paddle, move up. If not, move down.

if(food.getY()>snakeRight.getY()+200)

{

snakeRight.setBounds(snakeRight.getX(),snakeRight.getY()+4,30,200);

}

if(food.getY()<snakeRight.getY())

{

snakeRight.setBounds(snakeRight.getX(),snakeRight.getY()−4,30,200);

}

//the refresh delay

Thread.sleep(4);

}

catch(Exception e){ }

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

if(event.getKeyChar()= =’w’)

{

snakeLeft.setBounds(snakeLeft.getX(),snakeLeft.getY()−10,30,200);

}

if(event.getKeyChar()= =’s’)

{

snakeLeft.setBounds(snakeLeft.getX(),snakeLeft.getY()+10,30,200);

}

if(event.getKeyChar()= =’q’)

{

bulletsLeft.add(venomLeft);

cont.add(venomLeft);

cont.setComponentZOrder(venomLeft,0);

venomLeft.setBounds(snakeLeft.getX()+30,snakeLeft.getY()+30,20,10);

}

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event){ }

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event){ }

}

public static void main (String[ ] args)

{

new SnakePit();

}

}

Figures 28-1 and 28-2 display the venom battle.

their venom. When one of these nasty creatures Chaos is about to unfold! In the next project, gets hit, not only will the score change, but the you will track collisions between the snakes and injured snake will wither in pain.

149

Figure 28-1

Player fires venom!

Project 28: Snake Pit—Snake Bite! Figure 28-2 AI spits back.

150

Project 29: Snake Pit—King Cobra

Project 29: Snake Pit—King Cobra

Project

When you type the period, options pop-up. Choose one of the uppercase choices, such as “BOLD” or Stand back! You’re about to make the snakes recoil

“NORMAL.”

when stricken and create a scoring system to keep track of venom hits. And there’s more – you’ll add Making the game

a background image to the pit.

New building blocks

Add if-statements in the loops that move the

venom to check for a collision between the venom Font

and the snakes. If there is a collision, change the score accordingly.

Font

Remember when you created that ImageIcon of

the snakes being attacked? Finally, it is time to use You can easily change the font of JLabels. Simply it! Set the JLabel’s icon to that image for

use the following code:

100 milliseconds. Then, add a background image by creating another ImageIcon and a JLabel. You lbl.setFont(new Font(“<font name>”,

can also change the font of the score JLabels to

<font type>, <size>));

make them contrast against the background.

<font name> is the name of the font, such as You can even add a small delay to the game before

“Times New Roman” or “Arial.”

the mouse starts moving so the player has a

<

moment to prepare for the attack.

font type> give you options: bold,

underlined, etc. To select the type, enter “Font.”

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SnakePit extends JFrame

{

//these two arraylists will hold the labels that represent the bullets ArrayList bulletsLeft = new ArrayList();

ArrayList bulletsRight = new ArrayList();

//this array will hold both arraylists

ArrayList[ ] bullets = {bulletsLeft, bulletsRight};

//these variable will help to determine when the

//ball leaves the screen

int width = 800;

int height = 600;

//the two scores and the JLabels to show them: int scoreLeft = 0;

int scoreRight = 0;

JLabel left = new JLabel(“Score: “+scoreLeft); JLabel right = new JLabel(“Score: “+scoreRight); 151

//SNAKE ICONS:

ImageIcon snakeLeftImg = new ImageIcon(“snakeLeft.PNG”); ImageIcon snakeRightImg = new ImageIcon(“snakeRight.PNG”); ImageIcon snakeLeftHit = new ImageIcon(“snakeLeftHit.PNG”); ImageIcon snakeRightHit = new ImageIcon(“snake RightHit.PNG”);

//these are the snake JLabels

JLabel snakeLeft = new JLabel(snakeLeftImg);

JLabel snakeRight = new JLabel(snakeRightImg); JLabel food = new JLabel(new ImageIcon(“food.PNG”)); JLabel venomRight = new JLabel(new ImageIcon(“venomRight.png”)); JLabel venomLeft = new JLabel(new ImageIcon (“venomLeft.png”));

//these variables represent how much the food moves

//in the x and y directions:

int foodX = 1;

int foodY = 1;

//global container:

Container cont;

public SnakePit()

{

//create the JFrame...

super(“Snake Pit”);

setVisible(true);

setSize(width,height);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

//this is the container:

cont = getContentPane();

cont.setLayout(null);

//add the score labels:

cont.add(left);

left.setFont(new Font(“Times New Roman”, Font.BOLD, 20)); left.setBounds(50,50,100,30);

left.setForeground(Color.WHITE);

cont.add(right);

right.setFont(new Font(“Times New Roman”, Font.BOLD, 20)); right.setBounds(width−150,50,100,30);

right.setForeground(Color.WHITE);

//set the layout to null

cont.setLayout(null);

//add the two snakes and set their bounds to the correct positions cont.add(snakeLeft);

snakeLeft.setBounds(50,height/2,30,200);

cont.add(snakeRight);

snakeRight.setBounds(width−80,height/2,30,200);

//now, add the food (the mouse), and put it in the center cont.add(food);

food.setBounds(width/2,height/2,30,30);

//the thread for the snakes

SnakeThread st = new SnakeThread();

st.start();

//this thread will control the intervals of the enemy’s attack Attack attack = new Attack();

attack.start();

//set the background of the container with an image JLabel background = new JLabel(new ImageIcon(“background.PNG”)); cont.add(background);

Project 29: Snake Pit—King Cobra

background.setBounds(0,0,800,600);

152

Project 29: Snake Pit—King Cobra

}

public class Attack extends Thread

{

public void run()

{

while(true)

{

try

{

int interval = (int)(Math.random()*2000);

Thread.sleep(interval);

bulletsRight.add(venomRight);

cont.add(venomRight);

cont.setComponentZOrder(venomRight,0);

venomRight.setBounds(snakeRight.getX()−30, snakeRight.getY()+30,20,10);

}

catch(Exception e){ }

}

}

}

//the thread:

public class SnakeThread extends Thread implements KeyListener

{

public void run()

{

try

{

Thread.sleep(2000);

}

catch(Exception e){ }

addKeyListener(this);

while(true)

{

try

{

//move the bullets

//this for loop goes through the two arraylists for(int i = 0; i <bullets.length; i++)

{

int distance = 0;

if(i= =0)

distance = 1;

else

distance = −1;

for(int j = 0; j <bullets[i].size(); j+ +)

{

JLabel temp = ((JLabel)bullets[i].get(j));

//check for collisions between the snakes and bullets if(i= =0)

{

if(snakeRight.getBounds().intersects(temp.getX(),temp.getY(),20,10))

{

snakeRight.setIcon(snakeRightHit);

scoreLeft+ +;

left.setText(“Score: “+scoreLeft);

bullets[i].remove(j);

Thread.sleep(100);

snakeRight.setIcon(snakeRightImg);

}

}

153

else

{

if(snakeLeft.getBounds().intersects(temp.getX(),temp.getY(),20,10))

{

snakeLeft.setIcon(snakeLeftHit);

scoreRight+ +;

right.setText(“Score: “+scoreRight);

bullets[i].remove(j);

Thread.sleep(100);

snakeLeft.setIcon(snakeLeftImg);

}

}

((JLabel)bullets[i].get(j)).setBounds(temp.getX()+distance,temp.getY(),20,10);

}

}

//if the food hits the left or right sides...

if(food.getX()<0 || food.getX()>width)

{

//then reset the ball and add a point to the correct player food.setBounds(width/2,height/2,30,30);

foodX = 1;

foodY = 1;

if(food.getX()<0)

{

scoreLeft+ +;

}

else

{

scoreRight+ +;

}

left.setText(“Score: “+scoreLeft);

right.setText(“Score: “+scoreRight);

}

//if the food goes too high or low, make it bounce else if(food.getY()>height−30 || food.getY()<0)

{

foodY *= −1;

}

//if the paddle is hit

else if((food.getX()<80 && food.getY()>snakeLeft.getY()

&&food.getY()<snakeLeft.getY()+200) ||(food.getX()>width−80

&&food.getY()>snakeRight.getY() &&food.getY()<snakeRight.getY()+200))

{

foodX *= −1;

}

//move the food

food.setBounds(food.getX()−foodX, food.getY()−foodY,30,30);

//this code controls the AI. If the food is higher

//than the computer’s paddle, move up. If not, move down.

if(food.getY()>snakeRight.getY()+200)

{

snakeRight.setBounds(snakeRight.getX(),snakeRight.getY()+4,30,200);

}

if(food.getY()<snakeRight.getY())

{

snakeRight.setBounds(snakeRight.getX(),snakeRight.getY()−4,30,200);

}

//the refresh delay

Thread.sleep(4);

Project 29: Snake Pit—King Cobra

154

Project 29: Snake Pit—King Cobra

}

catch(Exception e){ }

}

}

//you must also implement this method from KeyListener public void keyPressed(KeyEvent event)

{

if(event.getKeyChar()= =’w’)

{

snakeLeft.setBounds(snakeLeft.getX(),snakeLeft.getY()−10,30,200);

}

if(event.getKeyChar()= =’s’)

{

snakeLeft.setBounds(snakeLeft.getX(),snakeLeft.getY()+10,30,200);

}

if(event.getKeyChar()= =’q’)

{

bulletsLeft.add(venomLeft);

cont.add(venomLeft);

cont.setComponentZOrder(venomLeft,0);

venomLeft.setBounds(snakeLeft.getX()+30,snakeLeft.getY()+30,20,10);

}

}

//you must also implement this method from KeyListener public void keyReleased(KeyEvent event){ }

//you must also implement this method from KeyListener public void keyTyped(KeyEvent event){ }

}

public static void main (String[ ] args)

{

new SnakePit();

}

}

Figures 29-1 through 29-3 illustrate the vicious Add another mouse—double food!

snake fight.

Substitute a mongoose for the mouse—if it

collides with the snake, the snake dies!

Customizing the game

Create power-ups: freeze your opponent for

several seconds.

Vary the speed of the snakes and mouse: faster, Dual-wielding: shoot several venomous shots at slower, or randomly changing.

once.

Give the snake the ability to spit venom like a Change the snakes into scorpions and have them machine gun.

shoot stingers instead of venom.

Add two more snakes to the top and bottom of

the arena.

155

Figure 29-1

Creative background image.

Project 29: Snake Pit—King Cobra Figure 29-2 Snake recoils from venom spit.

156

Project 30: Space Destroyers—The Landscape

Figure 29-3

Player is winning!

Project 30: Space Destroyers—The Landscape

MouseMotionListener

Space Destroyers

The MouseMotionListener does exactly what is

Planet Earth is being invaded. You will design and says: it listens for the mouse’s movements. Just command a military spaceship to destroy the

like the ActionListener and the KeyListener, the aliens. Your arsenal of weapons includes plasma MouseMotionListener has two mandatory

machine guns, health packs, and reflector beams.

methods:

Save our planet!

public void mouseMoved(MouseEvent event)

and

Project

public void mouseDragged(MouseEvent event)

Create the landscape and the spacecraft.

To get the X position of the cursor, use:

event.getX()

New building blocks

To get the Y position, use:

MouseMotionListener

event.getY()

157

JLabel and set the ImageIcon of the basic

Making the game

spaceship to it.

Add a MouseMotionListener to the class. In

Start making the game by creating a JFrame that is mouseMoved, use the spaceship’s setBounds

500 by 700 pixels. Set the background color to method to move the spaceship to the location of black. For the military spaceship, create two

the cursor.

ImageIcons: one of the basic spaceship; the other of the spaceship damaged. Then, create a

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SpaceDestroyers extends JFrame implements MouseMotionListener

{

//this holds the components

Container cont;

//these are the ship’s images

ImageIcon shipImg = new ImageIcon(“ship.PNG”); ImageIcon shipHit = new ImageIcon(“shipHit.PNG”);

//this is the player’s ship

JLabel ship = new JLabel(shipImg);

Project 30: Space Destroyers—The Landscape Figure 30-1 Spaceship ready for action!

158

Project 30: Space Destroyers—The Landscape

public SpaceDestroyers()

{

super(“Space Destroyers”);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500,700);

cont = getContentPane();

cont.setLayout(null);

//set the background color

cont.setBackground(Color.BLACK);

cont.add(ship);

ship.setBounds(225, 550,50,50);

addMouseMotionListener(this);

setContentPane(cont);

}

public void mouseMoved(MouseEvent event)

{

ship.setBounds(event.getX()−25,event.getY()−40,50,50);

}

public void mouseDragged(MouseEvent event){ }

public static void main (String[ ] args)

{

new SpaceDestroyers();

}

}

Figure 30-2

Spaceship follows cursor.

159

Figures 30-1 and 30-2 illustrate the spaceship Move on to add weapons to your spaceship. But

and its initial movement.

what’s the point of weapons if there is no target?

That’s why you will also be creating those

threatening aliens.

Project 31: Space Destroyers—Lasers

Project

Add the basic alien image to a JLabel. Next,

create two variables: level and numOfEnemies.

Who better than an Evil Genius to create evil

The number of enemies should correspond to the aliens? But first, you will add lasers to your square of each level (e.g. the second level should spaceship to give mankind a fighting chance.

have 22, 4 enemies; the third, 32, 9 enemies). In the constructor, use a loop to initialize the enemies. In the infinite while loop, move the aliens downward.

Making the game

Now, make an ArrayList to hold the aliens. Create an if-statement to check the number of enemies Create an ImageIcon and JLabel for the ship’s

still viable. If it is 0, increment level by 1 and lasers. Go on and make an ArrayList to store all of re-add the aliens to the screen and the ArrayList.

the lasers shot by the spaceship (you have already To make life easier, you can also create a method practiced this technique in Project 28, the Snake that populates the ArrayList. Also, don’t forget to Pit game). Once the ArrayList is complete, add a have the aliens reappear on the top of the screen KeyListener to determine when to fire the lasers.

after disappearing offscreen!

When the space bar is pressed, add the laser to both the content pane and the ArrayList. After creating a Important: check for collisions between the

thread and an infinite loop, use a

ship’s lasers and the aliens in the infinite loop. If a for loop and the

setBounds method to shoot the lasers upward.

collision occurs, remove the aliens and the laser.

And remember to set the alien’s icon to the

Now it’s time to create the aliens. Make two

damaged image before removing it.

ImageIcons: one of a basic alien (see Figure 31-1) and one of a damaged alien (see Figure 31-2).

Project 31: Space Destroyers—Lasers Figure 31-1 Basic alien.

Figure 31-2

Damaged alien.

160

Project 31: Space Destroyers—Lasers

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SpaceDestroyers extends JFrame implements KeyListener,MouseMotionListener

{

//this holds the components

Container cont;

//this is the current level:

int currentLevel = 1;

//this is the number of enemies:

int numOfEnemies = 1;

//this is the bullet’s image:

ImageIcon shipBullet = new ImageIcon (“shipBullet.PNG”);

//this holds the player’s bullets

ArrayList playerBullets = new ArrayList();

//this holds the enemies

ArrayList enemies = new ArrayList();

//these are the ship’s images

ImageIcon shipImg = new ImageIcon(“ship.PNG”); ImageIcon shipHit = new ImageIcon(“shipHit.PNG”);

//these are the images of the enemies

ImageIcon enemyImg = new ImageIcon (“enemy.PNG”); ImageIcon enemyHit = new ImageIcon (“enemyHit.PNG”);

//this is the player’s ship

JLabel ship = new JLabel(shipImg);

public SpaceDestroyers()

{

super(“Space Destroyers”);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500,700);

cont = getContentPane();

cont.setLayout(null);

//set the background color

cont.setBackground(Color.BLACK);

cont.add(ship);

ship.setBounds(225, 550,50,50);

addKeyListener(this);

addMouseMotionListener(this);

populateEnemies();

Play play= new Play();

play.start();

setContentPane(cont);

}

public void populateEnemies()

{

for(int i = 0; i <= numOfEnemies; i+ +)

{

JLabel tempEnemy = new JLabel(enemyImg);

int randLocation = (int)(Math.random()*500);

enemies.add(tempEnemy);

161

cont.add((JLabel)(enemies.get(i)));

tempEnemy.setBounds(randLocation,10,30,30);

cont.setComponentZOrder(((JLabel)(enemies.get(i))),0);

}

}

public class Play extends Thread

{

public void run()

{

while(true)

{

try

{

for(int i = 0; i < enemies.size(); i++)

{

JLabel tempEnemy = (JLabel)(enemies.get(i));

int distance = (int)(Math.random()*2);

tempEnemy.setBounds(tempEnemy.getX(),tempEnemy.getY()+distance,30,30); if(tempEnemy.getBounds().intersects(ship.getBounds()))

{

cont.remove(tempEnemy);

}

if(tempEnemy.getY()>550)tempEnemy.setBounds(tempEnemy.getX(), 10, 30, 30);

}

//chack if the player’s bullets hit the aliens boolean breakAll = false;

for(int i = 0; i < playerBullets.size(); i+ +)

{

JLabel temp = ((JLabel)(playerBullets.get(i))); temp.setBounds(temp.getX(),temp.getY()−8,10,20); if(temp.getY()<0)

{

cont.remove(temp);

playerBullets.remove(i);

ι− −;

}

for(int j = 0; j < enemies.size(); j+ +)

{

JLabel tempEnemy = (JLabel)(enemies.get(j));

if(temp.getBounds().intersects(tempEnemy.getBounds()))

{

tempEnemy.setIcon(enemyHit);

Thread.sleep(100);

enemies.remove(j);

cont.remove(tempEnemy);

numOfEnemies—;

if(numOfEnemies<=0)

{

currentLevel+ +;

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

breakAll = true;

break;

}

}

}

if(breakAll)

break;

}

Project 31: Space Destroyers—Lasers

162

Project 31: Space Destroyers—Lasers

cont.repaint();

Tread.sleep(10);

}

catch(Exception e){ }

}

}

}

public void mouseMoved(MouseEvent event)

{

ship.setBounds(event.getX()−25,event.getY()−40,50,50);

}

public void mouseDragged(MouseEvent event){ }

public void keyPressed(KeyEvent event)

{

if(event.getKeyChar()= =‘ ’)

{

JLabel tempBullet = new JLabel(shipBullet);

tempBullet.setBounds(ship.getX()+20,ship.getY()−20,10,20); playerBullets.add(tempBullet);

cont.add((JLabel)(playerBullets.get(playerBullets.size()−1))); cont.setComponentZOrder((JLabel)(playerBullets.get(playerBullets.size()−1)),0);

}

}

Figure 31-3

Aliens are coming!

163

Figure 31-4

Aliens defeated. Second wave arrives.

public void keyReleased(KeyEvent event) { }

public void keyTyped(KeyEvent event) { }

public static void main (String[ ] args)

{

new SpaceDestroyers();

}

}

Figures 31-3 through 35-6 show the player

The aliens are now coming at you in droves. But defending the planet from the aliens.

it won’t be an epic battle unless they can return fire. Go on to the next project to learn how.

Project 31: Space Destroyers—Lasers

164

Project 32: Space Destroyers—Retaliation

Figure 31-5

Open fire!!!

Figure 31-6

Uh oh ... aliens spawn!

Project 32: Space Destroyers—Retaliation

Project

Next, create two variables. One represents the score and the other represents the health of the The fight intensifies! Give the aliens firepower!

spaceship. When the spaceship is attacked, subtract Create power-ups that appear every few rounds.

from its health. Add to the score when an alien is destroyed.

Making the game

Now for the power-ups. There are two types,

reflector beams and health packs. Reflector beams To arm the aliens, start by creating a random

randomize the aliens’ particles, making them

variable between 0 and 2500. If the value of that temporarily disappear. Health packs add energy to variable is less than or equal to 1, the alien fires its the spaceship. Every 3 rounds, a power-up appears.

laser. Create an ArrayList and use the same code Every 5 rounds, a health pack appears. At the

that triggers the spaceship to fire. In the infinite appropriate round, add the power-up to the top of loop, check for collisions between the alien lasers the screen and make it descend so the spaceship and the spaceship. If they collide, change the can capture it.

icon of the basic spaceship to the damaged

If the ship collects a health pack, remove the spaceship icon.

health pack and increase the spaceship’s health.

165

If the ship collides with a reflector beam, remove beam move upward using the setBounds method.

the reflector beam icon and add a new JLabel that If the beam collides with an alien, remove the alien covers the entire width of the screen. Make this and add points to the player’s score.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SpaceDestroyers extends JFrame implements KeyListener,MouseMotionListener

{

//this holds the components

Container cont;

//this is the current level:

int currentLevel = 1;

//this is the number of enemies:

int numOfEnemies = 1;

//this is the bullet’s image:

ImageIcon shipBullet = new ImageIcon(“shipBullet.PNG”); ImageIcon enemyBullet = new ImageIcon(“enemyBullet.PNG”);

//this holds the player’s bullets

ArrayList playerBullets = new ArrayList();

//this holds the enemies

ArrayList enemies = new ArrayList();

//this holds the bullets of the enemies

ArrayList enemyBullets = new ArrayList();

//these are the ship’s images

ImageIcon shipImg = new ImageIcon(“ship.PNG”); ImageIcon shipHit = new ImageIcon(“shipHit.PNG”);

//these are the images of the enemies

ImageIcon enemyImg = new ImageIcon(“enemy.PNG”); ImageIcon enemyHit = new ImageIcon(“enemyHit.PNG”);

//this is the powerup

JLabel powerup = new JLabel(new ImageIcon(“powerup.PNG”));

//this is the player’s ship

JLabel ship = new JLabel(shipImg);

//the attack from a powerup

JLabel powerAttack = new JLabel(new ImageIcon(“powerAttack.PNG”));

//this boolean keeps track of whether the power attack was used boolean useAttack = false;

//the health

JLabel healthPack = new JLabel(new ImageIcon(“health.PNG”));

//the score:

int score = 0;

//health

int health = 500;

//the final score:

int finalScore = 0;

Project 32: Space Destroyers—Retaliation

166

Project 32: Space Destroyers—Retaliation

public SpaceDestroyers()

{

super(“Space Destroyers”);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500,700);

cont = getContentPane();

cont.setLayout(null);

//set the background color

cont.setBackground(Color.BLACK);

cont.add(ship);

ship.setBounds(225, 550,50,50);

addKeyListener(this);

addMouseMotionListener(this);

populateEnemies();

Play play= new Play();

play.start();

setContentPane(cont);

}

public void title()

{

try

{

JLabel title = new JLabel(new ImageIcon(“title.PNG”)); cont.add(title);

title.setBounds(−60,−300,600,200);

do

{

title.setBounds(title.getX(),title.getY()+1,600,200); Thread.sleep(3);

}

while(title.getY()<700);

}

catch(Exception e){ }

}

public void populateEnemies()

{

for(int i = 0; i <= numOfEnemies; i+ +)

{

JLabel tempEnemy = new JLabel(enemyImg);

int randLocation = (int)(Math.random()*500);

enemies.add(tempEnemy);

cont.add((JLabel)(enemies.get(i)));

tempEnemy.setBounds(randLocation,10,30,30);

cont.setComponentZOrder(((JLabel)(enemies.get(i))),0);

}

}

public class Play extends Thread

{

public void run()

{

while(true)

{

try

{

for(int i = 0; i < enemies.size(); i++)

{

167

JLabel tempEnemy = (JLabel)(enemies.get(i));

int distance = (int)(Math.random()*2);

tempEnemy.setBounds(tempEnemy.getX(), tempEnemy.getY()+distance,30,30);

//check if the power attack hit the aliens

if(useAttack)

{

if(powerAttack.getBounds().intersects(tempEnemy.getBounds()))

{

cont.remove(tempEnemy);

i− −;

numOfEnemies− −;

score + =15;

}

}

if(tempEnemy.getBounds().intersects(ship.getBounds()))

{

health− −;

cont.remove(tempEnemy);

}

if(tempEnemy.getY()>550)tempEnemy.setBounds(tempEnemy.getX(), 10, 30, 30); int fire = (int)(Math.random()*2500);

if(fire<=1)

{

JLabel tempBullet = new JLabel(enemyBullet);

tempBullet.setBounds(tempEnemy.getX()+5,tempEnemy.getY()+30,10,20); enemyBullets.add(tempBullet);

cont.add((JLabel)(enemyBullets.get(enemyBullets.size()−1))); cont.setComponentZOrder((JLabel)(enemyBullets.get(enemyBullets.size()−1)),0);

}

}

//chack if the player’s bullets hit the aliens boolean breakAll = false;

for(int i = 0; i <playerBullets.size(); i+ +)

{

JLabel temp = ((JLabel)(playerBullets.get(i))); temp.setBounds(temp.getX(),temp.getY()−8,10,20); if(temp.getY()<0)

{

cont.remove(temp);

playerBullets.remove(i);

i− −;

}

for(int j = 0; j < enemies.size(); j+ +)

{

JLabel tempEnemy = (JLabel)(enemies.get(j));

if(temp.getBounds().intersects(tempEnemy.getBounds()))

{

score+=1000;

tempEnemy.setIcon(enemyHit);

Thread.sleep(100);

enemies.remove(j);

cont.remove(tempEnemy);

numOfEnemies—;

if(numOfEnemies<=0)

{

currentLevel+ +;

if(currentLevel%3 = = 0)

{

cont.add(powerup);

int randLoc = (int)(Math.random()*450);

Project 32: Space Destroyers—Retaliation

168

Project 32: Space Destroyers—Retaliation

powerup.setBounds(randLoc,0,30,30);

}

if(currentLevel%5= =0)

{

cont.add(healthPack);

int randLoc = (int)(Math.random()*450);

healthPack.setBounds(randLoc,0,30,30);

}

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

breakAll = true;

break;

}

}

}

if(breakAll)break;

}

//move the power attack

if(useAttack)

{

powerAttack.setBounds(0,powerAttack.getY()−1,500,10); if(powerAttack.getY()<0)

{

cont.remove(powerAttack);

useAttack = false;

currentLevel+ +;

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

}

}

//if it is every third round, allow the

//powerup to be moved

if(currentLevel%3= =0)

{

powerup.setBounds(powerup.getX(),powerup.getY()+1,30,30); if(powerup.getBounds().intersects(ship.getBounds()))

{

useAttack = true;

cont.add(powerAttack);

powerAttack.setBounds(0,ship.getY(),500,10);

cont.remove(powerup);

powerup.setBounds(−200,−200,30,30);

}

}

if(currentLevel%5= =0)

{

healthPack.setBounds(healthPack.getX(),healthPack.getY()+1,30,30); if(healthPack.getBounds().intersects(ship.getBounds()))

{

health+=50;

score+=100;

cont.remove(healthPack);

healthPack.setBounds(−100,−100,30,30);

}

}

//check if the aliens’ bullets hit the player

breakAll = false;

for(int i = 0; i <enemyBullets.size(); i+ +) 169

{

JLabel temp = ((JLabel)(enemyBullets. get(i))); temp.setBounds(temp.getX(),temp.getY()+2,10,20); if(temp.getY()>550)

{

cont.remove(temp);

enemyBullets.remove(i);

i—;

}

if(ship.getBounds().intersects(temp.getBounds()))

{

ship.setIcon(shipHit);

Thread.sleep(100);

ship.setIcon(shipImg);

score− =100;

health− =50;

cont.remove(temp);

enemyBullets.remove(i);

numOfEnemies—;

if(numOfEnemies<=0)

{

currentLevel+ +;

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

breakAll = true;

break;

}

}

if(breakAll)

break;

}

cont.repaint();

Thread.sleep(10);

}

catch(Exception e){ }

}

}

}

public void mouseMoved(MouseEvent event)

{

ship.setBounds(event.getX()−25,event.getY()−40,50,50);

}

public void mouseDragged(MouseEvent event){ }

public void keyPressed(KeyEvent event)

{

if(event.getKeyChar()= =‘ ’)

{

JLabel tempBullet = new JLabel(shipBullet);

tempBullet.setBounds(ship.getX()+20,ship.getY()−20,10,20); playerBullets.add(tempBullet);

cont.add((JLabel)(playerBullets.get(playerBullets.size()−1))); cont.setComponentZOrder(

(JLabel)(playerBullets.get(

playerBullets.size()−1)),0);

score−=2;

}

}

public void keyReleased(KeyEvent event) { }

Project 32: Space Destroyers—Retaliation

170

Project 32: Space Destroyers—Retaliation

public void keyTyped(KeyEvent event) { }

public static void main (String[ ] args)

{

new SpaceDestroyers();

}

}

Figures 32-1 through 32-4 show the fierce battle health packs look cool, they mean nothing because for Earth.

the player’s statistics are not displayed! In the next You need as much information as possible to

section, you will add this information to make the out-maneuver your enemies. Even though the

game more exciting.

Figure 32-1

Aliens retaliate.

171

Figure 32-2

Reflector beam power-up appears.

Project 32: Space Destroyers—Retaliation

172

Project 32: Space Destroyers—Retaliation

Figure 32-3

Reflector beam released.

Figure 32-4

Health pack appears.

173

Project 33: Space Destroyers—Life and Death

Project

Remember to update the JLabel after every

iteration of the infinite loop!

Display the score and health data. And for even Next, create an image that says “Space

more visual excitement, build scrolling title and Destroyers’ in a bold font. Attach that image to a end screens. Lock, load, and fire!

JLabel. To begin the game, scroll the title image across the screen. You can do this either in a Making the game

method called from the constructor or directly in the constructor.

First, create a JLabel that will display the current Next, the results. To display the score, create a level, score, and health of the spaceship. To

JLabel. Use setBounds to make this JLabel scroll enhance visibility of the display, increase the size across the screen. You can do this either in a of the font and change its color to white.

separate thread or a separate method.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class SpaceDestroyers extends JFrame implements KeyListener, MouseMotionListener

{

//this holds the components

Container cont;

//this is the current level:

int currentLevel = 1;

//this is the number of enemies:

int numOfEnemies = 1;

//this is the bullet’s image:

ImageIcon shipBullet = new ImageIcon(“shipBullet.PNG”); ImageIcon enemyBullet = new ImageIcon(“enemyBullet.PNG”);

//this holds the player’s bullets

ArrayList playerBullets = new ArrayList();

//this holds the enemies

ArrayList enemies = new ArrayList();

//this holds the bullets of the enemies

ArrayList enemyBullets = new ArrayList();

//these are the ship’s images

ImageIcon shipImg = new ImageIcon(“ship.PNG”); ImageIcon shipHit = new ImageIcon(“shipHit.PNG”);

//these are the images of the enemies

ImageIcon enemyImg = new ImageIcon(“enemy.PNG”); ImageIcon enemyHit = new ImageIcon(“enemyHit.PNG”);

//this is the powerup

Project 33: Space Destroyers—Life and Death 174

Project 33: Space Destroyers—Life and Death JLabel powerup = new JLabel(new ImageIcon(“powerup.PNG”));

//this is the player’s ship

JLabel ship = new JLabel(shipImg);

//the attack from a powerup

JLabel powerAttack = new JLabel(new ImageIcon(“powerAttack.PNG”));

//this boolean keeps track of whether the power attack was used boolean useAttack = false;

//the health

JLabel healthPack = new JLabel(new ImageIcon(“health.PNG”));

//the score:

int score = 0;

//health

int health = 500;

//the final score:

int finalScore = 0;

public SpaceDestroyers()

{

super(“Space Destroyers”);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(500,700);

cont = getContentPane();

cont.setLayout(null);

//set the background color

cont.setBackground(Color.BLACK);

cont.add(ship);

ship.setBounds(225, 550,50,50);

addKeyListener(this);

addMouseMotionListener(this);

populateEnemies();

Play play= new Play();

play.start();

setContentPane(cont);

}

public void title()

{

try

{

JLabel title = new JLabel(new ImageIcon(“title.PNG”)); cont.add(title);

title.setBounds(−60,−300,600,200);

do

{

title.setBounds(title.getX(),title.getY()+1,600,200); Thread.sleep(3);

}

while(title.getY()<700);

}

catch(Exception e){ }

}

public void populateEnemies()

{

for(int i = 0; i <= numOfEnemies; i + +)

{

175

JLabel tempEnemy = new JLabel(enemyImg);

int randLocation = (int)(Math.random()*500);

enemies.add(tempEnemy);

cont.add((JLabel)(enemies.get(i)));

tempEnemy.setBounds(randLocation,10,30,30);

cont.setComponentZOrder(((JLabel)(enemies.get(i))),0);

}

}

public class Play extends Thread

{

public void run()

{

while(true)

{

try

{

for(int i = 0; i < enemies.size(); i++)

{

JLabel tempEnemy = (JLabel)(enemies.get(i));

int distance = (int)(Math.random()*2);

tempEnemy.setBounds(tempEnemy.getX(),

tempEnemy.getY()+distance,30,30);

//check if the power attack hit the aliens

if(useAttack)

{

if(powerAttack.getBounds().intersects(tempEnemy.getBounds()))

{

cont.remove(tempEnemy);

i− −;

numOfEnemies− −;

score+=15;

}

}

if(tempEnemy.getBounds().intersects(ship.getBounds()))

{

health—;

cont.remove(tempEnemy);

}

if(tempEnemy.getY()>550)

tempEnemy.setBounds(tempEnemy.getX(), 10, 30, 30); int fire = (int)(Math.random()*2500);

if(fire<=1)

{

JLabel tempBullet = new JLabel(enemyBullet);

tempBullet.setBounds(tempEnemy.getX()+5,

tempEnemy.getY()+30,10,20);

enemyBullets.add(tempBullet);

cont.add((JLabel)(enemyBullets.get(enemyBullets.size()−1))); cont.setComponentZOrder((JLabel)(enemyBullets.get (enemyBullets.size()−

1)),0);

}

}

//chack if the player’s bullets hit the aliens boolean breakAll = false;

for(int i = 0; i < playerBullets.size(); i+ +)

{

JLabel temp = ((JLabel)(playerBullets.get(i))); temp.setBounds(temp.getX(),temp.getY()−8,10,20); if(temp.getY()

Project 33: Space Destroyers—Life and Death

<0)

176

Project 33: Space Destroyers—Life and Death

{

cont.remove(temp);

playerBullets.remove(i);

i− −;

}

for(int j = 0; j < enemies.size(); j+ +)

{

JLabel tempEnemy = (JLabel)

(enemies.get(j));

if(temp.getBounds().intersects

(tempEnemy.getBounds()))

{

score+=1000;

tempEnemy.setIcon(enemyHit);

Thread.sleep(100);

enemies.remove(j);

cont.remove(tempEnemy);

numOfEnemies− −;

if(numOfEnemies<=0)

{

currentLevel+ +;

if(currentLevel%3 = = 0)

{

cont.add(powerup);

int randLoc = (int)(Math.random()*450);

powerup.setBounds(randLoc,0,30,30);

}

if(currentLevel%5 = = 0)

{

cont.add(healthPack);

int randLoc = (int)(Math.random()*450);

healthPack.setBounds(randLoc,0,30,30);

}

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

breakAll = true;

break;

}

}

}

if(breakAll)

break;

}

//move the power attack

if(useAttack)

{

powerAttack.setBounds(0,powerAttack.getY()-1,500,10); if(powerAttack.getY()<0)

{

cont.remove(powerAttack);

useAttack = false;

currentLevel+ +;

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

}

}

//if it is every third round, allow the

//powerup to be moved

if(currentLevel%3 = = 0)

{

177

powerup.setBounds(powerup.getX(),powerup.getY()+1,30,30); if(powerup.getBounds().intersects(ship.getBounds()))

{

useAttack = true;

cont.add(powerAttack);

powerAttack.setBounds(0,ship.getY(),500,10);

cont.remove(powerup);

powerup.setBounds(-200,-200,30,30);

}

}

if(currentLevel%5= =0)

{

healthPack.setBounds(healthPack.getX(),healthPack.getY()+1,30,30); if(healthPack.getBounds().intersects(ship.getBounds()))

{

health+=50;

score+=100;

cont.remove(healthPack);

healthPack.setBounds(−100,−100,30,30);

}

}

//check if the aliens’ bullets hit the player

breakAll = false;

for(int i = 0; i <enemyBullets.size(); i+ +)

{

JLabel temp = ((JLabel)(enemyBullets.get(i))); temp.setBounds(temp.getX(),temp.getY()+2,10,20); if(temp.getY()>550)

{

cont.remove(temp);

enemyBullets.remove(i);

i− −;

}

if(ship.getBounds().intersects(temp.getBounds()))

{

ship.setIcon(shipHit);

Thread.sleep(100);

ship.setIcon(shipImg);

score− =100;

health− =50;

cont.remove(temp);

enemyBullets.remove(i);

numOfEnemies—;

if(numOfEnemies<=0)

{

currentLevel+ +;

numOfEnemies = currentLevel * currentLevel;

populateEnemies();

breakAll = true;

break;

}

}

if(breakAll)

break;

}

cont.repaint();

Thread.sleep(10);

}

Project 33: Space Destroyers—Life and Death 178

Project 33: Space Destroyers—Life and Death catch(Exception e){ }

}

}

}

public void mouseMoved(MouseEvent event)

{

ship.setBounds(event.getX()−25,event.getY()−40,50,50);

}

public void mouseDragged(MouseEvent event){ }

public void keyPressed(KeyEvent event)

{

if(event.getKeyChar()= =‘ ’)

{

JLabel tempBullet = new JLabel(shipBullet);

tempBullet.setBounds(ship.getX()+20,ship.getY()−20,10,20); playerBullets.add(tempBullet);

cont.add((JLabel)(playerBullets.get(playerBullets.size()-1))); cont.setComponentZOrder(

(JLabel)(playerBullets.get(

playerBullets.size()-1)),0);

score- =2;

}

}

public void keyReleased(KeyEvent event) { }

public void keyTyped(KeyEvent event) { }

public static void main (String[ ] args)

{

new SpaceDestroyers();

}

}

Figures 33-1 through 33-6 illustrate the game play Assign different powers to the aliens –

of Space Destroyers.

some fire lasers, some fire lightning

rings.

Add dual-wielding to the player’s ship. Fire up Customizing the game

to four lasers at once!

Change the spaceship’s initial health—make the Add a special, limited, bomb-like weapon for the game super hard or easy enough for n00bs.

spaceship that shoots shrapnel in all directions.

Add more power-ups. Make ultra-laser beams that Add extra health to the enemies: give them

are wider and can destroy multiple aliens at once.

enough body armor to survive the first attack by Add multiple spaceships: let up to four other

the spaceship.

players compete simultaneously!

Give the spaceship the power to become

invisible intermittently.

179

Figure 33-1

Customized title.

Project 33: Space Destroyers—Life and Death 180

Project 33: Space Destroyers—Life and Death Figure 33-2

Score display.

181

Figure 33-3

Results, part 1.

Figure 33-4

Results, part 2.

Project 33: Space Destroyers—Life and Death Figure 33-5 Results, part 3.

Figure 33-6

Results, part 4.

182

Section Five

Strategy Games

Project 34: Bomb Diffuser—Bomb Squad Noob

precise size of your image by clicking “Image” and then click “Attributes,” as illustrated in Figure 34-1.

Bomb Diffuser

Choose a light gray background color for the

bomb and detonator that blends in with the

As the newest member of the Bomb Squad, your

background of the JFrame. This way, if the game is job is to go out into the field and risk your life resized, the gap in between the image and the

defusing live explosive devices. Eye-hand

background will not be noticed.

coordination, quick thinking ... and a bit of luck is required.

There are two key parts of this image: the bomb and the detonator. Start by drawing the bomb at the top portion of the screen. Use the Rectangle and Pen tools, to make things easier. Don’t forget to Project

add the detonation cord and the text “TNT!”

Learn the inner workings of a bomb by creating an The next step is to add the detonator at the

inert one.

bottom portion of the screen. First, create a gray rectangle. Give it the appearance of being 3D by Making the game

adding perspective lines. Create spaces for a clue, the time left, and the disarm code. Later, you will First, create the JFrame. Set it to 500 by 550 pixels add components that go into these spaces.

and set the background color to gray. Next, you will Once you are done drawing the image of the

need to draw the image of the bomb and detonator.

bomb, go ahead and add it to the JFrame. Set it to To do this, open Microsoft Paint, specify the

position 0,0.

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class BombDiffuser extends JFrame

{

//the bomb label

JLabel bomb = new JLabel(new ImageIcon(“bomb.PNG”));

//the container of the components

Container cont;

183

public BombDiffuser()

{

super(“Bomb Diffuser”);

setSize(500,550);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.gray);

//add the background image

cont.add(bomb);

bomb.setBounds(0,0,500,500);

setContentPane(cont);

}

public static void main (String[ ] args)

{

new BombDiffuser();

}

}

Figure 34-4 illustrates the completed bomb.

You’ve graduated ... it’s time to stop

working on inert bombs and start diffusing

live ones!

Project 34: Bomb Diffuser—Bomb Squad Noob Figure 34-1 Image size.

184

Project 34: Bomb Diffuser—Bomb Squad Noob

Figure 34-2

Bomb design.

Figure 34-3

Completed bomb before placement on the JFrame.

185

Figure 34-4

Bomb displayed in the JFrame.

Project 35: Bomb Diffuser—Expert Diffuser

Project

Next, use the setBounds method to position the components. You can find the exact position by Here’s where you put your skills to use to prevent opening the image in Microsoft Paint and hovering detonation.

over the target area. The coordinates are displayed on the bottom right of the program, as illustrated in Figure 35-1.

Making the game

After adding the components, create a variable The first part of this project consists of adding four that will represent the time left. Use a Thread to components to the background bomb image: time, subtract one from that variable every second. Don’t clue, disarm button, and text input area. Begin by forget to reset the new text to the JLabel!

initializing these four components. Create the text Now it’s time to set up the process of diffusing input area with a component called a TextField.

the bomb. First, create a method that initializes the Create it the same way you create a JButton or code to a random number. Next, if the JButton is JLabel. You can get the inputted text with the clicked, change the JLabel that represents the clue following command:

to display whether the player’s guess is too high field.getText();

or too low.

Project 35: Bomb Diffuser—Expert Diffuser

186

Project 35: Bomb Diffuser—Expert Diffuser

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class BombDiffuser extends JFrame implements ActionListener

{

//the time before detonation

int timeLeft = 12;

//the JLabel that displays the time left

JLabel time = new JLabel(timeLeft+“”);

//the bomb label

JLabel bomb = new JLabel(new ImageIcon(“bomb.PNG”));

//the clue:

JLabel clue = new JLabel();

//the code:

int code = 0;

//where the disarm code is entered:

TextField attempt = new TextField(20);

//the button when you think you have the correct combo JButton disarm = new JButton(“DISARM”);

//the container of the components

Container cont;

//the thread

Countdown count;

public BombDiffuser()

{

super(“Bomb Diffuser”);

setSize(500,550);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.gray);

//add the background image

cont.add(bomb);

bomb.setBounds(0,0,500,500);

//set the font of the JLabel

time.setFont(new Font(“Courier”, Font.BOLD, 20));

//add the time left JLabel

cont.add(time);

//set the position

time.setBounds(250,371,150,18);

//put the label on top of the background

cont.setComponentZOrder(time,0);

//add the disarm button

cont.add(disarm);

disarm.setBounds(200,456,150,30);

disarm.addActionListener(this);

cont.setComponentZOrder(disarm,0);

clue.setText(“A number between 0 and “+20);

cont.add(clue);

clue.setBounds(167,435,250,20);

//put the label on top of the background

cont.setComponentZOrder(clue,0);

187

//add the text field

cont.add(attempt);

attempt.setBounds(271,404,150,25);

//set all the components

cont.validate();

setContentPane(cont);

setCode();

count = new Countdown();

count.start();

}

public void setCode()

{

code = (int)(Math.random()*20);

}

//the counting down thread:

public class Countdown extends Thread

{

public void run()

{

while(true)

{

try

{

timeLeft− −;

time.setText(timeLeft+“”);

Thread.sleep(1000);

}

catch(Exception e){ }

}

}

}

public void actionPerformed(ActionEvent event)

{

if(Integer.parseInt(attempt.getText())>code)

{

clue.setText(“CAUTION: Attempted Code is TOO HIGH”);

}

if(Integer.parseInt(attempt.getText())<code)

{

clue.setText(“CAUTION: Attempted Code is TOO LOW”);

}

if(attempt.getText().equals(“”+code))

{

//nothing happens ... yet!

}

}

public static void main (String[ ] args)

{

new BombDiffuser();

}

}

Figures 35-2 through 35-5 illustrate the attempt to Move on to the next project to learn how to add Project 35: Bomb Diffuser—Expert Diffuser diffuse a bomb.

the exploding images.

188

Project 35: Bomb Diffuser—Expert Diffuser

Figure 35-1

Coordinates displayed.

Figure 35-2

Detonator counts down.

189

Figure 35-3

Guess is too high.

Project 35: Bomb Diffuser—Expert Diffuser Figure 35-4 Guess is too low.

190

Project 36: Bomb Diffuser—Kaboom!!!

Figure 35-5

Bomb should explode now ... but it doesn’t.

Project 36: Bomb Diffuser—Kaboom!!!

Project

Make the bomb explode. Watch out! Take cover!

Run!

Making the game

To add flashing explosions, you need to create two images: the first represents a fiery explosion (see Figure 36-1); the second image is identical to the first, except the colors are inverted and the position is flipped (see Figure 36-2).

Create JLabels for each image. Then, in the

countdown thread, check to see if the time left is less than or equal to zero. If so, call a method that will display the JLabels.

Figure 36-1

First explosion.

191

The method removes every component from the

images. To alternate the images, call the setBounds container. All that remains are the two alternating method.

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class BombDiffuser extends JFrame implements ActionListener

{

//the time before detonation

int timeLeft = 12;

//the JLabel that displays the time left

JLabel time = new JLabel(timeLeft+“”);

//the bomb label

JLabel bomb = new JLabel(new ImageIcon(“bomb.PNG”));

//the clue:

JLabel clue = new JLabel();

//the exploded bomb:

JLabel exploded = new JLabel(new ImageIcon(“exploded.PNG”)); JLabel exploded2 = new JLabel(new ImageIcon(“exploded2.PNG”));

//the code:

int code = 0;

//where the disarm code is entered:

TextField attempt = new TextField(20);

//the button when you think you have the correct combo JButton disarm = new JButton(“DISARM”);

//the container of the components

Container cont;

//the thread

Countdown count;

public BombDiffuser()

{

super(“Bomb Diffuser”);

setSize(500,550);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.gray);

//add the background image

cont.add(bomb);

bomb.setBounds(0,0,500,500);

//set the font of the JLabel

time.setFont(new Font(“Courier”, Font.BOLD, 20));

//add the time left JLabel

cont.add(time);

//set the position

time.setBounds(250,371,150,18);

//put the label on top of the background

cont.setComponentZOrder(time,0);

//add the disarm button

cont.add(disarm);

Project 36: Bomb Diffuser—Kaboom!!!

disarm.setBounds(200,456,150,30);

192

Project 36: Bomb Diffuser—Kaboom!!!

disarm.addActionListener(this);

cont.setComponentZOrder(disarm,0);

clue.setText(“A number between 0 and 20”);

cont.add(clue);

clue.setBounds(167,435,250,20);

//put the label on top of the background

cont.setComponentZOrder(clue,0);

//add the text field

cont.add(attempt);

attempt.setBounds(271,404,150,25);

//add the explosion offscreen

cont.add(exploded);

exploded.setBounds(−1000,−1000,500,550);

cont.setComponentZOrder(exploded,0);

cont.add(exploded2);

exploded2.setBounds(−1000,−1000,500,550);

cont.setComponentZOrder(exploded2,0);

//set all the components

cont.validate();

setContentPane(cont);

setCode();

count = new Countdown();

count.start();

}

public void setCode()

{

code = (int)(Math.random()*20);

}

//the counting down thread:

public class Countdown extends Thread

{

public void run()

{

while(true)

{

try

{

if(timeLeft>0)

{

timeLeft− −;

time.setText(timeLeft+“”);

}

else

{

break;

}

Thread.sleep(1000);

}

catch(Exception e){ }

}

//call the method that displays the blasts

explode();

}

public void explode()

{

//first, remove everything else:

193

cont.remove(time);

cont.remove(bomb);

cont.remove(clue);

cont.remove(attempt);

cont.remove(disarm);

//move the explosion images to the correct location exploded.setBounds(0,0,500,550);

exploded2.setBounds(0,0,500,550);

while(true)

{

try

{

exploded.setBounds(0,0,500,550);

exploded2.setBounds(−1000,−1000,500,550);

Thread.sleep(100);

exploded2.setBounds(0,0,500,550);

exploded.setBounds(−1000,−1000,500,550);

Thread.sleep(100);

}

catch(Exception e){ }

}

}

}

public void actionPerformed(ActionEvent event)

{

if(Integer.parseInt(attempt.getText())>code)

{

clue.setText(“CAUTION: Attempted Code is TOO HIGH”);

}

if(Integer.parseInt(attempt.getText())<code)

{

clue.setText(“CAUTION: Attempted Code is TOO LOW”);

}

if(attempt.getText().equals(“”+code))

{

//this code will be added later

}

}

public static void main (String[ ] args)

{

new BombDiffuser();

}

}

Figures 36-3 through 36-5 display the steps of a Ready for more action? In the next project, add bomb exploding.

levels to your game. As you become a more experienced bomb diffuser, the codes get more challenging.

Project 36: Bomb Diffuser—Kaboom!!!

194

Project 36: Bomb Diffuser—Kaboom!!!

Figure 36-2

Second explosion.

Figure 36-3

Detonator counts down.

195

Figure 36-4

Flashing explosion.

Project 36: Bomb Diffuser—Kaboom!!! Figure 36-5 Alternate image of exploding bomb.

196

Project 37: Bomb Diffuser—Rising Through the Project 37: Bomb Diffuser—Rising Through the Ranks Project

Add levels to the game. Although you will breeze past the first few challenges, don’t get cocky ... the codes get more and more complex!

Making the game

Figure 37-1

Congratulate the player.

First, create a way to signal the user that he/she has diffused the bomb. To do this, create an image that congratulates the player such as the one in explodes the bomb! Why? You have not yet paused Figure 37-1.

the game.

Display this image in the if-statement that

Here’s how you do it: create a boolean that stops compares the user’s input and the random code.

the counter when its value is true. Then, you need Next, reset the code by using a higher number. You to create a button for the player to indicate he/she can do this by basing the code on a maximum

is ready to start the next round. Hint: don’t create a number. Increase the maximum number every round.

new button; use the same “disarm” button.

Because the levels get more complex, you need to There is only one more thing you need to add:

give the player more time to guess the disarm

a score. Create a JLabel that will display the score, code. To do this, create a multiplier that increases and increment the score by the remaining time left the starting time every round. Try playing the when a bomb is diffused. Don’t forget to reset the game. Once you beat a level, the detonator still text in the JLabel.

import java.awt.*;

import java.awt.event.*;

import javax.swing.*;

import javax.swing.event.*;

public class BombDiffuser extends JFrame implements ActionListener

{

//the player’s bomb diffusal rating/score

int score = 0;

//the time before detonation

int timeLeft = 12;

//the JLabel that displays the time left

JLabel time = new JLabel(timeLeft+“”);

//the bomb label

JLabel bomb = new JLabel(new ImageIcon(“bomb.PNG”));

//the clue:

Ranks

JLabel clue = new JLabel();

//this display’s the player’s score (aka bomb diffusal rating) JLabel rating = new JLabel(“Your Bomb Diffusal Success Rating: “+score);

//the exploded bomb:

JLabel exploded = new JLabel(new ImageIcon(“exploded.PNG”)); JLabel exploded2 = new JLabel(new ImageIcon(“exploded2.PNG”)); 197

//boolean that waits for the button to be pressed again boolean waiting = false;

//this will be displayed after the player disarms the bomb JLabel promote = new JLabel(new ImageIcon(“promote.PNG”));

//these are the difficulty level variables

//the multiplier for the number of digits:

int digitsMultiplier = 1;

int maxNum = 10;

//the code:

int code = 0;

//where the disarm code is entered:

TextField attempt = new TextField(20);

//the button when you think you have the correct combo JButton disarm = new JButton(“DISARM”);

//the container of the components

Container cont;

//the thread

Countdown count;

public BombDiffuser()

{

super(“Bomb Diffuser”);

setSize(500,550);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.gray);

//add the background image

cont.add(bomb);

bomb.setBounds(0,0,500,500);

//set the font of the JLabel

time.setFont(new Font(“Courier”, Font.BOLD, 20));

//add the time left JLabel

cont.add(time);

//set the position

time.setBounds(250,371,150,18);

//put the label on top of the background

cont.setComponentZOrder(time,0);

//set the completion label offscreen

cont.add(promote);

promote.setBounds(−300,−300,276,122);

cont.setComponentZOrder(promote,0);

//add the score to the screen

cont.add(rating);

rating.setBounds(5,480,500,30);

rating.setForeground(Color.white);

rating.setFont(new Font(“Courier”,Font.BOLD,19)); cont.setComponentZOrder(rating,0);

//add the disarm button

cont.add(disarm);

disarm.setBounds(200,456,150,30);

disarm.addActionListener(this);

cont.setComponentZOrder(disarm,0);

clue.setText(“A number between 0 and “+maxNum); Project 37: Bomb Diffuser—Rising Through the Ranks cont.add(clue);

198

Project 37: Bomb Diffuser—Rising Through the clue.setBounds(167,435,250,20);

//put the label on top of the background

cont.setComponentZOrder(clue,0);

//add the text field

cont.add(attempt);

attempt.setBounds(271,404,150,25);

//add the explosion offscreen

cont.add(exploded);

exploded.setBounds(−1000,−1000,500,550);

cont.setComponentZOrder(exploded,0);

cont.add(exploded2);

exploded2.setBounds(−1000,−1000,500,550);

cont.setComponentZOrder(exploded2,0);

//set all the components

cont.validate();

setContentPane(cont);

setCode();

count = new Countdown();

count.start();

}

public void setCode()

{

code = (int)(Math.random()*maxNum);

}

//the counting down thread:

public class Countdown extends Thread

{

public void run()

{

while(true)

{

try

{

if(!waiting)

{

if(timeLeft>0)

{

timeLeft—;

time.setText(timeLeft+“”);

}

else

{

break;

}

}

Thread.sleep(1000);

}

catch(Exception e){ }

}

//call the method that displays the blasts

explode();

}

Ranks

public void explode()

{

//first, remove everything else:

cont.remove(time);

cont.remove(bomb);

cont.remove(clue);

199

cont.remove(rating);

cont.remove(promote);

cont.remove(attempt);

cont.remove(disarm);

//move the explosion images to the correct location exploded.setBounds(0,0,500,550);

exploded2.setBounds(0,0,500,550);

while(true)

{

try

{

exploded.setBounds(0,0,500,550);

exploded2.setBounds(−1000,−1000,500,550);

Thread.sleep(100);

exploded2.setBounds(0,0,500,550);

exploded.setBounds(−1000,−1000,500,550);

Thread.sleep(100);

}

catch(Exception e){ }

}

}

}

public void actionPerformed(ActionEvent event)

{

if(waiting)

{

promote.setBounds(−300,−300,276,122);

setCode();

clue.setText(“A number between 0 and “+maxNum); timeLeft = 15*digitsMultiplier;

waiting = false;

}

else

{

if(Integer.parseInt(attempt.getText())>code)

{

clue.setText(“CAUTION: Attempted Code is TOO HIGH”);

}

if(Integer.parseInt(attempt.getText())<code)

{

clue.setText(“CAUTION: Attempted Code is TOO LOW”);

}

if(attempt.getText().equals(“”+code))

{

score+=timeLeft;

rating.setText(“Your Bomb Diffusal Success Rating: “+score); promote.setBounds(150,100,276,122);

waiting = true;

digitsMultiplier+ +;

maxNum*=5;

}

}

}

public static void main (String[ ] args)

{

new BombDiffuser();

Project 37: Bomb Diffuser—Rising Through the Ranks

}

}

200

Project 37: Bomb Diffuser—Rising Through the Figure 37-2

Detonator counts down.

Ranks

Figure 37-3

Bomb successfully diffused.

201

Figure 37-4

*#$%!!!... out of time!

Figures 37-2 through 37-4 illustrate the stress of Add letters and/or symbols to the code.

bomb diffusion.

Make the user work to break the code: offer

simple mathematical equations.

Customizing the game

To increase the stress level, have the timer not only display seconds, but milliseconds as well.

Place two bombs on the screen at the same time.

Give the player a limited number of guesses. If Alter the difficulty of the game by changing the he/she can’t guess correctly, BOOM! The bomb

time given for diffusion.

detonates.

Project 38: Trapper—Men on the Move

path or back up into your own trail—you’ll

Trapper

be trapped!

In this multiplayer strategy game, battle it out Project

with others by trapping them in the trail you leave behind. Don’t accidentally cross your adversary’s Construct two moving characters that are

Project 38: Trapper—Men on the Move

controlled by each opponent.

202

Project 38: Trapper—Men on the Move

see if the “A,” “S,” “W,” or “D” keys are pressed.

Making the game

These keys control the direction of player one.

The “J,” “K,” “I,” and “L” keys control the second Start by creating the JFrame; setting it to 500 by player’s direction. Now, to keep track of each 500 pixels. Now, create 10×10 pixel images for player’s direction, employ the same technique you each player. Make a JLabel for each image. Use did in Radical Racing: use different int values to the setBounds method to position the JLabels on represent different directions. Once these variables opposite sides of the field.

are created, change the variable in the

Construct two threads: one to control the first keyPressed method.

player’s direction; the other to control the direction Once the players’ orientations are established, of the second player. Because the direction of each they need to move around the arena. In each

player is controlled by the keyboard, each thread thread’s infinite loop, move the players by using must implement keyListener. Add the keyListener the setBounds method.

methods to both threads. In the methods, check to import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class Trapper extends JFrame

{

//the two JLabels that represent each player

JLabel p1 = new JLabel(new ImageIcon(“p1.PNG”)); JLabel p2 = new JLabel(new ImageIcon(“p2.PNG”)); boolean keepPlaying = true;

//these variables keep track of the direction

int UP = 1, RIGHT = 2, DOWN = 3, LEFT = 4;

int p1Direction = RIGHT;

int p2Direction = LEFT;

Container cont;

public Trapper()

{

super(“Trapper”);

setSize(500,500);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

cont = getContentPane();

cont.setLayout(null);

cont.add(p1);

cont.setComponentZOrder(p1,0);

p1.setBounds(20,245,10,10);

cont.add(p2);

cont.setComponentZOrder(p2,0);

p2.setBounds(455,245,10,10);

P1Move p1Thread = new P1Move();

p1Thread.start();

P2Move p2Thread = new P2Move();

p2Thread.start();

setContentPane(cont);

203

}

public class P1Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(keepPlaying)

{

try

{

if(p1Direction= =UP)

p1.setBounds(p1.getX(),p1.getY()−5,10,10);

if(p1Direction= =DOWN)

p1.setBounds(p1.getX(),p1.getY()+5,10,10);

if(p1Direction= =RIGHT)

p1.setBounds(p1.getX()+5,p1.getY(),10,10);

if(p1Direction= =LEFT)

p1.setBounds(p1.getX()−5,p1.getY(),10,10);

cont.validate();

Thread.sleep(75);

}

catch(Exception e){ }

}

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’a’)

p1Direction = LEFT;

if(e.getKeyChar()= =’s’)

p1Direction = DOWN;

if(e.getKeyChar()= =’d’)

p1Direction = RIGHT;

if(e.getKeyChar()= =’w’)

p1Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public class P2Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(keepPlaying)

{

try

{

if(p2Direction= =UP)

p2.setBounds(p2.getX(),p2.getY()−5,10,10);

if(p2Direction= =DOWN)

p2.setBounds(p2.getX(),p2.getY()+5,10,10);

if(p2Direction= =RIGHT)

p2.setBounds(p2.getX()+5,p2.getY(),10,10);

if(p2Direction= =LEFT)

p2.setBounds(p2.getX()−5,p2.getY(),10,10);

cont.validate();

Thread.sleep(75);

Project 38: Trapper—Men on the Move

}

204

Project 38: Trapper—Men on the Move

catch(Exception e){ }

}

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’j’)

p2Direction = LEFT;

if(e.getKeyChar()= =’k’)

p2Direction = DOWN;

if(e.getKeyChar()= =’l’)

p2Direction = RIGHT;

if(e.getKeyChar()= =’i’)

p2Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public static void main (String[ ] args)

{

new Trapper();

}

}

Figures 38-1 and 38-2 show the initial movement Keep going to add trails that the characters leave of the characters.

behind as they move. It’s time to start trapping!

Figure 38-1

Arena.

205

Figure 38-2

Characters move around.

Project 39: Trapper—Setting the Trap

Project

player two. In order to store all of the images, use an ArrayList. You will use this feature in the next You’re now ready to add trails to track the

project to detect collisions into the trail.

characters’ movements. This is the heart of the In each thread’s infinite loop, create a temporary game. Don’t get trapped and ... don’t let your JLabel that holds the image of the segment of the opponent escape your trap!

trail. Add this temporary JLabel to the ArrayList and to the container. Use setBounds to set the Making the game

position of the image to the location of the player.

Don’t forget to use the setComponentZOrder

Each player’s trail consists of a progressive line of method to keep the trail at position “1” so the lead 10 by 10 pixel images. Use a black segment to

image of the player is always displayed.

represent player one’s trail and a blue segment for import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class Trapper extends JFrame

{

Project 39: Trapper—Setting the Trap

//the two JLabels that represent each player

206

Project 39: Trapper—Setting the Trap

JLabel p1 = new JLabel(new ImageIcon(“p1.PNG”)); JLabel p2 = new JLabel(new ImageIcon(“p2.PNG”));

//these variables keep track of the direction

int UP = 1, RIGHT = 2, DOWN = 3, LEFT = 4;

int p1Direction = RIGHT;

int p2Direction = LEFT;

//this ArrayLists holds the trails of each player ArrayList trailList = new ArrayList();

Container cont;

public Trapper()

{

super(“Trapper”);

setSize(500,500);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

cont = getContentPane();

cont.setLayout(null);

cont.add(p1);

cont.setComponentZOrder(p1,0);

p1.setBounds(20,245,20,20);

cont.add(p2);

cont.setComponentZOrder(p2,0);

p2.setBounds(455,245,20,20);

P1Move p1Thread = new P1Move();

p1Thread.start();

P2Move p2Thread = new P2Move();

p2Thread.start();

setContentPane(cont);

}

public class P1Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(true)

{

try

{

//add the trail

JLabel temp = new JLabel(new ImageIcon(“p1trail.PNG”));; trailList.add(temp);

cont.add(temp);

cont.setComponentZOrder(temp,1);

temp.setBounds(p1.getX(),p1.getY(),10,10);

if(p1Direction= =UP)

p1.setBounds(p1.getX(),p1.getY()−5,20,20);

if(p1Direction= =DOWN)

p1.setBounds(p1.getX(),p1.getY()+5,20,20);

if(p1Direction= =RIGHT)

p1.setBounds(p1.getX()+5,p1.getY(),20,20);

if(p1Direction= =LEFT)

p1.setBounds(p1.getX()−5,p1.getY(),20,20);

cont.validate();

Thread.sleep(75);

}

207

catch(Exception e){ }

}

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’a’)

p1Direction = LEFT;

if(e.getKeyChar()= =’s’)

p1Direction = DOWN;

if(e.getKeyChar()= =’d’)

p1Direction = RIGHT;

if(e.getKeyChar()= =’w’)

p1Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public class P2Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(true)

{

try

{

//add the trail:

JLabel temp = new JLabel(new ImageIcon(“p2trail.PNG”));; trailList.add(temp);

cont.add(temp);

cont.setComponentZOrder(temp,1);

temp.setBounds(p2.getX(),p2.getY(),10,10);

if(p2Direction= =UP)

p2.setBounds(p2.getX(),p2.getY()−5,20,20);

if(p2Direction= =DOWN)

p2.setBounds(p2.getX(),p2.getY()+5,20,20);

if(p2Direction= =RIGHT)

p2.setBounds(p2.getX()+5,p2.getY(),20,20);

if(p2Direction= =LEFT)

p2.setBounds(p2.getX()−5,p2.getY(),20,20);

cont.validate();

Thread.sleep(75);

}

catch(Exception e){ }

}

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’j’)

p2Direction = LEFT;

if(e.getKeyChar()= =’k’)

p2Direction = DOWN;

if(e.getKeyChar()= =’l’)

p2Direction = RIGHT;

if(e.getKeyChar()= =’i’)

p2Direction = UP;

}

Project 39: Trapper—Setting the Trap

208

Project 39: Trapper—Setting the Trap

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public static void main (String[ ] args)

{

new Trapper();

}

}

Figure 39-1

Players start moving.

Figure 39-2

Players leave a trail.

209

Figure 39-3

Player 1 wins ... but it is a hollow victory until collision detection is added.

Figures 39-1 through 39-3 show the trapping trails Move on to learn how to add collision detection.

that follow each player.

Project 40: Trapper—Trapped!

Project

To determine if a player collides with a trail, use a for loop to check every JLabel —except the

Add collision detection. Watch out!

last 10—in the ArrayList. You do not need to

check the last 10 segments because they always overlap the player. If there is a collision, use a Making the game

JOptionPane to announce the winner.

The collision detection checks two events: leaving When the program is executed, you will notice

the grid and colliding with a trail. To determine if the pop-up message displays continuously because a player leaves the grid, use a simple if-statement the threads are still running. To stop the display, use in each infinite loop. Check whether the “x” and a boolean that controls the infinite loop. Set the

“y” values of the player is above 500 or below 0.

boolean to “false” in order to terminate the threads.

If so, use a JOptionPane to announce the winner.

Project 40: Trapper—Trapped!

210

Project 40: Trapper—Trapped!

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class Trapper extends JFrame

{

//the two JLabels that represent each player

JLabel p1 = new JLabel(new ImageIcon(“p1.PNG”)); JLabel p2 = new JLabel(new ImageIcon(“p2.PNG”)); boolean keepLooping = true;

//these variables keep track of the direction

int UP = 1, RIGHT = 2, DOWN = 3, LEFT = 4;

int p1Direction = RIGHT;

int p2Direction = LEFT;

//this ArrayLists holds the trails of each player ArrayList trailList = new ArrayList();

Container cont;

public Trapper()

{

super(“Trapper”);

setSize(500,500);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

cont = getContentPane();

cont.setLayout(null);

cont.add(p1);

cont.setComponentZOrder(p1,0);

p1.setBounds(20,245,10,10);

cont.add(p2);

cont.setComponentZOrder(p2,0);

p2.setBounds(455,245,10,10);

P1Move p1Thread = new P1Move();

p1Thread.start();

P2Move p2Thread = new P2Move();

p2Thread.start();

setContentPane(cont);

}

public class P1Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(keepLooping)

{

try

{

//check to see if p2 hits the walls

if(p1.getX()>500 || p1.getX()<0 || p1.getY()>500 || p1.getY()<0)

{

p1Lose();

}

//check to see if p2 hits the trails

for(int i = 0; i < trailList.size()−10; i+ +)

{

211

JLabel tempTrail = (JLabel) trailList.get(i);

if(p1.getBounds().intersects(tempTrail.getBounds()))

{

p1Lose();

}

}

//add the trail

JLabel temp = new JLabel(new ImageIcon(“p1trail.PNG”));; trailList.add(temp);

cont.add(temp);

cont.setComponentZOrder(temp,1);

temp.setBounds(p1.getX(),p1.getY(),10,10);

if(p1Direction= =UP)

p1.setBounds(p1.getX(),p1.getY()−5,10,10);

if(p1Direction= =DOWN)

p1.setBounds(p1.getX(),p1.getY()+5,10,10);

if(p1Direction= =RIGHT)

p1.setBounds(p1.getX()+5,p1.getY(),10,10);

if(p1Direction= =LEFT)

p1.setBounds(p1.getX()−5,p1.getY(),10,10);

cont.validate();

Thread.sleep(75);

}

catch(Exception e){ }

}

}

public void p1Lose()

{

keepLooping = false;

JOptionPane.showMessageDialog(null,”Player 2 Wins!!!”);

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’a’)

p1Direction = LEFT;

if(e.getKeyChar()= =’s’)

p1Direction = DOWN;

if(e.getKeyChar()= =’d’)

p1Direction = RIGHT;

if(e.getKeyChar()= =’w’)

p1Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public class P2Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(keepLooping)

{

try

{

//check to see if p2 hits the walls

if(p2.getX()>500 || p2.getX()<0 || p2.getY()>500 || p2.getY()<0)

{

Project 40: Trapper—Trapped!

p2Lose();

212

Project 40: Trapper—Trapped!

}

//check to see if p2 hits the trails

for(int i = 0; i < trailList.size()−10; i+ +)

{

JLabel tempTrail = (JLabel) trailList.get(i);

if(p2.getBounds().intersects(tempTrail.getBounds()))

{

p2Lose();

}

}

//add the trail:

JLabel temp = new JLabel(new ImageIcon(“p2trail.PNG”));; trailList.add(temp);

cont.add(temp);

cont.setComponentZOrder(temp,1);

temp.setBounds(p2.getX(),p2.getY(),10,10);

if(p2Direction= =UP)

p2.setBounds(p2.getX(),p2.getY()−5,10,10);

if(p2Direction= =DOWN)

p2.setBounds(p2.getX(),p2.getY()+5,10,10);

if(p2Direction= =RIGHT)

p2.setBounds(p2.getX()+5,p2.getY(),10,10);

if(p2Direction= =LEFT)

p2.setBounds(p2.getX()−5,p2.getY(),10,10);

cont.validate();

Thread.sleep(75);

}

catch(Exception e){ }

}

}

public void p2Lose()

{

keepLooping = false;

JOptionPane.showMessageDialog(null,”Player 1 Wins!!!”);

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’j’)

p2Direction = LEFT;

if(e.getKeyChar()= =’k’)

p2Direction = DOWN;

if(e.getKeyChar()= =’l’)

p2Direction = RIGHT;

if(e.getKeyChar()= =’i’)

p2Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public static void main (String[ ] args)

{

new Trapper();

}

}

Figures 40-1 and 40-2 depict a strategy of the trails.

213

Read the next project to uncover ways to add a more striking background and a bolder way to alert players of wins and losses.

Figure 40-1

Players battle it out!

Project 40: Trapper—Trapped! Figure 40-2 Player One successfully traps Player Two.

214

Project 41: Trapper—Showdown

Project 41: Trapper—Showdown

Project

Once a player wins, add a fun way of

“rewinding” the game. You can “undo” the players’

Add an eye-catching background image and attention-moves by using a for loop and removing the trail grabbing graphics to notify players of the winner.

segments. To do this, create a for loop that

counts down from the number of components in

Making the game

the container minus 4. This leaves the background image and the actual player images. To find the Let your imagination go wild. Draw a 500 by 500

number of components in the container, use the pixel background image in Microsoft Paint. Create following:

a JLabel for it and use the setBounds method to cont.getComponentCount()

center it. Don’t forget to use the

Remember to refresh the container after

setComponentZOrder method to send the

removing each trail segment. In addition, create background image behind the other icons.

a JLabel that holds the same text as the

Now, draw an image—any image you want—to

JOptionPanes from the previous project.

notify the players of the winner. Display this image instead of the JOptionPane when a player wins.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

public class Trapper extends JFrame

{

//the two JLabels that represent each player

JLabel p1 = new JLabel(new ImageIcon(“p1.PNG”)); JLabel p2 = new JLabel(new ImageIcon(“p2.PNG”)); boolean keepPlaying = true;

//these variables keep track of the direction

int UP = 1, RIGHT = 2, DOWN = 3, LEFT = 4;

int p1Direction = RIGHT;

int p2Direction = LEFT;

//this ArrayLists holds the trails of each player ArrayList trailList = new ArrayList();

Container cont;

public Trapper()

{

super(“Trapper”);

setSize(500,500);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

cont = getContentPane();

cont.setLayout(null);

//this is the background JLabel:

JLabel bg = new JLabel(new ImageIcon(“bg.png”)); 215

cont.add(bg);

bg.setBounds(0,0,500,500);

cont.add(p1);

cont.setComponentZOrder(p1,0);

p1.setBounds(20,245,10,10);

cont.add(p2);

cont.setComponentZOrder(p2,0);

p2.setBounds(455,245,10,10);

P1Move p1Thread = new P1Move();

p1Thread.start();

P2Move p2Thread = new P2Move();

p2Thread.start();

setContentPane(cont);

}

public class P1Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(keepPlaying)

{

try

{

//check to see if p2 hits the walls

if(p1.getX()>500 || p1.getX()<0 || p1.getY()>500 || p1.getY()<0)

{

p1Lose();

}

//check to see if p2 hits the trails

for(int i = 0; i < trailList.size()−10; i+ +)

{

JLabel tempTrail = (JLabel) trailList.get(i);

if(p1.getBounds().intersects(tempTrail.getBounds()))

{

p1Lose();

}

}

//add the trail

JLabel temp = new JLabel(new ImageIcon(“p1trail.PNG”));; trailList.add(temp);

cont.add(temp);

cont.setComponentZOrder(temp,1);

temp.setBounds(p1.getX(),p1.getY(),10,10);

if(p1Direction= =UP)

p1.setBounds(p1.getX(),p1.getY()−5,10,10);

if(p1Direction= =DOWN)

p1.setBounds(p1.getX(),p1.getY()+5,10,10);

if(p1Direction= =RIGHT)

p1.setBounds(p1.getX()+5,p1.getY(),10,10);

if(p1Direction= =LEFT)

p1.setBounds(p1.getX()−5,p1.getY(),10,10);

cont.validate();

Thread.sleep(75);

}

catch(Exception e){ }

}

}

Project 41: Trapper—Showdown

public void p1Lose()

216

Project 41: Trapper—Showdown

{

try

{

keepPlaying = false;

JLabel winner = new JLabel(“Player 2 (blue) Wins!!!”); cont.add(winner);

cont.setComponentZOrder(winner,0);

winner.setFont(new Font(“arial”,Font.BOLD,30)); winner.setBounds(75,50,400,100);

for(int i = cont.getComponentCount()−4; i > 0; i− −)

{

cont.remove(i);

cont.repaint();

Thread.sleep(25);

}

}

catch(Exception e){ }

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’a’)

p1Direction = LEFT;

if(e.getKeyChar()= =’s’)

p1Direction = DOWN;

if(e.getKeyChar()= =’d’)

p1Direction = RIGHT;

if(e.getKeyChar()= =’w’)

p1Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public class P2Move extends Thread implements KeyListener

{

public void run()

{

addKeyListener(this);

while(keepPlaying)

{

try

{

//check to see if p2 hits the walls

if(p2.getX()>500 || p2.getX()<0 || p2.getY()>500 || p2.getY()<0)

{

p2Lose();

}

//check to see if p2 hits the trails

for(int i = 0; i < trailList.size()−10; i+ +)

{

JLabel tempTrail = (JLabel) trailList.get(i);

if(p2.getBounds().intersects(tempTrail.getBounds()))

{

p2Lose();

}

}

//add the trail:

JLabel temp = new JLabel(new ImageIcon(“p2trail.PNG”));; trailList.add(temp);

cont.add(temp);

217

cont.setComponentZOrder(temp,1);

temp.setBounds(p2.getX(),p2.getY(),10,10);

if(p2Direction= =UP)

p2.setBounds(p2.getX(),p2.getY()−5,10,10);

if(p2Direction= =DOWN)

p2.setBounds(p2.getX(),p2.getY()+5,10,10);

if(p2Direction= =RIGHT)

p2.setBounds(p2.getX()+5,p2.getY(),10,10);

if(p2Direction= =LEFT)

p2.setBounds(p2.getX()−5,p2.getY(),10,10);

cont.validate();

Thread.sleep(75);

}

catch(Exception e){ }

}

}

public void p2Lose()

{

try

{

keepPlaying = false;

JLabel winner = new JLabel(“Player 1 (black) Wins!!!”); cont.add(winner);

cont.setComponentZOrder(winner,0);

winner.setFont(new Font(“arial”,Font.BOLD,30)); winner.setBounds(75,50,400,100);

for(int i = cont.getComponentCount()−4; i > 0; i− −)

{

cont.remove(i);

cont.repaint();

Thread.sleep(25);

}

}

catch(Exception e){ }

}

public void keyPressed(KeyEvent e)

{

if(e.getKeyChar()= =’j’)

p2Direction = LEFT;

if(e.getKeyChar()= =’k’)

p2Direction = DOWN;

if(e.getKeyChar()= =’l’)

p2Direction = RIGHT;

if(e.getKeyChar()= =’i’)

p2Direction = UP;

}

public void keyTyped(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

}

public static void main (String[ ] args)

{

new Trapper();

}

}

Project 41: Trapper—Showdown

218

Project 41: Trapper—Showdown

Figure 41-1 and 41-2 illustrate the ultimate game Add two additional characters so up to four

play of Trapper.

players can compete at once.

No friends? Add artificial intelligence to battle Customizing the game

the computer.

Construct the game so players are limited to

Dramatically increase the speed of one player

right turns only ... or reverse direction only.

while slowing down the other. Strategy note: each speed has its own advantages and disadvantages.

Randomize the keys in the middle of the game.

The players have no idea which way the image

Modify the size of the players: supersized or mini!

will turn!

Create levels: best out of three, five, or eleven rounds wins.

Figure 41-1

Background image in place as players

Figure 41-2

Player One wins; trails begin to

compete.

disappear.

219

This page intentionally left blank

Section Six

Retro Games

Project 42: Oiram—The Platform

You can access elements in two dimensional

arrays the same way you access elements in

Oiram

normal arrays:

int element =

Help Oiram capture the stars and stomp out his twoDArray[<rows>][<columns>];

enemies by leaping from platform to platform! Be warned, however . . . this is a multi-level game.

Use the following code to find the number of

As Oiram defeats enemies, more are waiting to

rows and columns in the two dimensional array: appear in the next round.

int rows = twoDArray.length;

int columns = twoDArray[0].length;

Project

Making the game

Begin by creating the platform in which Oiram

battles.

There are three different areas of the game board: land, air, and ladders. Each of these areas occupies New Building Blocks

a 50 by 50 pixel zone on the board. To keep track of each of these zones, use a two dimensional

Two Dimensional Arrays

array with “#” representing land, “|” representing Two dimensional arrays

ladder, and a “space” representing air. You must draw these images before you add the zones to the Two dimensional arrays are like normal arrays, JFrames. Each image should be 50 by 50 pixels.

except they hold additional information in another Figures 42-2 through 43-4 represent the three

dimension. Figure 42-1 explains the similarities different zones.

and differences.

To display the board in a JFrame, iterate through To make a two dimensional array, create a

the array in the constructor by using two for

normal array with a second set of brackets:

loops. On each iteration, use if-statements to verify whether the current area is air, land, or a int twoDArray [ ][ ] =

ladder. Use the setBounds method to display the

{{1,2,3},{4,5,6},{7,8,9}}

correct image.

221

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class Oiram extends JFrame

{

Container cont;

//the 2 dimensional array

String arena[ ][ ] =

{{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“#”,“ ”},

{“ ”,“#”,“#”,“#”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

{“ ”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“ ”,“ ”,“#”,“#”,“#”,“#”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

public Oiram()

{

super(“Oiram”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.BLACK);

//generate the board:

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

JLabel lbl = null;

if(arena[j][i].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“ground.png”));

}

else if(arena[j][i].equals(“ ”))

{

lbl = new JLabel(new ImageIcon(“air.png”));

}

else if(arena[j][i].equals(“|”))

{

lbl = new JLabel(new ImageIcon(“ladder.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

}

}

repaint();

cont.validate();

setContentPane(cont);

}

public static void main (String[ ] args)

{

new Oiram();

Project 42: Oiram—The Platform

}

}

222

Project 42: Oiram—The Platform

Figure 42-3

Air.

Figure 42-1

Two types of arrays.

Figure 42-2

Land.

Figure 42-4

Ladder.

Figure 42-5

Platform.

223

Figure 42-5 shows Oiram’s world: the platform.

In the next project, set Oiram free ... and give him stars to collect!

Project 43: Oiram—Go, Oiram, Go

Project

jump/climb, if he is already in the air. If Oiram is not climbing, check whether the spot above Oiram Put Oiram in his home and give him the ability is air. If it is, determine whether Oiram is jumping to move around. Add stars for him to chase and and if the location below him is air. If the location capture.

below him is not air and he is not jumping, move Oiram up 50 pixels. If Oiram is climbing, move him up 50 pixels and again check whether he is in Making the game

the air. If Oiram is in the air, move him 50 pixels to the right because he has reached the top of Create Oiram. Start by drawing a 50 by 50 pixel the ladder. Then, set the climbing boolean to

picture of him. Use a JLabel and the setBounds false.

method to place Oiram in the bottom left

corner. Figure 43-1 displays Oiram’s starting

When the “D” key is pressed, Oiram moves right.

location.

First, check whether Oiram is inside the arena. If he is, check whether the space to Oiram’s right is air. If Oiram’s world consists of moving on the ground, so, move Oiram 50 pixels to the right. If the location jumping in the air, and climbing ladders. Create to the right is a ladder, move Oiram 50 pixels to the booleans to represent jumping and climbing. Next, right and set the climbing variable to true.

add a keyListener. In the keyTyped method, check whether the “A,” “W,” or “D” key is pressed to Now, run the game. You will notice that when

determine Oiram’s movements.

Oiram climbs up a ladder, as shown in Figure 43-2, Oiram looks weird.

When the “A” key is pressed, Oiram moves left.

Remember to check the boolean that represents

To fix this, create a new 50 by 50 pixel image of whether Oiram is climbing. If Oiram is climbing, Oiram climbing the ladder. Only display it when set the boolean to false. If Oiram is not climbing, the climbing variable is true. Figure 43-3 illustrates move him 50 pixels to the left.

the new and improved image.

When the “W” key is pressed, Oiram jumps

Now that Oiram can move around, you need to

(or, if he is on a ladder, climbs). Oiram should not add stars for him to catch. Do this by creating a method that randomly generates the location of stars. Use two for loops to iterate through the array of the board. If the location of the board contains air, use a random number between 0 and 9 to give a one in ten chance for a star to appear. If the number is 0, generate a star in that location. Don’t forget to add the star to an ArrayList. Call this Project 43: Oiram—Go, Oiram, Go Figure 43-1 Oiram’s starting location.

method from the constructor.

224

Project 43: Oiram—Go, Oiram, Go

Figure 43-3

Oiram, not looking weird, climbs.

Figure 43-2

Oiram, looking weird, climbs.

container and ArrayList. Next, create an if-

statement that checks whether Oiram is jumping.

If he is jumping, move Oiram up 50 pixels and

There are only two things left to do: make

then end his jump by setting the boolean to false.

Oiram fall and let him collect the stars. To do this, If Oiram is not jumping, check whether the spot create a Thread called Runner. In the infinite loop, below him is air. If it is, lower Oiram 50 pixels.

iterate through the ArrayList of stars. If Oiram Don’t forget to add the Thread.sleep method to intersects a star, remove the star from both the your infinite loop.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class Oiram extends JFrame implements KeyListener

{

Container cont;

//the two dimensional array:

String arena[ ][ ] =

{{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“#”,“ ”},

{“ ”,“#”,“#”,“#”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

{“ ”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“ ”,“ ”,“#”,“#”,“#”,“#”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

225

ArrayList stars = new ArrayList();

JLabel character = new JLabel(new ImageIcon(“oiram.png”)); boolean jumping = false;

boolean climbing = false;

Runner runner;

public Oiram()

{

super(“Oiram”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

addKeyListener(this);

cont.setBackground(Color.BLACK);

cont.add(character);

character.setBounds(0,400,50,50);

generateStars();

//generate the board:

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

JLabel lbl = null;

if(arena[j][i].equals())

{

lbl = new JLabel(new ImageIcon(“ground.png”));

}

else if(arena[j][i].equals(“ ”))

{

lbl = new JLabel(new ImageIcon(“air.png”));

}

else if(arena[j][i].equals(“|”))

{

lbl = new JLabel(new ImageIcon(“ladder.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

}

}

repaint();

cont.validate();

runner = new Runner();

runner.start();

setContentPane(cont);

}

//add the stars

public void generateStars()

{

for(int i = 1; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

//check if the current location is air

if(arena[i][j].equals(“ ”))

Project 43: Oiram—Go, Oiram, Go

{

226

Project 43: Oiram—Go, Oiram, Go

//this random number gives a 1 in 10 chance of a star being placed here int placeOrNot = (int)(Math.random()*10);

if(placeOrNot= =0)

{

JLabel star = new JLabel(new ImageIcon(“star.png”)); cont.add(star);

star.setBounds(j*50,i*50,50,50);

cont.setComponentZOrder(star,0);

cont.setComponentZOrder(character,0);

stars.add(star);

}

}

}

}

}

public class Runner extends Thread

{

public void run()

{

while(true)

{

try

{

//if Oiram touches a star, remove it

for(int i = 0; i < stars.size(); i++)

{

JLabel star = (JLabel) stars.get(i);

if(star.getBounds().intersects(character.getBounds()))

{

cont.remove(star);

stars.remove(star);

}

}

//let Oiram fall

if(!jumping)

{

if(arena[(character.getY()/50)+1][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX(),character.getY()+50,50,50);

}

}

else

{

//end Oiram’s jump at the next iteration

jumping = false;

//move Oiram up:

if(arena[(character.getY()/50)−1][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX(),character.getY()−50,50,50);

}

}

Thread.sleep(250);

}

catch(Exception e){ }

}

}

}

public void keyPressed(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

public void keyTyped(KeyEvent e)

227

{

//move left

if(e.getKeyChar()= =‘a’)

{

if(climbing)

{

climbing = false;

character.setIcon(new ImageIcon(“oiram.png”));

}

if(character.getX()>=50 &&

arena[character.getY()/50][(character.getX()/50)−1].equals(“ ”))

{

character.setBounds(character.getX()−50,character.getY(),50,50);

}

}

//move right

if(e.getKeyChar()= =‘d’)

{

if(character.getX()<=400 && arena

[character.getY()/50][(character.getX()/50)+1].equals(“ ”))

{

character.setBounds(character.getX()+50,character.getY(),50,50);

}

if(arena[character.getY()/50][(character.getX()/50)+1].equals(“|”))

{

character.setBounds(character.getX()+50,character.getY(),50,50); climbing = true;

character.setIcon(new ImageIcon(“onladder.png”));

}

}

//move up

if(e.getKeyChar()= =‘w’)

{

if(!climbing)

{

if(arena[(character.getY()/50)−1][character.getX()/50].equals(“ ”))

{

if(!jumping && !arena[(character.getY()/50)+1][character.getX()/50].equals(“ ”))

{

jumping = true;

character.setBounds(character.getX(),character.getY()−50,50,50);

}

}

}

else

{

character.setBounds(character.getX(), character.getY()−50,50,50); if(arena[character.getY()/50][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX()+50,character.getY(),50,50); climbing = false;

character.setIcon(new ImageIcon(“oiram.png”));

}

}

}

}

public static void main (String[ ] args)

{

new Oiram();

}

Project 43: Oiram—Go, Oiram, Go }

228

Project 43: Oiram—Go, Oiram, Go

Figures 43-4 and 43-5 show Oiram in action.

project and learn how to make Oiram’s life

Every Evil Genius knows a game is not

miserable.

complete without adversaries. Move on to the next Figure 43-4

Platform.

Figure 43-5

Collecting stars.

229

Projct 44: Oiram—Bad Guys

Project

The chase is on! Here you design Oiram’s enemies.

They’re fast, they’re relentless . . . they’re deadly.

Making the game

First, draw a 50 by 50 pixel image of Oiram’s

enemy like the one in Figure 44-1.

Next, create a method that adds the enemies

to the platform. Use a loop to generate two

enemies. Place them at the very top of the board Figure 44-1

Oiram’s enemy.

and give them a random “X” coordinate. In

addition, add the enemies to an ArrayList for easy enemy is air. If it is, move the enemy 50 pixels to access later.

the right. If the random number is one, check

Oiram’s enemies are controlled by simple logic: whether the space to the left of the enemy is air. If if there is air below them, they fall. If not, they so, move the enemy 50 pixels to the left.

either move left or right. In the Thread’s loop, use Now that the enemies are mobile, you need to

a for loop to examine each enemy in the

give Oiram a fighting chance. If he jumps on an ArrayList. Use an if-statement to determine

enemy, the enemy dies. Use an if-statement to

whether the location below the enemy is air. If so, compare the location of Oiram and his adversary.

lower the enemy 50 pixels. Next, generate a

If Oiram is 50 pixels above the enemy, remove the random number (0 or 1) by multiplying the

enemy from the container. If Oiram occupies

Math.random method by two. If the number is

the same location as his adversary, remove Oiram: zero, check whether the location to the right of the the enemy wins.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class Oiram extends JFrame implements KeyListener

{

//the container:

Container cont;

//the 2 dimensional array

String arena[ ][ ] =

{{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“#”,“ ”},

{“ ”,“#”,“#”,“#”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

Projct 44: Oiram—Bad Guys

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

230

Projct 44: Oiram—Bad Guys

{“ ”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“ ”,“ ”,“#”,“#”,“#”,“#”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

//this holds the stars:

ArrayList stars = new ArrayList();

//Oiram!

JLabel character = new JLabel(new ImageIcon(“oiram.png”));

//whether or not Oiram is jumping/climbing

boolean jumping = false;

boolean climbing = false;

//the Thread

Runner runner;

//this holds the enemies

ArrayList enemies = new ArrayList();

public Oiram()

{

super(“Oiram”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

addKeyListener(this);

cont.setBackground(Color.BLACK);

//add Oiram

cont.add(character);

character.setBounds(0,400,50,50);

//create teh stars and enemies

generateStars();

generateEnemies();

//generate the board:

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

JLabel lbl = null;

if(arena[j][i].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“ground.png”));

}

else if(arena[j][i].equals(“ ”))

{

lbl = new JLabel(new ImageIcon(“air.png”));

}

else if(arena[j][i].equals(“|”))

{

lbl = new JLabel(new ImageIcon(“ladder.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

}

}

repaint();

cont.validate();

//start the Thread:

runner = new Runner();

231

runner.start();

setContentPane(cont);

}

public void generateStars()

{

//loop through te two dimensional array

for(int i = 1; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

if(arena[i][j].equals(“ ”))

{

//give a 1 in 10 chance of placing a star

int placeOrNot = (int)(Math.random()*10);

if(placeOrNot= =0)

{

//add the star

JLabel star = new JLabel(new ImageIcon(“star.png”)); cont.add(star);

star.setBounds(j*50,i*50,50,50);

cont.setComponentZOrder(star,0);

cont.setComponentZOrder(character,0);

stars.add(star);

}

}

}

}

}

public void generateEnemies()

{

//add the new enemies

for(int i = 0; i < 2; i+ +)

{

JLabel enemy = new JLabel(new ImageIcon(“enemy.png”)); cont.add(enemy);

int xLoc = (int)(Math.random()*8);

enemy.setBounds(xLoc*50,0,50,50);

cont.setComponentZOrder(enemy,0);

enemies.add(enemy);

}

}

public class Runner extends Thread

{

public void run()

{

while(true)

{

try

{

//check the following on every enemy

for(int i = 0; i < enemies.size(); i+ +)

{

JLabel enemy = (JLabel) enemies.get(i);

//only apply the following to onscreen enemies if(enemy.getY()<=450 && enemy.getX()<=450)

{

//move the enemy down, if possible

if(arena[(enemy.getY()/50)+1][enemy.getX()/50].equals(“ ”)) Projct 44: Oiram—Bad Guys

{

232

Projct 44: Oiram—Bad Guys

enemy.setBounds(enemy.getX(),enemy.getY()+50,50,50);

}

//move the enemy left/right

int direction = (int)(Math.random()*2);

if(direction= =0)

{

if(arena[enemy.getY()/50][(enemy.getX()/50)+1].equals(“ ”))

{

enemy.setBounds(enemy.getX()+50,enemy.getY(),50,50);

}

}

else

{

if(arena[enemy.getY()/50][(enemy.getX()/50)−1].equals(“ ”))

{

enemy.setBounds(enemy.getX()−50,enemy.getY(),50,50);

}

}

//if Oiram jumps on an enemy, remove the enemy if(enemy.getY()−50= =character.getY() && enemy.getX()= =character.getX())

{

enemy.setBounds(1000,1000,50,50);

cont.remove(enemy);

}

//if an enemy eats Oiram, display the losing image if(enemy.getY()= =character.getY() && enemy.getX()= =character.getX())

{

cont.remove(character);

}

}

}

//check the following on every star

for(int i = 0; i < stars.size(); i+ +)

{

JLabel star = (JLabel) stars.get(i);

//if Oiram captures a star, remove it

if(star.getBounds().intersects(character.getBounds()))

{

cont.remove(star);

stars.remove(star);

}

}

//let Oiram fall

if(!jumping)

{

if(arena[(character.getY()/50)+1][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX(),character.getY()+50,50,50);

}

}

//let Oiram jump

else

{

jumping = false;

if(arena[(character.getY()/50)−1][character.getX()/50] .equals(“ ”))

{

character.setBounds(character.getX(),character.getY()−50,50,50);

}

}

233

//delay

Thread.sleep(250);

}

catch(Exception e){ }

}

}

}

public void keyPressed(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

public void keyTyped(KeyEvent e)

{

//move Oiram left

if(e.getKeyChar()= =‘a’)

{

//check if Oiram is climbing. if so, end the climb if(climbing)

{

climbing = false;

character.setIcon(new ImageIcon(“oiram.png”));

}

//Move Oiram left, if possible

if(character.getX()>=50 && arena[character.getY()/50][(character.getX()/50)−

1].equals(“ ”))

{

character.setBounds(character.getX()−50,character.getY(),50,50);

}

}

//move Oiram right

if(e.getKeyChar()= =‘d’)

{

//don’t let Oiram go offscreen!’

if(character.getX()<=400 &&

arena[character.getY()/50][(character.getX()/50)+1].equals(“ ”))

{

character.setBounds(character.getX()+50,character.getY(),50,50);

}

//if Oiram hits a ladder, begin to climb

if(arena[character.getY()/50][(character.getX()/50)+1].equals(“|”))

{

character.setBounds(character.getX()+50,character.getY(),50,50); climbing = true;

character.setIcon(new ImageIcon(“onladder.png”));

}

}

//jump/climb

if(e.getKeyChar()= =‘w’)

{

//if Oiram is not climbing, then jump up!

if(!climbing)

{

if(arena[(character.getY()/50)−1][character.getX()/50].equals(“ ”))

{

if(!jumping && !arena[(character.getY()/50)+1][character.getX()/50].equals(“ ”))

{

jumping = true;

character.setBounds(character.getX(),character.getY()−50,50,50);

}

}

}

Projct 44: Oiram—Bad Guys

234

Projct 44: Oiram—Bad Guys

//move Oiram up the ladder ...

else

{

character.setBounds(character.getX(), character.getY()−50,50,50);

//Oiram reached the top of the ladder. change his icon

//and move hime over.

if(arena[character.getY()/50][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX()+50,character.getY(),50,50); climbing = false;

character.setIcon(new ImageIcon(“oiram.png”));

}

}

}

}

public static void main (String[ ] args)

{

new Oiram();

}

}

Figures 44-2 through 44-4 illustrate enemy

It’s not over yet for Oiram! Keep going to learn action.

how to add more levels of increasing difficulty.

Figure 44-2

Enemies are alive!

235

Figure 44-3

One enemy down.

Figure 44-4

Remaining enemy kills Oiram.

Projct 44: Oiram—Bad Guys

236

Project 45: Oiram—Complicated World

Project 45: Oiram—Complicated World

Project

Oiram collects a star or defeats an enemy, subtract one from the appropriate variable. In the infinite Add levels of increasing difficulty and

loop, check the values of both variables. Once both winning/losing images to your game board.

variables are zero, increment the level variable by one. Call the methods that generate the stars and enemies. In addition, create a JLabel that displays Making the game

the current level. Remember to refresh the JLabel whenever the level changes.

Oiram will fight through five levels: each level will add more enemies. To increase the number of

To give Oiram a score, create a variable.

enemies, slightly modify the method that draws Increment it by 100 each time Oiram captures a them. To do this, create one global variable that star. Increment it by 200 when Oiram defeats an keeps track of the level of play. Declare another adversary. Display the score in a JLabel.

variable inside the method that holds a random You can also add a fun title image. Draw Oiram number (1 or 2). Add that random number to the in a 500 by 50 pixel image. Display the JLabel that level variable. Create that number of enemies.

holds the image at the top of the platform.

A new level begins when Oiram defeats all of

To add winning/losing images, create two 500 by his opponents and captures all of the stars. To 500 pixel images. Start by displaying them

begin a new level, initialize two variables: one that offscreen. If Oiram dies or wins by getting past keeps track of the number of enemies and one that level five, move the appropriate image to the center keeps track of the number of stars. Each time

of the arena. Remember to remove all other images.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class Oiram extends JFrame implements KeyListener

{

//the container:

Container cont;

//the 2 dimensional array

String arena[ ][ ] =

{{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“#”,“ ”},

{“ ”,“#”,“#”,“#”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“|”,“#”,“ ”,“ ”},

{“ ”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“ ”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“ ”,“ ”,“#”,“#”,“#”,“#”},

{“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”,“ ”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

237

//this holds the stars:

ArrayList stars = new ArrayList();

//Oiram!

JLabel character = new JLabel(new ImageIcon(“oiram.png”));

//whether or not Oiram is jumping/climbing

boolean jumping = false;

boolean climbing = false;

//the Thread

Runner runner;

//Oiram’s score’

int score = 0;

//the number of remaining stars

int starsLeft;

//this holds the enemies

ArrayList enemies = new ArrayList();

//the winning/losing images

JLabel win = new JLabel(new ImageIcon(“win.png”)); JLabel lose = new JLabel(new ImageIcon(“lose.png”));

//the title image

JLabel title = new JLabel(new ImageIcon(“title.png”));

//the current level

int level = 1;

//the number of enemies

int enemyCount = 1;

//displays the level/score:

JLabel levelLbl = new JLabel(“Level “+level+”/5”); JLabel scoreLbl = new JLabel(“Score “+score);

public Oiram()

{

super(“Oiram”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

addKeyListener(this);

cont.setBackground(Color.BLACK);

//add the win/lose images offscreen

cont.add(win);

win.setBounds(500,500,500,500);

cont.add(lose);

lose.setBounds(500,500,500,500);

//add the level label

cont.add(levelLbl);

levelLbl.setFont(new Font(“arial”,Font.BOLD,20)); levelLbl.setBounds(375,5,150,50);

//add the score label

cont.add(scoreLbl);

scoreLbl.setFont(new Font(“arial”,Font.BOLD,20)); scoreLbl.setBounds(20,5,150,50);

//add the title image

cont.add(title);

title.setBounds(0,0,500,50);

//add Oiram

cont.add(character);

character.setBounds(0,400,50,50);

//create teh stars and enemies

generateStars();

Project 45: Oiram—Complicated World

generateEnemies();

238

Project 45: Oiram—Complicated World

//generate the board:

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j+ +)

{

JLabel lbl = null;

if(arena[j][i].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“ground.png”));

}

else if(arena[j][i].equals(“ ”))

{

lbl = new JLabel(new ImageIcon(“air.png”));

}

else if(arena[j][i].equals(“|”))

{

lbl = new JLabel(new ImageIcon(“ladder.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

}

}

repaint();

cont.validate();

//start the Thread:

runner = new Runner();

runner.start();

setContentPane(cont);

}

public void generateStars()

{

//loop through te two dimensional array

for(int i = 1; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j+ +)

{

if(arena[i][j].equals(“ ”))

{

//give a 1 in 10 chance of placing a star

int placeOrNot = (int)(Math.random()*10);

if(placeOrNot= =0)

{

//add the star

JLabel star = new JLabel(new ImageIcon(“star.png”)); cont.add(star);

star.setBounds(j*50,i*50,50,50);

cont.setComponentZOrder(star,0);

cont.setComponentZOrder(character,0);

stars.add(star);

starsLeft+ +;

}

}

}

}

}

public void generateEnemies()

{

//add a random number of enemies

int increaseBy = (int)(Math.random()*2)+1;

239

enemyCount = level+increaseBy;

//add the new enemies

for(int i = 0; i < enemyCount; i+ +)

{

JLabel enemy = new JLabel(new ImageIcon(“enemy.png”)); cont.add(enemy);

int xLoc = (int)(Math.random()*8);

enemy.setBounds(xLoc*50,0,50,50);

cont.setComponentZOrder(enemy,0);

enemies.add(enemy);

}

}

public class Runner extends Thread

{

public void run()

{

while(true)

{

try

{

//the current score

scoreLbl.setText(“Score ”+score);

//check the following on every enemy

for(int i = 0; i < enemies.size(); i+ +)

{

JLabel enemy = (JLabel) enemies.get(i);

//only apply the following to onscreen enemies if(enemy.getY()<=450 && enemy.getX()<=450)

{

//move the enemy down, if possible

if(arena[(enemy.getY()/50)+1]

[enemy.getX()/50].equals(“ ”))

{

enemy.setBounds(enemy.getX(),

enemy.getY()+50,50,50);

}

//move the enemy left/right

int direction = (int)(Math.random()*2);

if(direction= =0)

{

if(arena[enemy.getY()/50][(enemy.getX()/50)+1].equals(“ ”))

{

enemy.setBounds(enemy.getX()+50,enemy.getY(),50,50);

}

}

else

{

if(arena[enemy.getY()/50][(enemy.getX()/50)−1].equals(“ ”))

{

enemy.setBounds(enemy.getX()−50,enemy.getY(),50,50);

}

}

//if Oiram jumps on an enemy, remove the enemy if(enemy.getY()−50= =character.getY() && enemy.getX()= =character.getX())

{

enemy.setBounds(1000,1000,50,50);

cont.remove(enemy);

enemyCount− −;

score+=200;

}

//if an enemy eats Oiram, display the losing image Project 45: Oiram—Complicated World

if(enemy.getY()= =character.getY() &&enemy.getX()= =character.getX()) 240

Project 45: Oiram—Complicated World

{

lose.setBounds(0,0,500,500);

cont.setComponentZOrder(lose,0);

for(int j=2; j < cont.getComponentCount(); j++)

{

cont.remove(j);

}

cont.validate();

}

}

}

//get to level 5 to win!

if(level>=5)

{

win.setBounds(0,0,500,500);

cont.setComponentZOrder(win,0);

for(int i = 2; i < cont.getComponentCount(); i++)

{

cont.remove(i);

}

cont.validate();

}

//increase levels

if(enemyCount<=0 && starsLeft<=0)

{

level+ +;

generateStars();

generateEnemies();

levelLbl.setText(“Level “+level+”/5”);

}

//check the following on every star

for(int i = 0; i < stars.size(); i++)

{

JLabel star = (JLabel) stars.get(i);

//if Oiram captures a star, remove it

if(star.getBounds().intersects(character.getBounds()))

{

score+=100;

cont.remove(star);

stars.remove(star);

starsLeft− −;

}

}

//let Oiram fall

if(!jumping)

{

if(arena[(character.getY()/50)+1][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX(),character.getY()+50,50,50);

}

}

//let Oiram jump

else

{

jumping = false;

if(arena[(character.getY()/50)−1][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX(),character.getY()−50,50,50);

}

}

241

//delay

Thread.sleep(250);

}

catch(Exception e){ }

}

}

}

public void keyPressed(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

public void keyTyped(KeyEvent e)

{

//move Oiram left

if(e.getKeyChar()= =‘a’)

{

//check if Oiram is climbing. if so, end the climb if(climbing)

{

climbing = false;

character.setIcon(new ImageIcon(“oiram.png”));

}

//Move Oiram left, if possible

if(character.getX()>=50 &&

arena[character.getY()/50][(character.getX()/50)−1] .equals(“ ”))

{

character.setBounds(character.getX()−50,character.getY(),50,50);

}

}

//move Oiram right

if(e.getKeyChar()= =‘d’)

{

//don’t let Oiram go offscreen!’

if(character.getX()<=400 &&

arena[character.getY()/50][(character.getX()/50)+1].equals(“ ”))

{

character.setBounds(character.getX()+50,character.getY(),50,50);

}

//if Oiram hits a ladder, begin to climb

if(arena[character.getY()/50][(character.getX()/50)+1].equals(“|”))

{

character.setBounds(character.getX()+50,character.getY(),50,50); climbing = true;

character.setIcon(new ImageIcon(“onladder.png”));

}

}

//jump/climb

if(e.getKeyChar()= =‘w’)

{

//if Oiram is not climbing, then jump up!

if(!climbing)

{

if(arena[(character.getY()/50)−1][character.getX()/50].equals(“ ”))

{

if(!jumping && !arena[(character.getY()/50)+1][character.getX()/50].equals(“ ”))

{

jumping = true;

character.setBounds(character.getX(),character.getY()−50,50,50);

}

}

}

//move Oiram up the ladder...

Project 45: Oiram—Complicated World

242

Project 45: Oiram—Complicated World

else

{

character.setBounds(character.getX(),character.getY()−50,50,50);

//Oiram reached the top of the ladder. change his icon

//and move hime over.

if(arena[character.getY()/50][character.getX()/50].equals(“ ”))

{

character.setBounds(character.getX()+50,character.getY(),50,50); climbing = false;

character.setIcon(new ImageIcon(“oiram.png”));

}

}

}

}

public static void main (String[ ] args)

{

new Oiram();

}

}

Figures 45-1 through 45-3 depict the life and

Change Oiram’s icon into a hot air balloon that death of Oiram.

allows him to drop bombs onto his enemies.

Add sound effects whenever Oiram collects a

star or kills an enemy. Program applause for wins Customizing the game

and boos for losses.

Change the layout of the arena. Add more

Add super-stars that give Oiram temporary

platforms, more ladders, etc.

flying abilities.

Figure 45-1

Level and score display.

243

Increase the size of the board: make each zone Place an invisible enemy within the playing

10 by 10 pixels.

field. When close by, program the screen to

Clone Oiram so that there are two—or even

“shake” to alert the player of Oiram’s enemy’s three—of them in the arena.

whereabouts.

Figure 45-2

Oiram bites the dust.

Project 45: Oiram—Complicated World Figure 45-3 Oiram prevails.

244

Project 46: Java Man—Java Man’s Universe

Project 46: Java Man—Java Man’s Universe

A JavaMan board can be created the same way:

##########

Java Man

#

#

#

# # #

#

#

Java and C+ +, the two largest programming

# # #

#

#

languages, battle it out! Maneuver Java Man to

# #

##

#

collect all the dots on the field before C+ + drinks him dry.

# ##

#

#

# #

# #

#

Project

# #

# #

#

#

#

#

Begin by creating Java Man’s universe—the game

##########

board.

In the constructor, use a loop to examine each element in the array. The position of the elements Making the game

in the two dimensional array should correspond with their placement on the JFrame. Draw a 50 by To create the course, use a two dimensional array 50 pixel image of a solid yellow block and a 50 by of Strings. Use “#” to represent the walls and a 50 pixel image of a black square with a white

“space” to denote empty areas.

circle inside. Use the yellow block for the “#”

For example, an empty box is shown below:

character and the black block for the empty

space.

####

# #

The use of arrays makes it easy to modify the

# #

layout of the board.

####

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class JavaMan extends JFrame

{

Container cont;

//the 2 dimensional array

String arena[ ][ ] =

{{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”},

{“#”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“#”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“#”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“#”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

245

public JavaMan()

{

super(“JavaMan”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

cont.setBackground(Color.BLACK);

//create the board

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

JLabel lbl = null;

if(arena[i][j].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“border.png”));

}

else

{

lbl = new JLabel(new ImageIcon(“track_full.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

}

}

repaint();

cont.validate();

setContentPane(cont);

}

public static void main (String[ ] args)

{

new JavaMan();

}

}

Figure 46-1 illustrates Java Man’s universe.

In the next project, bring JavaMan to life! Prepare him for the fight of his life by making him mobile.

Project 46: Java Man—Java Man’s Universe

246

Project 47: Java Man—Java Man Lives!

Figure 46-1

Java Man game board.

Project 47: Java Man—Java Man Lives!

Project

Next, create a thread to move Java Man forward by either adding or subtracting 50 from the x or Place Java Man within the field of play. Then give y coordinates. To prevent Java Man from passing Java Man the power of movement by adding

through the walls, check his position against the keyboard controls to change his direction.

value of the corresponding element in the two

dimensional array. If the element is “#”, move Java Man back one space.

Making the game

Now that you have the course, it’s time to add Java Man. In Microsoft Paint, create a 50 by 50 pixel image of a coffee mug. In the constructor, add this image before you add the board. Set it to the top left corner, position (50,50), as shown in Figure 47-1.

Make Java Man free to move. First, add a

KeyListener to the class. Don’t forget to add the three mandatory methods. Just like in the game Radical Racing, use variables to keep track of Java Man’s orientation (1 represents up, 2 down,

3 right, and 4 left). Now, in the KeyPressed

method, change JavaMan’s direction.

Figure 47-1

Java Man—starting position.

247

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class JavaMan extends JFrame implements KeyListener

{

Container cont;

int UP = 0, DOWN = 1, RIGHT = 2, LEFT = 3;

int direction = RIGHT;

int positionX = 1, positionY = 1;

String arena[ ][ ] =

{{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”},

{“#”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“#”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“#”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“#”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

JLabel javaMan = new JLabel(new ImageIcon(“man.PNG”)); public JavaMan()

{

super(“JavaMan”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

addKeyListener(this);

cont.setBackground(Color.BLACK);

//add JavaMan

cont.add(javaMan);

javaMan.setBounds(50,50,50,50);

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j+ +)

{

JLabel lbl = null;

if(arena[i][j].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“border.png”));

}

else

{

lbl = new JLabel(new ImageIcon(“track_full.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

System.out.println(“X: ”+i*50+“ − − Y: ”+j*50);

}

}

repaint();

Project 47: Java Man—Java Man Lives!

cont.validate();

248

Project 47: Java Man—Java Man Lives!

Runner run = new Runner();

run.start();

setContentPane(cont);

}

public class Runner extends Thread

{

public void run()

{

while(true)

{

try

{

if(direction = = RIGHT)

{

javaMan.setBounds(javaMan.getX()+50,javaMan.getY(),50,50); positionX+ +;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX()−50,javaMan.getY(),50,50); positionX− −;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = LEFT)

{

javaMan.setBounds(javaMan.getX()−50,javaMan.getY(),50,50); positionX− −;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX()+50,javaMan.getY(),50,50); positionX+ +;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = UP)

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()−50,50,50); positionY− −;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()+50,50,50); positionY+ +;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = DOWN)

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()+50,50,50); positionY+ +;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()−50,50,50); positionY− −;

}

cont.setComponentZOrder(javaMan,1);

}

cont.validate();

Thread.sleep(500);

}

catch(Exception e){ }

249

}

}

}

public void keyTyped(KeyEvent e)

{

if(e.getKeyChar()= =‘w’)

direction = UP;

if(e.getKeyChar()= =‘a’)

direction = LEFT;

if(e.getKeyChar()= =‘s’)

direction = DOWN;

if(e.getKeyChar()= =‘d’)

direction = RIGHT;

}

public void keyPressed(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

public static void main (String[ ] args)

{

new JavaMan();

}

}

Figure 47-2 and 47-3 illustrates Java Man’s mobility.

Java Man is done with training ... it’s time to add the C+ + adversaries. Let’s get going ...

Project 47: Java Man—Java Man Lives! Figure 47-2 Java Man comes to life.

250

Project 48: Java Man—C

Figure 47-3

Java Man moves!

++

Project 48: Java Man—C+ + Attacks

Attacks

Project

direction of the random number (1 represents up, 2 down, 3 left, 4 right). To prevent the enemies Create and unleash the enemies. Although the C++

from running through walls, use the same

enemies blindly move around, they are swift and technique you used in the last project.

relentless!

Next, add an if-statement to the loop. Compare the position of the C+ + enemy and Java Man.

Making the game

If they are the same, Java Man loses. Add a

JOptionPane that tells the player the sad news.

Start by drawing a 50 by 50 pixel image of the While Java Man is avoiding C+ +, he is also

C+ + culprit. In order to keep track of his clones, trying to devour the circles on the game board.

use an array 3 elements large. Each element will When Java Man moves over a circle, replace that hold an enemy that occupies one corner of the

tile of the arena with a 50 by 50 pixel black image.

board. Remember, the movements of the C+ +

Also, decrease the variable that keeps track of the clones are random. To create the movement, make number of remaining circles. When the count

another array 3 elements large in the thread. Each reaches zero, Java Man wins. Use an if-statement element of the new array stores the orientation of to check for the win. If Java Man wins, add a

each C+ + character by holding a random number JOptionPane alerting the player of the victory.

between 1 and 4. Next, move each enemy in the

251

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class JavaMan extends JFrame implements KeyListener

{

Container cont;

//the direction

int UP = 0, DOWN = 1, RIGHT = 2, LEFT = 3;

int direction = RIGHT;

int score = 0;

int positionX = 1, positionY = 1;

//the 2 dimensional array

String arena[ ][ ] =

{{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”},

{“#”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“#”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“#”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“#”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

//the JLabel icons

Attacks

JLabel javaMan = new JLabel(new ImageIcon(“man.PNG”)); JLabel enemies[ ] = {new JLabel(new ImageIcon(“monster.png”)),new JLabel(new ImageIcon (“monster.png”)),new JLabel(new ImageIcon(“monster.png”))}; int dotsLeft = 44;

++

public JavaMan()

{

super(“JavaMan”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

addKeyListener(this);

cont.setBackground(Color.BLACK);

//add JavaMan

cont.add(javaMan);

javaMan.setBounds(50,50,50,50);

//add the board

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j+ +)

{

JLabel lbl = null;

if(arena[i][j].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“border.png”));

}

else

Project 48: Java Man—C

{

252

Project 48: Java Man—C

lbl = new JLabel(new ImageIcon(“track_full.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

System.out.println(“X: ”+i*50+“ — Y: ”+j*50);

}

}

//set the position of the enemies

cont.add(enemies[0]);

enemies[0].setBounds(400,50,50,50);

cont.setComponentZOrder(enemies[0],1);

cont.add(enemies[1]);

enemies[1].setBounds(50,400,50,50);

cont.setComponentZOrder(enemies[1],1);

cont.add(enemies[2]);

enemies[2].setBounds(400,400,50,50);

cont.setComponentZOrder(enemies[2],1);

repaint();

cont.validate();

Runner run = new Runner();

run.start();

setContentPane(cont);

}

public class Runner extends Thread

{

++

public void run()

{

while(true)

Attacks

{

try

{

//check if JavaMan wins

if(dotsLeft<=0)

{

JOptionPane.showMessageDialog(null,“You Win!”);

}

//enemy movement loop

int dir[ ] = new int[3];

for(int i = 0; i < dir.length; i+ +)

{

dir[i] = (int)(Math.random()*4);

if(dir[i]= =UP)

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()−50,50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()+50,50,50);

}

}

if(dir[i]= =DOWN)

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()+50,50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()−50,50,50);

}

253

}

if(dir[i]= =LEFT)

{

enemies[i].setBounds(enemies[i].getX()−50,enemies[i].getY(),50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX()+50,enemies[i].getY(),50,50);

}

}

if(dir[i]= =RIGHT)

{

enemies[i].setBounds(enemies[i].getX()+50,enemies[i].getY(),50,50); if(arena[enemies[i].getX()/50][enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX()−50,enemies[i].getY(),50,50);

}

}

//you lose!

if(enemies[i].getX()/50= =positionX && enemies[i].getY()/50= =positionY)

{

JOptionPane.showMessageDialog(null,”You Lose!”);

}

cont.setComponentZOrder(enemies[i],1);

}

//remove the circle

if(arena[positionX][positionY].equals(“ ”))

{

arena[positionX][positionY] = “.”;

Attacks

dotsLeft− −;

JLabel lbl = new JLabel(new ImageIcon(“track_empty.png”)); cont.add(lbl);

lbl.setBounds(positionX*50,positionY*50,50,50);

++

cont.setComponentZOrder(lbl,1);

score+ +;

}

//move Java Man

if(direction = = RIGHT)

{

javaMan.setBounds(javaMan.getX()+50,javaMan.getY(),50,50); positionX+ +;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX()−50,javaMan.getY(),50,50); positionX− −;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = LEFT)

{

javaMan.setBounds(javaMan.getX()−50,javaMan.getY(),50,50); positionX− −;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX()+50,javaMan.getY(),50,50); positionX+ +;

}

cont.setComponentZOrder(javaMan,1);

}

Project 48: Java Man—C

if(direction = = UP)

254

Project 48: Java Man—C

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()−50,50,50); positionY− −;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()+50,50,50); positionY+ +;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = DOWN)

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()+50,50,50); positionY+ +;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()−50,50,50); positionY− −;

}

cont.setComponentZOrder(javaMan,1);

}

cont.validate();

Thread.sleep(500);

}

catch(Exception e){ }

}

}

++

}

public void keyTyped(KeyEvent e)

{

Attacks

if(e.getKeyChar()= =‘w’)

direction = UP;

if(e.getKeyChar()==‘a’)

direction = LEFT;

if(e.getKeyChar()==‘s’)

direction = DOWN;

if(e.getKeyChar()==‘d’)

direction = RIGHT;

}

public void keyPressed(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

public static void main (String[ ] args)

{

new JavaMan();

}

}

Figures 48-1 through 48-3 depict Java Man’s

Keep reading to learn how to add more eye-

quest for survival.

catching win/lose images.

255

Figure 48-1

C++ lives!

Attacks

++

Figure 48-2

Java Man chomps up the dots.

Project 48: Java Man—C

256

Project 49: Java Man—Obituaries

Figure 48-3

C++ wins ... .

Project 49: Java Man—Obituaries

Project

500 pixel images: one of C+ + drinking spilled coffee from the fallen Java Man; the other, a

Turn up the graphic impact of the win/lose display.

defeated C+ + falling into the hot cup of Java.

In the constructor, add these two images

Making the game

offscreen. When there is a win or loss, replace the JOptionPane code with the setBounds method.

Replace those dull JOptionPanes with something Don’t forget to use a loop to remove all other fresh! Use Microsoft Paint to draw two 500 by

components!

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

import java.util.*;

import java.awt.geom.*;

public class JavaMan extends JFrame implements KeyListener

{

Container cont;

int UP = 0, DOWN = 1, RIGHT = 2, LEFT = 3;

//the direction of JavaMan

int direction = RIGHT;

int score = 0;

257

//JavaMan’s position

int positionX = 1, positionY = 1;

//the two dimensional array

String arena[ ][ ] =

{{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”},

{“#”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“#”,“ ”,“#”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“#”,“ ”,“ ”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“#”,“ ”,“ ”,“#”,“ ”,“#”,“ ”,“#”},

{“#”,“ ”,“ ”,“ ”,“ ”,“#”,“ ”,“ ”,“ ”,“#”},

{“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”,“#”}};

//the JLabels

JLabel javaMan = new JLabel(new ImageIcon(“man.PNG”)); JLabel enemies[ ] = {new JLabel(new ImageIcon(“monster.png”)),new JLabel(new ImageIcon (“monster.png”)),new JLabel(new ImageIcon(“monster.png”))}; JLabel win = new JLabel(new ImageIcon(“win.png”)); JLabel lose = new JLabel(new ImageIcon(“lose.png”)); int dotsLeft = 44;

public JavaMan()

{

super(“JavaMan”);

setSize(500,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

addKeyListener(this);

cont.setBackground(Color.BLACK);

cont.add(win);

win.setBounds(500,500,500,500);

cont.add(lose);

lose.setBounds(500,500,500,500);

//add JavaMan

cont.add(javaMan);

javaMan.setBounds(50,50,50,50);

//create the arena

for(int i = 0; i < arena.length; i+ +)

{

for(int j = 0; j < arena[0].length; j++)

{

JLabel lbl = null;

if(arena[i][j].equals(“#”))

{

lbl = new JLabel(new ImageIcon(“border.png”));

}

else

{

lbl = new JLabel(new ImageIcon(“track_full.png”));

}

cont.add(lbl);

lbl.setBounds(i*50,j*50,50,50);

System.out.println(“X: ”+i*50+“ − − Y: ”+j*50);

}

}

Project 49: Java Man—Obituaries

258

Project 49: Java Man—Obituaries

//add the enemies

cont.add(enemies[0]);

enemies[0].setBounds(400,50,50,50);

cont.setComponentZOrder(enemies[0],1);

cont.add(enemies[1]);

enemies[1].setBounds(50,400,50,50);

cont.setComponentZOrder(enemies[1],1);

cont.add(enemies[2]);

enemies[2].setBounds(400,400,50,50);

cont.setComponentZOrder(enemies[2],1);

repaint();

cont.validate();

Runner run = new Runner();

run.start();

setContentPane(cont);

}

public class Runner extends Thread

{

public void run()

{

while(true)

{

try

{

//check if JavaMan wins

if(dotsLeft<=0)

{

win.setBounds(0,0,500,500);

cont.setComponentZOrder(win,0);

for(int j = 2; j < cont.getComponentCount(); j+ +)

{

cont.remove(j);

}

}

//control the C+ +

int dir[ ] = new int[3];

for(int i = 0; i < dir.length; i+ +)

{

//get the random direction

dir[i] = (int)(Math.random()*4);

if(dir[i]= =UP)

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()−50,50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()+50,50,50);

}

}

if(dir[i]= =DOWN)

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()+50,50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].

equals(“#”))

{

enemies[i].setBounds(enemies[i].getX(),enemies[i].getY()−50,50,50);

}

}

if(dir[i]= =LEFT)

259

{

enemies[i].setBounds(enemies[i].getX()-50,enemies[i].getY(),50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX()+50,enemies[i].getY(),50,50);

}

}

if(dir[i]= =RIGHT)

{

enemies[i].setBounds(enemies[i].getX()+50,enemies[i].getY(),50,50); if(arena[enemies[i].getX()/50]

[enemies[i].getY()/50].equals(“#”))

{

enemies[i].setBounds(enemies[i].getX()-50,enemies[i].getY(),50,50);

}

}

if(enemies[i].getX()/50= =positionX && enemies[i].getY()/50= =positionY)

{

lose.setBounds(0,0,500,500);

cont.setComponentZOrder(lose,0);

for(int j = 2; j < cont.getComponentCount(); j+ +)

{

cont.remove(j);

}

}

cont.setComponentZOrder(enemies[i],1);

}

//remove the dot

if(arena[positionX][positionY].equals(“ ”))

{

arena[positionX][positionY] = “.”;

dotsLeft− −;

JLabel lbl = new JLabel(new ImageIcon(“track_empty.png”)); cont.add(lbl);

lbl.setBounds(positionX*50,positionY*50,50,50);cont.setComponentZOrder(lbl,1);s core+ +;

}

//move Java Man

if(direction = = RIGHT)

{

javaMan.setBounds(javaMan.getX()+50,javaMan.getY(),50,50); positionX+ +;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX()−50,javaMan.getY(),50,50); positionX− −;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = LEFT)

{

javaMan.setBounds(javaMan.getX()−50,javaMan.getY(),50,50); positionX− −;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX()+50,

javaMan.getY(),50,50);

positionX+ +;

}

cont.setComponentZOrder(javaMan,1);

Project 49: Java Man—Obituaries

}

260

Project 49: Java Man—Obituaries

if(direction = = UP)

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()-50,50,50); positionY− −;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()+50,50,50); positionY+ +;

}

cont.setComponentZOrder(javaMan,1);

}

if(direction = = DOWN)

{

javaMan.setBounds(javaMan.getX(),javaMan.getY()+50,50,50); positionY+ +;

if(arena[positionX][positionY].equals(“#”))

{

javaMan.setBounds(javaMan.getX(),java

Man.getY()-50,50,50);

positionY− −;

}

cont.setComponentZOrder(javaMan,1);

cont.setComponentZOrder(win,1);

cont.setComponentZOrder(lose,1);

}

cont.validate();

Thread.sleep(500);

}

catch(Exception e){ }

}

}

}

public void keyTyped(KeyEvent e)

{

if(e.getKeyChar()= =‘w’)

direction = UP;

if(e.getKeyChar()= =‘a’)

direction = LEFT;

if(e.getKeyChar()= =‘s’)

direction = DOWN;

if(e.getKeyChar()= =‘d’)

direction = RIGHT;

}

public void keyPressed(KeyEvent e){ }

public void keyReleased(KeyEvent e){ }

public static void main (String[ ] args)

{

new JavaMan();

}

}

Figures 49-1 through 49-3 illustrate Java Man

Add more enemies.

versus C+ +.

Change the icons of the players to laser ships or geometric shapes.

Customizing the game

Speed up or slow down the game ... or, make

speed freak zones within the field.

Change the pathway of the board or, make it an open field.

261

Add special dots that give Java Man

Add fun slurping sounds when Java Man loses

superpowers.

and splashing sounds when Java Man wins.

Instead of random movements, make the C++

Add a sink hole on the board that vaporizes

chase Java Man.

anything crossing its path.

Change the win/lose images.

Figure 49-1

Battle.

Project 49: Java Man—Obituaries Figure 49-2 C++ wins 262

Project 49: Java Man—Obituaries

Figure 49-3

Java Man is victorious!

263

This page intentionally left blank

Section Seven

Brain Busters

Project 50: Memory—Grid Design

Memory

Although the biochemical process of memory

remains a mystery, you can test yours by playing this game. A set of images flashes before your Figure 50-1

Sample image.

eyes. The challenge? Match the identical pictures before time runs out.

Then, initialize a normal array of ints that stores the number of times each image is used. This will Project

prevent images from appearing more than twice.

Now, use two for loops to go through the

Plan and develop the 16 grid game frame.

JButton array. At each iteration, create a random number between 1 and 8, inclusive. Using the

Making the game

normal array you created earlier, check whether the image corresponding to the random number

The game, “Memory,” consists of a 4 by 4 grid

has been used more than once. If so, generate a containing eight pairs of images. You will learn how new random number. Once a satisfactory random

to integrate photographs to create the images of your number has been generated, increment by one the choosing in Project 53. For now, however, simply appropriate value in the single dimensional array.

draw eight 100 by 100 pixel images and name them Don’t forget to set the icon of the JButton to your

“img1.png,” “img2.png,” etc. In each generic image, new image. How do you keep track of the location write the image number, as shown in Figure 50-1.

of each image? Easy! Create a two dimensional

global array 8 ints long. Set the appropriate

Now that you have created the images, store

element to the random number.

them in a two dimensional array of JButtons that is 4 by 4 elements large. In the constructor, use two Now that the images are displayed, you need to hide them. Use a Thread.sleep method and pause for loops to add the JButtons to the JFrame.

Don’t attach the images you created just yet ...

instead, attach a new 100 by 100 pixel image, like the one shown in Figure 50-2, that displays the name of the game (“Memory”).

Next, create a method that randomly assigns

your images to the JButtons. To do this, use the Thread.sleep method to pause for half a second.

Figure 50-2

“Memory” image.

265

for 3 seconds to give players a chance to memorize Set the icons back to the starting image (the one the images. Then, make a new set of two for loops.

that says “Memory”).

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class Memory extends JFrame

{

//the blank image

ImageIcon blank = new ImageIcon(“blank.png”);

//the buttons

JButton buttons[ ][ ] = {{new JButton(blank),new JButton(blank), new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)}};

//the locations of the images

int locations[ ][ ] = {{0,0,0,0},{0,0,0,0},{0,0,0,0}, {0,0,0,0}}; Container cont;

public Memory()

{

super(“Memory”);

setSize(415,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

for(int i = 0; i <buttons[0].length; i++)

{

for(int j = 0; j <buttons.length; j+ +)

{

//add the button to the board

cont.add(buttons[i][j]);

buttons[i][j].setBounds(i*100,j*100,100,100);

}

}

mixup();

}

public void mixup()

{

try

{

//pause

Thread.sleep(500);

//this prevent an image from being used more than twice int usedCount[ ] = {0,0,0,0,0,0,0,0};

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//create a random number

int rand = (int)(Math.random()*8)+1;

Project 50: Memory—Grid Design

while(usedCount[rand − 1]>1)

{

266

Project 50: Memory—Grid Design

//find a better random number

rand = (int)(Math.random()*8)+1;

}

//don’t use an image more than twice!

usedCount[rand−1]+ +;

//set the image

buttons[i][j].setIcon(new ImageIcon(“img”+rand+”.png”));

//keep track of the images

locations[i][j] = rand;

cont.validate();

}

}

//pause

Thread.sleep(3000);

//two for loops

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//change the icons back

buttons[i][j].setIcon(blank);

cont.validate();

}

}

}

catch(Exception e){}

}

public static void main (String[ ] args)

{

new Memory();

}

}

Figure 50-3

Display of “Memory” images.

267

Figure 50-4

Numbered images on the JFrame.

Project 50: Memory—Grid Design Figure 50-5 Return of “Memory” images.

268

Project 51: Memory—Match Time

Figures 50-3 through 50-5 illustrate the initial The next step: challenging the players to match Memory game board.

the images. Read on!

Project 51: Memory—Match Time

Project

global variables and to set the boolean that

represents the turn number to the second position.

Construct the code that allows the player to test When it is the player’s second turn, iterate

his/her memory by matching images.

through all of the buttons in the array. Use the e.getSource() method to check whether the button Making the game

selected is the current one in the loop. If so, change the icon and set the button, row, and

Start by implementing ActionListener. Remember column numbers in global variables. Set the

to add it to each button in the loop. Keep in mind boolean that represents whether the computer

that each guess consists of two clicks: the first is needs to check for a match to “true.” Also, set the the base image; the second is the matching image.

other boolean that represents whether it is the Now, create two booleans: one to represent a

player’s first click to “true.”

player’s first image click; another to represent the It’s now time to create a Thread. In the thread’s second. In the actionPerformed method, check the loop, use an if-statement to determine whether the first boolean to confirm it is the player’s first click.

boolean that represents if the board should be If so, use a for loop to iterate through all of the checked for a win is “true.” If so, pause the game buttons. Use the e.getSource() method to check for half a second. Next, check if the two images whether the button selected is the current one in selected by the player are different (i.e. incorrect the loop. If confirmed, hold the image number in a guess). If so, reset the board by setting both icons to global variable. Then, set the icon of the button to the original image. If the two images are identical the appropriate image. Don’t forget to keep track (i.e. correct guess), the images will remain revealed.

of the row and column numbers of the button in import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class Memory extends JFrame implements ActionListener

{

//the blank image

ImageIcon blank = new ImageIcon(“blank.png”);

//the array of buttons

JButton buttons[ ][ ] = {{new JButton(blank),new JButton(blank), new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

269

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)}};

//the image that is at each button

int locations[ ][ ] = {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; Container cont;

//whether the player has guessed once

boolean guessedOne = false;

boolean readyToCheck = false;

//the first guess

int firstGuess;

//the first guess pos 1 in the array

int firstGuessPos1;

//the first guess pos 2 in the array

int firstGuessPos2;

//the second guess

int secGuess;

//the second guess pos 1 in the array

int secGuessPos1;

//the second guess pos 2 in the array

int secGuessPos2;

public Memory()

{

super(“Memory”);

setSize(415,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

//the Memory images

for(int i = 0; i <buttons[0].length; i ++)

{

for(int j = 0; j < buttons.length; j + +)

{

cont.add(buttons[i][j]);

buttons[i][j].setBounds(i*100,j*100,100,100);

buttons[i][j].addActionListener(this);

}

}

mixup();

Checker checker = new Checker();

checker.start();

}

public class Checker extends Thread

{

public void run()

{

while(true)

{

if(readyToCheck)

{

try

{

sleep(500);

}

catch(Exception ex){ }

if(firstGuess!=secGuess)

{

//if it is wrong, reset the images

Project 51: Memory—Match Time

270

Project 51: Memory—Match Time

buttons[firstGuessPos1][firstGuessPos2].setIcon(blank); buttons[secGuessPos1][secGuessPos2].setIcon(blank);

}

readyToCheck = false;

}

}

}

}

public void mixup()

{

try

{

//pause

Thread.sleep(500);

//this prevent an image from being used more than twice int usedCount[ ] = {0,0,0,0,0,0,0,0};

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//create a random number

int rand = (int)(Math.random()*8)+1;

while(usedCount[rand −1]>1)

{

//find a better random number

rand = (int)(Math.random()*8)+1;

}

//don’t use an image more than twice!

usedCount[rand−1]+ +;

//set the image

buttons[i][j].setIcon(new ImageIcon (“img”+rand+”.png”));

//keep track of the images

locations[i][j] = rand;

cont.validate();

}

}

//pause

Thread.sleep(3000);

//two for loops

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//change the icons back

buttons[i][j].setIcon(blank);

cont.validate();

}

}

}

catch(Exception e){}

}

public void actionPerformed(ActionEvent e)

{

//if it is the first guess

if(!guessedOne)

{

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

271

if(e.getSource()= =buttons[i][j])

{

//display the image

int picNum = locations[i][j];

buttons[i][j].setIcon(new ImageIcon(“img”+picNum+”.png”)); firstGuess = picNum;

firstGuessPos1 = i;

firstGuessPos2 = j;

}

}

}

guessedOne = true;

}

//if it is the second guess

else

{

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

if(e.getSource()= =buttons[i][j])

{

//display the image

int picNum = locations[i][j];

buttons[i][j].setIcon(new ImageIcon (“img”+picNum+“.png”)); secGuess = picNum;

secGuessPos1 = i;

secGuessPos2 = j;

cont.validate();

}

}

//let the thread check for a win

guessedOne = false;

readyToCheck = true;

}

}

}

public static void main (String[ ] args)

{

new Memory();

}

}

Figures 51-1 through 51-3 displays the play

The player’s satisfaction in completing

sequence of Memory.

the first level is short-lived as you create

more levels with more intense challenges.

Project 51: Memory—Match Time

272

Project 51: Memory—Match Time

Figure 51-1

Game begins.

Figure 51-2

On the verge of a win.

273

Figure 51-3

Victory!

Project 52: Memory—Beat the Clock

Project

variable that represents the time remaining from the maximum time. Then, set the time left variable Complications ... with a twist. The player must to the new maximum time.

beat his/her own time from the previous round.

Create a new Thread. In the infinite loop, delay The better you are, the harder it gets.

for one second and then subtract one from the

variable that represents the time remaining in the Making the Game

round. Display the time remaining in a JLabel. You can change the font to make it look like the

In order to create the timer, make two global

example in Figure 52-1.

variables: one that represents the allotted time given for the round, the other the time remaining in each round. Next, in the method that mixes up the icons (refer to Project 50), increment by one a new variable that keeps track of the level count.

Project 52: Memory—Beat the Clock Find the new maximum time by subtracting the Figure 52-1

JLabel displays time remaining

274

Project 52: Memory—Beat the Clock

Now, in the thread from Project 51, make a new the method that randomizes the images. If the time if-statement that checks whether the player’s guess left variable is less than or equal to one, use a is correct. If so, subtract one from the variable that JOptionPane to alert the player that he/she has lost keeps track of the number of pairs left. If that the game.

number is zero, it is time for the next round. Call import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class Memory extends JFrame implements ActionListener

{

//the blank image

ImageIcon blank = new ImageIcon(“blank.png”);

//the array of buttons

JButton buttons[ ][ ] = {{new JButton(blank),new JButton(blank), new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)}};

//the image that is at each button

int locations[ ][ ] = {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; Container cont;

//whether the player has guessed once

boolean guessedOne = false;

//the first guess

int firstGuess;

//the first guess pos 1 in the array

int firstGuessPos1;

//the first guess pos 2 in the array

int firstGuessPos2;

//the second guess

int secGuess;

//the second guess pos 1 in the array

int secGuessPos1;

//the second guess pos 2 in the array

int secGuessPos2;

//the number of pairs remaining

int pairsLeft = 8;

//whether the thread should check for a win

boolean readyToCheck = false;

//starting time

int maxTime = 90;

//remaining time

int timeLeft = 0;

//current level

int levelCount = 0;

JLabel time = new JLabel(“Time Remaining: ” + timeLeft); public Memory()

{

super(“Memory”);

setSize(415,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 275

cont = getContentPane();

cont.setLayout(null);

//the Memory images

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j <buttons.length; j+ +)

{

cont.add(buttons[i][j]);

buttons[i][j].setBounds(i*100,j*100,100,100);

buttons[i][j].addActionListener(this);

}

}

cont.add(time);

time.setBounds(130,385,300,100);

time.setFont(new Font(“arial”, Font.BOLD, 14)); mixup();

Checker checker = new Checker();

checker.start();

Counter count = new Counter();

count.start();

}

public class Counter extends Thread

{

public void run()

{

while(true)

{

//count down the time

timeLeft− −;

time.setText(“Time Remaining: ”+timeLeft);

try

{

Thread.sleep(1000);

}

catch(Exception e){}

}

}

}

public class Checker extends Thread

{

public void run()

{

while(true)

{

if(readyToCheck)

{

try

{

sleep(500);

}

catch(Exception ex){}

//if the guess is correct, remove a pair

if(firstGuess= =secGuess)

{

pairsLeft− −;

}

else

{

Project 52: Memory—Beat the Clock

//if it is wrong, reset the images

276

Project 52: Memory—Beat the Clock

buttons[firstGuessPos1][firstGuessPos2].setIcon(blank); buttons[secGuessPos1][secGuessPos2].setIcon(blank);

}

readyToCheck = false;

}

if(pairsLeft<=0)

{

//if the user wins, start the next level

mixup();

}

//if the time is up, display an image

if(timeLeft<0)

{

JOptionPane.showMessageDialog(null, "YOU LOSE!");break;

}

}

}

}

public void mixup()

{

levelCount+ +;

maxTime = maxTime−timeLeft;

timeLeft = maxTime;

pairsLeft = 8;

try

{

//pause

Thread.sleep(500);

//this prevent an image from being used more than twice int usedCount[ ] = {0,0,0,0,0,0,0,0};

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//create a random number

int rand = (int)(Math.random()*8)+1;

while(usedCount[rand−1]>1)

{

//find a better random number

rand = (int)(Math.random()*8)+1;

}

//don’t use an image more than twice!

usedCount[rand−1]+ +;

//set the image

buttons[i][j].setIcon(new ImageIcon(“img”+rand+“.png”));

//keep track of the images

locations[i][j] = rand;

cont.validate();

}

}

//pause

Thread.sleep(3000);

//two for loops

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//change the icons back

buttons[i][j].setIcon(blank);

cont.validate();

277

}

}

}

catch(Exception e){}

}

public void actionPerformed(ActionEvent e)

{

//if it is the first guess

if(!guessedOne)

{

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

if(e.getSource()= =buttons[i][j])

{

//display the image

int picNum = locations[i][j];

buttons[i][j].setIcon(new ImageIcon(“img”+picNum+”.png”)); firstGuess = picNum;

firstGuessPos1 = i;

firstGuessPos2 = j;

}

}

}

guessedOne = true;

}

//if it is the second guess

else

{

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

if(e.getSource()= =buttons[i][j])

{

//display the image

int picNum = locations[i][j];

buttons[i][j].setIcon(new ImageIcon(“img”+picNum+“.png”)); secGuess = picNum;

secGuessPos1 = i;

secGuessPos2 = j;

cont.validate();

}

}

//let the thread check for a win

guessedOne = false;

readyToCheck = true;

}

}

}

public static void main (String[ ] args)

{

new Memory();

}

}

Project 52: Memory—Beat the Clock

278

Project 52: Memory—Beat the Clock

Figures 52-2 and 52-3 illustrate the rush to beat Open up a world of possibilities by using

the clock.

photographs to customize your game. Next ...

Figure 52-2

Countdown.

Figure 52-3

A heartbreaking loss .

279

Project 53: Memory—Photo Finish

Project

Now that the image has been properly sized,

select “Save As” and overwrite the generic image Here’s your chance to let your evil mind drive the you created in the first project.

players into madness. Pick a group of photos to Now it’s time to create the performance

use as the matching images. Make them as subtle announcements that appear at the end of the game.

as you want to increase the difficulty of the game There are three images/phrases that correspond to and confuse the players. You will also insert

great, mediocre, or poor performances. Draw a fun announcement graphics to let the players know

icon and create an innovative phrase for each rank.

how well—or how poorly—they performed.

Figures 53-2 through 53-4 illustrate a few

examples.

Making the game

When the player loses, use a loop to remove all components from the container. Next, create a new Photograph eight random objects. Transfer them to JLabel that displays the number of levels the

your computer and open them with Microsoft

player has completed. Place the JLabel in the

Paint. Press “Ctrl+A” to select each image and center of the JFrame. Now, you need to know

drag it until “100,100” pixels is displayed on the which image to display for the current level. If the bottom right, as shown in Figure 53-1.

player reaches level seven or above, place the Project 53: Memory—Photo Finish Figure 53-1 Photograph resized to 100 by 100 pixels.

280

Project 53: Memory—Photo Finish

image that represents the highest rank

rank (Figure 53-2). And don’t forget to use the (Figure 53-4). If the player reaches levels three setComponentZOrder method to place the JLabel

through six, display the image representing the in front of the image representing the player’s middle rank (Figure 53-3). For levels zero through standing.

five, display the image representing the lowest Figure 53-2

Lowest possible rank—Remember to

Figure 53-3

Middle rank—Evil, but not a Genius.

keep trying.

Figure 53-4

Highest rank—Evil Genius!

281

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class Memory extends JFrame implements ActionListener

{

//the blank image

ImageIcon blank = new ImageIcon(“blank.png”);

//the array of buttons

JButton buttons[ ][ ] = {{new JButton(blank),new JButton(blank), new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)},

{new JButton(blank),new JButton(blank),

new JButton(blank),new JButton(blank)}};

//the image that is at each button

int locations[ ][ ] = {{0,0,0,0},{0,0,0,0},{0,0,0,0},{0,0,0,0}}; Container cont;

//whether the player has guessed once

boolean guessedOne = false;

//the first guess

int firstGuess;

//the first guess pos 1 in the array

int firstGuessPos1;

//the first guess pos 2 in the array

int firstGuessPos2;

//the second guess

int secGuess;

//the second guess pos 1 in the array

int secGuessPos1;

//the second guess pos 2 in the array

int secGuessPos2;

//the number of pairs remaining

int pairsLeft = 8;

//whether the thread should check for a win

boolean readyToCheck = false;

//starting time

int maxTime = 90;

//remaining time

int timeLeft = 0;

//current level

int levelCount = 0;

JLabel time = new JLabel(“Time Remaining: ” + timeLeft); public Memory()

{

super(“Memory”);

setSize(415,500);

setVisible(true);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); cont = getContentPane();

cont.setLayout(null);

//the Memory images

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j+ +)

Project 53: Memory—Photo Finish

{

cont.add(buttons[i][j]);

282

Project 53: Memory—Photo Finish

buttons[i][j].setBounds(i*100,j*100,100,100);

buttons[i][j].addActionListener(this);

}

}

cont.add(time);

time.setBounds(130,385,300,100);

time.setFont(new Font(“arial”, Font.BOLD, 14)); mixup();

Checker checker = new Checker();

checker.start();

Counter count = new Counter();

count.start();

}

public class Counter extends Thread

{

public void run()

{

while(true)

{

//count down the time

timeLeft − −;

time.setText(“Time Remaining: ”+timeLeft);

try

{

Thread.sleep(1000);

}

catch(Exception e){}

}

}

}

public class Checker extends Thread

{

public void run()

{

while(true)

{

if(readyToCheck)

{

try

{

sleep(500);

}

catch(Exception ex){}

//if the guess is correct, remove a pair

if(firstGuess= =secGuess)

{

pairsLeft− −;

}

else

{

//if it is wrong, reset the images

buttons[firstGuessPos1][firstGuessPos2].setIcon(blank); buttons[secGuessPos1][secGuessPos2].setIcon(blank);

}

readyToCheck = false;

}

if(pairsLeft<=0)

{

//if the user wins, start the next level

283

mixup();

}

//if the time is up, display an image

if(timeLeft<0)

{

//remove the other components

for(int i = 0; i <buttons[0].length; i+ +)

{

for(int j = 0; j <buttons.length; j+ +)

{

cont.remove(buttons[i][j]);

}

}

cont.remove(time);

JLabel levelLbl = new JLabel(“- - - Levels Completed: “+ (levelCount−1)+” - - -”); cont.add(levelLbl);

levelLbl.setForeground(Color.white);

levelLbl.setFont(new Font(“arial narrow”, Font.PLAIN, 20)); levelLbl.setBounds(115,385,300,50);

if(levelCount>=7)

{

//evil genius status

JLabel help = new JLabel(new ImageIcon (“genius.png”)); cont.add(help);

help.setBounds(0,0,415,500);

}

else if (levelCount>=3)

{

//evil but not genius

JLabel help = new JLabel(new ImageIcon(“notGenius.png”)); cont.add(help);

help.setBounds(0,0,415,500);

}

else

{

//you need to practice

JLabel help = new JLabel(new ImageIcon(“needHelp.png”)); cont.add(help);

help.setBounds(0,0,415,500);

}

cont.setComponentZOrder(levelLbl,0);

cont.validate();

break;

}

}

}

}

public void mixup()

{

levelCount+ +;

maxTime = maxTime−timeLeft;

timeLeft = maxTime;

pairsLeft = 8;

try

{

//pause

Thread.sleep(500);

//this prevent an image from being used more than twice int usedCount[ ] = {0,0,0,0,0,0,0,0};

Project 53: Memory—Photo Finish

284

Project 53: Memory—Photo Finish

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//create a random number

int rand = (int)(Math.random()*8)+1;

while(usedCount[rand−1]>1)

{

//find a better random number

rand = (int)(Math.random()*8)+1;

}

//don’t use an image more than twice!

usedCount[rand−1]+ +;

//set the image

buttons[i][j].setIcon(new ImageIcon(“img”+rand+“.png”));

//keep track of the images

locations[i][j] = rand;

cont.validate();

}

}

//pause

Thread.sleep(3000);

//two for loops

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

//change the icons back

buttons[i][j].setIcon(blank);

cont.validate();

}

}

}

catch(Exception e){ }

}

public void actionPerformed(ActionEvent e)

{

//if it is the first guess

if(!guessedOne)

{

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

if(e.getSource()= =buttons[i][j])

{

//display the image

int picNum = locations[i][j];

buttons[i][j].setIcon(new ImageIcon(“img”+picNum+“.png”)); firstGuess = picNum;

firstGuessPos1 = i;

firstGuessPos2 = j;

}

}

}

guessedOne = true;

}

//if it is the second guess

else

{

285

for(int i = 0; i < buttons[0].length; i++)

{

for(int j = 0; j < buttons.length; j++)

{

if(e.getSource()= =buttons[i][j])

{

//display the image

int picNum = locations[i][j];

buttons[i][j].setIcon(new ImageIcon(“img”+picNum+“.png”)); secGuess = picNum;

secGuessPos1 = i;

secGuessPos2 = j;

cont.validate();

}

}

//let the thread check for a win

guessedOne = false;

readyToCheck = true;

}

}

}

public static void main (String[ ] args)

{

new Memory();

}

}

Project 53: Memory—Photo Finish Figure 53-5 Counter counts down ... .

286

Project 53: Memory—Photo Finish

Figure 53-6

Zero levels completed.

Figure 53-7

Memory failure at Level 4.

287

Figure 53-8

A true Evil Genius!

Figures 53-5 through 53-8 illustrate the

Shuffle the images mid-game.

completed game of Memory.

Program a new set of images for each level.

Replace the images with sounds ... try matching Customizing the game

those!

To really confuse the players, overlay sensory Change the images to random colors.

input. Play loud rock music throughout the test ...

Change the 4×4 grid of 16 images into a super

or the incessant sounds of a baby crying or a dog challenging 10×10 grid of 100 images.

barking.

Randomly add on or subtract time.

Project 53: Memory—Photo Finish

288

Project 54: Ian Says—Color Quad

Project 54: Ian Says—Color Quad

First, create a 400 by 400 pixel JFrame.

Then, program a paint method. In the paint

Ian Says

method, draw four filled squares, each 200 by

200 pixels, as shown in Figure 54-1. Paint one Don’t blink as the computer flashes a series of square red; another, blue; another, green; the colors that the player must remember and repeat.

last, yellow. Next, pause the game for one second Ian Says becomes more difficult at each level as so the player will have time to prepare for the the sequence grows longer and longer. How good round.

is your recall? Make one small mistake and you start all over again.

Now, create a method that will randomly

choose one of the four colors. The method should return a char that represents the randomly chosen color.

Project

Using the paint method, call the method you

Build the game board and program the color

just created. Change the chosen square to a

sequencing of Level 1.

brighter shade of the same color. Then, add

text that displays the name of the color (see

Making the game

Figure 54-2).

Pause the game for a quarter of a second. Next, The basic game board of Ian Says consists

reset the board to the standard shade of the color of four squares of different colors, each

by calling a new method you must create to

200 by 200 pixels (see Figure 54-1).

re-initialize the board.

Figure 54-1

Sample square.

Figure 54-2

“Green” displayed on the bright green

square.

289

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class IanSays extends JFrame

{

public IanSays()

{

super(“Ian Says”);

setSize(400,400);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

}

public void paint(Graphics g)

{

super.paint(g);

//red square

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

//blue square

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

//green square

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

//yellow square

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

try

{

Thread.sleep(1000);

}

catch(Exception e){}

String newColor = newColor();

//draw the appropriate new color

if(newColor.equals(“r”))

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

Project 54: Ian Says—Color Quad

g.setFont(new Font(“arial”, Font.BOLD, 40));

290

Project 54: Ian Says—Color Quad

g.drawString(“Green”,50,280);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

try

{

Thread.sleep(250);

}

catch(Exception e){}

reset(g);

}

//generate a new random number

public String newColor()

{

int rand = (int)(Math.random()*4);

if(rand= =0)

{

return “r”;

}

if(rand= =1)

{

return “b”;

}

if(rand= =2)

{

return “g”;

}

if(rand= =3)

{

return “y”;

}

return “ ”;

}

public void reset(Graphics g)

{

//reset the squares

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

}

public static void main (String[ ]args)

{

new IanSays();

}

}

291

Figures 54-3 through 54-5 illustrate the first The first part of the color sequence has been

visual cue of Ian Says.

displayed. In the next project, learn how to test the player’s memory skills.

Figure 54-3

Game board with standard colors.

Project 54: Ian Says—Color Quad Figure 54-4 Brightened green square.

292

Project 55: Ian Says—Brain Drain

Figure 54-5

Game board with standard colors.

Project 55: Ian Says—Brain Drain

Project

square. If the X position is greater than 200 and the Y position is less than 200, the player is The action begins here. Program the computer to clicking the top right square. If the Y position is determine whether or not the player has entered greater than 200 and the X position is less than the correct sequence of colors.

200, the player is clicking the bottom left square.

If both the X an Y positions are greater than 200, the player is clicking the bottom right square.

Making the game

Change a variable called “lastGuess” to the square the player last clicked. In addition, add the clicked In order to let the user repeat the sequence,

color to a String representing the player’s guess.

implement “mouseListener.” Don’t forget to

Call “repaint().”

include all five mandatory methods. In the

mouseClicked method, set a boolean that

You will need to modify the paint method.

represents if the computer is displaying the

Check the boolean that represents if the computer sequence to false. Next, increment by one a

is displaying a sequence. If it is not, brighten the variable that represents the number of guesses last colored square that the player clicked by using the player has taken.

the “lastGuess” variable.

You must determine which square the user is

Now, back in the mouseClicked method, check

clicking. If the X and Y positions of the click are if the player’s sequence matches that of the

less than 200, the user is clicking the top left computer’s. To do this, use the “substring” method 293

to extract the part of the computer’s sequence that and the number of player guesses are the same as the player has guessed. Compare the two Strings.

the number of colors in the sequence, use a

If they are different, the user has guessed

JOptionPane message to tell the user he/she has incorrectly. Use a JOptionPane message to tell the correctly completed the sequence.

player he/she has lost. If the Strings are the same import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class IanSays extends JFrame implements MouseListener

{

Container cont;

String code = “”;

String guess = “”;

int guesses = 0;

String lastLetter;

boolean normal = true;

public IanSays()

{

super(“Ian Says”);

setSize(400,400);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

addMouseListener(this);

}

public void paint(Graphics g)

{

super.paint(g);

if(!normal)

{

reset(g);

String newColor = lastLetter;

//light up the correct square when clicked

if(newColor.equals(“r”))

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

}

try

Project 55: Ian Says—Brain Drain

{

294

Project 55: Ian Says—Brain Drain

Thread.sleep(250);

}

catch(Exception ex){}

reset(g);

}

else

{

//make the squares

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

try

{

Thread.sleep(1000);

}

catch(Exception e){ }

//iterate through the code

for(int i = 0; i <code.length(); i+ +)

{

try

{

Thread.sleep(250);

}

catch(Exception e){ }

//light up the next square

char letter = code.toCharArray()[i];

if(letter= =‘r’)

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(letter= =‘b’)

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(letter= =‘g’)

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Green”,50,280);

}

if(letter= =‘y’)

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

295

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

try

{

Thread.sleep(250);

}

catch(Exception e){}

reset(g);

}

try

{

Thread.sleep(250);

}

catch(Exception e){ }

String newColor = newColor();

//display the appropriate color

if(newColor.equals(“r”))

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Green”,50,280);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

try

{

Thread.sleep(250);

}

catch(Exception e){}

reset(g);

}

}

Project 55: Ian Says—Brain Drain

public String newColor()

296

Project 55: Ian Says—Brain Drain

{

//generate the random color

int rand = (int)(Math.random()*4);

if(rand= =0)

{

code+=“r”;

return “r”;

}

if(rand= =1)

{

code+=“b”;

return “b”;

}

if(rand= =2)

{

code+=“g”;

return “g”;

}

if(rand= =3)

{

code+=“y”;

return “y”;

}

return “ ”;

}

public void reset(Graphics g)

{

//reset the red square

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

//reset the blue square

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

//reset the green square

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

//reset the yellow square

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

}

public void mouseExited(MouseEvent e){ }

public void mouseEntered(MouseEvent e){ }

public void mouseReleased(MouseEvent e){ }

public void mousePressed(MouseEvent e){ }

public void mouseClicked(MouseEvent e)

{

normal = false;

guesses+ +;

//find out which square the player clicked

if(e.getX()<200 && e.getY()<200)

{

lastLetter = “r”;

guess+=“r”;

}

if(e.getX()>200 && e.getY()<200)

{

lastLetter = “b”;

guess+=“b”;

}

if(e.getX()<200 && e.getY()>200) 297

{

lastLetter = “g”;

guess+=“g”;

}

if(e.getX()>200 && e.getY()>200)

{

lastLetter = “y”;

guess+=”y”;

}

repaint();

String codeSeg = code.substring(0,guesses);

if(!codeSeg.equals(guess))

{

//game over!

JOptionPane.showMessageDialog(null,“GAME OVER!!!”);

}

else

{

//the player can proceed

if(guesses= =code.length())

{

JOptionPane.showMessageDialog(null,“Correct!!!”);

}

}

}

public static void main (String[ ]args)

{

new IanSays();

}

}

Figure 55-1

Computer’s sequence.

Project 55: Ian Says—Brain Drain

298

Project 55: Ian Says—Brain Drain

Figures 55-1 through 55-3 show the game’s

Simple ... right? Be prepared—things are

cycle.

going to get very complicated very quickly.

Figure 55-2

Correctly repeated.

Figure 55-3

Incorrectly repeated — L-O-S-E-R!!!

299

Project 56: Ian Says—More Rounds, More Frustration Project

Build an infinite number of levels containing an ever-increasing sequence of colors to memorize.

Making the game

In the mouseClicked method, remove the code that creates the JOptionPane that congratulates the player.

Replace it with code that resets the player’s guess and the length of the sequence. In addition, set the boolean that represents if the computer is creating a sequence to true. Next, call the “repaint” method.

Figure 56-1

Circle indicating level number.

In the paint method, program a for loop that

iterates through each letter of the code. On each iteration, use the following code to determine which color to use.

Now that there are multiple levels of play, you

<code>.toCharArray()[<element number

must indicate to the player what level he/she is on.

of the code>];

To do this, write a method that draws a white

The above method returns a char, which can then circle surrounded by black text, like the one shown be checked in an if-statement to determine if it in Figure 56-1.

contains an “r” (red), “b” (blue), “g” (green), or In the paint method, call the method that

“y” (yellow). Brighten the appropriate square and displays the circle and level number before the display the correct text to indicate its color.

Thread.sleep methods.

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class IanSays extends JFrame implements MouseListener

{

Container cont;

String code = “”;

String guess = “”;

int guesses = 0;

int levels = 0;

String lastLetter;

boolean normal = true;

public IanSays()

{

super(“Ian Says”);

setSize(400,400);

Project 56: Ian Says—More Rounds, More Frustration setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

300

Project 56: Ian Says—More Rounds, More Frustration Container cont = getContentPane();

cont.setLayout(null);

addMouseListener(this);

}

public void paint(Graphics g)

{

super.paint(g);

if(!normal)

{

reset(g);

String newColor = lastLetter;

//light up the correct square when clicked

if(newColor.equals(“r”))

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

}

drawLevel(g);

try

{

Thread.sleep(250);

}

catch(Exception ex){}

reset(g);

}

else

{

levels+ +;

//make the squares

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

drawLevel(g);

try

{

Thread.sleep(1000);

}

catch(Exception e){ }

301

//iterate through the code

for(int i = 0; i <code.length(); i+ +)

{

try

{

Thread.sleep(250);

}

catch(Exception e){}

//light up the next square

char letter = code.toCharArray()[i];

if(letter= =‘r’)

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(letter= =‘b’)

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(letter= =‘g’)

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Green”,50,280);

}

if(letter= =‘y’)

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

drawLevel(g);

try

{

Thread.sleep(250);

}

catch(Exception e){}

reset(g);

}

try

{

Thread.sleep(250);

}

catch(Exception e){}

String newColor = newColor();

//display the appropriate color

Project 56: Ian Says—More Rounds, More Frustration if(newColor.equals(“r”))

302

Project 56: Ian Says—More Rounds, More Frustration

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Green”,50,280);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

drawLevel(g);

try

{

Thread.sleep(250);

}

catch(Exception e){}

reset(g);

}

}

public void drawLevel(Graphics g)

{

//draw the oval and text that displays the level g.setColor(Color.white);

g.fillOval(160,160,80,80);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 15));

g.drawString(“Level ”+levels,175,205);

}

public String newColor()

{

//generate the random color

int rand = (int)(Math.random()*4);

if(rand= =0)

{

code+=“r”;

return “r”;

}

if(rand= =1)

303

{

code+=“b”;

return “b”;

}

if(rand= =2)

{

code+=“g”;

return “g”;

}

if(rand= =3)

{

code+=“y”;

return “y”;

}

return “ ”;

}

public void reset(Graphics g)

{

//reset the red square

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

//reset the blue square

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

//reset the green square

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

//reset the yellow square

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

drawLevel(g);

}

public void mouseExited(MouseEvent e){}

public void mouseEntered(MouseEvent e){}

public void mouseReleased(MouseEvent e){}

public void mousePressed(MouseEvent e){}

public void mouseClicked(MouseEvent e)

{

normal = false;

guesses+ +;

//find out which square the player clicked

if(e.getX()<200 && e.getY()<200)

{

lastLetter = “r”;

guess + = “r”;

}

if(e.getX()>200 && e.getY()<200)

{

lastLetter = “b”;

guess+=“b”;

}

if(e.getX()<200 && e.getY()>200)

{

lastLetter = “g”;

guess+=“g”;

}

if(e.getX()>200 && e.getY()>200)

{

lastLetter = “y”;

Project 56: Ian Says—More Rounds, More Frustration 304

Project 56: Ian Says—More Rounds, More Frustration guess+=“y”;

}

repaint();

String codeSeg = code.substring(0,guesses);

if(!codeSeg.equals(guess))

{

JOptionPane.showMessageDialog(null,”Game Over”);

}

else

{

//the player can proceed

if(guesses= =code.length())

{

guess = “”;

guesses = 0;

normal = true;

//next level!

repaint();

}

}

}

public static void main (String[ ]args)

{

new IanSays();

}

}

Figures 56-2 through 56-4 demonstrates sample

Add refinement to Ian Says by designing a

game levels.

background image with a start button that provides players time to prepare for their mental workout.

Figure 56-2

Game begins.

305

Figure 56-3

Level 6.

Project 56: Ian Says—More Rounds, More Frustration Figure 56-4 Game over.

306

Project 57: Ian Says—Play Accessories

Project 57: Ian Says—Play Accessories

Project

Construct a “start” image that alerts the player that the game is set to begin. Also, design images and messages to appear as the player completes levels.

Making the game

In Microsoft Paint, create a 400 by 400 pixel

starting image, like the one shown in Figure 57-1.

In the constructor, add the image to the JFrame.

Add a JButton on top of the image. Don’t forget to add an ActionListener. Next, create a boolean that Figure 57-1

Starting image.

represents if the game should start and set it to false. In the JButton’s actionPerformed method, set the boolean to true and move the button offscreen.

For example, if the player fails to remember any In the paint method, check if the boolean is true.

colors of the sequence ( ), display the text in If so, begin the game.

Figure 57-2. If the player remembers a 1 to 5 color At the end of the game, replace the JOptionPane sequence, display the text in Figure 57-3. If the with text. Display different phrases corresponding user remembers a sequence greater than 5, display to the length of the sequence the player mastered.

the text in Figure 57-4.

Figure 57-2

No sequential memory.

307

Figure 57-3

Good start ... but keep practicing.

Figure 57-4

Solid memory ... the basis of a true Evil Genius.

Project 57: Ian Says—Play Accessories

308

Project 57: Ian Says—Play Accessories

import javax.swing.*;

import javax.swing.event.*;

import java.awt.*;

import java.awt.event.*;

public class IanSays extends JFrame implements MouseListener, ActionListener

{

Container cont;

String code = “”;

String guess = “”;

int guesses = 0;

int levels = 0;

String lastLetter;

boolean over = false;

boolean normal = true;

boolean begin = false;

JButton start = new JButton(“START”);

public IanSays()

{

super(“Ian Says”);

setSize(400,400);

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true);

Container cont = getContentPane();

cont.setLayout(null);

cont.add(start);

start.addActionListener(this);

start.setFont(new Font(“arial”,Font.BOLD,20)); start.setBounds(145,250,100,50);

JLabel title = new JLabel(new ImageIcon(“title.png”)); cont.add(title);

title.setBounds(0,0,400,400);

addMouseListener(this);

}

public void paint(Graphics g)

{

super.paint(g);

if(!begin)

return;

if(over)

{

//GAME OVER!

reset(g);

g.setColor(Color.black);

g.setFont(new Font(“Arial”, Font.BOLD,50));

g.drawString(“Game Over!”,60,150);

g.setFont(new Font(“Arial”, Font.BOLD,20));

if((levels−1) = = 0)

{

g.drawString(“You didn’t memorize anything!!!”,50,285);

}

else if((levels−1)<=5)

{

g.drawString(“You memorized a random sequence of ”,15,275); g.drawString(“only “ + (levels −1)+” color (s).:(”,130,300);

}

else

{

g.drawString(“Congrats! You memorized a random”,15,275); g.drawString(“sequence of “+(levels−1)+” colors.:)”,100,300); 309

}

}

else

{

if(!normal)

{

reset(g);

String newColor = lastLetter;

//light up the correct square when clicked

if(newColor.equals(“r”))

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

}

drawLevel(g);

try

{

Thread.sleep(250);

}

catch(Exception ex){}

reset(g);

}

else

{

levels+ +;

//make the squares

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

drawLevel(g);

try

{

Thread.sleep(1000);

}

catch(Exception e){}

//iterate through the code

for(int i = 0; i <code.length(); i+ +)

{

Project 57: Ian Says—Play Accessories

310

Project 57: Ian Says—Play Accessories

try

{

Thread.sleep(250);

}

catch(Exception e){ }

//light up the next square

char letter = code.toCharArray()[i];

if(letter= = ‘r’)

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(letter= =‘b’)

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(letter= =‘g’)

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Green”,50,280);

}

if(letter= =‘y’)

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

drawLevel(g);

try

{

Thread.sleep(250);

}

catch(Exception e){ }

reset(g);

}

try

{

Thread.sleep(250);

}

catch(Exception e){ }

String newColor = newColor();

//display the appropriate color

if(newColor.equals(“r”))

{

g.setColor(new Color(255,0,0));

g.fillRect(0,0,200,200);

311

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Red”,50,80);

}

if(newColor.equals(“b”))

{

g.setColor(new Color(0,0,250));

g.fillRect(200,0,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Blue”,250,80);

}

if(newColor.equals(“g”))

{

g.setColor(new Color(0,255,0));

g.fillRect(0,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Green”,50,280);

}

if(newColor.equals(“y”))

{

g.setColor(new Color(255,255,0));

g.fillRect(200,200,200,200);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 40));

g.drawString(“Yellow”,250,280);

}

drawLevel(g);

try

{

Thread.sleep(250);

}

catch(Exception e){}

reset(g);

}

}

}

public void drawLevel(Graphics g)

{

//draw the oval and text that displays the level g.setColor(Color.white);

g.fillOval(160,160,80,80);

g.setColor(Color.black);

g.setFont(new Font(“arial”, Font.BOLD, 15));

g.drawString(“Level ”+levels,175,205);

}

public String newColor()

{

//generate the random color

int rand = (int)(Math.random()*4);

if(rand= =0)

{

code+=“r”;

return “r”;

}

if(rand= =1)

{

Project 57: Ian Says—Play Accessories

312

Project 57: Ian Says—Play Accessories

code+= “b”;

return “b”;

}

if(rand= =2)

{

code+=“g”;

return “g”;

}

if(rand= =3)

{

code+=“y”;

return “y”;

}

return “ ”;

}

public void reset(Graphics g)

{

//reset the red square

g.setColor(new Color(200,50,50));

g.fillRect(0,0,200,200);

//reset the blue square

g.setColor(new Color(50,50,200));

g.fillRect(200,0,200,200);

//reset the green square

g.setColor(new Color(50,200,50));

g.fillRect(0,200,200,200);

//reset the yellow square

g.setColor(new Color(200,200,0));

g.fillRect(200,200,200,200);

drawLevel(g);

}

public void actionPerformed(ActionEvent e)

{

//if start was pressed, start the game

start.setBounds(500,500,50,50);

begin = true;

repaint();

}

public void mouseExited(MouseEvent e){}

public void mouseEntered(MouseEvent e){}

public void mouseReleased(MouseEvent e){}

public void mousePressed(MouseEvent e){}

public void mouseClicked(MouseEvent e)

{

normal = false;

guesses+ +;

//find out which square the player clicked

if(e.getX()<200 && e.getY()<200)

{

lastLetter = “r”;

guess+= “r”;

}

if(e.getX()>200 && e.getY()<200)

{

lastLetter = “b”;

guess+=“b”;

}

if(e.getX()<200 && e.getY()>200) 313

{

lastLetter = “g”;

guess+=”g”;

}

if(e.getX()>200 && e.getY()>200)

{

lastLetter = “y”;

guess+=“y”;

}

repaint();

String codeSeg = code.substring(0,guesses);

if(!codeSeg.equals(guess))

{

//game over!

over = true;

repaint();

}

else

{

//the player can proceed

if(guesses= =code.length())

{

guess = “”;

guesses = 0;

normal = true;

//next level!

repaint();

}

}

}

public static void main (String[ ]args)

{

new IanSays();

}

}

Figures 57-5 and 57-6 shows the end of a

challenging round of Ian Says.

Customizing the game

Use auditory cues instead of colors as memory

targets.

Alter the design of the game board from

4 squares to piano keys.

Add additional squares of different colors to the grid after each successful round.

Project 57: Ian Says—Play Accessories

Give players a time limit for each round.

Figure 57-5

The game begins.

314

Project 57: Ian Says—Play Accessories

Figure 57-6

Devastating loss at level 4. Darn it!

Construct a finite number of levels and race

Congratulations! You have mastered the art of

against the clock to complete them.

programming video games.

In a test of eye-hand coordination, require right-

You are clever, creative, and are a computer

handed players to use their left hand and left-

wizard!

handed players to use their right hand to respond.

You are a true EVIL GENIUS!!!

Force players to delay their responses by

“freezing” the board for several seconds.

315

This page intentionally left blank

Index

Page references followed by f indicate an illustrative figure A

D

ActionListener 98–99

declarations 1

actionPerformed method 107

double 4

aliens, creating. see Space Destroyers, lasers and retaliation arguments 29

ArrayLists x, 20, 25

F

use of 21f

file IO (input/output) x, 14–15, 25

arrays viii, 17, 25

accessing files 14–15

two dimensional 221

creating files 14

use of 19f

see also input

Artificial Intelligence (AI). see Snake pit, snake bite; FileReader 15

Tic-Tac-Toe, knock out

flow control x, 1–2, 10, 25

see also loops

B

FlowLayout 95

font, changing the JLabel 151

board games ix, 95–136

Bomb Diffuser 183–202

bomb squad noob 183–186

G

illustrative figures 184f, 185f, 186f

Graphical User Interface (GUI) 27

expert diffuser 186–191

Guess the Password 3–7

coordinates displayed 189f

game play 6–7f

diffusing the bomb 189–191f

input dialog box 5f

kaboom 191–196

explosions 191f, 195f, 196f

steps of a bomb exploding 195–196f

I

rising through the ranks 197–202

Ian Says 289–315

congratulate the player 197f

brain drain 293–299

stress of bomb diffusion 201–202f

game’s cycle 298–299f

boolean 4

color quad 289–293

brain busters ix, 265–315

displaying name of color 292f

BufferedReader 15

first visual cue 292–293f

sample square 293f

C

customizing 314

casting 5

more rounds, more frustration 300–320

character 4

level number in circle 300f

classes 1–2

sample game levels 305–306f

collision detection 37–38

play accessories 307–315

example 37f

displaying a challenging round 314f, 315f

with components 141f

displaying different phrases 307f, 308f, 314f

color 28, 29f

starting image 307f

component color 137, 138f

if-statements x, 4–5, 25

Ian Says 289–315

images, creating 45–46

see also Microsoft paint

information, displaying. see Space Destroyers, comments x, 1, 25

life and death

components 95

inner classes. see threads

Crack the Code 14–17

input 5

file 14f

see also file IO

game play 16–17f

integer (int) 3, 29

317

J

N

Java API 56

NetBeans 28, 56

Java Man 245–277

colors 29f

C++ attacks 251–257

NullLayout 111

Java Man’s quest for survival 256–257f

Number Cruncher 7–9

customizing 261–263

illustrative figures 9f

Java Man lives 247–251

Number Cruncher Extreme 10–13

Java Man’s mobility 250–251f

game play 13f

starting position 247

Number Guesser 22–24

Java Man’s universe 245–247

game play 23–24f

game board 247f

obituaries 257–263

Java Man versus C++ 262–263f

O

Java Jumpstart 1–25

objects. see ArrayLists

quick review 25

Oiram 221–247

JButtons 95–96

bad guys 230–236

button with image 96f

enemy action 235–236f

simple button 96f

Oiram’s enemy 230f

JFrames 27–28

complicated world 237–244

color 28, 29f, 138f

life and death of Oiram 243–244f

rectangle 28, 29f

customizing 243–244

simple JFrame 28f

go, Oiram, go 224–229

JLabels 96–98

Oiram climbing 225f

illustrative figure 96f

Oiram in action 229f

JLabel font 137, 151

Oiram’s starting location 224f

JOptionPane x

platform 221–224

JRE (Java Runtime Environment) 10

illustrative figures of platform 223f

two types of arrays 223f

opponent, creating an. see Snake Pit, snake bite K

KeyListener 38

P

pausing x, 7, 25

L

photographs, use of. see Memory, photo finish loops 10

premade classes 56–57

“break” 10–11

R

M

racing games ix, 27–93

Memory 265–288

Radical Racing 27–55

beat the clock 274–288

cars 32–37

JLabel display of time remaining 274f

game play 36–37f

rush to beat the clock 279f

collision 37–45

grid design 265–269

illustrative figures 37f, 44f, 45f

initial memory game board 267–268f

making the game 38–45

memory image 265f

customizing 45–55

match time 269–274

images 45–46f

play sequence display 273–274f

making the game 46–54

photo finish 280–288

new graphics 54–55f

displaying levels of play 281f

suggestions 54

illustrative figures of completed game 286–288f track 27–32

resizing photos 280f

completed track 32f

methods 28–30

drawing a virtual racetrack 30–32

Microsoft paint, use of 183, 186, 215, 247, 257, illustrative figures of Jframes 25f, 28f, 29f

280, 307

random numbers x, 7, 25

MouseListener 55

see also Number Guesser

MouseMotionListener 93, 157–158

rectangle 28, 29f

moving components 140–141

Repeater, The 1–3

Index

318

Index

output of game 2–3f

print to the screen 2f

T

retro games ix, 221–263

threads 32–33

RPG (role playing game) 5

Tic-Tac-Toe Boxing 111–136

championship 127–136

S

GUI 136f

outcome 128f

Screen Skier 55–93

customizing 135

bulldozer 75–84

fight 115–119

add or delete track 82–84f

centered title and buttons 116f

ConfirmDialog box 75f

loop 116f

making the game 75–84

new title image and checks for knockouts 119f

competition 84–93

knock out 120–127

counter 84f

defensive play 120, 120f

game play 92–93f

offensive play 120, 120f

making the game 84–93

new AI 126–127f

customizing 93

ring 111–115

expert slope 66–74

game play 114–115f

background 67f

making the game 111–115

game play 72–74f

time-trial game. see Screen Skier, competition making the game 66–74

Trapper 202–219

practice run 60–66

customizing 219

making the game 60–66

men on the move 202–206

starting position 60f

initial movement of characters 205–206f

steps of drawing a track and positioning skier 64–66f setting the trap 206–210

slope 55–59

trapping trails 209–210f

line drawing capabilities 58–59f

showdown 215–219

making the game 57–59

ultimate game play 219f

shoot ‘em-up games ix, 137–182

trapped 210–214

Snake Pit 137–157

strategy of the trails 214f

arena 137–140

background color 138f

snake images 137–138, 138f

V

snake pit image 139f

variables x, 25

customizing 155

creation of 3–4

King Cobra 151–157

testing 4–5

snake fight 156–157f

Virtual Game Library 17–19

snake bait 140–145

arrays, use of 19f

collision detection 141f

Virtual Game Library Pro Edition 20–22

primary actions in snake pit 144–145f

use of ArrayLists 21–22f

snake bite 146–150

display the battle 150f

W

sound, adding 46, 106–107, 127–128, 288

Space Destroyers 157–182

weapons, creating. see Space Destroyers, lasers landscape 157–160

Whack-an Evil Genius 95–110

making the game 158–160

customizing 110

spaceship and its initial movement 158f, 159f

getting smarter 102–106

lasers 160–165

game over 103f

creating aliens 160f

game play 105–106f

fighting aliens 163f, 164f, 165f

lab 95–98

life and death 174–182

game so far 98f

customizing 179

illustrative figures of JButton 96f

game play 180–182f

illustrative figure of JLabel 96f

retaliation 165–173

making the game 97–98

battle 171–173f

quick! get ‘em 98–102

statements x, 1, 25

game play 101–102f

if-statements x, 4–5, 25

making the game 99–102

strategy games ix, 183–220

showdown 106–110

string 4

addictive game play 110f

title image 107f

319

Table of Contents

ailable for free from www.mcgraw-hill.

www.books.mcgraw-hill.com/authors/cinnamon