Moving object by single touch - Libgdx - libgdx

May be this will be a very basic question,but as a newbie,I am confused of it.
In my libGDX Project,I wants to move the player.
Initially player is on left side.For the first tap player should move to opposite side and occupy the position there.for the next tap it should move to left.and will continue like this.
I implemented this logic.Now problem is that my player is not at all moving but just occupying the opposite position on tap.I used a velocity value but it does not make any effect on the code.
I want to make it move along the way,not just occupying the position.
Please help.
public float ninjaX = Constants.W_WIDTH;
public float ninjaY =Constants.WORLD_HEIGHT/2+Constants.WORLD_HEIGHT/4;
public float ninjaVelocity =100f;
public boolean isLeftBool=true;
public void ninjaMove() {
if (isLeftBool) {
ninjaX = ninjaX+ ninjaVelocity;
setPosition(Constants.WORLD_WIDTH - (Constants.W_WIDTH+Constants.PLAYER_HEIGHT/2), ninjaY);
isLeftBool = false;
}
else
{
ninjaX=ninjaX-ninjaVelocity;
setPosition(ninjaX,ninjaY);
isLeftBool = true;
}
}
updating player in render:
if (MyInputProcessor.isTap) {
MyInputProcessor.isTap = false;
ninja.ninjaMove();
}

