Browsing: Androidアプリ

Unityで2Dアクションゲーム開発Vol1



「Unity4.6/5.0でつくる 2Dゲーム制作入門」

この本の2Dアクションゲームを参考に、オリジナルのアクションゲームを作成します!

あくまで、参考書をベースに実装しているのでご了承ください。

■ゲームのテーマ
ハムスターが操作キャラで、左右&ジャンプボタンを使用して
ひまわりの種をあつめながら家を目指す。

色々な障害物などがある。
・床(動かない・動く・落ちる)
乗れます
・いがぐり(動かない・動く)
当たると死ぬ
・ひまわりの種
絵に触れるとゲットできます
・家
ひまわりの種をすべてゲットした状態で触れるとゴール
・ハリネズミ(敵・動く)
当たると死ぬ
・ブロック(押せる)
乗れます
・くるみ(上から落ちてくる)
当たると死ぬ
・猫の手(横から出てくる)
当たると死ぬ
・2弾ジャンプアイテム
ゲットすると2弾ジャンプできます。
・速度アップアイテム
ゲットすると移動速度がアップします。
・回転車(押せる)
乗れます

画面は横向きです。
画面より大きいマップの時はカメラが追従するようにします。

画面構成は、「トップ画面」「ステージ選択画面」「メイン画面」

■やること
1.操作キャラ実装
2.ゲームクリア・ゲームオーバー
3.各障害物の実装
4.バーチャルパッドの実装
5.カメラ追従機能の実装
6.各画面実装
7.ステージマップ作成
8.背景画像
9.絵の本番差替え
10.演出、音楽
11.広告導入
12.アナリティクス導入

と、まぁざっくりやることを列挙しました。

現在は2までやっていて、障害物を着々と実装しています。
※絵はとりあえずであててるので、あとからちゃんとした絵に差し替える予定です。
実装ずみの障害物は下記です。
・床(動かない・動く・落ちる)
・いがぐり(動かない・動く)
・ひまわりの種
・家
・回転車

■現在の進捗画像
%e9%80%b2%e6%8d%97%ef%bc%93

Unity始めたばかりで、最初のアプリ作成なので、色々苦戦してますが、何とかリリースまで行けるように頑張りたいと思います。

開発スピートは遅いですけど、頑張るぞーー

{ Add a Comment }

Unityはじめました!



Unityはじめました!

長らく更新していませんでした。
どうもお久しぶりです(誰も見てないかも知れませんが。)

9月に入ってからとうとうUnityをさわりはじめました!

始めるといっても使い方がさっぱりなので、どうしようか悩んでましたが。。

格安の参考書があったので購入して1ヶ月ほど勉強してました!

「Unity4.6/5.0でつくる 2Dゲーム制作入門」

ミニゲームを三つほど作成しながら勉強してくスタイルでした!
この内容で、なんと!「500円」でした!
すばらしい!
※購入時点ではKindle版のみでした。

と、まぁ別にこの参考書の宣伝したいわけではないんですけどねw

この参考書+もう一冊+ネットのチュートリアル的なものをやろうと思ったんですが、ゲーム作りたい欲が強すぎて早速開発に取りかかってしまいました(;・ω・)

2Dのアクションゲームつくります!
ざっくり言うと、ハムスターがひまわりの種を集めながら家に帰るゲームです。

Unityはじめてで苦戦しそうですが。。
がんばるぞー!

広告とかアナリティクスとかも実装して勉強しようと思います。

進捗随時更新していくのでお楽しみにー

{ Add a Comment }

Andengine_Android6以上でjava.lang.UnsatisfiedLinkErrorphysicsbox2dextension.so



Andengine Android6以上でエラー!!

java.lang.UnsatisfiedLinkError: dlopen failed: /data/app/{}-1/lib/arm/libandenginephysicsbox2dextension.so: has text relocations

Android6以上で重力ライブラリを使用した「ぼっちサッカー。。」で何やらエラーで出て強制終了してしまった。

