Nape Physics ShapeDebug seems to be scaled - actionscript-3

i have a strange problem with a simple nape demo... here's my code
package com.secretpackage {
import flash.display.Sprite;
import flash.events.Event;
import flash.text.TextField;
import nape.phys.Body;
import nape.shape.Circle;
import nape.space.Space;
import nape.util.ShapeDebug;
import nape.geom.Vec2;
import nape.phys.BodyType;
import nape.phys.Material;
public class Main extends Sprite {
// -------
private var world_db:Space=new Space(new Vec2(0,1000));
private var debug:ShapeDebug;
private var napeDebugSprite:Sprite = new Sprite();
private var sphere:Body;
private var labels:TextField;
// -------
public function Main():void
{
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
debug = new ShapeDebug(stage.stageWidth, stage.stageHeight, stage.color);
labels = new TextField();
var posX:int = stage.stageWidth/4;
var posY:int = stage.stageHeight/4;
var r:int = 10;
sphere= new Body(BodyType.KINEMATIC, new Vec2(posX, posY));
sphere.shapes.add(new Circle(r, new Vec2(posX, posY), Material.rubber()));
sphere.space = world_db;
labels.x = 0;
labels.y = 0;
addChild(labels);
var tc:test_circle = new test_circle();
addChild(tc);
tc.x = stage.stageWidth / 2;
tc.y = stage.stageHeight / 2;
addChild(napeDebugSprite);
debug.drawConstraints=true;
napeDebugSprite.addChild(debug.display);
addEventListener(Event.ENTER_FRAME, update);
}
private function update(e:Event):void {
world_db.step(1/stage.frameRate, 10, 10);
debug.clear();
debug.draw(world_db);
debug.flush();
labels.text = sphere.position.x + " - " + sphere.position.y +
"\n" + stage.stageWidth + " - " + stage.stageHeight +
"\n" + napeDebugSprite.width + " - " + napeDebugSprite.height +
"\n" + debug.display.width + " - " + debug.display.height;
}
}
}
Plese note:
- sphere is a Circle with radius=10 placed at StageWidth/4 and StageHeight/4;
- test_circle is a Movieclip of a circle with radius=10 placed at StageWidth/2 and StageHeight/2;
When i compile this script i get ... http://i.imgur.com/MAYF3j9.png?1
The two circles are centered and sphere has a doubled radius.
Am i doing something wrong?
Thank you.

You set up the Body to have position (stageWidth/4, stageHeight/4), you then added a Circle shape, whose local offset is also (stageWidth/4, stageHeight/4), so when the body is un-rotated the circle will end up being at (stageWidth/2, stageHeight/2).
As to the graphical size difference, I can only assume that your graphic is not actually 'radius 10' but 'width/height 10' which is half the width/height of a radius 10 circle (whose width/height is 20)

A temporary solution is to scale debug:ShapeDebug, so code becomes...
....
addChild(napeDebugSprite);
debug.drawConstraints=true;
//Scaling
debug.display.scaleY = 0.5;
debug.display.scaleX = 0.5;
napeDebugSprite.addChild(debug.display);
....
This fixes the problem, but it is just a workaround.

Related

Make three MovieClips appear and disappear inside a snowglobe when shaken