Your player coordinates changes should depend on delta time:
x1 = x0 + v * Δt
x1 - is new coordinate
x0 - is current coordinate
v - speed
Δt - time span between x0 and x1
LibGDX provides the method to get the time span between current and last frames:
Gdx.graphics.getDeltaTime();
So, changing your code accordingly should make your player move smoothly (depends on velocity):
ninjaX = ninjaX + ninjaVelocity * Gdx.graphics.getDeltaTime();
Same thing for substraction in your else block.
You also probably want to set x coordinate (ninjaX) as well as y (currently you're no passing it in your setPosition method):
setPosition(ninjaX, ninjaY);
*I'm guessing here because I don't know what the method does

This is just an example of how you could solve this.
You don't give an explanation of what setPosition() does and why it is called so I will ignore it.
In your render():
public void render(float delta){
....
ninja.update(delta);
}
In your Ninja.class
private final Vector2 leftPos = new Vector(20, 60);
private final Vector2 rightPos = new Vector(80, 60);
private Rectangle bound = new Rectangle(80,60,32,32);
private Vector2 currentPos;
private float moveSpeed = 100f;
public Ninja(){
currentPos = leftPos;
}
public void update(float delta){
if(bound.x > currentPos.x)bound.x += moveSpeed * delta;
else bound.x -= moveSpeed * delta;
}
public void move(){
if(currentPos == leftPos)currentPos = rightPos;
else currentPos = leftPos;
}
Then in you input processor call ninja.move() in touchDown()
None of this is tested.
The reason you need to multiply moveSpeed with delta time is to make movement independent of fps. This way ninja will move the same distance in the same time no matter how many fps the game runs.

Related

How to make the camera follow the player?

I'm making a game in libgdx which includes the player being able to move vertically beyond the set screen size.
As for my question, if I have the screen size set at a certain width and height, what is required to make the actual game world larger for the camera to follow the player?
This is of course my targeted screen size in the Main game class:
public static final int WIDTH = 480, HEIGHT = 800;
Below that I currently have :
public static final int GameHeight = 3200;
GameHeight is the value I test for whether the player is going out of bounds.
Here is the problem. With this code, the player is centered on the screen, and moves horizontally, rebounding off the screen bounds (As it would without the camera, but neglecting the change in y-position)
public GameScreen(){
cam = new OrthographicCamera();
cam.setToOrtho(false, 480, 800);
}
#Override
public void render(float delta) {
// TODO Auto-generated method stub
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
cam.position.y = player.getPosition().y;
cam.update();
batch.setProjectionMatrix(cam.combined);
player.update();
player.draw(batch);
}
If I remove:
cam.position.y = player.getPosition().y;
The camera is placed at the bottom of the virtual world and the ball starts at the top (y = 3200) and travels downward. When it reaches y = 800, it shows up as it should.
I've found a lot of examples that indicate in writing that setting the cameras position to the players y position should force the camera to follow the player, whether it's moving up or down, but it either freezes y movement or sets the camera at the bottom the virtual world.
Any help is appreciated, thanks!
I would try doing cam.position.set(player.getPosition().x, player.getPosition().y). This will make the camera follow your player and it should not cause any "freezing."
private val worldTransform = Matrix4()
private val cameraPosition = Vector3()
private val objPosition = Vector3()
private var rot = Quaternion()
private var carTranslation = Vector3(0f, 0f, 0f)
fun focus(obj: BulletObject) {
// worldTransform
obj.entity?.motionState?.getWorldTransform(worldTransform)
// objPosition
worldTransform.getTranslation(objPosition)
obj.entity?.modelInstance?.transform?.getTranslation(carTranslation)
// get rotation
worldTransform.getRotation(rot)
println("rot.angle: ${rot.getAngleAround(Vector3.Y)}")
val rad = Math.toRadians(rot.getAngleAround(Vector3.Y).toDouble())
// pointFromCar
val pointFromCar = Vector2(-3f * sin(rad.toFloat()), -3f * cos(rad.toFloat()));
cameraPosition.set(Vector3(objPosition.x + pointFromCar.x, objPosition.y + 1f, objPosition.z + pointFromCar.y))
// camera set position
camera.position.set(cameraPosition)
camera.lookAt(objPosition)
camera.up.set(Vector3.Y)
camera.update()
}

AS3 tracking and using coordinates of a rotated object

How does one track and use the coordinates of an object that is rotated on initialization?
Let's say I have a sword that is put on the stage in Main init(); and rotated (adjusted) so that it would look ok together with the character perspective. In another class however, I am making the sword rotate some more on a keypress timer event so to create a 'swing' animation.
All this is done through flashdevelop. I only used CS6 to create the symbols. And as this 'swing' is happening, I want to add another symbol onto the tip of the sword which is a collision point object. It's being added to the stage when the swing starts and removed after every swing. I want this object to follow the very tip of the sword, yet it seems like I can only achieve that it follows the coordinates of the original sword object, as if I hadn't initially modified the rotation of the said sword. I tried to implement GlobalToLocal() and LocalToGlobal() methods, but I don't think I fully understand what is happening with that.
I hope I'm being clear enough of what I'm trying to do. Thank you. This is the relevant code in question. The code is as was before I tried the two mentioned methods and the issue currently is exactly as described before that. Do I want any of those methods or am I just doing something else wrong?
Main initialization:
sword = new Sword();
sword.x = 53;
sword.y = 90;
addChild(sword);
sword.rotationZ = -150;
sword.rotationY = 25;
sword.rotationX = -15;
Coll_Point = new coll_point();
The class that deals with the swing has a method like this:
private function SwingTime(event:Event):void
{
Main.Coll_Point.x = Main.sword.x + Main.sword.width;
Main.Coll_Point.y = Main.sword.y + Main.sword.height;
Main.MazeNr1.addChild(Main.Coll_Point);
if (Main.sword.rotationZ > -330)
Main.sword.rotationZ -= 20;
if (Main.sword.rotationX < 15)
Main.sword.rotationX += 10;
if ((Main.sword.rotationZ == -330) && (Main.sword.rotationX == 15))
{
SwingTimer.stop();
SwingBckTimer.start();
}
}
Edit:
A more holistic version of the code:
public class Main extends MovieClip
{
public static var from_point:Point = null;
public static var to_point:Point = new Point();
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
// Puts everything on the stage here.
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
PlayerInst = new Dorf();
PlayerInst.x = 45;
PlayerInst.y = 51;
addChild(PlayerInst);
sword = new Sword();
sword.x = 53;
sword.y = 90;
sword.rotationZ = -150;
sword.rotationY = 25;
sword.rotationX = -15;
from_point = new Point (Main.sword.width, Main.sword.height);
to_point = sword.localToGlobal(from_point);
addChild(sword);
swordBD = new BitmapData(32, 32, true, 0x0000000000);
swordBD.draw(sword);
Coll_Point = new coll_point();
Coll_PointBD = new BitmapData(2, 2, true, 0x0000000000);
Coll_PointBD.draw(Coll_Point);
}
}
This is how the Main looks like and literally every single object instantiation is added onto the stage this way. Including collision points, background, characters, gradient fills of line of sight radius, etc. And the relevant symbol class goes somewhat like this:
public class Creature extends MovieClip
{
protected var Swing:Boolean;
private var SwingTimer:Timer = new Timer (5, 0);
private var SwingBckTimer:Timer = new Timer (150, 1);
// Constructor.
public function Creature()
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
// Initializer.
private function init(event:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
SwingTimer.addEventListener(TimerEvent.TIMER, SwingTime);
SwingBckTimer.addEventListener(TimerEvent.TIMER, SwingBack);
}
private function SwingAction():void
{
if (Swing == true)
{
SwingTimer.start();
}
}
private function SwingTime(event:Event):void
{
Main.Coll_Point.x = Main.sword.localToGlobal(Main.from_point).x;
Main.Coll_Point.y = Main.sword.localToGlobal(Main.from_point).y;
Main.sword.addChild(Main.Coll_Point);
trace(Main.Coll_Point.x);
trace(Main.Coll_Point.y);
if (Main.sword.rotationZ > -330)
Main.sword.rotationZ -= 20;
if (Main.sword.rotationX < 15)
Main.sword.rotationX += 10;
if ((Main.sword.rotationZ == -330) && (Main.sword.rotationX == 15))
{
SwingTimer.stop();
SwingBckTimer.start();
}
}
private function SwingBack(event:Event):void
{
Main.sword.rotationZ = -150;
Main.sword.rotationX = -15;
//Main.MazeNr1.removeChild(Main.Coll_Point);
}
There is also a rather long update(); function that animates and moves every single object that needs moving.
I think your problem might be in
Main.Coll_Point.x = Main.sword.x + Main.sword.width;
Main.Coll_Point.y = Main.sword.y + Main.sword.height;
Coll_Point expects global coordinates.
The parts + Main.sword.width and + Main.sword.height only work as expected if the sword is not rotated so that height is aligned with the y-axis and width with the x-axis.
You should use localToGlobal() on the position that is local to Main.sword (
Main.sword.width, Main.sword.height) to get the global position that represents the swords rotated tip before you add it as a child.
There are two ways you can approach this (you seem to have somewhat combined both). You can either
Add the Coll_Point as a child to something above the sword in hierarchy (Stage, MazeNr1, ...) and update the position manually every timer callback. You would have to recalculate the position everytime, so take the localToGlobal() from init to your timer function. It won't update if it doesn't get called.
For that you should have this kind of code in the timer callback:
var local:Point = new Point(Main.sword.width, Main.sword.height);
var global:Point = Main.sword.localToGlobal(local);
Main.Coll_Point.x = global.x;
Main.Coll_Point.y = global.y;
Add the point as a child to the sword. This might be a better approach as then the position will be updated automatically. What I did not remember before was that you then give the coordinates in "local" form, so do not use localToGlobal()
Run this once where you create the Collision_Point:
Coll_Point.x = <your x offset>;
Coll_Point.y = <your y offset>;
Main.sword.attachChild(Coll_Point);
Instead of sword height and width you might want to try something like -height and width/2.
Here is a quick (and not the prettiest) picture to demonstrate the problem. Local space is rotated with the object:
The only thing I can imagine to help you with this problem is to have your collision object have the same registration point as the sword. What I mean is that the orientation points should match, and the collision graphic should be moved inside of the sprite so that it matches the position of the top of the sword.
This way you can put the collision object at the very same location of the sword and apply the very same rotation. This way it will move along with the top of the sword and still have hitTest working properly.
I cannot imagine any other way to figure this out as any code will get bounds and positions. But the real thing that matters is the registration point and the top of the sword, which is a graphic thing and cannot be dealt with coding.
I hope you can imagine what I mean - if now, just say and I will provide an image for you :)