調べてもよく分からなかったけど一個だけ同じような質問してるページを見つけた!!
要はライブラリ入れ替えて解決でした。

原因はよく分からなかったのですが、そこまで追求する気は今はないので
解決したのならオッケー!!


ここ
に書いてあるライブラリ入れ替え!

{ Add a Comment }

Unity2Dチュートリアルのたこ焼きゲームのParticleのスプライトが表示されない



へいへーい!
また躓いたので誰かさんの為に書いとくぜーい。

こちらのサイトでは。
【Unity2D】Unityで2Dミニゲームを作るチュートリアル

Unity_tutorial_error5

と表示されるけど

僕のUnityくんは表示されない。

Unity_tutorial_error6

なんじゃこりゃああああ!!

ん、これ背景の後ろに隠れてるだけじゃん!
Z-INDEXの指定が全Spriteで一緒だからこうなったのかな。

とりあえず「Order in Layer」を1にしてみたら表示された!

Unity_tutorial_error8

よしよし。いいかんじー

{ Add a Comment }

Unity2Dチュートリアルのたこ焼きゲームのNullReferenceException



今度は何よ!もう!

「NullReferenceException: Object reference not set to an instance of an object
Token.GetWorldMin (Boolean noMergin) (at Assets/Scripts/Token.cs:395)
Enemy.Update () (at Assets/Scripts/Enemy.cs:23)」

はい、こんなエラー。

Token.cs:395っていうとこの記述。

Camera.main.ViewportToWorldPoint (Vector2.zero);

ふむふむ、何やら「Cameraオブジェクトのインスタンスがない」と言ってる模様。

30分ほどチュートリアルと見比べました。

で!見つけた!
犯人はこの中にいる!

それはおまえだぁああああ!!


Unity_tutorial_error4

Tagが「Untagged」になってるじゃないの!!
チュートリアルだと「MainCamera」になってるわ!!

こんなことで30分以上つかってしまった。
Unity恐るべし。

仕組みはよくわかってないけどとりあえず今は動けばOKとしよう!

楽しくやらないとモチベーションが上がらないので
動いたー!たのしー!うひょひょー!!
とテンションがあがってから考えることにしよう。そうしよう。

とりあえず、これでたこ焼きくんが跳ね返るようになりました!

{ Add a Comment }

Unity2Dチュートリアルのたこ焼きゲームのToken.csビルドエラー



どうもどうも。

とうとう今日からUnityさわってみてます。

とりあえず3Dは難しそうなので2Dのチュートリアルしてます。

下記のチュートリアルでお世話になってます。
ありがたや。。
Unity2D】Unityで2Dミニゲームを作るチュートリアル

ところが途中でたこ焼きくんをランダムで動かそうとするときにエラーが。。。

ナンデナン。カイテアルトオリニヤッタノニ。。

all compiler errors have to be fixed before you can enter playmode

ん?何言ってんのこれ。
得意の翻訳サイトペタペタで解読してみると
「あなたがplaymodeを入力できる前に、すべてのコンパイラエラーは固定される必要がある」

むむむ。。まぁ要はコンパイルエラーあるから直せよってことかな?

どれどれ。どこがマズってんのよ。

UnityさんのConsoleに何かでてるじゃない。

・Assets/Scripts/Token.cs(211,19): error CS0619: `UnityEngine.Component.rigidbody2D’ is obsolete: `Property rigidbody2D has been deprecated. Use GetComponent() instead. (UnityUpgradable)’
・Assets/Scripts/Token.cs(211,31): error CS1061: Type `UnityEngine.Component’ does not contain a definition for `velocity’ and no extension method `velocity’ of type `UnityEngine.Component’ could be found (are you missing a using directive or an assembly reference?)
・Assets/Scripts/Token.cs(219,19): error CS0619: `UnityEngine.Component.rigidbody2D’ is obsolete: `Property rigidbody2D has been deprecated. Use GetComponent() instead. (UnityUpgradable)’
・Assets/Scripts/Token.cs(219,31): error CS1061: Type `UnityEngine.Component’ does not contain a definition for `velocity’ and no extension method `velocity’ of type `UnityEngine.Component’ could be found (are you missing a using directive or an assembly reference?)

