Place an object at another objects current position - actionscript-3

I am trying to place an object at my players current position but when i move away the object sticks to my player. I kind of know why it sticking to my player but i cant think of any other code to use.
Hero is my player that i move around the screen.
Thanks Lochy
var trap1:trap = new trap();
function keydown(event:KeyboardEvent) :void {
if(event.keyCode ==32)
addChild(trap1);
trap1.x = hero.x;
trap1.y = hero.y;

There are several ways to accomplish this task. There is basically a detail you have to know. In Flash, the display list is responsible for managing elements on the screen. The DisplayObject and DisplayObjectContainer classes provide the API to access and manipulate the display list.
A naive approach would be
function placeAbove(d1:DisplayObject, d2:DisplayObject):void
{
if (!d1 || !d2) return;
d1.x = d2.x;
d1.y = d2.y;
}
But when both DisplayObjects have different parents, the DisplayObjects are not part of te same coordinate system, so this little method won't work. I coded a small example:
package
{
import flash.display.DisplayObject;
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.geom.Point;
public class Points extends Sprite
{
public function Points()
{
const child1:Sprite = createSquare(50, 50, 0xFF0000, .5)
, child2:Sprite = createSquare(100, 100, 0x0000FF, .5)
, container1:Sprite = new Sprite()
, container2:Sprite = new Sprite();
DisplayObjectContainer(placeRandomly(addChild(container1))).addChild(child1);
DisplayObjectContainer(placeRandomly(addChild(container2))).addChild(child2);
placeAbove(child1, child2);
}
private function createSquare(width:Number, height:Number, color:uint = 0, alpha:Number = 1):Sprite
{
const sprite:Sprite = new Sprite();
sprite.graphics.beginFill(color, alpha);
sprite.graphics.drawRect(0, 0, width, height);
sprite.graphics.endFill();
return sprite;
}
private function placeAbove(child1:Sprite, child2:Sprite):void
{
const point:Point = child2.localToGlobal(new Point(0, 0))
, point2:Point = child1.globalToLocal(point);
child1.x = point2.x;
child1.y = point2.y;
}
private function placeRandomly(displayObject:DisplayObject):DisplayObject
{
displayObject.x = Math.random() * 100;
displayObject.y = Math.random() * 100;
return displayObject;
}
}
}
The Application generate 2 squares and adds it into different parents. The containers (parents) are placed randomly on the screen and so are the two child display objects. The placeAbove method does all the magic. It calculates the position from the second display object globally and the maps it to the first display objects target local position within the parent's coordinate system.
Ii hope it helps.

It's not very clear how your display list is organized, but try adding the trap as a child of the hero's parent. i.e.:
hero.parent.addChild(trap1);

Related

Endless repeating scrolling background

I got a problem with AS3 and AIR. I'm working on a side-scrolling game for smartphones with a plane and I use different backgrounds as layers.
Before all other: I use GPU and only bitmaps, quality is set to low. So Performance settings are all set for smartphone use.
I putted them into a rectangle using the drawing API and move the background with a matrix:
protected var scrollingBitmap:BitmapData;
protected var canvas:Graphics;
protected var matrix:Matrix;
public function move(dx:Number, dy:Number):void {
matrix.translate(dx, dy);
if(dx != 0) matrix.tx %= scrollingBitmap.width;
if(dy != 0) matrix.ty %= scrollingBitmap.height;
drawCanvas();
}
protected function drawCanvas():void {
canvas.clear();
canvas.beginBitmapFill(scrollingBitmap, matrix, true, true);
canvas.drawRect(0, -scrollingBitmap.height, 1404, scrollingBitmap.height);
}
UPDATE2 (
Take a look at this: http://plasticsturgeon.com/2010/06/infinite-scrolling-bitmap-backgrounds-in-as3/
I used this to create my backgrounds.
With this I can simulate that my plane is flying to the right without moving the whole background and I can use a small single graphic which repeats every time (for the foreground layer).
For the background layer I use this method, too, but with a much larger graphic and I move it only with less the speed of my plane to simulate a far background.
My move-method is on an enterframe event. So I can update the background every frame with the "movement" of my plane.
)
The plane can exceed the height of the bitmaps. Everytime the bitmap comes back into the window/screen a real long lag occurs. And when the plane flies very fast, the game start to lag, too.
My first approach was to use .PNG files (but they are very big: 1-3MB size).
My next approach was to use .GIF files (much less size).
With both it's the same. So it can't be that.
I read about draw() and copyPixels() but I don't know, how I can use those to repeat the image.
UPDATE1:
protected var scrollingBitmap:BitmapData;
protected var canvas:Bitmap;
protected function init(e:Event):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
canvas = new Bitmap(new BitmapData(1404, scrollingBitmap.height, true), "auto", true);
this.addChild(canvas);
drawCanvas();
}
public function move(dx:Number, dy:Number):void {
if(dx != 0) dx %= scrollingBitmap.width;
if(dy != 0) dy %= scrollingBitmap.height;
drawCanvas(dx, dy);
}
protected function drawCanvas(xPos:Number = 0, yPos:Number = 0):void {
canvas.bitmapData.copyPixels(scrollingBitmap, new Rectangle(0, 0, 1404, scrollingBitmap.height), new Point(xPos, yPos), scrollingBitmap);
}
I think you'd be better off with a Bitmap instead of using the graphics object with fill. copyPixels is very fast. So what you'd do is simply copyPixels over the top of whatever was there before, presuming everything is opaque. If everything is not opaque, you'll need to use your source bitmap as its own alpha data so previously drawn pixels don't show through.
Let's reframe your canvas so it is a Bitmap and not a MC. your new code will look like:
protected function drawCanvas():void {
canvas.bitmapData.copyPixels(scrollingBitmap, new Rectangle(0, 0, scrollingBitmap.width, scrollingBitmap.height), new Point(0,0), scrollingBitmap);
}
Oh, and look at that! Not only is this code faster, it's only one line of code!
EDIT: Added working code
package {
import flash.display.MovieClip;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.geom.Rectangle;
import flash.geom.Point;
public class EndlessBG extends MovieClip{
//this one stays stationary, we're getting the pixels for the right side of the pic from here
private var _source:BitmapData;
//this is the one moving to the left (the pixels for the right side are not visible except for once a cycle);
private var _movingPixels:BitmapData;
private var _canvas:Bitmap;
private var _xOffset:int = 0;
private var _rect:Rectangle = new Rectangle();;
private var _point:Point = new Point();
public function EndlessBG() {
super();
_source = new BathroomStillLife();
_canvas = new Bitmap(new BitmapData(_source.width, _source.height));
_canvas.bitmapData.draw(_source);
_canvas.x = stage.stageWidth/2 - _canvas.width/2;
_canvas.y = 5;
addChild(_canvas);
addEventListener(Event.ENTER_FRAME, gameLoop);
setGeometryDefaults();
_movingPixels = new BitmapData(_source.width, _source.height);
_movingPixels.copyPixels(_source, _rect, _point);
//turn this on to watch red pixels be drawn where the source pixels are coming in
//_source = new BitmapData(_source.width, _source.height, false, 0xFF0000);
}
private function gameLoop(e:Event):void {
_xOffset--;//where the background is moving to
if (_xOffset < -_source.width) {
_xOffset = 0;
//this doesn't seem to work correctly:
//_movingPixels.scroll(_source.width, 0);
_movingPixels = new BitmapData(_source.width, _source.height);
_movingPixels.copyPixels(_source, _rect, _point);
}
trace(_xOffset);
setGeometryDefaults();
_movingPixels.scroll(-1, 0);
//draw the moved part of the canvas
_canvas.bitmapData.copyPixels(_movingPixels, _rect, _point);
//If we stop here, we get a smear to the right
//so, get the remaining pixels directly from the source
//1) reset our rect and point to be to the right side
_rect.x = 0;
_rect.width = -_xOffset;
_point.x = _source.width + _xOffset;
//2) copy from the source
_canvas.bitmapData.copyPixels(_source, _rect, _point);
}
private function setGeometryDefaults():void {
_rect.x=0;
_rect.y=0;
_rect.width = _source.width;
_rect.height = _source.height;
_point.x = 0;
_point.y = 0;
}
}
}
Not ideal, and not polished enough yet for a blog post, but should get you started.
Edit:
Eventually I did write that blog post.
http://www.greensock.com/blitmask
This might help although not free

