Drag, rotate and ease in ActionScript - actionscript

I need to make a MovieClip rotate around it's center point to the left or right depending on mouse drag. I got some basic semblance of what i want going, but it's pretty hackish. Normally i calculate the angle and such but i only really need to use the distance the mouse travels and apply it to the movieclip and for flavor add some nice easing when you let go.
public function Main()
{
var wereld:MainScreen = new MainScreen();
addChild( wereld );
wereld.x = -510;
planet = wereld["planet"];
wereld.addEventListener( MouseEvent.MOUSE_DOWN, startRotatingWorld );
}
private function startRotatingWorld( e:MouseEvent ):void
{
m_mouseStartPos = stage.mouseX;
stage.addEventListener( MouseEvent.MOUSE_UP, stopRotatingWorld );
stage.addEventListener( Event.MOUSE_LEAVE, stopRotatingWorld);
}
private function applyRotationToWorld( e:MouseEvent ):void
{
//Calculate the rotation
var distance:Number = (m_mouseStartPos - stage.mouseX) / 10000;
//apply rotation
planet.rotation += -distance //* 180 / Math.PI;
}
private function stopRotatingWorld():void
{
stage.removeEventListener( MouseEvent.MOUSE_MOVE, applyRotationToWorld );
}

here is source and demo of a potential solution for you:
http://wonderfl.net/c/o8t0
I based the drag rotation detection on keith peter's minimalcomps, specifically the source for his knob component
In the Minimal Comp's Knob source, you can get rotational, horizontal, and vertical movement in the 'onMouseMoved' function.
Finally I used TweenLite to handle the easing back. In my code I Tween the 'this' object, but in practice you should create a public value in the object you are tweening and tween that item, so you can have more that one item tweening easily.
If this is for a public facing project, let me know when you've implemented it; wouldn't mind taking a look on what it is for ^_^

Related

OpenLayers - lock rotation of box or rectangle geometry while modifying

Openlayers provides useful functions for drawing boxes and rectangles and also has ol.geom.Geometry.prototype.rotate(angle, anchor) for rotating a geometry around a certain anchor. Is it possible to lock the rotation of a box/rectangle while modifying it?
Using the OpenLayers example located here to draw a box with a certain rotation to illustrate the point:
I would like the box/rectangle to maintain its rotation while still being able to drag the sides longer and shorter. Is there a simple way to achieve this?
Answering with the solution I came up with.
First of all, add the feature(s) to a ModifyInteraction so you are able to modify by dragging the corners of the feature.
this.modifyInteraction = new Modify({
deleteCondition: eventsCondition.never,
features: this.drawInteraction.features,
insertVertexCondition: eventsCondition.never,
});
this.map.addInteraction(this.modifyInteraction);
Also, add event handlers upon the events "modifystart" and "modifyend".
this.modifyInteraction.on("modifystart", this.modifyStartFunction);
this.modifyInteraction.on("modifyend", this.modifyEndFunction);
The functions for "modifystart" and "modifyend" look like this.
private modifyStartFunction(event) {
const features = event.features;
const feature = features.getArray()[0];
this.featureAtModifyStart = feature.clone();
this.draggedCornerAtModifyStart = "";
feature.on("change", this.changeFeatureFunction);
}
private modifyEndFunction(event) {
const features = event.features;
const feature = features.getArray()[0];
feature.un("change", this.changeFeatureFunction);
// removing and adding feature to force reindexing
// of feature's snappable edges in OpenLayers
this.drawInteraction.features.clear();
this.drawInteraction.features.push(feature);
this.dispatchRettighetModifyEvent(feature);
}
The changeFeatureFunction is below. This function is called for every single change which is done to the geometry as long as the user is still modifying/dragging one of the corners. Inside this function, I made another function to adjust the modified rectangle into a rectangle again. This "Rectanglify"-function moves the corners which are adjacent to the corner which was just moved by the user.
private changeFeatureFunction(event) {
let feature = event.target;
let geometry = feature.getGeometry();
// Removing change event temporarily to avoid infinite recursion
feature.un("change", this.changeFeatureFunction);
this.rectanglifyModifiedGeometry(geometry);
// Reenabling change event
feature.on("change", this.changeFeatureFunction);
}
Without going into too much detail, the rectanglify-function needs to
find rotation of geometry in radians
inversely rotate with radians * -1 (e.g. geometry.rotate(radians * (-1), anchor) )
update neighboring corners of the dragged corner (easier to do when we have a rectangle which is parallel to the x and y axes)
rotate back with the rotation we found in 1
--
In order to get the rotation of the rectangle, we can do this:
export function getRadiansFromRectangle(feature: Feature): number {
const coords = getCoordinates(feature);
const point1 = coords[0];
const point2 = coords[1];
const deltaY = (point2[1] as number) - (point1[1] as number);
const deltaX = (point2[0] as number) - (point1[0] as number);
return Math.atan2(deltaY, deltaX);
}

