DFdou's Blog Life is short,Be yourself.

1305/108

AS3-LightOut

来个LightOut小游戏,至于LightOut是啥,可以看这里:http://en.wikipedia.org/wiki/Lights_Out_%28game%29
如果该页面被和谐,那可以看下@dfdou的简单介绍,LightOut是一个开/关游戏,游戏的目的很简单,在5x5的的方阵里,把全部的图换成亮着的状态就过关了,Demo里是白色方块代表亮起状态。
规则是点击一个方块,在方块4周的4个方块和方块本身的状态会发生改变,是亮起就变成关掉,是关掉就变成亮起~

Demo在这里:

下边来讲下代码部分,比较简单,3个类搞定。

2104/101

Android-AS3的AStar复刻版

因为需要,所以直接把AS3版本的AStar复刻成了Java版,基本上什么都没改。
唉,让人比较无语的是Java里的ArrayList和Array咩有shift和unshift之类的常用函数的?
问了班里几个似乎在做Java的人,得到的答案=没有答案。
下边是复刻之后的代码:
AStar.java:

/**
 *
 */
package util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

import android.util.Log;

/**
 * @author DFdou
 *
 */

public class AStar {
    // 待考察表
    private ArrayList<node> _open = new ArrayList</node><node>();
    // 已考察表
    private ArrayList</node><node> _closed = new ArrayList</node><node>();
    // 网格
    private Grid _grid;
    // 开始节点
    private Node _startNode;
    // 结束节点
    private Node _endNode;
    // 终点节点的数组
    private ArrayList</node><node> _path = new ArrayList</node><node>();
    // 曼哈顿估价函数,算横竖距离和
    //private Function _heuristic = manhattan;
    // 几何估价法,算直线距离
    // private var _heuristic:Function = euclidian;
    // 对角线估价法
    // private var _heuristic:Function=diagonal;
    // 直线前进代价
    private float _straightCost = 1.0f;
    // 对角线前进代价
    private float _diagCost = 1.414f;

    public AStar() {
    }

    // 8方向
    public boolean findPath(Grid grid) {
	_grid = grid;
	// 创建待考察列表
	_open.clear();
	// 创建已考察列表
	_closed.clear();
	// 起点
	_startNode = _grid.getStartNode();
	// 终点
	_endNode = _grid.getEndNode();
	_startNode.g = 0;
	// 选一个估价函数,传入起点
	_startNode.h = manhattan(_startNode);
	_startNode.f = _startNode.g + _startNode.h;
	// 返回寻路结果
	return search();
    }

    public boolean search() {
	// 将起点节点设为当前节点
	Node node = _startNode;
	// 如果木有到达目标节点
	while (node != _endNode) {
	    // 循环的节点范围,不需要检测grid范围以外的节点
	    int startX = Math.max(0, node.x - 1);
	    int endX = Math.min(_grid.getNumCols() - 1, node.x + 1);
	    int startY = Math.max(0, node.y - 1);
	    int endY = Math.min(_grid.getNumRows() - 1, node.y + 1);
	    for (int i = startX; i < = endX; i++) {
		for (int j = startY; j <= endY; j++) {
		    // 尝试节点
		    Node test = _grid.getNode(i, j);
		    // 尝试节点为当前节点,或者为不可通过的节点,或者临接节点都不能通过那么就跳过该节点
		    if (test == node || !test.walkable
			    || !_grid.getNode(node.x, test.y).walkable
			    || !_grid.getNode(test.x, node.y).walkable) {
			continue;
		    }
		    float cost = _straightCost;
		    // 如果不在同直线距离上,就是对角线了~
		    if (!((node.x == test.x) || (node.y == test.y))) {
			cost = _diagCost;
		    }
		    // 计算g值
		    double g = node.g + cost * test.costMultiplier;
		    // 计算h值
		    double h = manhattan(test);
		    // 相加得到f
		    double f = g + h;
		    // 如果测试点已经在待考察列表或者已考察列表里,就比较已考察的结果是否比当前结果大,是的话就重新赋值,也就是说找到了更优的点
		    if (isOpen(test) || isClosed(test)) {
			if (test.f > f) {
			    test.f = f;
			    test.g = g;
			    test.h = h;
			    test.parent = node;
			}
			// 测试点不再待考察列表中,赋值,设置父节点,加入待考察列表
		    } else {
			test.f = f;
			test.g = g;
			test.h = h;
			test.parent = node;
			_open.add(test);
		    }
		}
	    }
	    // 根据f进行排序,最后一个是f值最小的
	    // _open.sortOn("f", Array.NUMERIC);
	    Comparator comp = new NodeFComparator();
	    Collections.sort(_open, comp);
	    // 作为当前节点
	    // node = _open.shift();
	    node = _open.get(0);
	    _open.remove(0);
	    _open.trimToSize();
	}
	buildPath();
	return true;
    }