lineTo not working properly

i'm having problems with my code or something... the thing is i'm using lineTo from one objects coordinates to the other's, but no mater where the second object is the line always goes off to a random direction somewhere in the lower left corner and i'm stuck.
here is the code:
var spr:Shape = new Shape();
spr.graphics.clear();
spr.graphics.lineStyle(2,0xffffff);
spr.x = latM[1].x;
spr.y = latM[1].y;
spr.graphics.lineTo(latM[0].x,latM[0].y);
trace("latM[0].x = "+latM[0].x+"\tlatM[0].y = "+latM[0].y+
"\nlatM[1].x = "+latM[1].x+"\tlatM[1].y = "+latM[1].y);
spr.graphics.lineTo(latM[0].x,latM[0].y);
addChild(spr);
after a few tries i found out that all lines point [wrote lean by mistake] towards the lower left TT_TT..
I assume latM[1] and latM[0] are the two shapes your trying to draw a line between. If that is case did you notice you have two lineTo going to the same point?
What you need is.
spr.graphics.moveTo(latM[0].x, latM[0].y);
spr.graphics.lineTo(latM[1].x, latM[1].y);
Here is a small prototype to show you how it works. (This is not meant to be super solid code it is a quick and dirty prototype.)
package src
{
import flash.display.Sprite;
import flash.events.Event;
public class Main extends Sprite
{
private var obj1:Sprite = new Sprite();
private var obj2:Sprite = new Sprite();
private var lineSprite:Sprite = new Sprite();
// for testing your line.
// we don't really need it for this prototype however it
// is being used since this is how your accessing your Objects.
private var latM:Array = [];
public function Main()
{
addEventListener(Event.ADDED_TO_STAGE, initMain);
}
private function initMain(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, initMain);
obj1.graphics.lineStyle(1, 0);
obj1.graphics.beginFill(0xccccff);
obj1.graphics.drawCircle(0, 0, 20);
obj1.graphics.endFill();
obj1.x = 100;
obj1.y = 100;
obj2.graphics.lineStyle(1, 0);
obj2.graphics.beginFill(0xffcccc);
obj2.graphics.drawCircle(0, 0, 20);
obj2.graphics.endFill();
obj2.x = 400;
obj2.y = 200;
// for testing your line.
latM.push(obj1, obj2);
addChild(obj1);
addChild(obj2);
addChild(lineSprite);
addEventListener(Event.ENTER_FRAME, handleEnterFrame);
}
private function handleEnterFrame(e:Event):void
{
// this will clear and redraw the line between the two sprites
// every frame and thus always be up to date.
lineSprite.graphics.clear();
lineSprite.graphics.lineStyle(2, 0xff0000);
lineSprite.graphics.moveTo(latM[0].x, latM[0].y);
lineSprite.graphics.lineTo(latM[1].x, latM[1].y);
//obj1.x++; // uncomment this line and you can watch it move and keep the line perfect.
}
}
}
What do you mean lean towards the lower left?
You can only draw a straight line with lineTo.
"lineTo" only goes from the current point to the point set via its parameters.
The moveTo function will move the point without drawing.
The following code will draw a box 100 X 100
var spr:Shape = new Shape();
spr.graphics.clear();
spr.graphics.lineStyle(2,0xff00ff);
spr.graphics.moveTo(0,0);
spr.graphics.lineTo(0,100);
spr.graphics.lineTo(100,100);
spr.graphics.lineTo(100,0);
spr.graphics.lineTo(0,0);
addChild(spr);

