How to call Update function's code by button click - function

How can I call the codes, inside the Update function using a public method?
What I need to archive is, calling Update using another function.
So that Update triggers using that other method.
One more thing, code should run only when a button long press.
Many Thanks four help
using UnityEngine;
using System.Collections;
public class CarController : MonoBehaviour
{
public float speed = 1500f;
public float rotationSpeed = 15f;
public WheelJoint2D backWheel;
public WheelJoint2D frontWheel;
public Rigidbody2D rb;
private float movement = 0f;
private float rotation = 0f;
void Update()
{
rotation = Input.GetAxisRaw("Horizontal");
movement = -Input.GetAxisRaw("Vertical") * speed;
}
void FixedUpdate()
{
if (movement == 0f)
{
backWheel.useMotor = false;
frontWheel.useMotor = false;
}
else
{
backWheel.useMotor = true;
frontWheel.useMotor = true;
JointMotor2D motor = new JointMotor2D { motorSpeed = movement, maxMotorTorque = 10000 };
backWheel.motor = motor;
frontWheel.motor = motor;
}
rb.AddTorque(-rotation * rotationSpeed * Time.fixedDeltaTime);
}
//public void Rotate()
//{
// rotate = true;
// print("aa");
//}
//public void Move()
//{
// rotation = Input.GetAxisRaw("Horizontal");
// movement = -Input.GetAxisRaw("Vertical") * speed;
//}
}

Those are actually two questions.
1. A long press button
The Unity UI.Button hasn't per se a method for a long press but you can use the IPointerXHandler interfaces for implementing that on your own:
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;
using UnityEngine.UI;
// RequireComponent makes sure there is Button on the GameObject
[RequireComponent(typeof(Button))]
public class LongPressButton : MonoBehaviour, IPointerDownHandler, IPointerUpHandler, IPointerExitHandler
{
private void Awake()
{
ResetButton();
}
// set the long press duration in the editor (in seconds)
public float LongPressDuration = 0.5f;
// Here you reference method just like in onClick
public UnityEvent onLongPress;
private float _timer;
private bool _isPressed;
private bool _pressInvoked;
private void Update()
{
// prevent multiple calls if button stays pressed
if (_pressInvoked) return;
// if button is not pressed do nothing
if (!_isPressed) return;
// reduce the timer by the time passed since last frame
_timer -= Time.deltaTime;
// if timeout not reached do nothing
if (!(_timer <= 0)) return;
// Invoke the onLongPress event -> call all referenced callback methods
onLongPress.Invoke();
_pressInvoked = true;
}
// reset all flags and timer
private void ResetButton()
{
_isPressed = false;
_timer = LongPressDuration;
_pressInvoked = false;
}
/* IPointer Callbacks */
// enable the timer
public void OnPointerDown(PointerEventData eventData)
{
_isPressed = true;
}
// reset if button is released before timeout
public void OnPointerUp(PointerEventData eventData)
{
ResetButton()
}
// reset if cursor leaves button before timeout
public void OnPointerExit(PointerEventData eventData)
{
ResetButton();
}
}
This script has to be placed next to the Button component.
You don't reference the callback method(s) in the Button's
onClick but instead in this LongPressButton's onLongPress
and don't forget to adjust LongPressDuration also in the inspector.
Example
2. Calling CarController's Update
I don't know why you want this (I guess you disabled the component but want to call Update anyway)
Solution A
In order to be able to reference that method in the Inspector there are a few options:
Simply make your Update method public
public void Update()
{
rotation = Input.GetAxisRaw("Horizontal");
movement = -Input.GetAxisRaw("Vertical") * speed;
}
wrap the content of Update in another public method and use that one instead:
private void Update()
{
DoUpdateStuff();
}
public void DoUpdateStuff()
{
rotation = Input.GetAxisRaw("Horizontal");
movement = -Input.GetAxisRaw("Vertical") * speed;
}
the other way round (how you requested it) - call Update from another public method:
private void Update()
{
rotation = Input.GetAxisRaw("Horizontal");
movement = -Input.GetAxisRaw("Vertical") * speed;
}
public void DoUpdateStuff()
{
Update();
}
So all that's left is referencing the CarController's Update or DoUpdateStuff method in the LongPressButton's onLongPress event.
Solution B
Alternatively you could add that callback directly on runtime without referencing anything nor making the callback method public so you could directly use private void Update without a wrapper method.
Drawback: For this method you somehow have to get the reference to that LongPressButton in your CarController script instead
public class CarController : MonoBehaviour
{
// Somehow get the reference for this either by referencing it or finding it on runtime etc
// I will asume this is already set
public LongPressButton longPressButton;
private void Awake()
{
// make sure listener is only added once
longPressButton.onLongPress.RemoveListener(Update);
longPressButton.onLongPress.AddListener(Update);
}
private void Update()
{
rotation = Input.GetAxisRaw("Horizontal");
movement = -Input.GetAxisRaw("Vertical") * speed;
}
private void OnDestroy()
{
// clean up the listener
longPressButton.onLongPress.RemoveListener(Update);
}
//...
}