    // 4方向
    public boolean findPath4(Grid grid) {
	_grid = grid;
	// 创建待考察列表
	_open.clear();
	// 创建已考察列表
	_closed.clear();
	// 起点
	_startNode = _grid.getStartNode();
	// 终点
	_endNode = _grid.getEndNode();
	_startNode.g = 0;
	// 选一个估价函数,传入起点
	_startNode.h = manhattan(_startNode);
	_startNode.f = _startNode.g + _startNode.h;
	// 返回寻路结果
	return search4();
    }

    public boolean search4() {
	// 将起点节点设为当前节点
	Node node = _startNode;
	// 如果木有到达目标节点
	while (node != _endNode) {
	    // 循环的节点范围,不需要检测grid范围以外的节点
	    int startX = Math.max(0, node.x - 1);
	    int endX = Math.min(_grid.getNumCols() - 1, node.x + 1);
	    int startY = Math.max(0, node.y - 1);
	    int endY = Math.min(_grid.getNumRows() - 1, node.y + 1);
	    for (int i = startX; i < = endX; i++) {
		for (int j = startY; j <= endY; j++) {
		    // 尝试节点
		    Node test = _grid.getNode(i, j);
		    // 尝试节点为当前节点,或者为不可通过的节点,或者临接节点都不能通过那么就跳过该节点
		    // PS:在四方向寻路情况下跳过对角线点
		    if (test == node || !test.walkable
			    || !_grid.getNode(node.x, test.y).walkable
			    || !_grid.getNode(test.x, node.y).walkable
			    || Math.abs(i - node.x) + Math.abs(j - node.y) > 1) {
			continue;
		    }
		    float cost = _straightCost;
		    // 如果不在同直线距离上,就是对角线了~
		    if (!((node.x == test.x) || (node.y == test.y))) {
			cost = _diagCost;
		    }
		    // 计算g值
		    double g = node.g + cost * test.costMultiplier;
		    // 计算h值
		    double h = manhattan(test);
		    // 相加得到f
		    double f = g + h;
		    // 如果测试点已经在待考察列表或者已考察列表里,就比较已考察的结果是否比当前结果大,是的话就重新赋值,也就是说找到了更优的点
		    if (isOpen(test) || isClosed(test)) {
			if (test.f > f) {
			    test.f = f;
			    test.g = g;
			    test.h = h;
			    test.parent = node;
			}
			// 测试点不再待考察列表中,赋值,设置父节点,加入待考察列表
		    } else {
			test.f = f;
			test.g = g;
			test.h = h;
			test.parent = node;
			_open.add(test);
		    }
		}
	    }

	    // 当前节点已经考察过了,所以就加入已考察列表
	    _closed.add(node);
	    // 检查待考察表里面有没有节点,没有就意味着没有可行的路径
	    if (_open.size() == 0) {
		return false;
	    }
	    // 根据f进行排序,最后一个是f值最小的
	    // _open.sortOn("f", Array.NUMERIC);
	    Comparator comp = new NodeFComparator();
	    Collections.sort(_open, comp);
	    // 作为当前节点
	    // node = _open.shift();
	    node = _open.get(0);
	    _open.remove(0);
	    _open.trimToSize();
	}
	buildPath();
	return true;
    }

    // 建立路径
    private void buildPath() {
	_path.clear();
	Node node = _endNode;
	_path.add(node);
	while (node != _startNode) {
	    node = node.parent;
	    // _path.unshift(node);
	    _path.add(0, node);
	}
    }

    public ArrayList</node><node> getPath() {
	return _path;
    }

    private boolean isOpen(Node node) {
	int len = _open.size();
	for (int i = 0; i < len; i++) {
	    if (_open.get(i) == node) {
		return true;
	    }
	}
	return false;
    }

    private boolean isClosed(Node node) {
	int len = _closed.size();
	for (int i = 0; i < len; i++) {
	    if (_closed.get(i) == node) {
		return true;
	    }
	}
	return false;
    }