I used a creative cow tutorial to create my own snow globe that moves and snow reactivates - it really is a great tutorial.
What I'm trying to do is Change between 3 Movie clips in the ActionScript - But each time I add my movie clip names - Or try and add a simple visibility code I break my snow globe actions.
I have my MovieClip instances named friendsSceneThree, BuddiesSceneTwo and HatsOffSceneOne. I would think they'd be good but somewhere I'm missing something. Right now I can't get the code to even SEE The movieclips I'm getting a simple:
TypeError: Error #1006: value is not a function.at SnowGlobeContainer/update()
Down in the 'if drag' Update is where I'd like to Change from One MClip to the Next.
What Am I Not Seeing?!?! Any help would be greatly appreciated! Thanks
Here is the ActionScript:
package {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.geom.Point;
public class SnowGlobeContainer extends Sprite {
public var snowForeground:SnowGeneratorCircle;
public var snowBackground:SnowGeneratorCircle;
public var friendsSceneThree:MovieClip;
public var buddiesSceneTwo:MovieClip;
public var hatsOffSceneOne:MovieClip;
public var drag:Boolean = false;
public var over:Boolean = false;
public var startPos:Point = new Point;
public var mouseDownOffset:Point = new Point;
public var bounds:Rectangle = new Rectangle;
public var vel:Point = new Point(0,0);
public var pos:Point = new Point(x,y);
public var old:Point = new Point(x,y);
public var gravity:Number = 5+(Math.random()*1);
public var restitution:Number = 0.5;
public var friction:Number = 0.9;
public function SnowGlobeContainer() {
// save some initial persistant properties
startPos.x = this.x;
startPos.y = this.y;
old.x = this.x;
old.y = this.y;
bounds.x = 0;
bounds.y = 0;
bounds.width = 600;
bounds.height = startPos.y;
// add mouse interaction listeners and show the cursor on rollover
this.mouseChildren = false;
this.useHandCursor = true;
this.buttonMode = true;
this.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
this.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
this.addEventListener(Event.ENTER_FRAME, update);
}
protected function onMouseOver(e:MouseEvent=null):void { over = true; }
protected function onMouseOut(e:MouseEvent=null):void { over = false; }
protected function onMouseDown(e:MouseEvent=null):void {
// Save the offset of your mouse when you first start dragging. Same functionality as startDrag(false)
mouseDownOffset.x = mouseX;
mouseDownOffset.y = mouseY;
drag = true;
}
protected function onMouseUp(e:MouseEvent=null):void {
vel.x = vel.y = 0;
pos.x = x;
pos.y = y;
drag = false;
}
public function update(e:Event):void {
// this if/else statement controls the mouse over and out instead of using event listeners
if(mouseY < -175 || mouseY > 175 || mouseX < -175 || mouseX > 175){
if(over) onMouseOut();
}else{
if(!over) onMouseOver();
}
if(drag){
// drag around..
this.x = parent.mouseX - mouseDownOffset.x;
this.y = parent.mouseY - mouseDownOffset.y;
// keep this thing on the table :)
if(y >= bounds.height) y = bounds.height;
// if you "shake" or move the mouse quickly, we are going to reset the snow particles
var d:Point = new Point(Math.abs(old.x - x), Math.abs(old.y - y));
if(d.x > 50 || d.y > 50 ){
snowForeground.reset();
snowBackground.reset();
friendsSceneThree.visible = false;
}
// update the history position
old.x = x;
old.y = y;
vel.y = (y-old.y)/2;
}else{
// if you drop this object it should have a bit of realistic falling..
vel.y += gravity;
pos.y += vel.y;
// bounce
if(pos.y > bounds.height){
pos.y = bounds.height;
vel.y *= -(Math.random()*restitution);
}
y = pos.y;
}
}
}
}
I appreciate the help -- If you haven't noticed I'm new to all of this scripting. I'm looking in on lynda.com and other forums. the SnowGeneratorCircle.as is:
package {
import flash.display.Sprite;
import flash.events.Event;
public class SnowGeneratorCircle extends Sprite {
var totalFlakes:int = 500;
var flakes:Array = new Array();
public function SnowGeneratorCircle() {
addSnowFlakes();
addEventListener(Event.ENTER_FRAME, update);
}
protected function addSnowFlakes():void{
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = new SnowFlake();
addChild(f);
flakes.push(f);
}
}
public function reset():void{
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = flakes[i];
f.reset();
}
}
public function update(e:Event=null):void {
for(var i:int=0; i<totalFlakes; i++){
var f:SnowFlake = flakes[i];
f.update(0);
}
}
}
}
I debugged - didn't clean up the code, because every time I did - it broke the actions. So I left the code with the double spacing. That's how it went in when I copied and pasted from the tutorial anyway.
Here's the error on line 173 - which is the MovieClip I'd like to have change.
Attempting to launch and connect to Player using URL /Volumes/Lacie Biggest S2S/GRaid/Veronica
/V/Rubio/Work/SUBARU/SnowGlobe Subaru/SnowGlobeAnima/snowGlobeShakev3.swf
[SWF] Volumes:Lacie Biggest S2S:GRaid:Veronica:V:Rubio:Work:SUBARU:SnowGlobe >Subaru:SnowGlobeAnima:snowGlobeShakev3.swf - 468081 bytes after decompression
TypeError: Error #1006: value is not a function.
at SnowGlobeContainer/update()[/Volumes/Lacie Biggest S2S/GRaid/Veronica/V/Rubio/Work/SUBARU
/SnowGlobe Subaru/SnowGlobeAnima/SnowGlobeContainer.as:173]
I just don't know how to get the actionscript to find my MovieClips and then swap them out wt each shake of the globe.