Actionscript 3/Flash: Basic Game Loop Stuttering Problems

I'm trying to make a basic game in Flash and Actionscript 3.
As of now, I've been working on a smooth game loop but ran into problems. I tried to implement a fixed time-stamp loop seen: http://gafferongames.com/game-physics/fix-your-timestep/ and in Flixel.
The main issue that I have right now is that moving a simple object across the screen produces noticeable stuttering. I am aiming for a smoother experience but can't seem to figure out what the issue is.
The main loop is called on an Event.ENTER_FRAME at 60 fps.
These variables are instantiated first:
public var total:uint = 0;
public var fixedDT:Number = 1000.0/60.0; //Shoot for 60 FPS in MS
public var accumulator:int = 0;
public var maxAccumulation:uint = 120;
This is the main loop on every ENTER_FRAME:
//Most times are in ms
var mark:uint = getTimer();
var elapsedMS:uint = mark-total;
total = mark;
accumulator += elapsedMS;
if(accumulator > maxAccumulation){
accumulator = maxAccumulation;
}
while(accumulator > fixedDT){
step();
accumulator = accumulator - fixedDT;
}
//Convert from ms to secs. to interpolate graphics drawing (linear interpolation)
renderGameState(accumulator/fixedDT/1000.0);
step() is just updating every game-object with the fixed delta-time. The game object update function is simple and is as follows:
//First part is just updating the previous position for graphic interpolation
position.x += velocity.x*deltaTime;
position.y += velocity.y*deltaTime;
For rendering, I am just drawing bitmap.copyPixel. The graphical interpolation I mentioned is using a basic linear interpolation function that uses prev./curr. position and deltaTime to calculate the drawX/Y.
public function render(bitmap:BitmapData, deltaTime:Number, xOff:Number, yOff:Number):void{
this.x = lerp(prevPosition.x,position.x,deltaTime) + xOff;
this.y = lerp(prevPosition.y,position.y,deltaTime) + yOff;
bitmap.copyPixels(bitmapData, bitmapData.rect,new Point(this.x,this.y),null,null,true);
}
public function lerp(v0:Number, v1:Number, t:Number):Number {
return (1-t)*v0 + t*v1;
}
However, there is noticeable stuttering appearing. In the image below, I don't clear the bitmap before drawing to it. You should be able to see that there's a lot of variation between the spacing of circles rendered, and sometimes it's extremely noticeable.
http://i.stack.imgur.com/00c39.png
I would appreciate any help at all, thanks!
I don't know if this helps but here's the code I use to fix my time step.
private var _pause :Boolean;
private var _prevTimeMS :int;
private var _simulationTime :Number;
override public function update():void
{
super.update();
if (!_pause)
{
var curTimeMS:uint = getTimer();
if (curTimeMS == _prevTimeMS)
{
return;
}
var deltaTime:Number = (curTimeMS - _prevTimeMS) / 1000;
if (deltaTime > 0.05)
{
deltaTime = 0.05;
}
_prevTimeMS = curTimeMS;
_simulationTime += deltaTime;
while (space.elapsedTime < _simulationTime)
{
// Your game step goes here.
_space.step((stage.frameRate > 0) ? (1 / stage.frameRate) : (1 / 60));
}
}
}
(Originally taken from a Nape Physics sample)

