Q. StrideシナリオをJavaシナリオに変更したい

A. クラス名を右クリックして「Convert to Java」を選択します。


Q. テキストボックスを表示して文字列を入力したい。

A. Greenfoot.ask メソッドを使います。
なおテキストボックスを表示している間は動作が停止します。

z を押したら「好きな食べ物は?」を表示し、入力した文字列を画面に表示する例

public void act()
{
     if( Greenfoot.isKeyDown( "z" ) ){
         String answer = Greenfoot.ask( "好きな食べ物は?" );
         getWorld().showText( answer, 100, 50 );
     }
 }

Q. act メソッドの中でマウスの座標やクリックした時のボタン番号、カーソルの下にいるアクターを取得したい

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 );
            }
           
        }

Q. act メソッドの中で何かの条件を満たした時、他のオブジェクトでは無く自分自身を削除したい

A. removeObject メソッドの引数に this を指定します。

getWorld().removeObject( this );

Q. ワールドの端まで来たら自分自身を削除したい

A. isAtEdge メソッドを使うと自分が所属するワールドの端にいるかどうか分かります。

if( isAtEdge() ){
    getWorld().removeObject( this );
}

Q. act メソッドの中で自分自身の座標を取得したい

A. getX 、getY メソッドで現在の自分の座標を取得できます。

int x = getX();
int y = getY();

Q. act メソッドの中で自分自身の幅と高さを取得したい

A. getImage().getWidth() と getImage().getHeight() メソッドで自分の幅と高さを取得できます。

int w = getImage().getWidth();
int h = getImage().getHeight();
getWorld().showText( "width="+w+",height="+h, 100, 50 );

Q. 画像を半透明にしたい

A. getImage().setTransparency() で透明度(0:透明〜255:不透明)を指定できます。コンストラクタあたりで指定しておくと良いと思います。

getImage().setTransparency(128);

Q. 画像の大きさを変更したい

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++ );
    }
}

Q. setRotation と move を使ってオブジェクトを動かすと画像が回転してしまうが、回転させないで動かす方法は無いか?

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 );
        }
    }   
}

Q. 実行中にキャラクターの画像を変更したい

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")); 
        } 
    }     
}

Q. 一時停止(スリープ)したい

A. Greenfoot.delay() で一時停止(スリープ)します。引数で停止時間を指定しますが、秒数ではないので注意して下さい(スピードスライダーの値により停止する秒数が変化します)。

Greenfoot.delay(500);

Q. タイトル画面とかゲーム画面のように用途別にワールドを複数用意し、それらを切り替えて表示したい。

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 );
    }
}

Q. プロジェクトフォルダ内にある画像ファイルを読み込んでワールドクラスの背景に描画したい

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 );
        }
    }    

}

Q. 背景を無限スクロールさせたい

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 );
    }
}

Q. ワールドを切り替えたときに、他のワールドで使っていた(得点とかハイスコアみたいな)フィールドの値を使いたい

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 );
    }
}

Q. 弾などを発射したい時、キーを押しっぱなしにすると高速で連射状態になってしまう。一度キーから指を離さないと次の弾が出ないようにするか、少し間隔を開けて連射されるようにしたい。

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;  // 数字を変えると発射間隔が変わる
            }
        }
    }    
}

Q. キャラを実行する順番を変えたい、キャラを描画する順番を変更したい

A. ワールドクラスの中(例えばコンストラクタ内)で setActOrder メソッドを呼ぶと、実行する(=描画する)クラスの順番を変更出来ます。なお、同じクラス内のキャラの実行順は変更できません。

以下の例では JIRO クラス → HANAKO クラス → TARO クラスの順に実行され、JIRO は HANAKO の下、HANDKO は TARO の下に描画される

setActOrder(JIRO.class, HANAKO.class, TARO.class);

Q. 効果音を鳴らしたい

A. sounds フォルダの中に音声ファイルを入れてから Greenfoot.playSound メソッドを使います。
音声ファイルの形式は wav や MP3(※) 等です ※ greenfoot のバージョンが古いと MP3を再生出来ない場合があります

space を押したら test.wav を鳴らす例

public void act()
{
    if( Greenfoot.isKeyDown( "space" ) ){
            Greenfoot.playSound("test.wav");
    }
}

Q. ゲームを開始したらBGMを再生し、ゲームを停止したら BGM を停止したい

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();
    }
}



Q. ワールドを複数用意しておき、違うワールドに切り替えたら鳴らしている BGM も切り替えたい

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();
        }
    }    
}


Q. reset ボタンを押して停止状態の時はタイトルロゴを表示しておき、run ボタンを押してゲームが始まったらタイトルロゴを消したい

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;
        }
    }
}


Q. ジャンプアクションゲームを作りたいがジャンプの仕方とか地面との接地判定とかの仕方が分からない

A. 説明が難しいのでサンプルを参考にしてください。

Q. 文字列の大きさを変えたり、色を変えたり、太字にしたい

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 );