parallax scrolling down with ActionScript 3.0

i want create road parallax scrolling down with flash in as3, when i run the script, the parallax moving up. and this my code
package {
import flash.display.MovieClip;
import flash.events.Event;
public class kelas extends MovieClip{
this i create variable
public var road:road1;
public var road2:road1;
public var roadContainer:MovieClip;
public var roadBreadth:Number;
public var car:Car;
public function kelas(){
and this create car , road and container
car = new Car();
road = new road1();
road2 = new road1();
roadBreadth = 653.7;
car.y = 10.0;
car.x = 10;
road.y = 10.0;
road.x = 10;
road2.y = road.y + roadBreadth;
road2.x = road.x;
//* add child object
roadContainer = new MovieClip();
roadContainer.addChild(road);
roadContainer.addChild(road2);
this.addChild(roadContainer);
this.addEventListener(Event.ENTER_FRAME, onEnterFrame);
public function onEnterFrame(event:Event):void
{
car.y = car.y + 15;
roadContainer.y = 10 - car.y + 10;
if (road.y + roadBreadth + roadContainer.y < 0)
{
road.y = road.y + (2 * roadBreadth);
}
if (road2.y + roadBreadth + roadContainer.y < 0)
{
road2.y = road2.y + (2 * roadBreadth);
}
}
}
i want this backgroung moving down is not moving up, please help me
Have a look at this sample, it's a pretty simple idea to wrap an object around. Make sure your multiplier is set to the amount of roads that you're wrapping.
if (road.y > 600) {
road.y -= road.y * 2;
} else {
road.y++;
}
may be your roadContainer contains road, so when you move roadContainer, you moves road too.
so, just move don't let it contains, add when you move the background.y++, road will like moving up

Shaking effect - Flash CS6 ActionScript3.0

This question is related to ActionScript 3.0 and Flash CS6
I am trying to make an object shake a bit in a certain for some seconds. I made it a "movieclip" and made this code:
import flash.events.TimerEvent;
var Machine_mc:Array = new Array();
var fl_machineshaking:Timer = new Timer(1000, 10);
fl_machineshaking.addEventListener (TimerEvent.TIMER, fl_shakemachine);
fl_machineshaking.start ();
function fl_shakemachine (event:TimerEvent):void {
for (var i = 0; i < 20; i++) {
Machine.x += Math.random() * 6 - 4;
Machine.y += Math.random() * 6 - 4;
}
}
When testing the movie I get multiple errors looking exactly like this one:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
at Historieoppgave_fla::MainTimeline/fl_shakemachine()
at flash.utils::Timer/_timerDispatch()
at flash.utils::Timer/tick()
Also, the object doesnt shake, but it moves steadily upwards to the left a bit every tick.
To the point:
I wish to know how I stop the script after the object is not in the stage/scene anymore and also how to make it shake around, as I do not see what is wrong with my script, please help, thank you ^_^
AStupidNube brought up a great point about the original position. So adding that to shaking that should be a back and forth motion, so don't rely on random values that may or may not get you what you want. Shaking also has a dampening effect over time, so try something like this:
Link to working code
• http://wonderfl.net/c/eB1E - Event.ENTER_FRAME based
• http://wonderfl.net/c/hJJl - Timer Based
• http://wonderfl.net/c/chYC - Event.ENTER_FRAME based with extra randomness
**1 to 20 shaking items Timer Based code - see link above for ENTER_FRAME code••
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.events.TimerEvent;
import flash.geom.Point;
import flash.text.TextField;
import flash.utils.Timer;
public class testing extends Sprite {
private var shakeButton:Sprite;
private var graphic:Sprite;
private var shakerPos:Array;
private var shakers:Array;
private var numShakers:int = 20;
private var dir:int = 1;
private var displacement:Number = 10;
private var shakeTimer:Timer;
public function testing() {
this.shakers = new Array();
this.shakerPos = new Array();
this.addEventListener(Event.ADDED_TO_STAGE, this.init);
}
private function init(e:Event):void {
this.stage.frameRate = 30;
this.shakeTimer = new Timer(33, 20);
this.shakeTimer.addEventListener(TimerEvent.TIMER, this.shake);
this.graphics.beginFill(0x333333);
this.graphics.drawRect(0,0,this.stage.stageWidth, this.stage.stageHeight);
this.graphics.endFill();
this.createShakers();
this.shakeButton = this.createSpriteButton("Shake ");
this.addChild(this.shakeButton);
this.shakeButton.x = 10;
this.shakeButton.y = 10;
this.shakeButton.addEventListener(MouseEvent.CLICK, this.shakeCallback);
}
private function createSpriteButton(btnName:String):Sprite {
var sBtn:Sprite = new Sprite();
sBtn.name = btnName;
sBtn.graphics.beginFill(0xFFFFFF);
sBtn.graphics.drawRoundRect(0,0,80,20,5);
var sBtnTF:TextField = new TextField();
sBtn.addChild(sBtnTF);
sBtnTF.text = btnName;
sBtnTF.x = 5;
sBtnTF.y = 3;
sBtnTF.selectable = false;
sBtn.alpha = .5;
sBtn.addEventListener(MouseEvent.MOUSE_OVER, function(e:Event):void { sBtn.alpha = 1 });
sBtn.addEventListener(MouseEvent.MOUSE_OUT, function(e:Event):void { sBtn.alpha = .5 });
return sBtn;
}
private function createShakers():void {
var graphic:Sprite;
for(var i:int = 0;i < this.numShakers;i++) {
graphic = new Sprite();
this.addChild(graphic);
graphic.graphics.beginFill(0xFFFFFF);
graphic.graphics.drawRect(0,0,10,10);
graphic.graphics.endFill();
// add a 30 pixel margin for the graphic
graphic.x = (this.stage.stageWidth-60)*Math.random()+30;
graphic.y = (this.stage.stageWidth-60)*Math.random()+30;
this.shakers[i] = graphic;
this.shakerPos[i] = new Point(graphic.x, graphic.y);
}
}
private function shakeCallback(e:Event):void {
this.shakeTimer.reset();
this.shakeTimer.start();
}
private function shake(e:TimerEvent):void {
this.dir *= -1;
var dampening:Number = (20 - e.target.currentCount)/20;
for(var i:int = 0;i < this.numShakers;i++) {
this.shakers[i].x = this.shakerPos[i].x + Math.random()*10*dir*dampening;
this.shakers[i].y = this.shakerPos[i].y + Math.random()*10*dir*dampening;
}
}
}
}
Now this is a linear dampening, you can adjust as you see fit by squaring or cubing the values.
You have to remember the original start position and calculate the shake effect from that point. This is my shake effect for MovieClips. It dynamically adds 3 variables (startPosition, shakeTime, maxShakeAmount) to it. If you use classes, you would add them to your clips.
import flash.display.MovieClip;
import flash.geom.Point;
function shake(mc:MovieClip, frames:int = 10, maxShakeAmount:int = 30) : void
{
if (!mc._shakeTime || mc._shakeTime <= 0)
{
mc.startPosition = new Point(mc.x, mc.y);
mc._shakeTime = frames;
mc._maxShakeAmount = maxShakeAmount;
mc.addEventListener(Event.ENTER_FRAME, handleShakeEnterFrame);
}
else
{
mc.startPosition = new Point(mc.x, mc.y);
mc._shakeTime += frames;
mc._maxShakeAmount = maxShakeAmount;
}
}
function handleShakeEnterFrame(event:Event):void
{
var mc:MovieClip = MovieClip(event.currentTarget);
var shakeAmount:Number = Math.min(mc._maxShakeAmount, mc._shakeTime);
mc.x = mc.startPosition.x + (-shakeAmount / 2 + Math.random() * shakeAmount);
mc.y = mc.startPosition.y + (-shakeAmount / 2 + Math.random() * shakeAmount);
mc._shakeTime--;
if (mc._shakeTime <= 0)
{
mc._shakeTime = 0;
mc.removeEventListener(Event.ENTER_FRAME, handleShakeEnterFrame);
}
}
You can use it like this:
// shake for 100 frames, with max distance of 15px
this.shake(myMc, 100, 15);
BTW: In Flash, you should enable 'permit debugging' in your 'publish settings' to have more detailed errors. This also gives back the line numbers where your code is breaking.
update:
Code now with time / maximum distance separated.
Here is a forked version of the chosen answer, but is a bit more flexible in that it allows you to set the frequency as well. It's also based on time as opposed to frames so you can think in terms of time(ms) as opposed to frames when setting the duration and interval.
The usage is similar to the chosen answer :
shake (clipToShake, durationInMilliseconds, frequencyInMilliseconds, maxShakeRange);
This is just an example of what I meant by using a TimerEvent as opposed to a ENTER_FRAME. It also doesn't require adding dynamic variables to the MovieClips you are shaking to track time, shakeAmount, and starting position.
public function shake(shakeClip:MovieClip, duration:Number = 3000, frequency:Number = 30, distance:Number = 30):void
{
var shakes:int = duration / frequency;
var shakeTimer:Timer = new Timer(frequency, shakes);
var startX:Number = shakeClip.x;
var startY:Number = shakeClip.y;
var shakeUpdate:Function = function(e:TimerEvent):void
{
shakeClip.x = startX + ( -distance / 2 + Math.random() * distance);
shakeClip.y = startY + ( -distance / 2 + Math.random() * distance);
}
var shakeComplete:Function = function(e:TimerEvent):void
{
shakeClip.x = startX;
shakeClip.y = startY;
e.target.removeEventListener(TimerEvent.TIMER, shakeUpdate);
e.target.removeEventListener(TimerEvent.TIMER_COMPLETE, shakeComplete);
}
shakeTimer.addEventListener(TimerEvent.TIMER, shakeUpdate);
shakeTimer.addEventListener(TimerEvent.TIMER_COMPLETE, shakeComplete);
shakeTimer.start();
}
-4 <= Math.random() * 6 - 4 < 2
You add this offset to Machine.x 20 times, so chances for moving to the left is greater, than to the right.
It seems that you looking for something like this:
for each (var currentMachine:MovieClip in Machine_mc)
{
currentMachine.x += Math.random() * 6 - 3;
currentMachine.y += Math.random() * 6 - 3;
}

Creating 10 circles in ActionScript 3

Iam trying to create a simple method in AS3 that adds 10 circles, each 30px in diameter in a column down the left-hand-side of the stage, so the first appears in the top-left corner and the last in the bottom-right. I would appreciate any help here. Thanks.
My current code follows: - It currently just returns 10 circles with no positioning.
package
{
import flash.display.*;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Circles extends MovieClip
{
private var timer:Timer = new Timer(100, 10);
public function Circles()
{
timer.addEventListener(TimerEvent.TIMER, createCircles);
timer.start();
}
private function createCircles(e:TimerEvent):void
{
var bcircle:MovieClip = new MovieClip();
var xpos:int = 0;
var ypos:int = 0;
bcircle.graphics.beginFill(0x0033CC);
bcircle.graphics.drawCircle(xpos,ypos,15);
bcircle.graphics.endFill();
bcircle.x = Math.random() * stage.stageWidth;
bcircle.y = Math.random() * stage.stageHeight;
addChild(bcircle);
}
}
}
bcircle.x = Math.random() * stage.stageWidth;
bcircle.y = Math.random() * stage.stageHeight;
These are the lines you want to be paying attention to as these lines control where each circle is placed when added to the stage.
Circle diameter = 30px, stage height (for example) = 400px.
30 goes into 400 13.33 times (400/30) so each circle needs to be spaced 13.3px further down than the last.
You can store a variable that counts how many circles are already on the stage and use it to multiply 13.3 to find the appropriate y value:
var i:int = 0;
private function createCircles(e:TimerEvent):void
{
var bcircle:MovieClip = new MovieClip();
var xpos:int = 0;
var ypos:int = 0;
bcircle.graphics.beginFill(0x0033CC);
bcircle.graphics.drawCircle(xpos,ypos,15);
bcircle.graphics.endFill();
bcircle.x = 0;
bcircle.y = (30 + 13.3) * i; // First circle placed at 0, Second placed at 43.3...
i++; // Increment i each time function is called
addChild(bcircle);
}
You can apply a similar method to then increment the x position of each circle once i reaches 10 (10 circles have been placed), use a trigger to detect this: if(i == 10)
This might help ...
package {
import flash.display.Graphics;
import flash.display.Sprite;
import flash.events.TimerEvent;
import flash.utils.Timer;
public class Circles extends Sprite {
private const _circles:Array = []; // reusable container
private var _timer:Timer;
public function Circles() {
_timer = new Timer(1000, 10);
_timer.addEventListener(TimerEvent.TIMER, timer_timerHandler);
_timer.addEventListener(TimerEvent.TIMER_COMPLETE, timer_timerCompleteHandler);
_timer.start();
}
private function createCircle():Sprite {
const sprite:Sprite = new Sprite();
drawCircleInGraphics(sprite.graphics);
addChild(sprite);
return sprite;
}
private function drawCircleInGraphics(graphics:Graphics, color:uint = 0x0033CC, radius:uint = 15):void {
graphics.beginFill(color);
graphics.drawCircle(0, 0, radius);
graphics.endFill();
}
private function createNewCircleAndPositionIt():void {
_circles[_circles.length] = createCircle();
if (_circles.length > 1) {
const last:Sprite = _circles[_circles.length - 1],
predecessor:Sprite = _circles[_circles.length - 2];
last.x = predecessor.x + 30;
last.y = predecessor.y + 30;
}
}
private function timer_timerHandler(event:TimerEvent):void {
createNewCircleAndPositionIt();
}
private function timer_timerCompleteHandler(event:TimerEvent):void {
_timer.removeEventListener(TimerEvent.TIMER, timer_timerHandler);
_timer.removeEventListener(TimerEvent.TIMER_COMPLETE, timer_timerCompleteHandler);
_timer = null;
}
}
}

Getting from getCharBoundaries to BitMapData

I'm trying to convert all letters in a textfield to bitmap data. I then want to animate each of them. I'm able to return an array of rectangles using getCharBoundaries. But then how do I convert each letter to BitMapData?
package
{
import flash.display.Sprite;
import flash.geom.Rectangle;
import flash.text.TextField;
import flash.text.TextFieldType;
import flash.text.TextFormat;
public class LetterBitmapData extends Sprite
{
private var tf:TextField;
private var letterSprite:Sprite;
public function LetterBitmapData()
{
makeTF();
getRectangles();
};
private function makeTF():void
{
tf = new TextField();
tf.width = 400;
tf.height = 100;
tf.selectable = false;
tf.multiline = true;
tf.wordWrap = true;
tf.text = "Now is the winter of our discontent made glorious summer by this sun of York.";
tf.setTextFormat(new TextFormat("_sans", 16, 0));
addChild(tf);
}
private function getRectangles():Array
{
var result:Array = [];
var rectangle:Rectangle;
for (var i:int = 0; i < tf.text.length; i++)
{
rectangle = tf.getCharBoundaries(i);
result.push(rectangle); //create an array of CharBoundary rectangles
//trace("RECTANGLE x: " + rectangle.x + " y: " + rectangle.y + " width: " + rectangle.width + " height: " + rectangle.height );
}
return result;
}
}
}
You could animate your letters without turning them into Bitmaps as long as you're using embed fonts that is...
Instead of creating an array of rectangles, you could create an array of TextFields , associated to their specific rectangle in order to keep the coordinates of each letter. After that it should be possible to animate each TextField.