when tracing the mouseX / mouseY or localX / localY coordinates of a display object, why does x start at 1 while y starts at 0?
for example, i've drawn a simple 400 x 400 pixel sprite onto the stage with a MouseEvent.MOUSE_MOVE event listener that calls a handler function to trace the local coordinates of the mouse.
the first, top-left pixel returns {x:1, y:0} and the last, bottom-right pixel returns {x:400, y:399}. shouldn't both the x and y start and end with the same value? i'm not sure which makes more sense for a the first mouse coordinate (either 0 or 1) but it certainly doesn't make sense that they are different?
[SWF(width = "1000", height = "600", backgroundColor = "0xCCCCCC")]
import flash.display.Sprite;
import flash.events.MouseEvent;
var darkBlueRect:Sprite = createSprite();
darkBlueRect.x = 23;
darkBlueRect.y = 42;
addChild(darkBlueRect);
darkBlueRect.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveEventHandler);
function mouseMoveEventHandler(evt:MouseEvent):void
{
trace(darkBlueRect.mouseX, evt.localX, darkBlueRect.mouseY, evt.localY);
}
function createSprite():Sprite
{
var result:Sprite = new Sprite();
result.graphics.beginFill(0x0000FF, 0.5);
result.graphics.drawRect(0, 0, 400, 400);
result.graphics.endFill();
return result;
}
Report a bug, you've found one:
http://bugs.adobe.com/flashplayer/
I thought perhaps it was to make room for a line applied to the sprite among other things but all those tests proved not to be the case. This is, in my opinion, a bug. File it and I'll second it, or if you can't be bothered let me know I'll file it cause it should be fixed.
Update
I've just tried another test where I set the stageScaleMode to allow for scaling, then zoomed in 2-3 times to the object and tried to get a 0/0 reading on MOUSE_DOWN. Just can't be done apparently. I did get a 0 reading on the X finally but then the Y is out. I think this issue may come down to the fact that flash returns X/Y pointer position as a Number and not an int, and you can get decimal values on the pointer position as you'll notice if you're zoomed in. Perhaps it's just buggy code or it comes down to floating point precision issues based on how the decimal points are calculated, or if you're not zoomed in and the object isn't scaled, flash rounds that decimal value off an int and this may also explain the weird behavior. Dunno just guessing, thought I'd add the results of this extra test.
Related
I am working on a game. I constructed my player as here: (I am using a gravity on my world)
private ArrayMap<String, GameObject.Constructor> constructors = new ArrayMap<String, GameObject.Constructor>(String.class, GameObject.Constructor.class);
private ArrayList<GameObject> instances = new ArrayList<GameObject>();
assets.load("hand.obj", Model.class);
...
model = assets.get("hand.obj", Model.class);
constructors.put("hand", new GameObject.Constructor(model, new btBoxShape(new Vector3(2.5f, 7.5f, 2.5f)), 1f));
...
hand = constructors.get("hand").construct(); // that construct method returns me model, shape and constructions.. the GameObject extends ModelInstance, so i can use it like a modelinstance
hand.transform.setToTranslation(x, y, z);
hand.body.proceedToTransform(hand.transform);
hand.body.setUserValue(instances.size());
hand.body.setCollisionFlags(hand.body.getCollisionFlags()| btCollisionObject.CollisionFlags.CF_CUSTOM_MATERIAL_CALLBACK);
world.addRigidBody(hand.body);
hand.body.setContactCallbackFlag(OBJECT_FLAG);
hand.body.setContactCallbackFilter(OBJECT_FLAG);
Then, in render method I am moving it:
if (!hand.body.isActive()) hand.body.activate();
if (Gdx.input.isKeyPressed(Keys.W)){
hand.body.translate(new Vector3(0,0,-1));
}
else if (Gdx.input.isKeyPressed(Keys.S)) {
hand.body.translate(new Vector3(0,0,+1));
}
That's nice! The moving now works good, when I am moving at the flat ground. Whenever there is an object before me, it is not as expected. Because my player shape is biger than
object shape (which is 2.5f, 2.5f, 2.5f), it kind of falls on it. So I would like to set the rotation to be still the same, so the object will not be rotating (so it will not "fall" on the object before). And so I tried to do it, and I failed. Because there are functions like rotate, and I want to something like setRotation
. And so, there is a setToRotation, but you can not pass there a Quaternion.
I need help. I tried to use a btKinematicCharacterController but it was bad. The ghostObject every time falled through object, but the objects got a collision from him.
and so I want to create a player movment, like in games like Wow, minecraft, and so on.
I looked at the btKinematicCharacterController again. The reason why my ghostobject falled through the ground was. Generally, I don't know the reason: D probably I was using another broadphase for ghost, that for world. This line fixes it: characterController.setUseGhostSweepTest(false);
and I am getting another problem, when I am walking on my ground (a lot of objects), the character is getting to lesser Y position. I don't know why.
Here is my construction:
btPairCachingGhostObject ghostObject;
btConvexShape ghostShape;
btKinematicCharacterController characterController;
Vector3 characterDirection = new Vector3();
Vector3 walkDirection = new Vector3();
...
ghostObject = new btPairCachingGhostObject();
ghostObject.setWorldTransform(hand.transform);
ghostShape = new btCapsuleShape(5f, 0.5f);
ghostObject.setCollisionShape(ghostShape);
ghostObject.setCollisionFlags(btCollisionObject.CollisionFlags.CF_CHARACTER_OBJECT);
characterController = new btKinematicCharacterController(ghostObject, ghostShape, .00001f);
// And add it to the physics world
characterController.setUseGhostSweepTest(false);
world.addCollisionObject(ghostObject,
(short)btBroadphaseProxy.CollisionFilterGroups.CharacterFilter,
(short)(btBroadphaseProxy.CollisionFilterGroups.StaticFilter | btBroadphaseProxy.CollisionFilterGroups.DefaultFilter));
world.addAction(characterController);
... (in render - moving)
if (!load)
{
if (Gdx.input.isKeyPressed(Keys.LEFT)) {
hand.transform.rotate(0, 1, 0, 5f);
ghostObject.setWorldTransform(hand.transform);
}
if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
hand.transform.rotate(0, 1, 0, -5f);
ghostObject.setWorldTransform(hand.transform);
}
// Fetch which direction the character is facing now
characterDirection.set(-1,0,0).rot(hand.transform).nor();
// Set the walking direction accordingly (either forward or backward)
walkDirection.set(0,0,0);
if (Gdx.input.isKeyPressed(Keys.UP))
walkDirection.add(characterDirection);
if (Gdx.input.isKeyPressed(Keys.DOWN))
walkDirection.add(-characterDirection.x, -characterDirection.y, -characterDirection.z);
walkDirection.scl(4f * Gdx.graphics.getDeltaTime());
// And update the character controller
characterController.setWalkDirection(walkDirection);
// And fetch the new transformation of the character (this will make the model be rendered correctly)
}
world.stepSimulation(delta, 5, 1f/60f);
if (!load)
ghostObject.getWorldTransform(hand.transform);
How to fix this?
I set up the debugDrawer, so i was able to see the shapes of the bullet objects.. and my problem was that: the ghostObject(charController) was pushing my objects down.. Although my objects were static. So i set the mass of the objects to 0 and problem is fixed. But I still dont know, how it could push static objects. But i dont care. :)
EDIT: i will accept this answer in 2 hours, because now i cant.
I hope this hasn't been asked too much before. When I search I only get questions pertaining to rescaling to window size.
Now my question. I got one space ship firing a beam against another ship. I want the beam to show for some time and I want it to "bridge" the two ships. In other words, I want the beam to extend its width between the two ships.
I try to do this with a dot movie clip that is 1 pixel wide and high (and aligned left edge). I try to resize it with the following code: (target is the ship to be fire at and owner is the ship firing)
dist.vx = target.x - owner.x;
dist.vy = target.y - owner.y;
dist.dist = Math.sqrt(dist.vx*dist.vx + dist.vy*dist.vy);
width = dist.dist;
x = owner.x;
y = owner.y;
rotation = Math.atan2(target.y-y, target.x-x)*180/Math.PI;
This doesn't work as intended because 1) dot also gets alot bigger in the other dimension - how can I "turn off" this behavior? and 2) sometimes it seems to get way to wide - but only in certain angles...
Any suggestions on either solving the heigh/width scaling or on another way to achieve the same effect?
(I'm new to coding and flash.) Thanks!
By resizing a dot, you will have a rectangle...
You can dynamically create a sprite covering both ships and moveTo the hit point of one ship then lineTo the other ship... You do not need distance calculation at all. What you have to do is being careful on the placement of the sprite. So that you can calculate relative hitting points by simple math.
Suppose you have mc space contining mc ship1 and mc ship2, and hit point coords on ships are named hx, hy and you will use sprite s, calculation will be as follows.
// calculate hit points relative to mc space
var s1HX:int = ship1.x + ship1.hx,
s1HY:int = ship1.y + ship1.hy,
s2HX:int = ship2.x + ship2.hx,
s2HY:int = ship2.y + ship2.hy,
// sprite relative moveTo lineTo coords will be these.
mX: int, mY: int,
lX: int, lY: int;
// top left of sprite will be minimum of the hit coords.
s.x = (s1HX <= s2HX)? s1HX : s2HX;
s.y = (s1HY <= s2HY)? s1HY : s2HY;
// now we can get sprite relative moveTo lineTo coordinates:
mX = s1HX - s.x;
mY = s1HY - s.y;
lX = s2HX - s.x;
lY = s2HY - s.y;
The rest is implementation with using these with fancy line styles etc...
To create a new sprite:
var s:Sprite = new Sprite();
Adding / removing it to/from mc space:
space.addChild(s);
space.removeChild(s);
For graphics use the graphics object of sprite.
s.graphics
For setting line styles you can use:
s.graphics.lineStyle(...) ,
s.graphics.lineBitmapStyle(...),
s.graphics.lineGradientStyle(...)
Functions, please read the manual for usage.
After setting the line style to draw the line use:
s.graphics.moveTo(mX,mY);
s.graphics.lineTo(lX,lY);
For pulsating effects you have to do a little more complicated things such as using tween class which you can read about here: http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/fl/transitions/Tween.html
Note that:
Sprites are no complicated magic, they are like mc's but they do not have timelines etc.
Sprites try to scale when width or height change programmatically. So do not touch them, moveTo lineTo automatically sets the size of a sprite...
I'm making a simple game and have a Vector full of enemies in order to do hit-checking on them from my "laser" object (it's a space shmup). Every laser loops through the Vector and checks if it's occluding the hit circle. The problem lies in when one laser destroys an enemy, the rest of the lasers try to also check the same Vector, only to go out of bounds since the enemy's already been spliced out and it's changed the size of the Vector.
for each (var enemy:Enemy in enemies){
var distanceX = this.x - enemy.x;
var distanceY = this.y - enemy.y;
var distance = Math.sqrt( (distanceX*distanceX) + (distanceY*distanceY) );
if (distance <= enemy.hitRadius) {
enemy.removeEnemy();
enemies.splice(enemies.indexOf(enemy),enemies.indexOf(enemy));
}
}
How would I go about collecting the index of individual elements in the Vector to be deleted, then only deleting them when every Laser object is finished its checking?
edit: here's my removeEnemy() function from my Enemy class, just in case:
public function removeEnemy(){
removeEventListener(Event.ENTER_FRAME, move);
parent.removeChild(this);
trace("removed Enemy", enemies.indexOf(this));
}
edit edit: I'm also getting a null reference pointer error to "parent" in my removeEnemy() function... but only sometimes. I have a feeling that if I fix one of these two problems, the other will also be fixed but I'm not sure.
I fixed it! The problem was actually in how I used the "splice()" method. Turns out that the second parameter isn't the end index of where to stop splicing, it's the number of elements to be spliced. So when I was trying to splice element 0, I wasn't splicing anything, and when I was trying to splice element 3, I was also splicing 4 and 5. I feel like such a dunce for not reading the API right and wasting a couple hours on this. Thanks to everyone who commented-- you guys helped me rule out what I thought the problem was.
First of all sorry for some english mistakes. Portuguese is my first language(I am from Brazil)
Im trying to make a space game from scratch in AS3 and the way to move the ship is like in the game Air Traffic Chief.
I succeed at some point. But when the ship is very fast it start to shake and its not very smooth and clean as I want.
Here is what i have done: http://megaswf.com/s/2437744
As the code is very big so I pasted in pastebin: pastebin.com/1YVZ23WX
I also wrote some english documentation.
This is my first game and my first post here. I really hope you guys can help me.
Thanks in advance.
Edit:
As the code is very big i will try to clarify here.
When the user MouseDown and MouseMove the ship every coordinate is passed to an array.
When the user MouseUP this array is passed to a function that fix the array.
For example: If the distance between two coordinates is greater than 5px, the function creates a coordinate in the middle of the two coordinates.
if I take this function off the problem seen to be solved. But if the user move the mouse very slow it still happens. It also creates a problem that i was trying to solve with that function. as the distance of the two coordinates are very big when the ship arrive in one coordinate most of the line path disappear.
I uploaded a version without the function that fixes the array. http://megaswf.com/s/2437775
I think there is 2 ways for solving this problem
1- Try to fix the noise in the array of coordinates 2- Take off the function that create an coordinate between two points and try to fix the problem of the line path disappear.
Here is the 2 important functions:
this function moves the ship
private function mover():void
{
if (caminhoCoords[0]!=null) // caminhoCoords is the array that contain the path
{
var angulo:Number = Math.atan2(this.y - caminhoCoords[0][1], this.x - caminhoCoords[0][0]);
this.rotation = angulo / (Math.PI / 180);
this.x = this.x - velocidade * (Math.cos(angulo));
this.y = this.y - velocidade * (Math.sin(angulo));
var testex:Number = Math.abs(this.x - caminhoCoords[0][0]); //test to see the distance between the ship and the position in the array
var testey:Number = Math.abs(this.y - caminhoCoords[0][1]);
if (testey<=velocidade+2 && testex<=velocidade+2) // if is velocidade+2 close then go to the next coordnate
{
caminhoCoords.shift();
}
}
}
This function draw the line:
private function desenhaCaminho():void //draw the black Path
{
if(caminhoCoords.length>=1)
{
caminho.graphics.clear();
caminho.graphics.lineStyle(1, 0x000000, 1,true);
caminho.graphics.moveTo(caminhoCoords[0][0],caminhoCoords[0][1]);
for (var i:int = 1; i < caminhoCoords.length; i++)
{
caminho.graphics.lineTo(caminhoCoords[i][0], caminhoCoords[i][1]);
}
}else
{
caminho.graphics.clear();
}
}
Every time the ship arrive in one coordinate is take that coordinate off the array and redraw the array.
Is there a better way of doing that?
I believe if you set your registration point of the plane to the centre and use .snapto(path), it will improve the action.
Judging from just the look of the stuttering, I would guess you need to smooth out the "line" a fair bit. It's probably picking up a lot of noise in the line, which is then translated into the rotation of the plane. Either smooth out the rotation/position of the plane, or the line itself.
I'm learning ActionScript/Flash. I love to play with text, and have done a lot of that kind of thing with the superb Java2D API.
One of the things I like to know is "where, exactly, are you drawing that glyph?" The TextField class provides the methods getBounds and getCharBoundaries, but these methods return rectangles that extend far beyond the actual bounds of the whole text object or the individual character, respectively.
var b:Sprite = new Sprite();
b.graphics.lineStyle(1,0xFF0000);
var r:Rectangle = text.getCharBoundaries(4);
r.offset(text.x, text.y);
b.graphics.drawRect(r.x,r.y,r.width,r.height);
addChild(b);
b = new Sprite();
b.graphics.lineStyle(1,0x00FF00);
r = text.getBounds(this);
b.graphics.drawRect(r.x,r.y,r.width,r.height);
addChild(b);
Is there any way to get more precise information about the actual visual bounds of text glyphs in ActionScript?
Richard is on the right track, but BitmapData.getColorBounds() is much faster and accurate... I've used it a couple of times, and optimized for your specific needs its not as slow as one might think.
Cory's suggestion of using flash.text.engine is probably the "correct" way to go, but I warn you that flash.text.engine is VERY (very!) hard to use compared to TextField.
Not reasonably possible in Flash 9 -- Richard's answer is a clever work-around, though probably completely unsuitable for production code (as he mentions) :)
If you have access to Flash 10, check out the new text engine classes, particularly TextLine.
I'm afraid all the methods that are available on TextField are supposed to do what you have already found them to do. Unless performance is key in your application (i.e. unless you intend to do this very often) maybe one option would be to draw the text field to a BitmapData, and find the topmost, leftmost, et c colored pixels within the bounding box retrieved by getCharBoundaries()?
var i : int;
var rect : Rectangle;
var top_left : Point;
var btm_right : Point;
var bmp : BitmapData = new BitmapData(tf.width, tf.height, false, 0xffffff);
bmp.draw(tf);
rect = tf.getCharBoundaries(4);
top_left = new Point(Infinity, Infinity);
btm_right = new Point(-Infinity, -Infinity);
for (i=rect.x; i<rect.right; i++) {
var j : int;
for (j=rect.y; j<rect.bottom; j++) {
var px : uint = bmp.getPixel(i, j);
// Check if pixel is black, i.e. belongs to glyph, and if so, whether it
// extends the previous bounds
if (px == 0) {
top_left.x = Math.min(top_left.x, i);
top_left.y = Math.min(top_left.y, j);
btm_right.x = Math.max(btm_right.x, i);
btm_right.y = Math.max(btm_right.y, j);
}
}
}
var actualRect : Rectangle = new Rectangle(top_left.x, top_left.y);
actualRect.width = btm_right.x - top_left.x;
actualRect.height = btm_right.y - top_left.y;
This code should loop through all the pixels that were deemed part of the glyph rectangle by getCharBoundaries(). If a pixel is not black, it gets discarded. If black, the code checks whether the pixels extends further up, down, right or left than any pixel that has previuosly been checked in the loop.
Obviously, this is not optimal code, with nested loops and unnecessary point objects. Hopefully though, the code is readable enough, and you are able to make out the parts that can most easily be optimized.
You might also want to introduce some threshold value instead of ignoring any pixel that is not pitch black.