    private double manhattan(Node node) {
	return Math.abs(node.x - _endNode.x) * _straightCost
		+ Math.abs(node.y + _endNode.y) * _straightCost;
    }

    private double euclidian(Node node) {
	float dx = node.x - _endNode.x;
	float dy = node.y - _endNode.y;
	return Math.sqrt(dx * dx + dy * dy) * _straightCost;
    }

    private double diagonal(Node node) {
	float dx = Math.abs(node.x - _endNode.x);
	float dy = Math.abs(node.y - _endNode.y);
	float diag = Math.min(dx, dy);
	float straight = dx + dy;
	return _diagCost * diag + _straightCost * (straight - 2 * diag);
    }

    // public float getVisited() {
    // return ArrayUtils.addAll(_closed, _open);
    // }
}

2004/102

AS3-Sokoban推箱子-寻路扩展

恩,是寻路扩展,而不是自动求解~自动求解那个实在过于复杂,不考虑呀么不考虑。
先看demo:

依然是前几天的Sokoban,只不过修改了下地图数据,另外加了个点击寻路功能。
在要去的点上点一下鼠标,就会自动移过去了。
下边来说下具体实现。

1404/1011

AS3-Sokoban推箱子

先是Demo:

方向键控制移动,红色的方块是你~
UI嘛,就不说了,网上偷了点图,就这么放着了,有兴趣的可以弄弄呗。

Source code:https://dl.dropbox.com/u/477487/flash/game/sokoban.rar

PS:如果该地址被和谐,而你又想要源代码,联系我,服务很周到的~

推箱子的实现方法很多,各有各的做法,下边是我的实现方式:
Sokoban.as:

package {
	import flash.display.Sprite;
	import flash.events.Event;
	/**
	 * ...
	 * @author DFdou
	 */
	public class Sokoban extends Sprite {
		private var _lv = 0;
		private var _map:Map;

		public function Sokoban() {
			init();
		}
		private function init() {
			_map = new Map(_lv);
			addChild(_map);

			var role:Role = new Role(stage,_map,_lv);
			addChild(role);
		}

	}
}

文档类要干的事儿就是生成一个map,一个role。

1803/103

AS3-Mapppp~的一个生成方案

最近的一个Android里碰到一个Map的应用,做了下这个东西,这个东西挺简单的,就是根据给出的数组生成一个Map。
Demo出来玩下先:

大小是800*500,想看全景的点这里呗:http://nwhy.org/nwhy/game/MapConvert.swf

整个实现过程很简单,MapConvert.as:

/*
VERSION: 1.0 DATE:2010/03/18
ACTIONSCRIPT VERSION: 3.0
AUTHOR: DFdou
Copyright 2009, http://nwhy.org. All rights reserved.
*/
package{
	import flash.display.Sprite;

	public class MapConvert extends Sprite{
		private var map:Map;
		private var mapID:uint;

		public function MapConvert(){
			mapID = 0;
			map = new Map(mapID);
			addChild(map);
		}
	}
}

文档类干的事灰常简单,传一个mapID生成一个Map,加到显示列表,就完事儿了。
Map.as:

/*
VERSION: 1.0 DATE:2010/03/18
ACTIONSCRIPT VERSION: 3.0
AUTHOR: DFdou
Copyright 2009, http://nwhy.org. All rights reserved.
*/
package{
	import flash.display.Sprite;

	public class Map extends Sprite{
		private var data:Array;

		public function Map(id:uint){
			data = MapData.MAP[id];
			var row:uint = data.length;
			for(var i:uint = 0;i<row;i++){
				var col:uint = data[i].length;
				for(var j:uint = 0;j<col;j++){
					if(data[i][j]!=0){
						var tile:Tile = new Tile();
						tile.gotoAndStop(data[i][j]);
						tile.x = j * 50;
						tile.y = i * 50;
						addChild(tile);
					}
				}
			}
		}
	}
}

Map类也很简单,根据传过来的mapID载入对应的Map数组,然后就生成Tile来填充呗~
最后是示例性数据结构MapData.as:

/*
VERSION: 1.0 DATE:2010/03/18
ACTIONSCRIPT VERSION: 3.0
AUTHOR: DFdou
Copyright 2009, http://nwhy.org. All rights reserved.
*/
package {
	public class MapData {
		public static  const MAP:Array = [
										  [[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10],
										   [0,1,0,0,14,0,0,0,0,0,0,0,6,0,0,0],
										   [0,0,1,0,0,0,0,0,5,0,12,0,1,0,0,0],
										   [0,0,0,0,9,0,0,0,0,0,0,0,0,0,3,0],
										   [0,0,5,1,5,5,0,0,0,0,1,0,0,0,3,0],
										   [0,0,0,0,0,0,0,0,0,0,6,4,0,3,0,0],
										   [0,0,5,0,0,4,1,0,0,0,0,9,0,12,0,0],
										   [0,0,0,0,0,0,0,0,0,0,11,0,1,0,0,0],
										   [0,0,0,2,0,0,2,0,0,0,3,10,9,9,0,0],
										   [0,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0]],
										  ];
	}
}
Tagged as: 3 Comments
903/107

Flash-APE物理引擎学习<二>

昨天整理了下代码,新的Demo在这里:

在说具体实现之前,丢个Flash物理引擎在产品展示中的应用:http://www.carlosulloa.com/.
这是一款汽车产品的展示平台,用方向键控制机车移动,点鼠标左键复位汽车初始位置。
不过,这个不是2d物理引擎完成的,而是基于PV3D的,,,,恩,3D物理引擎是在比较难搞……有时间尝试整理下……

下边来说下Demo的具体实现,首先要收下物理引擎,物理引擎是干嘛用的呢?
物理引擎是一个处理物理现象的引擎。

那什么是物理现象呢?
举个例子,一个风筝在天上飞,它会受到风力,阻力,摩擦力,还有重力,绳子的作用力,etc。。。而物理引擎就是帮你处理这些力的一个框架集。
你要做的就是给它个重力,然后都作用在风筝上,至于这些里之间的相互作用,都由引擎来搞定。

下边来代码,先是文档类,也就是主容器了:

package org.nwhy.bubble_bobble{
	import flash.display.*;
	import flash.events.Event;
	import org.cove.ape.*;

	public class BubbleBobble extends Sprite{
		private var bulletHolder:Group;

		public function BubbleBobble(){
			init();
		}
		private function init(){
			initStage();
			initGroups()
		}
		private function initStage(){
			stage.scaleMode = StageScaleMode.NO_SCALE;//设置为不缩放
			//stage.align = StageAlign.TOP_LEFT;
			stage.frameRate = 55;//设置帧频
			stage.addEventListener(Event.ENTER_FRAME, run);
		}
		private function initGroups(){
			//初始化2D物理引擎
			APEngine.init(1/4);
			APEngine.container = this;
			APEngine.addForce(new VectorForce (false,0,1));//加上重力

			//放bullet的容器,bullet就是那个各种颜色的球~
			bulletHolder = new Group(true);
			APEngine.addGroup(bulletHolder);

			//加入墙壁
			var wall:Wall = new Wall();
			APEngine.addGroup(wall);

			//gun,就是下边那个大伯说有点像啥的那个啥……囧一个
			var gunGroup:GunGroup = new GunGroup(stage);
			APEngine.addGroup(gunGroup);

			//设置bullet的碰撞检测内容
			bulletHolder.addCollidableList(new Array(wall,gunGroup));
		}
		private function run(e:Event) {
			APEngine.step();
			APEngine.paint();
		}
		//增加bullet的对外接口
		public function addBullet(bullet:CircleParticle){
			bulletHolder.addParticle(bullet);
		}
	}
}

这里边干的事就是加入各种Group(APE物理引擎里的碰撞单元是Particle,单个或多个Particle组成Group),至于Group里具体是啥Group里自己处理。

503/102

Flash – APE物理引擎学习<一>

APE是什么就不介绍了,下边先上Demo:


点击鼠标发射子弹,击中那个囧就过关了。
代码实现其实也很简单,APE里边所有的Item都是以Group的形式存在。
在这个Demo里,上边的5个球是一组,例子里是Avatar类,里边有5个WheelParticle,不知道为何CircleParticle没有旋转的。

203/104

AS3-类似于机战的角色移动(基于Tile)

先来看下Demo:

源代码下载地址:http://dl.dropbox.com/u/477487/flash/game/mapMove.rar
只做了移动,重叠和阻挡的部分没做,短时间内不会有时间做的=,=
主要逻辑是这样,选中Role就显示可以行走的范围,选其中一点之后Role就移动。
下边看下简单的实现。主要是OverlayView.as和Role.as,我很懒,其他代码大家自己看……