Box2D Walls - same code: the left one works, the right one doesn't

I'm making a simple Box2D game ( http://iwanttobeacircle.com ), where you start off as a triangle and bounce off bigger shapes to gain sides.
I'm having a bizarre bug with my walls... both are created from the same class, yet the left one works and the right doesn't. If I only add the right one, then it works, but for some reason adding them both seems to be causing a problem somewhere.
The WallSegment class is below:
package com.carmstrong.iwanttobeacircle {
import flash.display.DisplayObjectContainer;
import flash.display.Sprite;
import flash.display.Shape;
import Box2D.Collision.Shapes.*;
import Box2D.Dynamics.*;
import Box2D.Common.Math.b2Vec2;
import com.carmstrong.iwanttobeacircle.Config;
public class WallSegment extends Actor {
private var _shape:Sprite;
private var _shapeBody:b2Body;
private var _colour:uint = 0x666666;
private var prevEdge:int;
private var thisEdge:int;
private var side:Number;
private var name:String;
private var _pathWidth:int;
private var _parent:DisplayObjectContainer;
public function WallSegment(Width:int, Position:String, Parent:DisplayObjectContainer) {
name = "Wall";
_pathWidth = Width;
_parent = Parent;
if(Position == "left") {
side = 1;
prevEdge = (Config.WIDTH - Config.PREV_WIDTH)/2;
thisEdge = (Config.WIDTH-_pathWidth)/2;
} else {
side = -1;
prevEdge = Config.WIDTH-(Config.WIDTH - Config.PREV_WIDTH)/2;
thisEdge = Config.WIDTH-(Config.WIDTH-_pathWidth)/2;
}// check if its left or right wall
//Create the costume
drawShape();
drawBody();
super(_shapeBody, _shape);
}//DynamicWall
private function drawShape():void {
//Draw visual
_shape = new Sprite();
var left:Sprite = new Sprite();
left.graphics.beginFill(_colour, 0.5);
left.graphics.moveTo(prevEdge, Config.HEIGHT/2);
left.graphics.lineTo(prevEdge-Config.WIDTH*side, Config.HEIGHT/2);
left.graphics.lineTo(thisEdge-Config.WIDTH*side, -Config.HEIGHT/2);
left.graphics.lineTo(thisEdge, -Config.HEIGHT/2);
left.graphics.endFill();
_shape.addChild(left);
_parent.addChild(_shape);
}//drawShape
private function drawBody():void {
//Create the shape definition
var shapeDef:b2PolygonDef = new b2PolygonDef();
shapeDef.vertexCount = 4;
b2Vec2(shapeDef.vertices[0]).Set(prevEdge/Config.RATIO, Config.HEIGHT/2/Config.RATIO);
b2Vec2(shapeDef.vertices[1]).Set((prevEdge-Config.WIDTH*side)/Config.RATIO, Config.HEIGHT/2/Config.RATIO);
b2Vec2(shapeDef.vertices[2]).Set((thisEdge-Config.WIDTH*side)/Config.RATIO, -Config.HEIGHT/2/Config.RATIO);
b2Vec2(shapeDef.vertices[3]).Set(thisEdge/Config.RATIO, -Config.HEIGHT/2/Config.RATIO);
shapeDef.density = 0;
shapeDef.friction = 10;
shapeDef.restitution = 0.45;
//Create the body definition (specify location here)
var shapeBodyDef:b2BodyDef = new b2BodyDef();
shapeBodyDef.position.Set(0, -Config.HEIGHT*(Config.CURRENT_SEGMENT+1)/Config.RATIO);
//Create the body
_shapeBody = Config.world.CreateBody(shapeBodyDef);
//Create the shape
_shapeBody.CreateShape(shapeDef);
}//drawBody
}//class
}//package
To keep the level dynamic, the walls are drawn just ahead of the player object each time in the main class, using the following code:
private function addWall(Width:int) {
Config.CURRENT_SEGMENT++;
//addWalls
var leftWall:WallSegment = new WallSegment(Width, "left",camera);
var rightWall:WallSegment = new WallSegment(Width, "right",camera);
Config.PREV_WIDTH = Width;
}//addWall
I'm getting this error:
TypeError: Error #1010: A term is
undefined and has no properties. at
com.carmstrong.iwanttobeacircle::GameContactListener/Add()
at
Box2D.Dynamics.Contacts::b2CircleContact/Evaluate()
at
Box2D.Dynamics.Contacts::b2Contact/Update()
at
Box2D.Dynamics::b2ContactManager/Collide()
at Box2D.Dynamics::b2World/Step() at
com.carmstrong.iwanttobeacircle::IWantToBeACircle/everyFrame()
Which refers to the GameContactListener class, shown below (the add function is at the bottom):
package com.carmstrong.iwanttobeacircle {
import Box2D.Collision.b2ContactPoint;
import Box2D.Dynamics.b2ContactListener;
public class GameContactListener extends b2ContactListener {
public function GameContactListener() {
}//GameContactListener
override public function Add(point:b2ContactPoint):void {
if (point.shape1.GetBody().GetUserData() is ShapeActor && point.shape2.GetBody().GetUserData() is ShapeActor) {
//trace("Two shapes collided: Shape 1 has "+ point.shape1.GetBody().GetUserData().sides + " sides and Shape 2 has " + point.shape2.GetBody().GetUserData().sides + " sides");
if (point.shape1.GetBody().GetUserData().sides > point.shape2.GetBody().GetUserData().sides) {
//remove side from shape 1 and add side to shape 2
point.shape1.GetBody().GetUserData().sides--;
point.shape2.GetBody().GetUserData().sides++;
//point.shape2.GetBody().GetUserData().updateColour;
} else if (point.shape1.GetBody().GetUserData().sides < point.shape2.GetBody().GetUserData().sides) {
//remove side from shape 2 and add side to shape 1
point.shape1.GetBody().GetUserData().sides++;
point.shape2.GetBody().GetUserData().sides--;
//point.shape2.GetBody().GetUserData().updateColour;
}// add side to smaller shape and take away from larger shape
if(point.shape1.GetBody().GetUserData().name == "player" || point.shape2.GetBody().GetUserData().name == "player") {
if(point.shape1.GetBody().GetUserData().name == "player" && point.shape2.GetBody().GetUserData().sides <= point.shape1.GetBody().GetUserData().sides) {
Config.FULFILLMENT++;
Config.SOUNDS[3+Math.ceil(Math.random()*5)][1].play();
trace(Config.FULFILLMENT);
} else if (point.shape2.GetBody().GetUserData().name == "player" && point.shape1.GetBody().GetUserData().sides <= point.shape2.GetBody().GetUserData().sides) {
Config.FULFILLMENT++;
Config.SOUNDS[Math.ceil(Math.random()*5)][1].play();
trace(Config.FULFILLMENT);
} else {
Config.SOUNDS[Math.ceil(Math.random()*3)][1].play();
Config.FULFILLMENT = int(Config.FULFILLMENT - 5);
trace(Config.FULFILLMENT);
}//if other shape is less than or equal to player
}//if one of the shapes is player
}// if both collider objects are shapes
super.Add(point);
}// override Add
}//class
}//package
I would appreciate any thoughts or ideas. Also, this is my first go at Box2D so would appreciate any tips on how to make my code more efficient.
Thanks in advance
You're asking two questions here
Why is the left and right wall collision detection not working?
Why is there an error on the GameContactListener/Add() method?
It looks like they may have the same root problem. I'm seeing you're adding the wall segments as children of the "camera" (had to trace where this add was happening... you pass a reference of "camera" into the constructor of the object.)
i.e. var leftWall:WallSegment = new WallSegment(Width, "left",camera);
Within there, you add the leftWall as a child of that object. But I'm not sure what "camera" is... Is this part of your game world object?
Also, what are your trace statements for point.shape1 and point.shape2?
What 2 objects are colliding?