Thanks for your descriptive reply. What I did was change my script to following and added Event Trigger component. Then call the public functions accordingly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CarMve : MonoBehaviour
{
bool move = false;
bool moveR = false;
public Rigidbody2D rb;
public float speed = 20f;
public float rotationSpeed = 2f;
private void FixedUpdate()
{
if (move == true)
{
rb.AddForce(transform.right * speed * Time.fixedDeltaTime * 100f, ForceMode2D.Force);
}
if (moveR == true)
{
rb.AddForce(transform.right *- speed * Time.fixedDeltaTime * 100f, ForceMode2D.Force);
}
}
/* Will be used on the UI Button */
public void MoveCar(bool _move)
{
move = _move;
}
public void MoveCarR(bool _moveR)
{
moveR = _moveR;
}
}

Related

Functions not doing anything

I have a gameObject called BounceBack that is supposed to bounce the ball back far away when they collide together.
public class BounceBack : MonoBehaviour
{
public GameObject Player;
public float force;
private void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.CompareTag(Player.tag))
{
Player.GetComponent<PlayerController>().ForceBack(force);
}
}
}
The ball Player (ball) script:
public class PlayerController : MonoBehaviour
{
public int acceleration;
public int speedLimit;
public int sideSpeed;
public Text countText;
public Text winText;
public GameObject pickUp;
public GameObject finishLine;
//internal void ForceBack() //Not sure what it does and why it's there.
//{
// throw new NotImplementedException();
//}
private int count;
private Rigidbody rb;
// Start is called before the first frame update
void Start()
{
rb = GetComponent<Rigidbody>();
SetCount();
}
// Update is called once per frame
void FixedUpdate()
{
float moveHorizontal = Input.GetAxis("Horizontal") * sideSpeed * rb.velocity.magnitude / acceleration;
//float moveVertical = Input.GetAxis("Vertical") * acceleration;
if (rb.velocity.magnitude <= speedLimit)
{
rb.AddForce(0.0f, 0.0f, acceleration); // add vertical force
}
rb.AddForce(moveHorizontal, 0.0f, 0.0f); // add horizontal force
}
private void OnTriggerEnter(Collider other)
{
if (other.gameObject.CompareTag(pickUp.tag))
{
other.GetComponent<Rotate>().Disapear();
count++;
SetCount();
}
if (other.gameObject.CompareTag(finishLine.tag))
{
acceleration = 0;
sideSpeed = 0;
finishLine.GetComponent<GameEnd>().FadeOut();
if (count >= 2)
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez remporté la partie!");
}
else
{
winText.GetComponent<WinTextFadeIn>().FadeIn("Vous avez perdu. Réesayer?");
}
}
}
private void SetCount()
{
countText.text = "Count : " + count.ToString();
}
public void ForceBack(float force)
{
Rigidbody rb = GetComponent<Rigidbody>();
rb.AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Debug.Log("Pass");
}
}
The AddForce function does not do anything. I tried with setActive(false) and it's not working either. The only thing that works is Debug.Log(). I'm not sure if the speedlimit and acceleration are interfering with the function.
EDIT: I'm not sure if the problem is from Unity but I can't access any variable of the class from the forceBack function inside the class.
EDIT2: I also tried to call the AddForce function directly in the Bounce Back script but it's not working either.
Player.GetComponent<Rigidbody>().AddForce(0.0f, 0.0f, -force, ForceMode.VelocityChange);
Player (Ball) Screenshot
Bounce Back Screenshot
So, a couple things:
1.) The physics system should already cause the ball to bounce if you've set up the colliders and rigidbodies properly. You should only need to do something like this if the ball should gain momentum when it bounces, which is unlikely. You should post screenshots of their inspectors if this answer doesn't help.
2.) On your rb.AddForce() call, you're applying a force in world-space, which may be the wrong direction to bounce. If you know the ball is oriented the way it's moving, then you can call AddRelativeForce with the same parameters. If the ball's orientation is not controlled, then you need to calculate the correct world-space direction to use before applying the force.
3.) Finally, just to confirm, the objects with BounceBack attached do have a non-zero value in the 'force' parameter in the inspector, right?