・・・。。

あ、エディタみたら何かでてた。
変数みつかんないってことかな。

Unity_tutorial_error1

どれどれ、なるほど。
なんか定義してある変数と違うねー

Unity_tutorial_error2

ってことで
「Vector2 v = rigidbody2D.velocity;」
これを
「Vector2 v = _rigidbody2D.velocity;」
こうしました!

よし、とりあえず動いたので先に進めるとします!!

{ Add a Comment }

アプリレビューサイト掲載依頼



アプリ掲載申請

今日はすでにリリースしていた3つのアプリをレビュー依頼しました!

今までは下記のサイトへの掲載のみでした。
放課後アプリ部
アンドロイダー

今日は下記の3つに申請しました!
オクトバ
favroid
smapli

ちゃんと掲載されるかはわかりませんが、少しでもDL数が伸びればいいなー

{ Add a Comment }

ランキング機能実装!(リーダーボード)



さて、今回はいつもと変わって
以前にリリースしたアプリの機能追加についてです。

追加された機能はなんと!

ランキング機能

です!

実は前からランキング機能は組み込みたかったのですが
なかなか。。

無料でランキングのサービスを提供してないか探したのですが
なかなか希望にあうものがなくて。

自前でやるには今かりてるサーバーだとPHPで実装しないといけなかったり。
(PHPあんまり好きじゃなくてw)

だったのですが、ようやくPHPに手をだして実装しました!

Android側では
・ユニークID発行
・ニックネーム入力
・ユーザー情報追加・更新のPHPのリクエスト
・WebViewにPHP側で作成したランキングページを表示

ってとこですかね。

HttpURLConnectionを使用してユーザー情報更新PHPを呼び出すところが
苦戦しました。
POSTでのリクエスト時にパラメータを渡すのがわからなくて。

[java]
OutputStreamWriter osw = new OutputStreamWriter(con.getOutputStream());
BufferedWriter bw = new BufferedWriter(osw);
// POSTのパラメータ
bw.write(param);
bw.close();
osw.close();
[/java]

抜粋してかくと、ここでリクエストしつつパラメータを付与してます。
はまったのが、上記の前にHttpURLConnectionの「con.connect();」をしたので
その後エラーになってました。

まぁ、冷静に調べればわかることだったのですが
ちょっと焦ってましてw

ということで、下記のような感じになりました!

vol4_4
ランキングとニックネームの機能追加。

vol4_5
ランキング押下時にWebViewにランキングページ表示。

これでみんなでスコアを競って遊べますね!

じゃんじゃんあそんでね!

{ Add a Comment }

ブロック崩し&シューティングゲームVol5_ステージ選択解放処理&広告表示



前回までは
・画面の重力制御
・ボールの表示
・プレイヤーの移動&移動方向の補助線
・ゲームクリア
・ゲームオーバー
・制限時間
・敵の実装
 キーパー
 ディフェンダー
 ディフェンダー2
・当たり判定
・クラッシュエフェクト
・ステージセレクト

今回はステージ解放の条件と広告の実装をします。
※AdMobのダミー広告を表示します。
 AdMobのSDKの導入が既に済んでいる想定の説明です。

ステージ解放

前回までのステージの実装だと、無条件で選択できてしまいます。
ゲームのやりこみ性をあげるために、クリアしたらどんどんステージが解放されるようにしましょう。

クリアしたステージ情報の保持

[java]
MainScene.java

private void showGameClear(){
long clearStage = SPUtil.getInstance(getBaseActivity()).getClearStage();
if(stage > clearStage){
SPUtil.getInstance(getBaseActivity()).setClearStage(stage);
}

・・・省略・・・
}
[/java]
[java]
package org.geex.battlesoccerplayer;