Papervision3D; rotate child objects within camera view

It's my first time with Papervision3D and I have created a slide show of images that is skewed on the y-axis. Smallest photos on the left, and they increase in size going to the right. So they zoom from left to right, smallest to biggest.
I have a tooltip that pops up when you hovers over the photo, but the tooltip also gets skewed proportionate to the camera view (slanted). I want the tooltip's angle to be independent of the entire camera view.
Any idea how to rotate objects independent of the parent's camera angle?
Thanks!
my_obj = new DisplayObject3D();
my_plane = my_obj.addChild(new Plane(bla bla));
my_obj.lookAt(camera);
The 'lookAt' bit is what you need.
Why not draw the tooltips in 2d? You can get the on-screen position of the images and then just draw a regular Sprite like so:
package
{
import flash.display.Sprite;
import flash.text.TextField;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.typography.Text3D;
import org.papervision3d.view.BasicView;
public class PVTest extends Sprite
{
private var world:BasicView;
private var text:Text3D;
private var text2d:TextField;
public function PVTest()
{
world = new BasicView(stage.width, stage.height, true, true);
var colorMat:ColorMaterial = new ColorMaterial();
colorMat.interactive = true;
var planeContainer:DisplayObject3D = new DisplayObject3D();
var plane:Plane;
for(var i:int = 0; i < 11; i++)
{
plane= new Plane(
colorMat,
100, 100,
10);
plane.x = (i * 105) - 500;
plane.addEventListener(InteractiveScene3DEvent.OBJECT_OVER, handleMouseOver);
plane.addEventListener(InteractiveScene3DEvent.OBJECT_OUT, handleMouseOut);
planeContainer.addChild(plane);
}
planeContainer.rotationY = 10;
world.scene.addChild(planeContainer);
world.camera.z = -500;
addChild(world);
world.startRendering();
}
private function handleMouseOver(event:InteractiveScene3DEvent):void
{
var plane:Plane = Plane(event.displayObject3D);
plane.calculateScreenCoords(world.camera);
const OFFSET_X:int = -20;
const OFFSET_Y:int = 30;
text2d = new TextField();
text2d.text = "toolTip";
text2d.x = plane.screen.x + (stage.width/2) + OFFSET_X;
text2d.y = plane.screen.y + (stage.height/2) + OFFSET_Y;
addChild(text2d);
}
private function handleMouseOut(event:InteractiveScene3DEvent):void
{
removeChild(text2d);
}
}
}
Even for this example you'd have to offset the y position of the tooltip based on the objects scale but it may be easier than working out the rotations and is the best way to get a consistent looking result.