Instantiate Class at Specific Time

I am trying to make a simple game using libgdx. One thing that I am stuck with is making enemies spawn at specific times. If I do something like
if (t == 10)
new Enemy();
I might miss this specific time or maybe spawn the same enemy twice. What I have right now is something like
float t = 0
float timeElapsed = 0;
update (float delta) {
timeElapsed += getDeltaTime();
if (timeElapsed > 0.1) {
t++;
timeElapsed = 0;
}
}
This gives me the approximate elapsed time in tenths of seconds for t, but it really doesn't feel like the way I should be doing this.
I have a solution I use in my games that might be useful. I actually created a Timer class:
public class Timer
{
protected float remaining;
protected float interval;
public Timer(float interval)
{
this.interval = interval;
this.remaining = interval;
}
public boolean hasTimeElapsed() { return (remaining < 0.0F); }
public void reset() { remaining = interval; }
public void reset(float interval) {
this.interval = interval;
this.remaining = interval;
}
public void update(float delta) { remaining -= delta; }
}
You initialize the Timer to a certain time period, then in your update(delta) method you call Timer.update(delta) on all your Timers, then check if any of the timers have elapsed by calling Timer.hasTimeElapsed().
In your case, you only need one Timer object, since the enemies are spawned in sequence. Once you spawn an enemy, you reset the Timer (changing the spawn period if you want) and wait for it to go off again.
You can also modify the Timer object to use the subject-observer pattern in order to trigger callbacks when a timer goes off. This is useful if you have logic that needs to know when a timed event occurs, but the logic does not have direct access to the delta time.
Also, if you have a slow frame with eg. getDeltaTime() = 0.2, the enemy's spawn will be delayed.
The simplest way that comes to mind is to get rid of t - compare directly against timeElapsed, and keep track of the object references to know whether you've spawned each enemy. ie.
if (enemy1 == NULL && elapsedTime > 10) {
enemy1 = new Enemy();
}
if (enemy2 == NULL && elapsedTime > 30) {
enemy2 = new Enemy();
}
For a more scalable approach, you could create a linked list of spawn times, and when you spawn an enemy advance the list pointer. That way you only have to compare against one time (the spawn-time on the current list node) per frame.
Addendum: it's rarely a good idea to use == in the context of floating point numbers. See http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html for gory details.
Why do you increment t and then you spawn enemies based on t value. Why don't you do it like this ?
final float step = 0.1f;
float timeElapsed = 0f;
update (float delta) {
timeElapsed += delta;
while (timeElapsed > step){
timeElapsed-=step;
createEnemy();
}
}
With this approach, when your game lags and you get delta lets say 0.5f and you step is 0.1, you will create 5 enemies. I don't know if you want or don't want this beviour