Unable to change position of ParticleEffect using update method

I am building a flappy bird style side scroller game and currently implementing collectible items for the main sprite to collect as it flies. I am not moving the main sprite but moving the background using ParallaxEffect and intend to move the collectibles (called orbs) towards the main sprite (bird). The Orbs are rendered in random positions but the position is not changed even after the update method is called.
Here is my CollectibleOrbs.java
public class CollectibleOrbs {
private static final int ORB_COUNT = 10;
private Array<Orb> orbs;
private Orb orb;
public CollectibleOrbs(){
orbs = new Array<Orb>();
for(int i=0;i<ORB_COUNT; i++) {
orb = new Orb();
orbs.add(orb);
}
}
public void update(float delta){
for(Orb orb: orbs){
orb.update(delta);
}
}
public void render(SpriteBatch sb){
for(Orb orb:orbs){
orb.draw(sb);
}
}
private class Orb{
private ParticleEffect effect;
private Vector2 position;
private Random rand;
public Orb(){
effect = new ParticleEffect();
rand = new Random();
position = new Vector2(rand.nextInt(Gdx.graphics.getWidth()),rand.nextInt(Gdx.graphics.getHeight()));
effect.load(Gdx.files.internal("particle/orbred.p"),
Gdx.files.internal("particle"));
effect.setPosition(position.x,position.y);
}
public void draw(SpriteBatch sb){
effect.draw(sb,Gdx.graphics.getDeltaTime());
}
public void update(float dt){
if(position.x< 10){
position.x = rand.nextInt(Gdx.graphics.getWidth());
position.y = rand.nextInt(Gdx.graphics.getHeight());
}
else
{
position.x-= 100*dt;
}
}
}
}
The orbs are rendered but they are not moving whereas the bird animation and the parallax background does:
I am calling the update method of CollectibleOrb class in the update of my game state and respectively for the render method while passing required parameters. How do to make sure the orbs move on the game screen?
The problem is that position is just unrelated to effect vector. Changing just position won't change effect's position. One way to solve it:
public void update(float dt){
if(position.x< 10){
position.x = rand.nextInt(Gdx.graphics.getWidth());
position.y = rand.nextInt(Gdx.graphics.getHeight());
}
else
{
position.x-= 100*dt;
}
// you should update ParticleEffect position too, just like you did in the constructor
effect.setPosition(position.x, position.y);
}

Libgdx | Custom Action

