flash on 2011-10-7
キャラクターの位置を基準とした画面スクロール処理のスケッチ
仕様
====
世界全体の広さを200x200 とする
世界全体は、縮小表示して画面いっぱいに表示されることもあるし(キャラクターがどこに居ようとスクロールの必要なし)、一部がズームアップして拡大されることもある(スクロール処理が必要)
世界の4隅に来た場合は行き止まり
スクロール処理
==============
表示画面が世界全体の一部である時はスクロール処理が必要
世界の左上の行き止まり処理をするために、キャラクターが2 の位置に来た時にスクロールを開始するようマージンをとる
[世 界 全 体]
margine
+-------|-------+------------------+
|1 | |
| | |
margine - 2 | |
| | |
| [表示画面] | |
+---------------+ |
| |
| |
| |
| |
| |
+----------------------------------+
世界の右下の行き止まり処理をするため、スクロールの最大量は下の図のA, B の範囲とし、上限を設定する
[世 界 全 体]
+----------------------------------+
| ^ |
| [表示画面の ] |
♥0 |
Line 108 |
Modified 2011-10-17 14:35:31 |
MIT License
archived:2017-03-20 07:02:24
ActionScript3 source code
/**
* Copyright harupiyo ( http://wonderfl.net/user/harupiyo )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/jwZy
*/
// キャラクターの位置を基準とした画面スクロール処理のスケッチ
//
// 仕様
// ====
//
// * 世界全体の広さを200x200 とする
// * 世界全体は、縮小表示して画面いっぱいに表示されることもあるし(キャラクターがどこに居ようとスクロールの必要なし)、一部がズームアップして拡大されることもある(スクロール処理が必要)
// * 世界の4隅に来た場合は行き止まり
//
// スクロール処理
// ==============
//
// * 表示画面が世界全体の一部である時はスクロール処理が必要
// * 世界の左上の行き止まり処理をするために、キャラクターが2 の位置に来た時にスクロールを開始するようマージンをとる
// [世 界 全 体]
// margine
// +-------|-------+------------------+
// |1 | |
// | | |
// margine - 2 | |
// | | |
// | [表示画面] | |
// +---------------+ |
// | |
// | |
// | |
// | |
// | |
// +----------------------------------+
// * 世界の右下の行き止まり処理をするため、スクロールの最大量は下の図のA, B の範囲とし、上限を設定する
// [世 界 全 体]
// +----------------------------------+
// | ^ |
// | [表示画面の ] | |
// | [視点位置(*)が] | A |
// | [動く範囲 ] | |
// | | |
// | v |
// |<- - - - - - - - - >*-------------+
// | B | |
// | | [表示画面] |
// | | |
// | | |
// +--------------------+-------------+
//
package {
import flash.display.*;
import flash.net.*;
import flash.events.*;
import flash.geom.*;
import flash.text.*;
[SWF(width="200", height="200", frameRate="30", backgroundColor="0x000000")]
public class FlashTest extends Sprite {
private var camera:Camera;
private var screen:Point;
private var bg_container:Sprite;
private var map:Loader;
private var piece:Sprite;
private var speed:int = 6;
public function FlashTest() {
camera = new Camera( 200, 200 );
screen = new Point( 200, 200 );
// 拡大縮小する面はこの1枚のスプライトとする。よって、拡大縮小の対象はすべてこの面に描画(addChild)すること.
bg_container = new Sprite();
addChild( bg_container );
var tURL:String = "http://mii-tetu.cocolog-nifty.com/photos/uncategorized/2008/05/24/050_2.jpg";
var urImage:URLRequest = new URLRequest( tURL );
map = new Loader();
map.load( urImage );
var info:LoaderInfo = map.contentLoaderInfo;
info.addEventListener(Event.COMPLETE, _init)
// コマ(操作できるキャラクター)
piece = new Sprite();
piece.graphics.beginFill(0x0000ff);
piece.graphics.drawRect(0, 0, 32, 32); // 手抜きですんません
piece.graphics.endFill();
piece.x = 0;
piece.y = 0;
stage.addEventListener( KeyboardEvent.KEY_DOWN, _KeyDownFunc); // MEMO: stage に対してaddEventListener しないといけないようだ. なぜ?
}
public function _init(evt:Event):void{
map.width = 200; // 画像が大きすぎるので適宜縮小
map.height = 200;
bg_container.addChild( map );
bg_container.addChild(piece);
addEventListener( Event.ENTER_FRAME, _enterFrame );
traceView();
}
private function _enterFrame(evt:Event):void {
camera.view( bg_container, piece.x, piece.y );
}
private function _KeyDownFunc(event:KeyboardEvent):void{
// キャラクターは、世界の大きさの範囲内で移動可能
switch( event.keyCode ){
case 37: piece.x-=speed; break;
case 38: piece.y-=speed; break;
case 39: piece.x+=speed; break;
case 40: piece.y+=speed; break;
}
if( piece.x < 0) piece.x = 0;
if( piece.y < 0) piece.y = 0;
if( piece.x > screen.x - 32 ) piece.x = screen.x - 32;
if( piece.y > screen.y - 32 ) piece.y = screen.y - 32;
}
private function traceView():void {
var t:TextField = new TextField();
t.autoSize = TextFieldAutoSize.LEFT;
t.textColor = 0x00FF0000;
stage.addChild(t);
trace = function(s:String):void { t.appendText(s + "\n"); };
cls = function():void { t.text = ""; };
}
private var trace:Function;
private var cls:Function;
}
}
import flash.display.*;
import flash.geom.*;
class Camera {
private var screen:Point;
private var cam:Vector3D;
private var f:Number = 1; // 焦点距離(F) を今回は1 にする
private var zmin:Number;
private var margine:Point;
private var sw:Boolean = true;
public function Camera( width:int, height:int ):void {
screen = new Point( width, height );
zmin = -width;
cam = new Vector3D( 0, 0, zmin ); // カメラ位置。原点から-width 離れると全体表示。z の取りうる値は zmin から0 まで。
margine = new Point( width / 3, height / 3 ); // 画面の1/3 に来た時にスクロール開始するように、初期マージン位置の設定値を保存
}
public function enlargement_factor():Number{
return f * screen.x / -cam.z;
}
// container: 表示する世界. ここではこれをどのくらいずらすか、拡大するかを計算する
// PoG(Point ob Gaze: 注視点=キャラクターのいる位置)
public function view( container:Sprite, x:Number, y:Number ):void {
// テスト用の拡大縮小
if(sw){
cam.z++;
if(cam.z >= -150) sw = false;
}else{
cam.z--;
if(cam.z <= zmin) sw = true;
}
// 現在のcam.z 位置から見た時の拡大率(1.0~)
var scale:Number = enlargement_factor();
// その拡大率の時の世界の広さ
var world:Point = new Point( screen.x * scale, screen.y * scale );
// 拡大率を考慮してマージン幅の計算. この範囲でスクロールする
var min_margine:Point = new Point( margine.x / scale, margine.y / scale );
var max_margine:Point = new Point( screen.x - (screen.x / scale), screen.y - (screen.y / scale) );
// PoG から、スクロール量を算出。ただし、マージン幅の制限を受ける
var scroll_x:Number = (x - min_margine.x) < 0 ? 0 : x - min_margine.x;
var scroll_y:Number = (y - min_margine.y) < 0 ? 0 : y - min_margine.y;
if(scroll_x > max_margine.x ) scroll_x = max_margine.x;
if(scroll_y > max_margine.y ) scroll_y = max_margine.y;
// 算出した拡大率、スクロール量を設定
container.scaleX = scale;
container.scaleY = scale;
container.x = -scroll_x * scale;
container.y = -scroll_y * scale;
}
}