Finding Something lighter than Sprites!

I am making a Sim City like game. There are lots of tiles. When I first started. I was just using a tilesheet. I was copying the necessary pieaces from the tilesheet. on to a blank bitMapData. I then took the bitMapData and put it into a bitMap which I then put into a DisplayObject. It worked great!
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);
Only problem was I needed to make my tiles interactive. I needed to highlight them and change colors and stuff. So I used the Sprite object. It works great but I can only have so many on the stage at once. or else it moves slow when I scroll. I need something Lighter then a sprite, but yet I can still turn into a object to make interactive. Anyone have any ideas ???
If you have a lot of tiles, that will impact performance because Flash needs to update the transformations of a lot of display objects (which internally means a lot of matrix calculations, and subsequent redraws of big areas of the screen.)
There is another way to achieve interactivity, if you find that you must use a single bitmap data for performance. Keep an "abstract" (i.e. not graphical) data model in memory, that stores your game state. Make sure that you are able to read from your store where a certain element is positioned in the game world. Then you can use a flat bitmap data to render the game world, because the individual positions are stored elsewhere.
When the user clicks the DisplayObject containing the bitmap data (a Sprite in which the bitmap is drawn using a bitmap fill, or that wraps a Bitmap), look in your model which of your game elements was hit by that click.
// 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());
}
}
}
Here, whenever the player clicks the world graphics, the loop tries to find that element which was directly under the mouse position. You will need to implement a hitTest() method on all your game element data models, of course. Such a method simply checks the supplied world space position against the tile's area:
// 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;
}
The GameElement class is not an display object, but has worldX and worldY properties indicating where it is located in the world. It's width and height properties define it's dimensions.
The trick from hereon is to make sure that the rendered bitmap and your model storage is synchronized, so that a tile's position on the bitmap really corresponds to it's worldX/worldY properties in the data model.
I am one step ahead of you. And that is a great idea. Its alot easier to keep a data representation of the world when the tiles are squared. I therefore can take my mouseX/tileWidth, and thats hw many columns I moved from left to right. same with the Y axis.
Not only that but coordinates start at top left corner.
But issue I have is that my tiles are Isometric. So instead of the X axis start off like...
012345678
0
1
2
3
4
5
6
7
8
My tiles are aligned like...
00
1 1
2 2
3 3
4 4
5 6
its a little sloppy. but the right side represents the y axis and the left represents the x axis. and the center origin is in the center of the screen. not on the top left. I am trying to figure out how to measure where my mouse is from the center and out on both sides. This sounds extremely difficult. I am not sure if its possible. The game is suppose to be like a sim city like game. The first sim city was squares not isometric. I dont think they went isometric until they started using 3d. I wonder if its possible to create a illusion of isometric on a square tile.
Ive been reading this great book on isometrics. They show to calculate tiles in 3d space. and even calculate your mouse in 3d space as well. here is the code. Its alot, but I hope someone else understands it more then I. The book was written by jobe makar on building multiplayer worlds. I wanted to share it because the code it is pretty simple as far as amount of code put into it. only 2 classes needed. I am not that good with trigonometry. so I cant really interpret how the math is getting the results. hopefully someone can explain that for me :D.
Y coordinates are not given because the width is = to height. The coordinates method is just a custom made Point class which holds x, y and 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];
}
}
}
Then we have the isometric class that calculates 3d space.
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);
}
}
}