A. クラス名を右クリックして「Convert to Java」を選択します。
A. Greenfoot.ask メソッドを使います。
なおテキストボックスを表示している間は動作が停止します。
z を押したら「好きな食べ物は?」を表示し、入力した文字列を画面に表示する例
public void act()
{
if( Greenfoot.isKeyDown( "z" ) ){
String answer = Greenfoot.ask( "好きな食べ物は?" );
getWorld().showText( answer, 100, 50 );
}
}
A. MouseInfo クラスを使うと出来ます。
// マウスが World 外にある時は null になるので注意
MouseInfo minfo = Greenfoot.getMouseInfo();
if( minfo != null ){
// マウス座標取得
int x = minfo.getX();
int y = minfo.getY();
getWorld().showText( "x="+x+",y="+y, 100, 50 );
// マウスボタンのクリック時に押したボタン番号を取得
// クリックした時だけ数値が入る。押しっぱなしの時やボタンを離した時は 0 になるので注意
int button = minfo.getButton();
if( button != 0 ){
getWorld().showText( "button="+button, 100, 100 );
}
// マウスを動かした時にカーソルの下にいるアクターを取得
// マウスを動かしてない時は null になるので注意
Actor actor = minfo.getActor();
if (actor != null){
getWorld().showText( "actor="+actor.getClass().getName(), 100, 150 );
}
}
A. removeObject メソッドの引数に this を指定します。
getWorld().removeObject( this );
A. isAtEdge メソッドを使うと自分が所属するワールドの端にいるかどうか分かります。
if( isAtEdge() ){
getWorld().removeObject( this );
}
A. getX 、getY メソッドで現在の自分の座標を取得できます。
int x = getX(); int y = getY();
A. getImage().getWidth() と getImage().getHeight() メソッドで自分の幅と高さを取得できます。
int w = getImage().getWidth(); int h = getImage().getHeight(); getWorld().showText( "width="+w+",height="+h, 100, 50 );
A. getImage().setTransparency() で透明度(0:透明〜255:不透明)を指定できます。コンストラクタあたりで指定しておくと良いと思います。
getImage().setTransparency(128);
A. 親クラスが World クラスか Actor クラスかでやり方が変わります。
親クラスが World クラスで、背景画像の大きさを変えたい場合はコンストラクタの中で getBackground().scale メソッドで幅と高さを変更できます。
例えば次のようにします。
getBackground().scale( 100, 100 );
親クラスが Actor クラスで、自画像の大きさを変えたい場合はコンストラクタの中で getImage().scale メソッドで幅と高さを変更できます。
ただしデフォルトではコンストラクタが無いので追加します。
この例ではクラス名を hoge としているので適宜変更する
public hoge()
{
getImage().scale( 100, 100 );
}
ただし act メソッドの中で繰り返し大きさを変更したい場合、次の様に getImage().scale を繰り返し呼び出すと画像が崩れて変になります。
失敗例: 画像が崩れる
この例ではクラス名を hoge としているので適宜変更する
import java.util.HashMap;
public class hoge extends Actor
{
private int width=50;
private int height= 50;
public hoge(){
getImage().scale( width,height );
}
public void act()
{
getImage().scale( width++,height++ );
}
}
そこでコンストラクタで画像のバックアップを取ってから、次の様に幅と高さを変更します。
成功例
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
private GreenfootImage img_bkup = null;
private int width=50;
private int height= 50;
public hoge(){
img_bkup = new GreenfootImage( getImage() );
getImage().scale( width,height );
}
public void act()
{
GreenfootImage img = new GreenfootImage(img_bkup);
// (注意) scale で画像サイズを変更してから setImage すること
img.scale( width++,height++ );
setImage(img);
}
}
なお次の様に setImage メソッドで画像をセットしてから scale で大きさを変更すると当たり判定が変になるので気をつけて下さい → 理由
失敗例: 当たり判定が変になる
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
private GreenfootImage img_bkup = null;
private int width=50;
private int height= 50;
public hoge(){
img_bkup = new GreenfootImage( getImage() );
getImage().scale( width,height );
}
public void act()
{
GreenfootImage img = new GreenfootImage(img_bkup);
// (注意) setImage してから scale で画像サイズを変更すると当たり判定が変になる
setImage(img);
getImage().scale( width++,height++ );
}
}
A. getX メソッドと getY メソッドで現在の座標を取得してから setLocation メソッドを使って移動先の座標を直接指定して動かせば画像は回転しません。
int x = getX();
int y = getY();
if( Greenfoot.isKeyDown( "left" ) ){
setLocation( x-1,y );
}
if( Greenfoot.isKeyDown( "right" ) ){
setLocation( x+1,y );
}
if( Greenfoot.isKeyDown( "up" ) ){
setLocation( x,y-1 );
}
if( Greenfoot.isKeyDown( "down" ) ){
setLocation( x,y+1 );
}
ちなみに、左右移動時に画像の向きを反転させたい時はフラグを一つ用意して次の様にします。
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
private boolean movingleft = true; // 画像が右向きの場合は false をセット
public void act()
{
int x = getX();
int y = getY();
if( Greenfoot.isKeyDown( "left" ) ){
if( ! movingleft ){
movingleft = true;
getImage().mirrorHorizontally();
}
setLocation( x-1,y );
}
if( Greenfoot.isKeyDown( "right" ) ){
if( movingleft ){
movingleft = false;
getImage().mirrorHorizontally();
}
setLocation( x+1,y );
}
if( Greenfoot.isKeyDown( "up" ) ){
setLocation( x,y-1 );
}
if( Greenfoot.isKeyDown( "down" ) ){
setLocation( x,y+1 );
}
}
}
A. コンストラクタで画像をロードしておいて、actメソッドの中で setImage で画像を変更できます。
右を押したら images フォルダ内にある neko.png に画像を変更する例
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
private GreenfootImage img = null;
public hoge()
{
img = new GreenfootImage( "images/neko.png" );
}
public void act()
{
if( Greenfoot.isKeyDown( "right" ) ){
setImage(img);
}
}
}
ちなみに、連想配列を使うと複数の画像が簡単に切り替えられます
連想配列を使って左を押すと left.png、右を押すと images フォルダ内にある right.png に切り替える例
この例ではクラス名を hoge としているので適宜変更する
import java.util.HashMap;
public class hoge extends Actor
{
private HashMap<String,GreenfootImage> imgmap = new HashMap<String,GreenfootImage>();
public hoge()
{
imgmap.put("left",new GreenfootImage( "images/left.png" ));
imgmap.put("right",new GreenfootImage( "images/right.png" ));
}
public void act()
{
if( Greenfoot.isKeyDown( "left" ) ){
setImage(imgmap.get("left"));
}
else if( Greenfoot.isKeyDown( "right" ) ){
setImage(imgmap.get("right"));
}
}
}
A. Greenfoot.delay() で一時停止(スリープ)します。引数で停止時間を指定しますが、秒数ではないので注意して下さい(スピードスライダーの値により停止する秒数が変化します)。
Greenfoot.delay(500);
A. 例として WorldTitle と WorldGame という 2 つのワールドがあるとします。
まずリセットボタンを押した時に表示するデフォルトワールドを WorldTitle にしたい時は、WorldTitle を右クリックして「new WorldTitle()」を選択します。
次に WorldTitle 表示中にスペースキーを押したら WorldGame に画面を切り替えるようにするには、以下のように WorldTitle に act メソッドを追加し、その中で Greenfoot.setWorld を呼び出します。
public void act()
{
if( Greenfoot.isKeyDown( "space" ) ){
World game = new WorldGame();
Greenfoot.setWorld( game );
}
}
A. GreenfootImage クラスを使って画像を読み込んでから getBackground().drawImage メソッドを使って画像を描画できます。
左キーを押したら images フォルダ内にある img1.png を座標(100,100)に、 img2.png を座標(200,200)に描画する例
public class MyWorld extends World
{
public MyWorld()
{
super(600, 400, 1);
}
public void act()
{
if( Greenfoot.isKeyDown( "left" ) ){
GreenfootImage img1 = new GreenfootImage( "images/img1.png" );
GreenfootImage img2 = new GreenfootImage( "images/img2.png" );
getBackground().drawImage( img1, 100, 100 );
getBackground().drawImage( img2, 200, 200 );
}
}
}
A. 背景画像とそれを左右反転させた画像を用意して images フォルダにコピーし、座標を変化させながら getBackground().drawImage で描画する
例えば
元画像 (800x450)
(クリックで拡大)
左右反転画像 (800x450)
(クリックで拡大)
という画像を images フォルダにコピーしてから MyWorld クラスを以下の様にする。
import greenfoot.*;
public class MyWorld extends World
{
GreenfootImage back;
GreenfootImage back_flop;
int back_dx = -5; // スクロール速度(マイナスにすると左から右)
int back_x = 0;
int back_width;
boolean flop = false;
public MyWorld()
{
super(800, 450, 1); // 画像サイズをセットする
back = new GreenfootImage( "./images/back.jpeg" );
back_flop = new GreenfootImage( "./images/back_flop.jpeg" );
back_width = back.getWidth();
}
public void act()
{
back_x += back_dx;
if( back_x > 0){
back_x -= back_width;
flop = !flop;
}
if( back_x < -back_width ){
back_x += back_width;
flop = !flop;
}
getBackground().drawImage( flop ? back_flop : back, back_x, 0 );
getBackground().drawImage( flop ? back : back_flop, back_x+back_width, 0 );
showText( "back_x : "+ back_x, 100, 10 );
}
}
A. カプセル化の観点からは好ましくありませんが、static public でフィールドを定義するのが一番手っ取り早いです。
下の例では MyWorld で定義したカウンタを MyWorld2 でも使い続けています。
MyWorld でカウンタの本体を定義
public class MyWorld extends World
{
static public int counter = 0; // カウンタ本体
public MyWorld()
{
super(600, 400, 1);
}
public void act()
{
++counter;
if( Greenfoot.isKeyDown( "space" ) ){ // スペースで MyWorld2 表示
World world2 = new MyWorld2();
Greenfoot.setWorld( world2 );
}
}
MyWorld2 でも MyWorldのカウンタを利用出来る
public class MyWorld2 extends World
{
public MyWorld2()
{
super(600, 400, 1);
}
public void act()
{
// MyWorld で定義されているカウンタを利用
MyWorld.counter++;
showText( "counter = " + MyWorld.counter, 100, 50 );
}
}
A. フィールドにフラグをひとつ用意すれば出来ます。
失敗例: スペースを押すと TAMA が高速大量に連射される
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
public void act()
{
if( Greenfoot.isKeyDown( "space" ) ){
getWorld().addObject( new TAMA(), getX(), getY() );
}
}
}
成功例 1: ブール型フラグを用意して一度スペースを離さないと次の TAMA が出ない様にする
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
private boolean flag_tama = false;
public void act()
{
if( Greenfoot.isKeyDown( "space" ) ){
if( flag_tama == false ){
getWorld().addObject( new TAMA(), getX(), getY() );
flag_tama = true;
}
}
else flag_tama = false;
}
}
成功例 2: int型フラグを用意してスペース押しっぱなしでも TAMA が発射される間隔を空ける様にする
この例ではクラス名を hoge としているので適宜変更する
public class hoge extends Actor
{
private int flag_tama = 0;
public void act()
{
if( flag_tama > 0 ) flag_tama--;
if( Greenfoot.isKeyDown( "space" ) ){
if( flag_tama == 0 ){
getWorld().addObject( new TAMA(), getX(), getY() );
flag_tama = 50; // 数字を変えると発射間隔が変わる
}
}
}
}
A. ワールドクラスの中(例えばコンストラクタ内)で setActOrder メソッドを呼ぶと、実行する(=描画する)クラスの順番を変更出来ます。なお、同じクラス内のキャラの実行順は変更できません。
以下の例では JIRO クラス → HANAKO クラス → TARO クラスの順に実行され、JIRO は HANAKO の下、HANDKO は TARO の下に描画される setActOrder(JIRO.class, HANAKO.class, TARO.class);
A. sounds フォルダの中に音声ファイルを入れてから Greenfoot.playSound メソッドを使います。
音声ファイルの形式は wav や MP3(※) 等です ※ greenfoot のバージョンが古いと MP3を再生出来ない場合があります
space を押したら test.wav を鳴らす例
public void act()
{
if( Greenfoot.isKeyDown( "space" ) ){
Greenfoot.playSound("test.wav");
}
}
A. まず sounds フォルダの中に音声ファイルを入れます。
音声ファイルの形式は wav や MP3(※) 等です ※ greenfoot のバージョンが古いと MP3を再生出来ない場合があります
それからコンストラクタの中で GreenfootSound クラスからそのファイルを読み込み、started メソッドで playLoop メソッドを、 stopped メソッドで stop メソッドを呼び出します。
test.mp3 を BGM として再生する例
public class MyWorld extends World
{
GreenfootSound bgm = null;
public MyWorld()
{
super(600, 400, 1);
bgm = new GreenfootSound( "test.mp3" );
}
public void started()
{
bgm.playLoop();
}
public void stopped()
{
bgm.stop();
}
}
A. 上のFAQの内容にしたがって BGM を鳴らしますが、それに加えてワールドを切り替えるときに明示的に started メソッドと stopeed メソッドを呼び出します。
MyWorld と MyWorld2 があって、Hoge というキャラクタが space キーを押すとワールドとBGM(test.mp3 → test2.mp3)を切り替える例
・ MyWorld クラス
public class MyWorld extends World
{
GreenfootSound bgm = null;
public MyWorld()
{
super(600, 400, 1);
bgm = new GreenfootSound( "test.mp3" );
}
public void started()
{
bgm.playLoop();
}
public void stopped()
{
bgm.stop();
}
}
・ MyWorld2 クラス
public class MyWorld2 extends World
{
GreenfootSound bgm = null;
public MyWorld2()
{
super(600, 400, 1);
bgm = new GreenfootSound( "test2.mp3" );
}
public void started()
{
bgm.playLoop();
}
public void stopped()
{
bgm.stop();
}
}
・ Hoge クラス
public class Hoge extends Actor
{
public void act()
{
if( Greenfoot.isKeyDown( "space" ) ){
getWorld().stopped();
World world = new MyWorld2();
Greenfoot.setWorld( world );
world.started();
}
}
}
A. タイトルロゴを Actor クラスのサブクラスとして作っておき、 World のフィールドで定義します。
それから World のコンストラクタで addObject() して表示しておき、run を押したら act() の中で一回だけ removeObject() を呼び出して消します。
例えば下の様にします。
public class MyWorld extends World
{
public Actor titlelogo = null;
public MyWorld()
{
super(600, 400, 1);
titlelogo = new TitleLogo();
addObject(titlelogo,100,100);
}
public void act()
{
if(titlelogo != null){
removeObject(titlelogo);
titlelogo = null;
}
}
}
A. 説明が難しいのでサンプルを参考にしてください。
A. 標準では出来ないので、MyWorld クラスに機能を追加する。
まず MyWorld クラスを以下の様に書き換える
import greenfoot.*;
import greenfoot.core.TextLabel;
import greenfoot.WorldVisitor;
import greenfoot.util.GraphicsUtilities;
import java.util.ArrayList;
import java.awt.Graphics2D;
public class MyWorld extends World
{
// Reffered from core/TextLabel.java
// Copyright (C) 2013,2014 Poul Henriksen and Michael Kolling
// Licence: GPL2
class TextLabelEx extends TextLabel
{
boolean enable;
int xpos;
int ypos;
int size;
boolean bold;
greenfoot.Color gfcolor;
java.awt.Color color;
String text;
String[] lines;
private GraphicsUtilities.MultiLineStringDimensions dimensions = null;
@Override
public int getX(){ return xpos;}
@Override
public int getY(){ return ypos;}
@Override
public String getText(){ return text;}
public TextLabelEx(String _text, int _xpos, int _ypos, int _size, boolean _bold, greenfoot.Color _gfcolor )
{
super("", 0, 0 );
lines = new String[1];
xpos = _xpos;
ypos = _ypos;
reset( _text, _size, _bold, _gfcolor );
}
public void reset( String _text, int _size, boolean _bold, greenfoot.Color _gfcolor )
{
if( text == _text && size == _size && bold == _bold && gfcolor == _gfcolor ) return;
text = _text;
size = _size;
bold = _bold;
gfcolor = _gfcolor;
lines[0] = text;
dimensions = null;
if( text.length() == 0 ) enable = false;
else enable = true;
}
@Override
public void draw(Graphics2D g, int cellsize)
{
if( !enable ) return;
if(dimensions == null) {
dimensions = GraphicsUtilities.getMultiLineStringDimensions(lines, bold ? java.awt.Font.BOLD : java.awt.Font.PLAIN, size);
color = new java.awt.Color( gfcolor.getRed(), gfcolor.getGreen(), gfcolor.getBlue(), gfcolor.getAlpha() );
}
int ydraw = ypos * cellsize - dimensions.getHeight() / 2 + cellsize / 2;
int xdraw = xpos * cellsize - dimensions.getWidth() / 2 + cellsize / 2;
g.translate(xdraw, ydraw);
GraphicsUtilities.drawOutlinedText(g, dimensions, color, java.awt.Color.BLACK);
g.translate(-xdraw, -ydraw);
}
}
public void showTextEx(String text, int x, int y, int size, boolean bold, greenfoot.Color color )
{
for( TextLabel label : WorldVisitor.getTextLabels(this) ){
if( label.getX() == x && label.getY() == y ){
if( label instanceof TextLabelEx ){
((TextLabelEx)label).reset(text, size, bold, color);
return;
}
}
}
WorldVisitor.getTextLabels(this).add(new TextLabelEx( text, x, y, size, bold, color ) );
//showText( "labels: "+WorldVisitor.getTextLabels(this).size(), 80, 20 );
}
public MyWorld()
{
super(600, 400, 1);
}
}
Actor クラスのサブクラスから上の MyWorld の中で定義した showTextEx() メソッドを以下の様にして呼び出す。
((MyWorld)getWorld()).showTextEx( 文字列, x 座標, y 座標, サイズ, 太字(true か false ), 色 ); ※ 色はマニュアルの Color のページを参考 使用例: ((MyWorld)getWorld()).showTextEx("hoge", 200, 200, 64, false, Color.RED );
MyWorld の中からは getWorld() を使わずに直接 showTextEx() メソッドを呼びだす。
showTextEx( 文字列, x 座標, y 座標, サイズ, 太字(true か false ), 色 ); ※ 色はマニュアルの Color のページを参考 使用例: showTextEx("hoge", 200, 200, 64, false, Color.RED );
A. 当たり判定を持っていないガワと当たり判定を持っている本体を作って同時に動かす。
まずActorの子クラスとして次の様に「ガワ(Gawa)」「本体(Hontai)」「敵(Teki)」を用意する(画像は適当)。
ガワ(Gawa)は次の様に何もしない。
import greenfoot.*;
public class Gawa extends Actor
{
public void act()
{
}
}
敵(Teki)も今回は動かさないので何もしない。
import greenfoot.*;
public class Teki extends Actor
{
public void act()
{
}
}
MyWorldクラスでは本体(Hontai)と敵(Teki)を addObject し、setActOrder 関数を使って本体(Hontai)よりもガワ(Gawa)の表示が下になるようにする。
import greenfoot.*;
public class MyWorld extends World
{
public MyWorld()
{
super(600, 400, 1);
addObject( new Hontai(), 100, 200 );
addObject( new Teki(), 200, 200 );
setActOrder(Gawa.class, Hontai.class);
}
}
最後に本体(Hontai)のactの中でガワ(Gawa)を作って同時に動かす。
import greenfoot.*;
public class Hontai extends Actor
{
Gawa gawa = null;
public Hontai()
{
// 当たり判定の大きさを調整
getImage().scale( 10, 10 );
// デバッグが終わったら 255 を 0 にして本体を透明にする
getImage().setTransparency(255);
}
public void act()
{
int x = getX();
int y = getY();
if( Greenfoot.isKeyDown( "left" ) ){
setLocation( x-1,y );
}
if( Greenfoot.isKeyDown( "right" ) ){
setLocation( x+1,y );
}
if( Greenfoot.isKeyDown( "up" ) ){
setLocation( x,y-1 );
}
if( Greenfoot.isKeyDown( "down" ) ){
setLocation( x,y+1 );
}
if(gawa == null){
gawa = new Gawa();
gawa.getImage().scale( 200, 200 );
getWorld().addObject(gawa,0,0);
}
gawa.setLocation(getX(),getY());
Actor teki = getOneIntersectingObject( Teki.class );
if( teki != null){
getWorld().showText( "ATARI", 100, 50 );
}
else{
getWorld().showText( "", 100, 50 );
}
}
}
実行すると下の図の様にガワ(Gawa)の部分が敵(Teki)と当たっても反応しなくなる。
当たり判定の大きさはコンストラクタの中にあるgetImage().scale関数で調整する。
デバッグが終わったらgetImage().setTransparency関数の数字を 0 にして本体(Hontai)を透明にする。