import android.content.Context;
import android.content.SharedPreferences;

public class SPUtil {
// 自身のインスタンス
private static SPUtil instance;

// シングルトン
public static synchronized SPUtil getInstance(Context context) {
if (instance == null) {
instance = new SPUtil(context);
}
return instance;
}

private static SharedPreferences settings;
private static SharedPreferences.Editor editor;

private SPUtil(Context context) {
settings = context.getSharedPreferences("shared_preference_1.0", 0);
editor = settings.edit();
}

public long getClearStage() {
return settings.getLong("ClearStage", 0);
}
public void setClearStage(long value) {
editor.putLong("ClearStage", value);
editor.commit();
}
}
[/java]
showGameClear時に、既に設定してあるステージクリア情報より大きい場合に更新するようにします。
(getClearStage/setClearStage)
※SPUtilの仕組みも「AndEngineでつくるAndroid 2Dゲーム」に記載があります。

[java]
StageSelectScene.java

@Override
public void init() {

if (0 <= clearStage) {

long clearStage = SPUtil.getInstance(getBaseActivity()).getClearStage();

if (1 <= clearStage) {
ButtonSprite stage2Btn = getBaseActivity().getResourceUtil()
.getButtonSprite("selectStage2.png", "selectStage2_2.png");
stage2Btn.setPosition((camera.getWidth() / 4) * 2 – (stage2Btn.getWidth() / 2), line1_height);
stage2Btn.setTag(TAG_BTN2);
stage2Btn.setOnClickListener(this);
attachChild(stage2Btn);
registerTouchArea(stage2Btn);
} else {
Sprite stage2Btn = getBaseActivity().getResourceUtil().getSprite("selectStage2_3.png");
stage2Btn.setPosition((camera.getWidth() / 4) * 2 – (stage2Btn.getWidth() / 2), line1_height);
attachChild(stage2Btn);
}

・・・省略・・・
}
[/java]
保持しているステージクリア情報を取得して、各ステージボタン表示の判定をしていきます。
>if (1 <= clearStage) { ステージクリア情報が「1」以上の場合、ステージ「②」のボタンをボタンスプライトで表示します。 elseの場合はただのスプライトで表示して、クリックしても意味がないようにします。 これを各ステージボタン毎に設定します。 そうすると、前ステージをクリアしていない場合は、ステージ選択できないようにする制御が可能になります。
vol6_10

広告の実装

トップ画面の下部とステージ画面の真ん中に広告を表示します。

activity_main.xmlにLinearLayoutで画面下部と画面中央に広告表示領域を確保します。

トップページの広告

[java]
MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

addAdView();
}

public void addAdView(){
if(null == adView) {
adView = new AdView(this);
adView.setAdUnitId("ca-app-pub-3940256099942544/6300978111"); // テスト用ID
adView.setAdSize(AdSize.BANNER);

layout_ad = (LinearLayout) findViewById(R.id.banner1);
layout_ad.addView(adView);

//AdRequest adRequest = new AdRequest.Builder().build();

AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR) // エミュレータ
.build();

adView.loadAd(adRequest);
}
}

public void removeAdView(){
layout_ad.removeView(adView);
adView = null;
}
[/java]

上記でトップ画面表示時に広告が表示できました。

ただし、このままだと画面遷移しても広告が表示されっぱなしになるので
InitialSceneで画面遷移時に広告の表示を削除します。
[java]
getBaseActivity().runOnUiThread(new Runnable(){
@Override
public void run() {
((MainActivity)getBaseActivity()).removeAdView();
}
});
[/java]

ステージ選択画面の広告

[java]
MainActivity.java