Tagged as: , Continue reading
802/102

AS3-aSpaceEscape 迷宫脱离游戏(四)整合部分

前边咱讲了地图和角色的生成以及逻辑代码部分,接下去就是2者的整合了。
这个整合的类我把它命名成Controller.as,在主场景的时间轴里写上:

import org.nwhy.aSpaceEscape.*;
var controller:Controller = new Controller(stage,0);
addChild(controller);

然后是Controller.as:

package org.nwhy.aSpaceEscape{
	import flash.display.Sprite;
	import flash.display.Stage;

	public class Controller extends Sprite{
		private var mStage:Stage;
		public static var level:uint;//等级
		private var role:Role;

		public function Controller(stage:Stage,levelID:uint){
			mStage = stage;
			level = levelID;
			drawMap();
			drawRole();
		}
		private function drawMap(){
			var map:Map = new Map(Config.MAP[level]);
			addChild(map);
		}

		private function drawRole(){
			role = new Role(mStage);
			addChild(role);
		}
	}
}

代码内容很简单,画一个Map,然后画一个Role,就完成了~
整个游戏的代码地址(Full source):http://dl.dropbox.com/u/477487/flash/game/aSpaceEscape.rar

Filed under: AIR+FB+AS3, Game 2 Comments
502/100

AS3-aSpaceEscape 迷宫脱离游戏(三)角色部分

刚我们讲了地图,看起来还是挺简单的,只要输入一个数组,或者说是一个地图矩阵块,一个地图就被生成了。
那下边我们无敌的主角就要上场了,就是那个看起来在大笑,那个很嚣张的东东,我们就起个类名叫Role好了,当然你也可以把这个类叫JJ,GG,MM,DD,etc~

跟角色有关的逻辑应该尽量都放在这个类内部,为啥说应该尽量呢,有些时候有变态的特殊需求嘛。
好,来看Role.as:

package org.nwhy.aSpaceEscape{
	import flash.display.Sprite;
	import flash.display.Stage;
	import flash.geom.Rectangle;
	import flash.events.*;

	public class Role extends Sprite {
		private var mStage:Stage;//根场景的stage;
		private var level:uint;
		private var mSpeed:int = Config.TILE_SIZE;//移动速度
		private var xSpeed:int;
		private var ySpeed:int;
		private var mDown:Array = [0,0,0,0];//按键组合,只需要上下左右不需要45度角,so...
		private var isKeyDown:Boolean;

		public function Role(stage:Stage):void {
			level = Controller.level;
			mStage = stage;
			reset();
			//添加事件监听
			addEventListeners();
		}
		private function addEventListeners():void{
			mStage.addEventListener(KeyboardEvent.KEY_DOWN, mKeyDownHandler);//Keyboard事件
			mStage.addEventListener(KeyboardEvent.KEY_UP, mKeyUpHandler);
			addEventListener(Event.ENTER_FRAME, mUpdate);
		}
		private function mKeyDownHandler(e:KeyboardEvent):void{
			if(!isKeyDown){
				switch (e.keyCode) {
					case 37 :
						mDown[0]=1;
						break;
					case 38 :
						mDown[1]=1;
						break;
					case 39 :
						mDown[2]=1;
						break;
					case 40 :
						mDown[3]=1;
					break;
				}
				isKeyDown = true;
			}
			checkKeyDown(mDown.join(""));
		}
		private function mKeyUpHandler(e:KeyboardEvent):void {
			switch (e.keyCode) {
				case 37 :
					mDown[0]=0;
					break;
				case 38 :
					mDown[1]=0;
					break;
				case 39 :
					mDown[2]=0;
					break;
				case 40 :
					mDown[3]=0;
					break;
			}
		}
		private function checkKeyDown(k:String){
			switch(k){
				case "1000" :
					//trace("left");
					xSpeed = - mSpeed;
					ySpeed = 0;
					break;
				case "0100" :
					//trace("top");
					xSpeed = 0;
					ySpeed = - mSpeed;
					break;
				case "0010" :
					//trace("right");
					xSpeed = mSpeed;
					ySpeed = 0;
					break;
				case "0001" :
					//trace("down");
					xSpeed = 0;
					ySpeed = mSpeed;
					break;
			}
		}
		private function mUpdate(e:Event){
			var posX:int = (x+xSpeed)/mSpeed;
			var posY:int = (y+ySpeed)/mSpeed;

			if(posX>=Config.TILE_PERLINE || posY>=Config.TILE_PERLINE || posX< =-1 || posY<=-1){
				trace("out of stage");
				xSpeed = 0;
				ySpeed = 0;
				reset();
				isKeyDown = false;
			}else if(Config.MAP[level][posY][posX] > 1 && Config.MAP[level][posY][posX] !=5){
				xSpeed = 0;
				ySpeed = 0;
				isKeyDown = false;
				//trace(posX,posY,Config.MAP[level][posY][posX]);
			}else if(Config.MAP[level][posY][posX] == 5){
				trace("succ");
				x += xSpeed;
				y += ySpeed;
				xSpeed = 0;
				ySpeed = 0;
			}

			x += xSpeed;
			y += ySpeed;
		}
		private function reset(){
			x = Config.ROLE_POSITION[Controller.level][0] * Config.TILE_SIZE;
			y = Config.ROLE_POSITION[Controller.level][1] * Config.TILE_SIZE;
		}
	}
}
402/100

