我正在制作一个类似游戏的模拟城市。有很多瓷砖。我刚开始的时候。我刚刚使用了瓷砖。我正在从瓷砖表中复制必要的馅饼。到一个空白的bitMapData。然后,我将bitMapData放入一个bitMap中,然后将其放入DisplayObject中。它工作得很好!
tileSheet:BitMapData <----- data is already in
loop { loop through and tiled
bg:bitMapData= new bitMapData();
bg.copyPixel(tileSheet,rect,point);
}
canvas.BitMap(bg);
addChild(canvas);
唯一的问题是我需要让我的瓷砖互动。我需要突出它们并改变颜色和东西。所以我使用了Sprite对象。它运作得很好,但我现在只能在舞台上有这么多。或者滚动时它移动得很慢。我需要一些更轻松然后一个精灵,但我仍然可以变成一个对象来进行交互。任何人都有任何想法???
答案 0 :(得分:1)
如果你有很多瓷砖,那会影响性能,因为Flash需要更新很多显示对象的转换(这在内部意味着大量的矩阵计算,以及随后重绘屏幕的大部分区域。)< / p>
如果您发现必须使用单个位图数据来提高性能,还有另一种实现交互性的方法。在内存中保留一个“抽象”(即非图形)数据模型,用于存储您的游戏状态。确保您能够从商店中读取游戏世界中某个元素的位置。然后,您可以使用平面位图数据来渲染游戏世界,因为各个位置都存储在其他位置。
当用户单击包含位图数据的DisplayObject(使用位图填充绘制位图的Sprite,或包装位图的Sprite)时,请在模型中查看该点击击中了哪些游戏元素。
// myTileSprite is a Sprite with a bitmap fill
myTileSprite.addEventListener(MouseEvent.CLICK, handleWorldClick);
function handleWorldClick(ev : MouseEvent) : void
{
var i : int;
// Loop through all game element data models
for (i=0; i<myGameElements.length; i++) {
// Test the mouse position against the element model
if (myGameElements[i].hitTest(myTileSprite.mouseX, myTileSprite.mouseY)) {
trace('this was the element that was clicked: '+myGameElements[i].toString());
}
}
}
在这里,每当玩家点击世界图形时,循环就会尝试找到直接位于鼠标位置的元素。当然,您需要在所有游戏元素数据模型上实现 hitTest()方法。这种方法只是根据瓷砖的区域检查提供的世界空间位置:
// GameElement.hitTest():
/**
* Tests a world position against the position and area of this game
* element tile. Returns a boolean indicating whether this tile was hit.
*/
public function hitTest(mouseX : Number, mouseY : Number) : void
{
var rect : Rectangle = new Rectangle(this.worldX, this.worldY, this.width, this.height);
if (mouseX > rect.left && mouseX < rect.right
&& mouseY > rect.top && mouseY < rect.top) {
return true;
}
else return false;
}
GameElement类不是显示对象,但具有 worldX 和 worldY 属性,指示它在世界中的位置。 width 和 height 属性定义了它的尺寸。
来自此处的技巧是确保渲染的位图和模型存储是同步的,这样位图上的位置实际上与数据模型中的worldX / worldY属性相对应。
答案 1 :(得分:0)
我比你领先一步。这是个好主意。当瓦片被平方时,它更容易保持世界的数据表示。因此,我可以使用我的mouseX / tileWidth,这就是我从左向右移动的许多列。与Y轴相同。
不仅如此,坐标从左上角开始。
但问题是我的瓷砖是等距的。因此,而不是像X轴一样开始......
012345678
0
1
2
3
4
5
6
7
8
我的瓷砖像......一样对齐。
00
1 1
2 2
3 3
4 4
5 6
它有点草率。但右侧表示y轴,左侧表示x轴。并且中心原点位于屏幕的中心。不在左上角。我试图找出如何测量我的鼠标从中心到两侧的位置。这听起来非常困难。我不确定它是否可行。游戏假设像游戏这样的模拟城市。第一个模拟城市是正方形而不是等距。在他们开始使用3D之前我不认为他们是等距的。我想知道是否有可能在方形瓷砖上创造出等长的幻觉。
答案 2 :(得分:0)
我一直在读这本关于等轴测图的好书。他们显示在3d空间中计算瓷砖。甚至还可以在3d空间中计算鼠标。这是代码。它很多,但我希望其他人比我更了解它。这本书由jobe makar撰写,用于构建多人游戏世界。我想分享它,因为就代码量而言,代码非常简单。只需要2个班级。我对三角学不太好。所以我无法解释数学如何得到结果。希望有人可以为我解释:D。
由于宽度为=到高度,因此未给出Y坐标。 coordinates方法只是一个定制的Point类,它包含x,y和z。
package com.gamebook.grid {
import com.gamebook.utils.geom.Coordinate;
import com.gamebook.utils.Isometric;
import flash.display.MovieClip;
import flash.events.MouseEvent;
/**
* ...
* @author Jobe Makar - jobe@electrotank.com
*/
public class Map extends MovieClip{
private var _grid:Array;
private var _iso:Isometric;
private var _tileWidthOnScreen:int;
private var _tileHeightOnScreen:int;
private var _tileWidth:Number;
private var _tileHeight:Number;
private var _cols:int;
private var _rows:int;
private var _lastTile:Tile;
public function Map() {
initialize();
}
private function initialize():void{
_iso = new Isometric();
//when mapped to the screen the tile makes a diamond of these dimensions
_tileWidthOnScreen = 64;
_tileHeightOnScreen = 32;
//figure out the width of the tile in 3D space
_tileWidth = _iso.mapToIsoWorld(64, 0).x;
//the tile is a square in 3D space so the height matches the width
_tileHeight = _tileWidth;
buildGrid();
addEventListener(MouseEvent.MOUSE_MOVE, mouseMoved);
}
private function mouseMoved(e:MouseEvent):void {
if (_lastTile != null) {
_lastTile.alpha = 1;
_lastTile = null;
}
var coord:Coordinate = _iso.mapToIsoWorld(mouseX, mouseY);
var col:int = Math.floor(coord.x / _tileWidth);
var row:int = Math.floor(Math.abs(coord.z / _tileHeight));
if (col < _cols && row < _rows) {
var tile:Tile = getTile(col, row);
tile.alpha = .5;
_lastTile = tile;
}
}
private function buildGrid():void{
_grid = [];
_cols = 10;
_rows = 10;
for (var i:int = 0; i < _cols;++i) {
_grid[i] = [];
for (var j:int = 0; j < _rows;++j) {
var t:Tile = new Tile();
var tx:Number = i * _tileWidth;
var tz:Number = -j * _tileHeight;
var coord:Coordinate = _iso.mapToScreen(tx, 0, tz);
t.x = coord.x;
t.y = coord.y;
_grid[i][j] = t;
addChild(t);
}
}
}
private function getTile(col:int, row:int):Tile {
return _grid[col][row];
}
}
}
然后我们有了计算3d空间的等距类。
package com.gamebook.utils { import com.gamebook.utils.geom.Coordinate;
/**
* @author Jobe Makar - jobe@electrotank.com
*/
public class Isometric {
//trigonometric values stored for later use
private var _sinTheta:Number;
private var _cosTheta:Number;
private var _sinAlpha:Number;
private var _cosAlpha:Number;
/**
* Isometric class contrustor.
* @param declination value. Defaults to the most common value, which is 30.
*/
public function Isometric() {
var theta:Number = 30;//even though the tiles are already isometric, you still have to put the degrees the tiles will be turned.
var alpha:Number = 45;//45 degrees on y axis, 30 dgrees on x axis
theta *= Math.PI/180; // then you translate to radians
alpha *= Math.PI/180;
_sinTheta = Math.sin(theta);
_cosTheta = Math.cos(theta);
_sinAlpha = Math.sin(alpha);
_cosAlpha = Math.cos(alpha);
}
/**
* Maps 3D coordinates to the 2D screen
* @param x coordinate
* @param y coordinate
* @param z coordinate
* @return Coordinate instance containig screen x and screen y
*/
public function mapToScreen(xpp:Number, ypp:Number, zpp:Number):Coordinate {
var yp:Number = ypp;
var xp:Number = xpp*_cosAlpha+zpp*_sinAlpha;
var zp:Number = zpp*_cosAlpha-xpp*_sinAlpha;
var x:Number = xp;
var y:Number = yp*_cosTheta-zp*_sinTheta;
return new Coordinate(x, y, 0);
}
/**
* Maps 2D screen coordinates into 3D coordinates. It is assumed that the target 3D y coordinate is 0.
* @param screen x coordinate
* @param screen y coordinate
* @return Coordinate instance containig 3D x, y, and z
*/
public function mapToIsoWorld(screenX:Number, screenY:Number):Coordinate {
var z:Number = (screenX/_cosAlpha-screenY/(_sinAlpha*_sinTheta))*(1/(_cosAlpha/_sinAlpha+_sinAlpha/_cosAlpha));
var x:Number = (1/_cosAlpha)*(screenX-z*_sinAlpha);
return new Coordinate(x, 0, z);
}
}
}