Fast moving object leaves a "ghost" trail

I'm trying to draw a bullet in Monogame with a high velocity. When I draw it for about 400px/sec "Which is quite slow" but around 1500px/sec it starts "duplicating" or "ghosting" the Texture. I am fairly new to Monogame and do not have alot of knowledge on Graphics.
How can I move an object with High Velocity without creating a "ghost" effect ?
SpriteBatch Begin :
sb.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, SamplerState.LinearWrap, DepthStencilState.None, RasterizerState.CullNone,
null, Global.Camera.GetViewTransformationMatrix());
Draw Method :
public override void Draw(SpriteBatch sb)
{
Vector2 origin = new Vector2(source.Width / 2, source.Height / 2);
Rectangle tRect = Bounds;
sb.Draw(
texture: TDTGame.GameAssets.Texture,
destinationRectangle: tRect,
sourceRectangle: source,
rotation: MathHelper.ToRadians(Rotation - 270f), //Set rotation to forward of the texture.
color: Color.White,
origin: origin,
layerDepth: 1f
);
}
Edit:
Youtube Link : here
Movement of the bullet :
float traveledDistance;
public override void Update(GameTime gt)
{
float deltaTime = (float)gt.ElapsedGameTime.TotalSeconds;
traveledDistance += Speed * deltaTime;
Position += Forward * Speed * deltaTime;
if (traveledDistance > Range)
{
Destroy();
}
}
This is likely an artifact of low frame rate. The higher the frame rate, the less your brain will register the fact that the bullet's "movement" is simply drawing the same image in multiple and changing locations over time :)
As stated the traces are probably in your eyes, not on the screen. If you want to overcome this effect, you may want to skip some frames (maybe completely remove the bullet from screen or at least skip movement).

I'm unable to make my sprites "Flip"

I'll start off by admitting that I am a beginner to ActionScript and I am in the process of coding my own basic arcade game (Similar to that of the old arcade game "Joust"). Whilst I have been able to code the sprite's movement I am looking to make the sprite flip to face the other way when I press the right arrow. I figured either I could try and rotate the object around its axis (Which I've tried multiple times and has proved difficult) or I could try and "Replace" the current sprite with another sprite (Which is just the sprite facing the opposite way). I've searched everywhere for a method of replacing a sprite with another sprite but to no avail. How would it be possible to give this sprite a flip effect when a certain keyCode is used?
Try this simple code below. Here 'object' is the movieclip/sprite that you want to flip
stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
function OnKeyDown(event:KeyboardEvent):void
{
var uiKeyCode:uint = event.keyCode;
switch (uiKeyCode)
{
case Keyboard.LEFT :
object.scaleX = -1; //flip
break;
case Keyboard.RIGHT :
object.scaleX = 1; //unflip
break;
}
}
NOTE: If you want the movieclip to flip without any shift in its position then the movieclip must be horizontally center registered.
Tell me if this works for you.
Are you using as2/as3? you could flip the axis Y 180 degrees
if your using as2 you will need to either mirror the bitmap via actionScript or
add a second bitmap that is mirrored to the display list.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedDown);
function keyPressedDown(event:KeyboardEvent):void
{
var key:uint = event.keyCode;
switch (key)
{
case Keyboard.LEFT :
myMovieClip.rotaionY = 180; // MC will be mirrored
break;
case Keyboard.RIGHT :
myMovieClip.rotaionY = 0;
}

Actionscript 3, rotate object on drag

I have an object I need to rotate by clicking and dragging. Following some AS2 code I got the object to rotate a bit every time the mouse is clicked, but can't get it to work with drag.
needle.addEventListener(MouseEvent.MOUSE_DOWN, fl_ClickToDrag_2);
stage.addEventListener(MouseEvent.MOUSE_UP, fl_ReleaseToDrop_2);
function fl_ClickToDrag_2(event:MouseEvent):void
{
var angle = Math.atan2(mouseY-needle.y,mouseX-needle.x);
// apply rotation to handle by converting angle into degrees
needle.rotation = angle*180/Math.PI;
// rotate the grip opposite the handle so it won't rotate along with it
//this.grip._rotation = -this._rotation;
}
function fl_ReleaseToDrop_2(event:MouseEvent):void
{
needle.stopDrag();
}
Well the problem I see is that the MOUSE_DOWN event only fires once per click, so you only run the code in the handler once.
There could be a better way than this but this is how I'd consider doing it:
EDITED FOR DETAIL:
public class Test extends MovieClip {
private var n:Needle;
public function Test() {
// constructor code
n = new Needle();
stage.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownF,false,0,true);
stage.addEventListener(MouseEvent.MOUSE_UP,mouseUpF,false,0,true);
n.x = stage.stageWidth/2; //center needle on stage
n.y = stage.stageHeight/2;
addChild(n); //add needle to stage
}
public function mouseDownF(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE,rotate,false,0,true);
}
public function rotate(e:MouseEvent):void {
var angle:Number = Math.atan2(mouseY - n.y,mouseX - n.x); //get angle in radians (pythagoras)
angle = angle * 180/Math.PI -90; //convert to degrees , the 90 is to have it point to the mouse
n.rotation = angle; //rotate
}
public function mouseUpF(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE,rotate);
}
}
So when the user clicks down (mouseDown) it activates an event listener that fires the rotate handler every time the mouse moves. When the user lets go of the click the event listener is destroyed. The false,0,true); when adding the event listener is to make it a weakly referenced listener so that it gets collected by the garbage collector and doesn't just sit in memory taking up space forever.