How can I create a custom action for an actor in libgdx? If I can't, than is there at least an action to run a custom piece of code (eg. call a method action)? Thanks.
EDIT:
I created this class :
class GapSizeAction extends TemporalAction {
private float newSize;
private Blocker blocker;
public static GapSizeAction getRotateAction(float newSize, float duration) {
return new GapSizeAction(newSize, duration);
}
public GapSizeAction(float newSize, float duration) {
super(duration);
System.out.println("Construct");
this.blocker = (Blocker)target;
this.newSize = newSize;
}
private float start, end;
protected void begin() {
System.out.println("Begin");
start = blocker.gap;
}
protected void update(float percent) {
blocker.gap = (start + (end - start) * percent);
}
}
The problem is that I am using a custom actor with a gap member (float). I try to cast the target to a blocker so that I can access the gap member variable, but gap ends up being null. I can confirm that gap is not null, I initialize it in the constructor. The blocker (Custom actor) is not null either. Am I going about this wrong?
Your problem is the line this.blocker = (Blocker)target; in your constructor. When the constructor is called, the action hasn't been set on a target yet, so target is null (and so will be blocker). Also, since you're changing a single float, you can extend FloatAction and save yourself some code. I would write your class as below. The constructor should be empty to support easy pooling, and you can set it up in your static factory method.
class GapSizeAction extends FloatAction {
public static GapSizeAction getRotateAction(float newSize, float duration){
GapSizeAction action = Actions.action(GapSizeAction.class);
action.setEnd(newSize);
action.setDuration(duration);
return action;
}
protected void begin () {
if (target instanceof Blocker)
setStart(((Blocker)target).gap);
else
Gdx.app.logError("Target is not a blocker: " + target.toString());
super.begin();
}
protected void update (float percent) {
super.update(percent);
if (target instanceof Blocker)
((Blocker)target).gap = getValue();
}
}
Fade In Action for example :
actor.AddAction(Actions.fadeIn(2.0f));

AS3 Windows style drag and drop