How to Draw a circle displaying a number in flex

I am flex newbie , so please forgive me if i am not using the right words to ask the following question. I want to know if there is a way to draw a circle which shows a number , like for ex. Graduated Circles representing its radius to show it's relevance. Is there a component which already do so , if not what is the best way to do this.
thanks.
Here's a quick example on how you could do it (to be continued to achieve your particular needs)
package
{
import flash.text.TextFormatAlign;
import flash.text.TextField;
import flash.display.Sprite;
import flash.text.TextFormat;
public class LabeledCircle extends Sprite
{
private var textField:TextField;
public function LabeledCircle(radius:Number, label:String = "")
{
// Prepares the textField
var textFormat:TextFormat = new TextFormat();
textFormat.align = TextFormatAlign.CENTER;
textField = new TextField();
textField.defaultTextFormat = textFormat;
addChild(textField);
// Sets the default parameters
this.radius = radius;
this.label = label;
}
public function set radius(radius:Number):void
{
// redraws the circle
graphics.clear();
graphics.beginFill(0x000000, .5);
graphics.drawCircle(0, 0, radius);
// recenters the textfield depending on the radius
textField.width = radius * 2;
textField.x = -radius;
}
public function set label(label:String):void
{
textField.text = label;
}
}
}
Flare has a component which is similar to the concentric circle example in the link you have posted. See Layouts > CirclePack in the demo.
I am not yet sure what you mean by 'associating a number'. Try this: Rendering text on a path.
Actionscript Drawing API - example here
Degrafa - Graphics framework which makes the Drawing API easier to use and includes a circle class