public void addAdView2(){
if(null == adView2) {
adView2 = new AdView(this);
adView2.setAdUnitId("ca-app-pub-3940256099942544/6300978111"); // テスト用ID
adView2.setAdSize(AdSize.BANNER);

layout_ad = (LinearLayout) findViewById(R.id.banner2);
layout_ad.addView(adView2);

//AdRequest adRequest = new AdRequest.Builder().build();

AdRequest adRequest = new AdRequest.Builder()
.addTestDevice(AdRequest.DEVICE_ID_EMULATOR) // エミュレータ
.addTestDevice("333B0DEDC6F2112DF53F6C3579DCD5DB") // テストデバイス
.build();

adView2.loadAd(adRequest);
}
}

public void removeAdView2(){
layout_ad.removeView(adView2);
adView2 = null;
}

[/java]
[java]
StageSelectScene.java

@Override
public void init() {
getBaseActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
((MainActivity) getBaseActivity()).addAdView2();
}
});

・・・省略・・・
}

public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX,
float pTouchAreaLocalY) {

getBaseActivity().runOnUiThread(new Runnable(){
@Override
public void run() {
((MainActivity)getBaseActivity()).removeAdView2();
}
});

・・・省略・・・
}
[/java]
StageSelectSceneのinitメソッドで広告の表示をするために
addAdView2を呼び出します。
画面遷移時にremoveAdView2を呼び出します。

これで、トップ画面・ステージ選択画面に広告が表示されるようになりました。

vol6_9

vol6_10

実際にリリースする際には、「ca-app-pub-3940256099942544/6300978111」のテスト用IDを
AdMobで実際に発行した広告枠のIDに変更する必要があります。

ほぼアプリの機能が完成しました!

後は、音楽とGoogleアナリティクスの設定と画像をちゃんとしたものに差し替えを行います。
ゲームクリア時の文字の表示方法もできれば変えたい。

そろそろアプリリリースに近づいてきました!
最後までがんばるぞー

{ Add a Comment }

ブロック崩し&シューティングゲームVol5_ステージ選択画面実装



前回までは
・画面の重力制御
・ボールの表示
・プレイヤーの移動&移動方向の補助線
・ゲームクリア
・ゲームオーバー
・制限時間
・敵の実装
 キーパー
 ディフェンダー
 ディフェンダー2
・当たり判定
・クラッシュエフェクト

今回はステージ選択画面を作成し、各ステージ毎に敵の配置を変えます。

ステージ選択

まず初めに、Secneを作成し、シーンの遷移を制御します。
現在は、MainActivity→InitialScene→MainSecne
修正後は、MainActivity→InitialScene→StageSelectScene→MainSecne
のようなシーンにします。

StageSelectSceneを作成

[java]
package org.geex.battlesoccerplayer;

import java.awt.Font;
import java.awt.event.KeyEvent;
import java.io.IOException;