AS3-aSpaceEscape 迷宫脱离游戏(二)地图生成部分

这个游戏一开始,我们需要一个地图类,用来生成地图,这里我用的是方格的形式,每个方格Tile使用的是同一个类Tile.as,至于不同的Tile素材,只要在库里弄个元件,不同帧放上不同的素材,然后绑定Tile类就可以了。
Map类的代码是这样:

package org.nwhy.aSpaceEscape{
	import flash.display.Sprite;

	public class Map extends Sprite{
		private var data:Array;

		public function Map(mapData:Array){
			data = mapData;
			drawMap();
		}
		private function drawMap(){
			var len:uint = data.length;
			var tile:Tile;
			for(var i:uint=0;i<len;i++){
				for(var j:uint=0;j<Config.TILE_PERLINE;j++){
					tile = new Tile(data[i][j]+1);
					tile.x = j * Config.TILE_SIZE;
					tile.y = i * Config.TILE_SIZE;
					addChild(tile);
				}
			}
		}
	}
}

填充的Tile.as:

package org.nwhy.aSpaceEscape{
	import flash.display.MovieClip;

	public class Tile extends MovieClip{
		private var tileID:uint;
		public function Tile(id:uint){
			tileID = id;
			showTile();
		}
		private function showTile(){
			gotoAndStop(tileID);
		}
	}
}

代码是相当的简单。给个tileID 然后跑到指定帧就可以了~
然后是配置文件:

package org.nwhy.aSpaceEscape{
	public class Config{
		public static const TILE_SIZE:uint = 30;
		public static const TILE_PERLINE:uint = 12;//指定每行的Tile数,列数并不固定
		public static const MAP:Array = [[[0,0,0,0,0,0,0,0,0,0,0,0],
										 [0,1,1,1,1,1,1,1,1,1,1,0],
									 	 [0,1,1,1,1,1,1,1,1,2,1,0],
										 [0,1,1,2,1,1,1,1,1,1,1,0],
										 [0,1,1,1,1,1,1,5,1,1,1,0],
										 [0,1,1,1,1,1,1,1,1,1,1,0],
										 [0,1,1,1,1,1,1,1,1,1,1,0],
										 [0,1,2,1,1,1,1,1,1,1,1,0],
										 [0,1,1,1,1,1,1,1,2,1,1,0],
										 [0,1,1,1,1,1,1,1,1,1,1,0],
										 [0,1,1,1,1,1,1,1,1,1,1,0],
										 [0,0,0,0,0,0,0,0,0,0,0,0]]];
		public static const ROLE_POSITION:Array = [[2,2]];
	}
}
Tagged as: No Comments
302/100

AS3-aSpaceEscape 迷宫脱离游戏(一)分析

分享知识点:
1.Flash里的代码(Class,Actionscript)和库中的UI元件(MovieClip,Sprite)如何绑定。
2.KeyboardEvent,按键事件的绑定和处理。
3.如何把一个库中的UI元件加入到场景中。
4.stage的使用。
5.视图的刷新。

最近在想,做点什么Flash的分享好。在上一个周末,玩了一个Flash小游戏,觉得还不错,就写了一个。
来来来,咱来看一下Demo:

先来说说游戏的玩法,用小键盘的上下左右键控制移动那个看起来很嚣张的怪物,话说这个怪物是啥我也不知道……XX表情里扣出来的……
怪物只能直线移动,中途不能换方向,碰到树桩就会停下,跑出屏幕外就挂了(接着会被搬回到出发点),跑到Exit的地方就过关了。

是个很简单的游戏对吧,那应该怎么来实现呢?Follow me~

首先我们来整理一下需要的东西(PS:不包括素材):

1.怪物对象(Role Class);就是那个很嚣张的怪物
2.地图对象(Map Class);看到的全部方块的集合,包括树,出口
3.填充地图的对象(Tile Class);树,出口等
4.参数配置对象(Config Class/XML);
5.控制器(Controller Class);场景控制
6.etc;占位,可能会需要的东西

Tagged as: No Comments
3010/092

AS3-getDefinitionByName

先来看下CS3版F1的介绍:

public function getDefinitionByName(name:String):Object
语言版本 : ActionScript 3.0
Player 版本 : Flash Player 9
返回 name 参数指定的类的类对象引用。
参数 name:String — 类的名称。
返回 Object — 返回 name 参数指定的类的类对象引用。
引发 ReferenceError — 不存在具有指定名称的公共定义。

下边是一个读取地图信息并显示的实例。文件有点多,先来看主文档,TD.as:

package{
	import flash.display.Sprite;
	import org.nwhy.TD.Config;
	import org.nwhy.TD.Controller;
	public class TD extends Sprite{
		public var screen:Sprite;
		public function TD(){
			screen = new Sprite();
			addChild(screen);
			var game:Controller = new Controller(screen,new Config());
		}
	}
}
1008/098

AS3-连连看的主要算法



这几天一直在忙的一个东西,因为时间的关系,只弄了主要的算法,计时,分数,划线,点击效果等内容都没有管=.=
先来看连连看的规则分析,这里将选中的2个Obj分3种情况来讨论,一是同位于X轴,二是同位于Y轴,三是不同X,Y轴。
而第三种情况其实又可以归结到第1和第2种情况,具体的操作是先判断是否同X,Y轴,是的话先检测能否直连,不能的话判断不直连的情况.
如果两者属于不同的X,Y轴,那么先判断通过一点连接,然后再判断通过两点连接的情况,这里图方便用了最烂的方法.

Tagged as: , Continue reading
2007/090

AS3-子弹躲避游戏(下)

接上一篇《AS3-子弹躲避游戏(上)》
有了Enemy和Role之后,自然就是游戏的主体控制部分了,这里是Game类:
这个类负责生成多少个Enemy,Role如何移动,游戏如何开始和如何结束,以及控制其他事务,比如记时类。