I'm making a windows style app with different windows which contain different elements. I know how to code a drag and drop function to change the position of the windows on the stage but I'd like to use a single code for all windows without repeating infinite functions. My code is:
public function fl_WindowDrag(event: MouseEvent): void {
instance.startDrag();
}
public function fl_WindowDrop(event: MouseEvent): void {
instance.stopDrag();
}
I'd like the istance name was retrived automatically from the selected window, is it possible?
I hope you understand my need
Any help is well accepted
Thanks in advance
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.Keyboard;
import flash.ui.Mouse;
import flash.display.MovieClip;
public class MainTimeline extends MovieClip {
//Variabili
public var VFullscreen: int = 1;
//Import var
public var VTerminal: Terminal = new Terminal();
public var nTerminal:String;
public function MainTimeline(): void {
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
//Import
//Terminal
VTerminal.x = 288;
VTerminal.y = 384;
stage.addChild(VTerminal);
//Event Listeners
//addEventListener(MouseEvent.CLICK, fl_BringToFront);
VTerminal.addEventListener(MouseEvent.MOUSE_DOWN, fl_WindowDrag);
VTerminal.addEventListener(MouseEvent.MOUSE_UP, fl_WindowDrop);
}
//public functions
//Gestione Fullscreen
public function fl_Fullscreen(event: MouseEvent): void {
switch (VFullscreen) {
case 0:
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
VFullscreen = 1;
break;
case 1:
stage.displayState = StageDisplayState.NORMAL;
VFullscreen = 0;
break;
}
}
public function fl_FSCheck(event: Event): void {
if (stage.displayState == StageDisplayState.NORMAL) {
VFullscreen = 0;
}
if (stage.displayState == StageDisplayState.FULL_SCREEN_INTERACTIVE) {
VFullscreen = 1;
}
}
//Primo Piano Finestre
public function fl_BringToFront(event: MouseEvent): void {
this.addChild(event.currentTarget as DisplayObject);
}
public function fl_WindowDrag(event: MouseEvent): void {
event.currentTarget.startDrag();
nTerminal = event.currentTarget.name.toString();
trace(nTerminal);
}
public function fl_WindowDrop(event: MouseEvent): void {
event.currentTarget.stopDrag();
}
//Chiusura
public function fl_Close(event: MouseEvent): void {
stage.nativeWindow.close();
}
//Apertura/Chiusura Terminal
public function fl_Terminal(event: MouseEvent): void {
if (contains(VTerminal)) {
removeChild(VTerminal);
} else {
VTerminal.x = 288;
VTerminal.y = 320;
addChild(VTerminal);
}
}
}
}
There are many ways you can do this.
You can prepare base class for all windows wich will inherit this behavior and if you plan to design over a dozen of windows this is definitelly thing you should consider. Another way is to create sperarate class designed to only do this and register all windows you want to it.
But since you asking if this is even possible I would recommend you to try some third party libraries.
GreenShock has a good tool for this but i didn't use their libralies a while and I don't know what are their licecing programs.
In case you don't like it, you can use my code i made some time ago.
It's very easy to use but it's not fully implemented(can't rotate and such) and documentation is very weak but if you were interested i can help you with this.
All you need to do is pass objects you want to move along with some bassic properties:
TransformTool.addClient(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Array = null, dragBounds:Array = null, grabRange:Number = 5):TransformData
terget - that would be your window.
operations - bit-flags representing type of transformation (scale, drag, rotate)
edgesMask - bit-flags defining which edges should be involved in scaling operation (left, right, top, bottom) all these flags values as well as operations flags can be found in TransformData class.
sizeBounds - array contian minimum and maximum size of scaled object accordingly for with and height.
dragBounds - position boundries for draged object. Basically those are arguments for flash Rectangle class.
grabRange - distance from mouse to edge in which you can grab and edge (or edges in case of corner). You can grab an edge also with mouse outside the object and scale two separate objects edges at once.
So assuming w and w2 are your windows, usage looks like this:
TransformTool.addClient(w, TransforData.SCALE|TransformData.DRAG, TransformData.BOTTOM_EDGE|TransformData.RIGHT_EDGE, null, null, 10);
TransformTool.addClient(w2, 3, 15, [20, 10, 350, 350], [100, 100, 600, 500], 10);
That is only this line required to use it.
You can also add listener if you would like to change cursor.
TransformTool.eventDispatcher.addEventListener(TransformToolEvent.EDGES_HIT, transformTestHit);
private function transformTestHit(e:TransformToolEvent):void
{
trace(TransformData(e.data).hitEdges);
}
Below is all the code involved. You can use it as you wish however be Aware that TransformTool is static class and uses only one stage instance.
I you want to develop app in Air and use native windows you would need to modify this code because each navtive window instance has its own unique stage.
TransformTool class:
package utils
{
import flash.display.DisplayObject;
import flash.display.InteractiveObject;
import flash.display.Sprite;
import flash.display.Stage;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* #author Audionysos
*/
public class TransformTool
{
private static var clients:Vector.<TransformData> = new Vector.<TransformData>();
private static var transforming:Vector.<TransformData> = new Vector.<TransformData>();
private static var _stage:Stage;
public static var checkEdgesOnMMove:Boolean = true;
private static var _eventDispatcher:EventDispatcher = new EventDispatcher();
public static function addClient(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Array = null, dragBounds:Array = null, grabRange:Number = 5):TransformData {
var sBR:Rectangle;
var dBR:Rectangle;
if (sizeBounds) sBR = new Rectangle(sizeBounds[0], sizeBounds[1], sizeBounds[2], sizeBounds[3]);
if (dragBounds) dBR = new Rectangle(dragBounds[0], dragBounds[1], dragBounds[2], dragBounds[3]);
var td:TransformData = new TransformData(target, operations, edgesMask, sBR, dBR, grabRange);
if (operations & TransformData.SCALE) td.allowDrag = true;
clients.push(td);
if (stage) return td;
if (!target.stage) target.addEventListener(Event.ADDED_TO_STAGE, onStage);
else { stage = target.stage; addStageListeners(); }
return td;
}
/**
* Return TransformData object associated with given target.
* #param target object associated with searched TransformData.
* #return TransformData object associated with given target.
*/
static public function getTransformData(target:InteractiveObject):TransformData {
for (var i:int = 0; i < clients.length; i++){
if (clients[i].targetObject == target) return clients[i];
}return null;
}
/**
* Mouse position relative to specifed object.
* #param target InteractiveObject or TransformData object.
* #return Mouse position relative to specifed object.
*/
static public function getTargetMouse(target:*):Point
{
var t:InteractiveObject = target as InteractiveObject;
if (!t && target as TransformData) t = TransformData(target).targetObject;
else throw new Error ("property object must be of type InteractiveObject or TransformData");
return new Point(t.parent.mouseX, t.parent.mouseY);
}
/**
* Adds MOUSE_DOWN and MOUSE_UP listener for current stage;
*/
static private function addStageListeners():void
{
//trace("TT adding stage listeners");
stage.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
static private function onStage(e:Event):void
{
//trace("TT client on stage");
InteractiveObject(e.target).removeEventListener(Event.ADDED_TO_STAGE, onStage);
stage = InteractiveObject(e.target).stage;
addStageListeners();
}
static private function onMUp(e:MouseEvent):void
{
for (var i:int = 0; i < transforming.length; i++){
transforming[i].isTransforming = false;
}
transforming = new Vector.<TransformData>();
}
static private function onMDown(e:MouseEvent):void
{
//trace("TT MousDown");
findAffectedObjects();
}
static private function findAffectedObjects():void
{
for (var i:int = 0; i < clients.length; i++) {
clients[i].hitEdges = findEdges(clients[i]);
if (!clients[i].hitEdges) continue;
//trace("TT got R", clients[i].hitEdges);
transforming.push(clients[i]);
clients[i].isTransforming = true;
clients[i].updateMouseVector();
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
}
static private function onMMove(e:MouseEvent):void
{
//trace("Transforming", transforming.length);
if (TransformTool.checkEdgesOnMMove) dispatchEdges();
//trace("TT Moving");
for (var i:int = 0; i < transforming.length; i++) {
if (transforming[i].operations & TransformData.ROTATE) rotateTarget();
//if (!checkEdgesOnMMove)
transforming[i].updateMouseVector();
scaleTarget(transforming[i]);
fixSize(transforming[i]);
fixPlacement(transforming[i]);
}
}
/**
* Performs fingEdges() operation on each client TransformData object and dispatches EDGES_HIT event if result is different form last hitEdges state;
*/
static private function dispatchEdges():void
{
for (var i:int = 0; i < clients.length; i++) {
if (clients[i].isTransforming) continue;
var r:uint = findEdges(clients[i]);
if (r != clients[i].hitEdges) {
clients[i].hitEdges = r;
_eventDispatcher.dispatchEvent(new TransformToolEvent(TransformToolEvent.EDGES_HIT, clients[i]));
}
}
}
static private function rotateTarget():void
{
}
/**
* If a part of an object is outside defined dragBounds rectangle area it will move this object to closest allowed position.
* #param td
*/
static public function fixPlacement(td:TransformData):void
{
if (!td.dragBounds) return;
td.targetObject.x = Math.max(td.targetObject.x, td.dragBounds.x);
td.targetObject.x = Math.min(td.dragBounds.right - td.targetObject.width, td.targetObject.x);
td.targetObject.y = Math.max(td.targetObject.y, td.dragBounds.y);
td.targetObject.y = Math.min(td.dragBounds.bottom-td.targetObject.height, td.targetObject.y);
}
/**
* Changes the object to fit min/max size defined in sizeBounds object of the transformation data.
* #param td
*/
static public function fixSize(td:TransformData):void
{
if (!td.sizeBounds) return;
td.targetObject.width = Math.min(td.targetObject.width, td.sizeBounds.width);
td.targetObject.width = Math.max(td.targetObject.width, td.sizeBounds.x);
td.targetObject.height = Math.min(td.targetObject.height, td.sizeBounds.height);
td.targetObject.height = Math.max(td.targetObject.height, td.sizeBounds.y);
}
/**
* Scales the object accordingly to grabed edges and move of the mouse.
* #param td
*/
static public function scaleTarget(td:TransformData):void
{
//trace("TT mouse vector", td.mouseVector);
var rD:Point = td.mouseVector//new Point(td.mouseVector.x * td.targetObject.parent.scaleX, td.mouseVector.y * td.targetObject.parent.scaleY); //relativeDisplacement
if (td.hitEdges & TransformData.LEFT_EDGE) { td.targetObject.width -= rD.x; td.targetObject.x += rD.x; }
if (td.hitEdges & TransformData.RIGHT_EDGE) { td.targetObject.width += rD.x; }
if (td.hitEdges & TransformData.TOP_EDGE) { td.targetObject.height -= rD.y; td.targetObject.y += rD.y; }
if (td.hitEdges & TransformData.BOTTOM_EDGE) { td.targetObject.height += rD.y; }
}
/**
* Check if mouse position is in grab range to any of specified object edge.
* #param target examined object
* #param grabRange minimal distance from mouse position to edge of the object.
* #return resul of the inspection.
*/
static public function findEdges(td:TransformData):uint
{
if (!isMouseNearTarget(td)) return 0;
var t:InteractiveObject = td.targetObject;
var gR:Number = td.grabRange;
var r:uint;
if (Math.abs(t.x - t.parent.mouseX) < gR && t.parent.mouseX) r |= TransformData.LEFT_EDGE;
if (Math.abs(t.x + t.width- t.parent.mouseX) < gR) r |= TransformData.RIGHT_EDGE;
if (Math.abs(t.y - t.parent.mouseY) < gR) r |= TransformData.TOP_EDGE;
if (Math.abs(t.y + t.height - t.parent.mouseY) < gR) r |= TransformData.BOTTOM_EDGE;
return r;
}
/**
* Check if mouse relative position is cantained within target rectangle + grabRange;
* #param td object to examine.
* #return true if mouse is near object (edges can be grabbed);
*/
static public function isMouseNearTarget(td:TransformData):Boolean
{
td.updateMouseVector();
var exRect:Rectangle = td.targetObject.getRect(td.targetObject.parent).clone();
exRect.inflate(td.grabRange, td.grabRange);
return exRect.containsPoint(td.mouseStart);
}
/**
* Dispatches events associated with transformed client objects.
* TransformToolEvent contains reference to interested TransformData object.
* #eventType TransformToolEvent.EDGE_HIT dispatched when mouse cursor is close enought client object edges to let it to be scaled.
* You can for example use it's hitEdges property to change cursor icon accordingly.
*/
static public function get eventDispatcher():EventDispatcher
{
return _eventDispatcher;
}
/**
* Stage property on which mouse events will be proceded.
* This will be set automaticly from client object (it it was null before).
*/
static public function get stage():Stage
{
return _stage;
}
static public function set stage(value:Stage):void
{
if (_stage) {
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMUp);
_stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMDown);
}
_stage = value;
addStageListeners();
if(checkEdgesOnMMove) value.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
}
}
TransformData class:
package utils
{
import flash.display.InteractiveObject;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.geom.Rectangle;
/**
* ...
* #author Audionysos
*/
public class TransformData
{
public static const SCALE:uint = 1;
public static const DRAG:uint = 2;
public static const ROTATE:uint = 4;
public static const TOP_EDGE:uint = 1;
public static const RIGHT_EDGE:uint = 2;
public static const BOTTOM_EDGE:uint = 4;
public static const LEFT_EDGE:uint = 8;
public var targetObject:InteractiveObject;
public var grabRange:Number;
public var sizeBounds:Rectangle;
public var dragBounds:Rectangle;
public var mouseStart:Point;
public var mouseVector:Point;
public var hitEdges:uint;
public var edgesMask:uint;
public var operations:uint;
public var isTransforming:Boolean;
private var _allowDrag:Boolean;
private var isDraging:Boolean;
public function TransformData(target:InteractiveObject, operations:uint = 3, edgesMask:uint = 15, sizeBounds:Rectangle = null, dragBounds:Rectangle = null, grabRange:Number = 5)
{
targetObject = target;
this.sizeBounds = sizeBounds;
this.dragBounds = dragBounds;
this.grabRange = grabRange;
this.edgesMask = edgesMask;
this.operations = operations;
}
public function updateMouseVector () {
var mP:Point = new Point(targetObject.parent.mouseX, targetObject.parent.mouseY);
if (!mouseStart) mouseStart = mP;
mouseVector = mP.subtract(mouseStart);
mouseStart = mP;
}
public function get allowDrag():Boolean
{
return _allowDrag;
}
public function set allowDrag(value:Boolean):void
{
if (_allowDrag && !value) {
targetObject.stage.removeEventListener(MouseEvent.MOUSE_UP, onMUp);
targetObject.removeEventListener(MouseEvent.MOUSE_DOWN, onMDown);
if (isDraging) targetObject.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
_allowDrag = value;
if (value) targetObject.addEventListener(MouseEvent.MOUSE_DOWN, onMDown);
}
private function onMDown(e:MouseEvent):void
{
isTransforming = true;
mouseStart = TransformTool.getTargetMouse(this);
targetObject.stage.addEventListener(MouseEvent.MOUSE_MOVE, onMMove);
targetObject.stage.addEventListener(MouseEvent.MOUSE_UP, onMUp);
}
private function onMUp(e:MouseEvent):void
{
isTransforming = false;
targetObject.stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMMove);
}
private function onMMove(e:MouseEvent):void
{
updateMouseVector();
targetObject.x += mouseVector.x;
targetObject.y += mouseVector.y;
TransformTool.fixPlacement(this);
}
}
}
TransformToolEvent:
package utils
{
import flash.events.Event;
/**
* ...
* #author Audionysos
*/
public class TransformToolEvent extends Event
{
public static const EDGES_HIT:String = "edgesHit";
private var _data:TransformData;
public function TransformToolEvent(type:String, data:TransformData, bubbles:Boolean=false, cancelable:Boolean=false) {
super(type, bubbles, cancelable);
_data = data;
}
public override function clone():Event {
return new TransformToolEvent(type, _data, bubbles, cancelable);
}
public override function toString():String {
return formatToString("TransformToolEvent", "type", "bubbles", "cancelable", "eventPhase", "data");
}
public function get data():TransformData {
return _data;
}
}
}
You can use the target or currentTarget propterty of the mouse-event to reference the instance that triggers the event, like this (i have not tested this code):
public function fl_WindowDrag(event: MouseEvent): void {
event.currentTarget.startDrag();
}
this way you can add the event handler to multiple instances. You can read more about the events properties here

Minusassign (-=) syntax error in ActionScript-3

Why can't I compile this little piece of code ?
I'm overriding x and y in my class so that's why I need super.x.
public class SimpleSprite extends Sprite
{
override public function set x(value: Number): void
{
super.x -= 12;
//super.x = super.x - 12;
}
}
// or
public class SimpleSprite2 extends Sprite
{
public function get xx(): Number
{
return super.x;
}
public function set xx(value: Number): void
{
super.x = value;
}
public function SimpleSprite2()
{
xx -= 12;
super.x -= 12;
// Error: Syntax error: expecting semicolon before minusassign.
}
}
I know I can write super.x = super.x - 12; but im lazy and i dont want 2 look 4 these inconsistencies when i get hit by syntax errors im also very much accustomed to those shortcuts with -=
Looks like my IDE (FlashDevelop 4.2.3) bears the blame for this.
There's nothing syntactically wrong with what your doing. Your code works fine in my Flash Builder 4.7.
However, remember that instance.x -= value; is short for
instance.x = instance.x - value;
//ie.
instance.[set]x = instance.[get]x - value;
I mention this because of your top code:
override public function set x(value: Number): void
{
super.x -= 12;
//super.x = super.x - 12;
}
Makes me think you're trying to do something funny. Why are you decrementing in the set function?
If you need to have a seperate x value for a subclass, but can't change the interface (ie. you still want users to be able to say mySubClassInstance.x = 123.0;) do this:
public class DerivedSprite extends Sprite
{
protected var derivedX:Number;
public override function get x():Number
{
super.x = derivedX;
return derivedX;
}
public override function set x(value:Number):void
{
super.x = value;
derivedX = value;
}
public function DerivedSprite()
{
super();
derivedX = super.x;
}
}