public class StageSelectScene extends KeyListenScene implements
ButtonSprite.OnClickListener {

private Font font;

private Camera camera;

private static final int TAG_BTN1 = 1;
private static final int TAG_BTN2 = 2;
private static final int TAG_BTN3 = 3;

public StageSelectScene(MultiSceneActivity context) {
super(context);
init();
}

@Override
public void init() {
camera = getBaseActivity().getEngine().getCamera();

font = FontFactory.create(getBaseActivity().getFontManager(), getBaseActivity().getTextureManager(), 256, 256, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32);
font.load();

Text title = new Text(0, 0, this.font,
"ステージセレクト" +
"", new TextOptions(HorizontalAlign.CENTER), getBaseActivity().getVertexBufferObjectManager());
title.setPosition(camera.getWidth() / 2 – title.getWidth() / 2, 100);
attachChild(title);

Sprite bg = getBaseActivity().getResourceUtil().getSprite(
"stageSelect.png");
bg.setPosition(0, 0);
attachChild(bg);

Sprite sprite = getBaseActivity().getResourceUtil().getSprite("pcman.png");
sprite.setPosition(20, 50 );
sprite.setScale(1.3f);
attachChild(sprite);

Sprite spriteTip = getBaseActivity().getResourceUtil().getSprite("stageSelectTip.png");
spriteTip.setPosition(150, 60);
spriteTip.setScale(1.5f);
attachChild(spriteTip);

int line1_height = 180;

ButtonSprite stage1Btn = getBaseActivity().getResourceUtil()
.getButtonSprite("selectStage1.png", "selectStage1_2.png");
stage1Btn.setPosition((camera.getWidth() / 4) – (stage1Btn.getWidth() / 2), line1_height);
stage1Btn.setTag(TAG_BTN1);
stage1Btn.setOnClickListener(this);
attachChild(stage1Btn);
registerTouchArea(stage1Btn);

ButtonSprite stage2Btn = getBaseActivity().getResourceUtil()
.getButtonSprite("selectStage2.png", "selectStage2_2.png");
stage2Btn.setPosition((camera.getWidth() / 4) * 2 – (stage2Btn.getWidth() / 2), line1_height);
stage2Btn.setTag(TAG_BTN2);
stage2Btn.setOnClickListener(this);
attachChild(stage2Btn);
registerTouchArea(stage2Btn);

ButtonSprite stage3Btn = getBaseActivity().getResourceUtil()
.getButtonSprite("selectStage3.png", "selectStage3_2.png");
stage3Btn.setPosition((camera.getWidth() / 4) * 3 – (stage3Btn.getWidth() / 2), line1_height);
stage3Btn.setTag(TAG_BTN3);
stage3Btn.setOnClickListener(this);
attachChild(stage3Btn);
registerTouchArea(stage3Btn);
}

public void onClick(ButtonSprite pButtonSprite, float pTouchAreaLocalX,
float pTouchAreaLocalY) {

ResourceUtil.getInstance(getBaseActivity()).resetAllTexture();
KeyListenScene scene = new MainScene(getBaseActivity(), MainActivity.camera, pButtonSprite.getTag());
// MainSceneへ移動
getBaseActivity().getEngine().setScene(scene);
// 遷移管理用配列に追加
getBaseActivity().appendScene(scene);

}
}
[/java]
特に難しい事はしてません。
ボタンを配置して、クリックイベントを拾ってMainSceneに移動しているだけ。
MainSceneのコンテキストで、どのステージのボタンが押下されたかの情報を渡しています。(pButtonSprite.getTag())

InitialSceneから画面遷移する際に、MainSceneをセットしていたのをStageSelectSceneに変更します。
※この当たりは「AndEngineでつくるAndroid 2Dゲーム」に記載があるので割愛します。

[java]
private void setStageData(int stage){

if(1 == stage){
currentTime = 30;
}else if(2 == stage){
currentTime = 20;
addEnemyPlayer(camera.getWidth() / 4 – 25, camera.getHeight() / 4);
addEnemyPlayer(camera.getWidth() / 2 – 25, camera.getHeight() / 4);
addEnemyPlayer2(camera.getWidth() – (camera.getWidth()) / 4 – 25, camera.getHeight() / 4);
}else if(3 == stage){
currentTime = 20;
addEnemyKeeper(camera.getWidth() / 2, 50);
}
}
[/java]
setStageDataメソッドで各ステージの設定を行います。
※initメソッドから呼び出しています。

currentTime:制限時間
addEnemyPlayer:ディフェンダーの位置を指定して配置
addEnemyPlayer2:ディフェンダー2の位置を指定して配置
addEnemyKeeper:ディフェンダー2の位置を指定して配置

ステージ毎に配置を変えるだけで、たくさんのステージが増やせますね!

vol6_8

今回は、Andengineの基本の部分の画面遷移が主だったので、かなり説明を簡単にしてます。
分からないことがあれば気軽にコメントください。

広告表示エリアが勢いあまって表示されてますが、それは次回記載します。

次回は
・ステージ解放の条件
・広告実装

おたのしみにー

{ Add a Comment }