package{
	import flash.display.Sprite;
	import flash.events.*;
	import flash.utils.Timer;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import fl.controls.Button;
	import Config;
	import Role;
	import Enemy;
	import TimeCount;

	public class Game extends Sprite{
		private var _role:Role;
		private var _enemy:Sprite;
		private var _time:TimeCount;
		private var _enemyTotal:uint;
		private var _gameFlag:Boolean;

		private var startBtn:Button;
		private var gameInfo:TextField;

		//存储四个方向键是否按下的变量
		private var leftArrow:Boolean=false;
		private var rightArrow:Boolean=false;
		private var upArrow:Boolean=false;
		private var downArrow:Boolean=false;

		public function Game():void{
			startBtn = new Button();
			startBtn.label = "StartGame";
			startBtn.x=(Config.STAGE_W-startBtn.width)/2;
			startBtn.y=(Config.STAGE_H-startBtn.height)/2;
			addChild(startBtn);
			startBtn.addEventListener(MouseEvent.MOUSE_DOWN,gameStart);
			gameInfo = new TextField();
			gameInfo.autoSize = TextFieldAutoSize.LEFT;
			gameInfo.selectable = false;
			gameInfo.text = "上下左右方向键控制方块移动,被黑球击中就挂了。";
			gameInfo.x = (Config.STAGE_W-gameInfo.width)/2;
			gameInfo.y = startBtn.y-30;
			addChild(gameInfo);
		}
		private function gameStart(_evt:MouseEvent):void{
			startBtn.removeEventListener(MouseEvent.MOUSE_DOWN,gameStart);
			startBtn.visible = false;
			gameInfo.visible = false;
			init();
		}
		private function init():void{
			initTime();
			initRole();
			initEnemy();
		}
		private function initTime():void{
			_time = new TimeCount();
			addChild(_time);
		}
		private function initRole():void{
			_role = new Role();
			addChild(_role);
			_role.x=(Config.STAGE_W-_role.width)/2;
			_role.y=(Config.STAGE_H-_role.height)/2;
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedDown);
			stage.addEventListener(KeyboardEvent.KEY_UP, keyPressedUp);
			_role.addEventListener(Event.ENTER_FRAME, roleMove);
			stage.addEventListener(Event.DEACTIVATE, missingStage);//Flash处于非活动状态时调用
		}

		private function initEnemy():void{
			_enemyTotal = Config.ENEMY_TOTAL;
			var t:Timer=new Timer(2000,1);
			t.addEventListener(TimerEvent.TIMER, timeToCreateEnemy);
            t.start();
		}

		private function createEnemy():void{
			var enemy=new Enemy();
			enemy.setRole(_role);
			_enemy.addChild(enemy);
		}
		private function getEnemyNum():uint{
			return this.numChildren;
		}

		private function timeToCreateEnemy(_evt:TimerEvent):void{
			_enemy = new Sprite();
			addChild(_enemy);
			for (var i:uint=0; i<_enemytotal ; i++) {
				createEnemy();
			}
			addEventListener(Event.ENTER_FRAME,checkFlag);
		}

		//按键时的检测,左上右下分别是37,38,39,40
		private function keyPressedDown(_evt:KeyboardEvent) {
			if (_evt.keyCode==37) {
				leftArrow=true;
			} else if (_evt.keyCode == 39) {
				rightArrow=true;
			} else if (_evt.keyCode == 38) {
				upArrow=true;
			} else if (_evt.keyCode == 40) {
				downArrow=true;
			}
		}

		//松开按键时
		private function keyPressedUp(_evt:KeyboardEvent) {
			if (_evt.keyCode==37) {
				leftArrow=false;
			} else if (_evt.keyCode == 39) {
				rightArrow=false;
			} else if (_evt.keyCode == 38) {
				upArrow=false;
			} else if (_evt.keyCode == 40) {
				downArrow=false;
			}
		}
		private function roleMove(_evt:Event) {
			//移动的速度
			var speed:Number=Config.ROLE_SPEED;
			if (leftArrow) {
				//MC的位置检测,下边相同
				if (0<=_role.x) {
					_role.x-=speed;
				}
			}
			if (rightArrow) {
				if (_role.x<=Config.STAGE_W-_role.width) {
					_role.x+=speed;
				}
			}
			if (upArrow) {
				if (0<=_role.y) {
					_role.y-=speed;
				}
			}
			if (downArrow) {
				if (_role.y<=Config.STAGE_H-_role.height*2) {
					_role.y+=speed;
				}
			}
		}

		//Flash处于非激活状态时
		private function missingStage(_evt:Event) {
			leftArrow=false;
			rightArrow=false;
			upArrow=false;
			downArrow=false;
		}
		private function checkFlag(_evt:Event):void{
			//trace(_gameFlag);
			if(_gameFlag){
				_gameFlag = false;
				gameOver();
			}
		}
		private function gameOver(){

			removeEventListener(Event.ENTER_FRAME,checkFlag);
			_time.stopTime();

			gameInfo.text = "You Failed At " + _time.getTime() + " Second!";
			var format:TextFormat = new TextFormat();
			format.font = "Arial";
            format.color = 0xFF0000;
            format.size = 30;
            gameInfo.setTextFormat(format);
			gameInfo.x=(Config.STAGE_W-gameInfo.textWidth)/2;
			gameInfo.y=(Config.STAGE_H-gameInfo.textHeight)/2;
			gameInfo.visible = true;

			startBtn.visible = true;
			startBtn.y = gameInfo.y + 40;
			startBtn.addEventListener(MouseEvent.MOUSE_DOWN,gameStart);

			//_role.roleClear();
			_role.removeEventListener(Event.ENTER_FRAME, roleMove);
			removeChild(_role);

			while(_enemy.numChildren>0){
				Enemy(_enemy.getChildAt(0)).enemyClear();
				_enemy.removeChildAt(0);
			}
			removeChild(_enemy);
		}
		public function setGameFlag(_value:Boolean):void{
			_gameFlag = _value;
		}
	}
}

Page 1 of 212