Changing Shape on Button Press Action Script 3.0

Alright, sorry if this is a pretty easy question to get answered, but I looked around through pages and pages on google and couldn't find anything somewhat related. I got a lot of help, but I still can't seem to get this part of my ActionScript working. I have a program, that when running, allows me to paint random color squares on mouse click. I added a button, that is supposed to be able to change the shape being painted from rectangle to circle. I can't seem to get that button to work. This is what my code looks like so far.
var color:Number;
stage.addEventListener(MouseEvent.MOUSE_DOWN, startDrawing);
stage.addEventListener(MouseEvent.MOUSE_UP, stopDrawing);
function startDrawing(e:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE, makeShapes);
color = Math.random() * 0xFFFFFF;
}
function stopDrawing(e:MouseEvent):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE, makeShapes);
}
function makeShapes(e:MouseEvent):void {
var rect:Rect = new Rect(10,10,color);
addChild(rect);
rect.x = mouseX;
rect.y = mouseY;
}
shape_btn.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
function mouseDownHandler(event:MouseEvent):void {
}
At the bottom I left it blank, it seems to be the part I'm stuck on. I've tried simply setting the VAR to my "Ellipse" class I had made, which gets it to work, but only that one time when I click the button. It doesn't stay a circle and allow me to paint with the shape. Again I'm sorry, I felt like I was getting pretty close to the solution, and then I hit a wall.
Hard to understand what the difficulty is, but I'll try to address what I understand.
First, the stage mouse down event will capture your button event, so you might as well get rid of it and stick to one mouse event.
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
private function onMouseDown(ev:Event):void
{
if (ev.target==shape_btn)
changeShape();
else if (ev.target==stage)
startDrawing();
}
Or something along those lines.
Second, I don't know what Rect is. Is it a class you have an access to? This is how I'd do it without a special class:
private function makeShape():void
{
switch (shapeType)
{
case "rect":
drawRect();
break;
case "circle":
drawCircle();
break;
}
}
private function drawRect():void
{
var rect:Shape = new Shape();
rect.graphics.beginFill(color);
rect.graphics.drawRect(0, 0, 10, 10);
rect.x = mouseX;
rect.y = mouseY;
addChild(rect);
}
private function drawCircle():void
{
var circle:Shape = new Shape();
circle.graphics.beginFill(0xff0000);
circle.graphics.drawCircle(0, 0, 10);
circle.x = mouseX;
circle.y = mouseY;
addChild(circle);
}
and finally, the changeShape function:
private function changeShape():void
{
shapeType = shapeType=="rect"?"circle":"rect";
}
There are better ways to go about it, but when dealing with two shape types only this is acceptable.
Of course you need to have a var shapeType:String = "rect" somewhere in your code, outside the functions.
I also think the color randomization should be in the mouse move handler rather than the mouse click. Is that on purpose?

Resources