flash rpg map scroll FlashでRPGのマップスクロールを作成
4x4のマップではスクロールするまでもないので、16x16のマップで、DragonQuestふうにマップがスクロールするようにする。
Flashで外部swfに埋め込んだMovieClipを使う の続き
ところでマップはどう作ろうか?
とりあえずExcel(互換ソフト)で作ってみた。
しかし、Excelや互換ソフトの関数だとセルの色を認識せず、セルを色分けてもそれをCSV出力などできないらしい。
Tiled Map Editor を使い、マップを並べてみる。 http://gushernobindsme.hatenablog.com/entry/2014/03/01/155532 http://2dgames.jp/2013/08/01/tiledmapeditor/ を参考にした。なんだか難しそうに思えたが、[ファイル-新しいファイル]で開始して、[マップ-新しいマップセット]でマップタイル(マップチップ)画像を読み込むだけだった。
必要なマップタイル(マップチップ)はFlash Proで作成して、32x32単位で配置して、72dpiでpng出力して、TiledMapEditorで[マップ-新しいマップセット]で読み込んだ。
Tiled Map Editorで[ファイル - 名前をつけて保存]で出力したjson形式だと以下のようなファイルになりましたよ。
{ "height":16,
"layers":[
{
"data":[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 3, 17, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3, 3, 1, 1, 3, 3, 15, 15, 3, 3, 3, 3, 1, 3, 3, 15, 15, 3, 1, 1, 3, 15, 15, 17, 15, 3, 3, 3, 3, 3, 3, 3, 15, 5, 1, 1, 3, 15, 15, 5, 5, 15, 3, 3, 3, 3, 3, 15, 15, 5, 1, 1, 3, 3, 15, 5, 5, 15, 15, 3, 3, 3, 3, 15, 17, 5, 1, 1, 1, 3, 15, 5, 5, 5, 5, 3, 3, 3, 15, 15, 5, 5, 1, 1, 1, 1, 15, 5, 5, 5, 5, 3, 3, 3, 3, 15, 15, 15, 1, 1, 1, 3, 15, 15, 5, 5, 3, 3, 3, 3, 17, 3, 3, 15, 1, 1, 1, 3, 17, 15, 15, 3, 3, 1, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 5, 3, 15, 15, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 3, 3, 15, 1, 1, 15, 15, 1, 15, 15, 1, 1, 1, 3, 5, 5, 5, 3, 3, 1, 15, 5, 5, 5, 15, 17, 15, 1, 1, 1, 3, 3, 5, 5, 5, 5, 5, 5, 15, 5, 5, 5, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
"height":16,
"name":"\u30bf\u30a4\u30eb\u30fb\u30ec\u30a4\u30e4\u30fc1",
"opacity":1,
"type":"tilelayer",
"visible":true,
"width":16,
"x":0,
"y":0
}],
"orientation":"orthogonal",
"properties":
{
},
"tileheight":32,
"tilesets":[
{
"firstgid":1,
"image":"maptipCS3.png",
"imageheight":110,
"imagewidth":224,
"margin":0,
"name":"maptipCS3",
"properties":
{
},
"spacing":0,
"tileheight":32,
"tilewidth":32
}],
"tilewidth":32,
"version":1,
"width":16
}この数字をマップチップと対照させると
var tilename:Object = {
1:'Sea', 3:'Grass', 5:'Sand', 7:'Player', 15:'Mountain', 17:'Event', 19:'Enemy1', 21:'Enemy2'
};となるのか。
まずはFlashで表示を試す。Main.asを以下のように変更。Preloader.asは前回のまま。
Main.as
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* @author itouhiro
*/
[SWF(width = "160", height = "160", frameRate = "30", backgroundColor = "0x888888")]
public class Main extends Sprite {
static public var isLoaded:Boolean = false;
static public var maptip:Object;
var tilename:Object = {1:'Sea', 3:'Grass', 5:'Sand', 7:'Player', 15:'Mountain', 17:'Event', 19:'Enemy1', 21:'Enemy2'};
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
maptip = { };
var maptipNames:Array = [];
for (var key in tilename) { maptipNames.push('Map' + tilename[key]); }
var preload:Preloader = new Preloader(maptipNames);
addChild(preload);
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
private function enterFrameHandler(e:Event):void {
if ( ! isLoaded) return;
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
var mapData:Array = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 3, 17, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3, 3, 1, 1, 3, 3, 15, 15, 3, 3, 3, 3, 1, 3, 3, 15, 15, 3, 1, 1, 3, 15, 15, 17, 15, 3, 3, 3, 3, 3, 3, 3, 15, 5, 1, 1, 3, 15, 15, 5, 5, 15, 3, 3, 3, 3, 3, 15, 15, 5, 1, 1, 3, 3, 15, 5, 5, 15, 15, 3, 3, 3, 3, 15, 17, 5, 1, 1, 1, 3, 15, 5, 5, 5, 5, 3, 3, 3, 15, 15, 5, 5, 1, 1, 1, 1, 15, 5, 5, 5, 5, 3, 3, 3, 3, 15, 15, 15, 1, 1, 1, 3, 15, 15, 5, 5, 3, 3, 3, 3, 17, 3, 3, 15, 1, 1, 1, 3, 17, 15, 15, 3, 3, 1, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 5, 3, 15, 15, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 3, 3, 15, 1, 1, 15, 15, 1, 15, 15, 1, 1, 1, 3, 5, 5, 5, 3, 3, 1, 15, 5, 5, 5, 15, 17, 15, 1, 1, 1, 3, 3, 5, 5, 5, 5, 5, 5, 15, 5, 5, 5, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
var mapWidth:int = 16;
var map:Sprite = new Sprite();
var mc:MovieClip;
for (var ay:int = 0; ay < mapWidth; ay++) {
for (var ax:int = 0; ax < mapData.length/mapWidth; ax++) {
mc = new maptip['Map'+tilename[mapData[ay*mapWidth+ax]]];
mc.x = ax * 32;
mc.y = ay * 32;
map.addChild(mc);
}
}
addChild(map);
mc = new maptip['MapPlayer'];
mc.x = 96;
mc.y = 32;
addChild(mc);
}
}
}実Flash。まだ操作不可。
修正する。
- 160x160pxでは表示範囲が狭いので、480x480pxのウィンドウにする。
- マップの外は海にする。
- カーソルキーで動作可能。
- 当たり判定をつける(海や山には入れない)。
Main.as
package {
import flash.display.MovieClip;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.ui.Keyboard;
/**
* ...
* @author itouhiro
*/
[SWF(width = "480", height = "480", frameRate = "30", backgroundColor = "0x888888")]
public class Main extends Sprite {
static public var isLoaded:Boolean = false;
static public var maptip:Object;
private var tilename:Object = { 1:'Sea', 3:'Grass', 5:'Sand', 7:'Player', 15:'Mountain', 17:'Event', 19:'Enemy1', 21:'Enemy2' };
private var map:MovieClip;
private var player:Sprite;
public function Main():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
maptip = { };
var maptipNames:Array = [];
for (var key in tilename) { maptipNames.push('Map' + tilename[key]); }
var preload:Preloader = new Preloader(maptipNames);
addChild(preload);
addEventListener(Event.ENTER_FRAME, initHandler);
}
private function initHandler(e:Event):void {
if ( ! isLoaded) return;
removeEventListener(Event.ENTER_FRAME, initHandler);
if ( ! map) mapInit();
addChild(map);
player = new maptip['MapPlayer'];
player.x = 480/2-16;
player.y = 480/2-16;
addChild(player);
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
addEventListener(Event.ENTER_FRAME, worldHandler);
//trace('initHandler');
}
private function keyDownHandler(e:KeyboardEvent):void {
if (map.nx !== 0 || map.ny !== 0) return;
var step:int = 32;
if (e.keyCode === Keyboard.UP) map.ny = step;
else if (e.keyCode === Keyboard.DOWN) map.ny = -step;
else if (e.keyCode === Keyboard.RIGHT) map.nx = -step;
else if (e.keyCode === Keyboard.LEFT) map.nx = step;
//trace('keyDownHandler e.keyCode:'+e.keyCode);
}
private function worldHandler(e:Event):void {
if (map.nx === 0 && map.ny === 0) return;
//trace('worldHandler');
var step:int = 4;
if (map.nx) {
if (Math.abs(map.nx) === 32) {
var nextX = map.nx > 0 ? 1 : -1;
if (isBlock(map.tile[map.py][map.px - nextX])) {
map.nx = 0;
return;
}
}
map.x += map.nx > 0 ? step : -step;
var dx = map.nx; //delta x
map.nx -= map.nx > 0 ? step : -step;
if (map.nx === 0) { map.px -= dx > 0 ? 1 : -1; trace('player:' + map.px +','+ map.py);}
}
if (map.ny) {
if (Math.abs(map.ny) === 32) {
var nextY = map.ny > 0 ? 1 : -1;
if (isBlock(map.tile[map.py - nextY][map.px])) {
map.ny = 0;
return;
}
}
map.y += map.ny > 0 ? step : -step;
var dy = map.ny;
map.ny -= map.ny > 0 ? step : -step;
if (map.ny === 0) { map.py -= dy > 0 ? 1 : -1; trace('player:' + map.px +','+ map.py);}
}
}
private function isBlock(tile:int):Boolean {
if (tile === 17) {
doEvent();
return false;
}else if (tile === 1 || tile === 15) {
return true;
}else {
return false;
}
}
private function doEvent():void {
return;
}
private function mapInit():void {
map = new MovieClip();
map.tile = [];
var mapData:Array = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 3, 3, 1, 1, 1, 3, 17, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 3, 3, 1, 1, 3, 3, 15, 15, 3, 3, 3, 3, 1, 3, 3, 15, 15, 3, 1, 1, 3, 15, 15, 17, 15, 3, 3, 3, 3, 3, 3, 3, 15, 5, 1, 1, 3, 15, 15, 5, 5, 15, 3, 3, 3, 3, 3, 15, 15, 5, 1, 1, 3, 3, 15, 5, 5, 15, 15, 3, 3, 3, 3, 15, 17, 5, 1, 1, 1, 3, 15, 5, 5, 5, 5, 3, 3, 3, 15, 15, 5, 5, 1, 1, 1, 1, 15, 5, 5, 5, 5, 3, 3, 3, 3, 15, 15, 15, 1, 1, 1, 3, 15, 15, 5, 5, 3, 3, 3, 3, 17, 3, 3, 15, 1, 1, 1, 3, 17, 15, 15, 3, 3, 1, 3, 3, 3, 3, 3, 1, 1, 1, 3, 3, 5, 3, 15, 15, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 5, 5, 3, 3, 15, 1, 1, 15, 15, 1, 15, 15, 1, 1, 1, 3, 5, 5, 5, 3, 3, 1, 15, 5, 5, 5, 15, 17, 15, 1, 1, 1, 3, 3, 5, 5, 5, 5, 5, 5, 15, 5, 5, 5, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
var mapWidth:int = 16;
var mc:MovieClip;
for (var ay:int = -12; ay < mapWidth + 12; ay++) {
if (ay >= 0 && ! map.tile[ay]) map.tile[ay] = [];
for (var ax:int = -12; ax < (mapData.length / mapWidth) + 12; ax++) {
if (ax < 0 || ay < 0 || ax >= mapWidth || ay * mapWidth + ax >= mapData.length) {
mc = new maptip['MapSea'];
}else{
mc = new maptip['Map' + tilename[mapData[ay * mapWidth + ax]]];
map.tile[ay][ax] = mapData[ay * mapWidth + ax];
}
mc.x = ax * 32;
mc.y = ay * 32;
map.addChild(mc);
}
}
map.px = 13; //player x(tile num)
map.py = 10;
map.x = (7 - map.px) * 32;
map.y = (7 - map.py) * 32;
map.nx = 0; // next moving x delta
map.ny = 0;
}
}
}実Flash。操作可。
次。立ち止まったとき、ステータスウィンドウを表示。 まだフォントはlocalにある(OSの)フォントを使用している(つまりlocalにインストールされていないとフォントが別ので表示される)。
--- a/src/Main.as
+++ b/src/Main.as
@@ -1,9 +1,13 @@
package {
+ import flash.display.GradientType;
+ import flash.display.Graphics;
import flash.display.MovieClip;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.KeyboardEvent;
+ import flash.text.TextField;
+ import flash.text.TextFormat;
import flash.ui.Keyboard;
/**
@@ -14,9 +18,11 @@
public class Main extends Sprite {
static public var isLoaded:Boolean = false;
static public var maptip:Object;
- var tilename:Object = { 1:'Sea', 3:'Grass', 5:'Sand', 7:'Player', 15:'Mountain', 17:'Event', 19:'Enemy1', 21:'Enemy2' };
- var map:MovieClip;
- var player:Sprite;
+ private var tilename:Object = { 1:'Sea', 3:'Grass', 5:'Sand', 7:'Player', 15:'Mountain', 17:'Event', 19:'Enemy1', 21:'Enemy2' };
+ private var map:MovieClip;
+ private var player:MovieClip;
+ private var statusWindow:Sprite;
+ private var isDisplayStatus:Boolean;
public function Main():void {
if (stage) init();
@@ -28,7 +34,7 @@
// entry point
maptip = { };
var maptipNames:Array = [];
- for (var key in tilename) { maptipNames.push('Map' + tilename[key]); }
+ for (var key:String in tilename) { maptipNames.push('Map' + tilename[key]); }
var preload:Preloader = new Preloader(maptipNames);
addChild(preload);
addEventListener(Event.ENTER_FRAME, initHandler);
@@ -41,8 +47,15 @@
addChild(map);
player = new maptip['MapPlayer'];
player.x = 480/2-16;
- player.y = 480/2-16;
+ player.y = 480 / 2 - 16;
+ player.name = 'えにくす';
+ player.level = 1;
+ player.energy = 99;
+ player.magic = 12;
+ player.exp = 5;
addChild(player);
+ player.stopCount = 0;
+ statusWindow = null;
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
addEventListener(Event.ENTER_FRAME, worldHandler);
//trace('initHandler');
@@ -59,21 +72,26 @@
}
private function worldHandler(e:Event):void {
+ player.stopCount++;
+ if (player.stopCount > 60 && ! statusWindow) displayStatus();
+
if (map.nx === 0 && map.ny === 0) return;
+ player.stopCount = 0;
+ if (statusWindow) { removeChild(statusWindow); statusWindow = null; }
//trace('worldHandler');
var step:int = 4;
if (map.nx) {
if (Math.abs(map.nx) === 32) {
- var nextX = map.nx > 0 ? 1 : -1;
+ var nextX:int = map.nx > 0 ? 1 : -1;
if (isBlock(map.tile[map.py][map.px - nextX])) {
map.nx = 0;
return;
}
}
map.x += map.nx > 0 ? step : -step;
- var dx = map.nx; //delta x
+ var dx:int = map.nx; //delta x
map.nx -= map.nx > 0 ? step : -step;
- if (map.nx === 0) { map.px -= dx > 0 ? 1 : -1; trace('player:' + map.px +','+ map.py);}
+ if (map.nx === 0) { map.px -= dx > 0 ? 1 : -1; trace('player:' + map.px +',' + map.py); }
}
if (map.ny) {
if (Math.abs(map.ny) === 32) {
@@ -90,6 +108,41 @@
}
}
+ private function displayStatus():void {
+ statusWindow = new Sprite();
+ var g:Graphics = statusWindow.graphics;
+ g.beginFill(0x000000, 0.7);
+ g.lineStyle(2, 0xffffff);
+ g.drawRoundRect(0, 0, 120, 168, 15, 15);
+ g.endFill();
+ statusWindow.x = 25;
+ statusWindow.y = 20;
+ var msg:Array = [player.name, 'レベル ' + fmtNum(player.level, 2), 'HP ' + fmtNum(player.energy, 3), 'MP ' + fmtNum(player.magic, 3), 'E ' + fmtNum(player.exp, 4)];
+ for (var i:int = 0; i < msg.length; i++) {
+ putChars(msg[i], statusWindow, 8, i*32);
+ }
+ addChild(statusWindow);
+ }
+
+ private function putChars(msg:String, theWindow:Sprite, locX:int, locY:int):void {
+ var chars:TextField = new TextField();
+ chars.defaultTextFormat = new TextFormat('Ueten 2m medium', 18, 0xffffff);
+ chars.text = msg;
+ chars.x = locX;
+ chars.y = locY;
+ theWindow.addChild(chars);
+ }
+
+ private function fmtNum(num:int, len:int):String {
+ var han2zen:Object = { 0:'0', 1:'1', 2:'2', 3:'3', 4:'4', 5:'5', 6:'6', 7:'7', 8:'8', 9:'9' };
+ var numZen = ' ';
+ var numHan = num.toString();
+ for (var i:int = 0; i < numHan.length; i++) {
+ numZen += han2zen[numHan.charAt(i)];
+ }
+ return numZen.substr( -len);
+ }
+
private function isBlock(tile:int):Boolean {
if (tile === 17) {
doEvent();



0 件のコメント:
コメントを投稿