Im kind of new in the whole papervision scene.
For a school assignment I'm making a panorama version of my own room using
a cube with 6 pictures in it. It created the panorama, it works great.
But now I want to add clickable objects in it. One of the requirements
is that my code is OOP focused. So that's what I am trying right now.
Currently I got two classes
- Main.as (Here i make the panorama cube as the room)
- photoWall.as (Here I want to create my first clickable object)
Now my problem is: I want to addChild a clickable object from photoWall.as
to my panorama room. But he doesn't show it? I think it has something to do with
the scenes. I use a new scene in Main.as and in photoWall.as. No errors or warnings are reported
This is the piece in photoWall.as were I want to addChild my object (photoList):
private function portret():void
{
//defining my material for the clickable portret
var material : BitmapFileMaterial = new BitmapFileMaterial('images/room.jpg');
var material_list : MaterialsList = new MaterialsList( { front: material, back: material } );
// I don't know if this is nessecary? that's my problem
scene = new Scene3D();
material.interactive = true;
// make the clickable object as a cube
var photoList : DisplayObject3D = new Cube(material_list, 1400, 1400, 1750, 1, 4, 4, 4);
// positioning
photoList.x = -1400;
photoList.y = -280;
photoList.z = 5000;
//mouse event
photoList.addEventListener( InteractiveScene3DEvent.OBJECT_CLICK, onPress);
// this is my problem! I cannot see 'photoList' within my scene!!!
scene.addChild(photoList);
// trace works, so the function must be loaded.
trace('function loaded');
}
Hope you guys can help me out here. Would really be great!
Thanks,
Sandor
you have to render before you can se anything.
missing:
viewport.startRender()
No I already rendered everything in another class.
I figured it out, the answer is: I have to make this class a displayobject3d.
that's it. everything you addchild on the stage now is a displayobject3d.
for details or code..just ask.
view the result of my little project here :
http://www.sandorkerst.com/papervision/bin
Related
This seems like it should have a simple answer, and probably does, but it's proving harder to find than I expected. As a specific example, let's say that I'm programming a chess game.
It seems like this is something I should be able to do just using CoreGraphics. It seems like using OpenGL or SpriteKit shouldn't be necessary.
I want to have a Board class that models the state of the board. Where should I declare my Board object? My impression is that it should be in the ViewController.
I want to have a view (actually a subview) that displays the current state of the board (by overloading drawRect). It should do this at the beginning, and should be updated when players make moves. How does the view access the data model to display the board state? Does giving the view a reference to the data violate MVC? If not, how would the reference be passed to the view? (I seem to just find lots of links about passing data between two ViewControllers.)
Should it instead be the ViewController "pushing" the data to the view whenever it needs to be drawn? My understanding, though, is that drawRect should not be called directly, and that instead setNeedsDisplay should be called, which will indirectly result in drawRect being called. This being the case, it's hard to see how the data would be passed.
Your code; your design decision. Nothing to comment on here.
You should have your model declaration in ViewController. True. That is how MVC works.
Having a reference of the data in a UIView DOES break MVC. Your view instance will not be independent anymore. Decoupling view and model is one of the main points of MVC and you are probably breaking it with this design.
What can you do about it?
Extending #Paulw11's comment, in your view controller you can declare a method that looks something like this :
func movePiece(somePiece : Piece, toSquare : Square) {
let pieceID = somePiece.id //I am just assuming the models structures
let pieceImageView = self.pieceImageViewFromID(id) //Assume that this method returns the reference of the image view. Assume that I am just working UIKit here.
let fromPoint : CGPoint = somePiece.origin
let toPoint : CGPoint = toSquare.coordinates
self.animateView(pieceImageView, fromPoint:fromPoint, toPoint:toPoint)
}
Note that in this design, the view is not holding any model references; the view controller will take care of setting its state and bring upon relevant animations.
If you are overriding drawRect:, then yes, for it be called, you should call setNeedsDisplay to update the changes. The view controller might call or you can add property observers to redraw itself based on a property change. One example for this could be:
class SillyView : UIView {
var drawPonies : Bool = false {
didSet {
if oldValue != drawPonies {
self.setNeedsDisplay()
}
}
}
override func drawRect(rect: CGRect) {
if drawPonies {
self.drawGoodLookingPony()
} else {
self.drawSomeOtherAnimal()
}
}
func drawGoodLookingPony() {
//Draw a good looking pony here
}
func drawSomeOtherAnimal() {
//Draw Something else
}
}
If your view controller decides to draw ponies all you have to do is, get the reference of the SillyView and set drawPonies to true.
self.sillyView.drawPonies = true
You are not passing your data model here, but important pieces of configuration information that will help the view redraw itself.
I am trying to delete the objects after it go outside the scene so so i can extenuate ram consumption
I should put the code i have tried but i dont know how to begin so i have nothing to put here sorry
EDIT
Or maybe i should detect if the object inside the view and delete it if not how i can know if the object is inside the view ?
There is a convenient method which checks whether two CGRects intersect each other or not
You can do something like this
if( CGRectIntersectsRect(object.frame, view.frame) ) {
// Don't delete your object
} else {
// Delete your object as it is not in your view
}
I hope this helps :)
You can check in different ways if node is off-screen, and that depends on how you move nodes.
First method :
if (!intersectsNode(yourNode)) {
// node is off-screen
}
To enumerate nodes you can use :
- enumerateChildNodesWithName:usingBlock: To access all nodes in a node tree read this.
Another way is to use actions:
let move = SKAction.moveTo(location: offScreenLocation, duration: 5)
let remove = SKAction.runBlock({yourNode.removeFromParent()})
let sequence = SKAction.sequence([move,remove])
yourNode.runAction(sequence, withKey:"moving") //Use action with key, to cancel the action if needed
Third method would be to use contact detection.
I have a scroll bar ( fl.controls.UIScrollBar ), which i create dynamically in a class, and add it to the stage.
public class Slider extends Sprite
{
private var scroll:UIScrollBar = new UIScrollBar();
// etc.
// constructor
addChild(scroll);
scroll.setSize(15.75, 205.3);
scroll.direction = ScrollBarDirection.HORIZONTAL;
scroll.setScrollProperties(150, minScrollPos, maxScrollPos,snapInterval);
scroll.addEventListener(ScrollEvent.SCROLL, scrollHandler);
}
Then, I try to call
scroll.scrollPosition = 30;
My method call will not update the scroll thumb.Any ideas why?
Salut Mihai,
I found that odd at first. I expected setting the value would suffice.
If I set scrollPosition in an enter frame loop, it works, but not if I use the setter straight away. This probably means that if you make the calls right after creating/setting up the component, internally, it's not ready yet. UIComponents(like UIScrollBar) have a whole lifecycle to deal with. Jeff Kamerer has a nice set of devnet articles on this, if you're interested.
Long story short, the component is not ready right away, so the best bet is to wait for it to be ready by listening to the RENDER event:
scroll.addEventListener(Event.RENDER,rendered);
function rendered(event:Event):void {
scroll.removeEventListener(Event.RENDER,rendered);
scroll.scrollPosition = 30;
}
I'm just going to explain the context so it is clearer.
I made this menu : my menu
I am looking to make an improved and more advanced version of the same menu.
I made an animation of waves on the cofee's surface and am looking to make it loop when the mouse is moving and to stop looping when it's not.
Sorry for the lack of specifications as I am quite new to actionscript, but I hope somebody will be able to help me. :)
Thanks,
Mathieu
Well, you said it - leverage MouseEvent.MOUSE_MOVE to set a conditional in your looping routine.
private var _isMoving:Boolean = false;
stage.addEventListener(MouseEvent.MOUSE_MOVE, checkMouse);
this.addEventListener(Event.ENTER_FRAME, doLoop);
private function checkMouse(e:MouseEvent):void
{
_isMoving = true;
}
private function doLoop(e:Event):void
{
trace("moving =" + _isMoving);
if(_isMoving)
{
// loop animation
}
_isMoving = false;
}
depending on how you want it to work I would do this as follows:
create an animation of wavy coffee
ensure the animation loops
note that clips loop by default, so all you have to do is match the first and last frames!
place the clip at the edge of your current coffee graphic
double click on the graphic to edit it
drag an instance of the looping animation from the library onto the "edge" of the graphic
OR just replace your entire light brown graphic with an animated one that loops
when the mouse is moving, call play on the animated loop clip
when the mouse stops, call stop on the animated loop clip
Some example code would be along the lines of:
public function init():void {
menuClip.addEventListener(MouseEvent.MOUSE_OVER, onMenuRollOver);
menuClip.addEventListener(MouseEvent.MOUSE_OUT, onMenuRollOut);
}
public function onMenuRollOver(event:MouseEvent):void {
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
/* do the stuff you're currently doing to animate the clip here.
something like: coffee graphic height = ease to mouseHeight */
}
public function onMenuRollOut(event:MouseEvent):void {
/* do the stuff you're currently doing to stop the clip here. */
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
coffeeClip.stop();
}
public function onMove(event:MouseEvent):void {
resetTimer();
coffeeClip.play(); //note: play has no effect when movie is playing (that's ideal in this case)
}
public function resetTimer():void {
if(mouseMovementTimer == null) createTimer();
mouseMovementTimer.reset();
mouseMovementTimer.start();
}
public function createTimer():Timer {
mouseMovementTimer = new Timer(DELAY, 1); //fiddle with the delay variable. Try 500, at first
mouseMovementTimer.addEventListener(TimerEvent.TIMER, stopAnimationLoop);
}
public function stopAnimationLoop(event:TimerEvent):void {
mouseMovementTimer.removeEventListener(TimerEvent.TIMER, stopAnimationLoop); //optional but recommended
mouseMovementTimer = null;
coffeClip.stop();
}
Of course, you would need to do things like call init() and import flash.utils.Timer and initialize variables like mouseMovementTimer, menuClip, coffeeClip and DELAY.
Warning: This code is off the top of my head and untested. So there's likely to be small bugs in it but you should get the general idea:
add a mouse listener when the user mouses over the menu
remove that listener if the user mouses out of the menu
have that listener play the looping movie clip
trigger an event that will stop the looping clip if movement hasn't been detected in a while
once the trigger goes of, stop the clip
The key is in detecting when the mouse stops moving. Flash detects interaction well but does not detect NON-INTERACTION for obvious reasons. One easy way to solve that is to trigger a timer that will go off once too much time has elapsed since the last activity. Then, when the timer triggers, you know action has stopped!
I think that's the key piece to solving your problem. I hope that helps someone in some way.
~gmale
I use StackOverflow for the first time, so please be friendly and understanding.
Few days ago I got interested in ActionScript. I have downloaded FlashDevelop (a free IDE) and FlexSDK4. Then I have learned the basics from some tutorials.
For now I am not really developing any big project, I'm rather just doing tests.
Anyway, a solution to my problem is really important for me. I have looked for it, but I couldn't find any.
I have just one button and a background in my app. Both the button and the background (below: "bg") are objects of the Sprite class.
When I click the button, the background gets painted with 10x10px squares of random colours.
The problem is that the more times I click the button, the longer time I have to wait until the background changes. And that's not all! I can change the background exactly 54 times! At the 55th time it doesn't change at all.
package {
// some imports here
public class Main extends Sprite {
private var button:Sprite;
private var bg:Sprite;
public function Main ():void {
init();
}
private function init (e:Event=null):void {
addChild (bg);
// in the original code there are some lines here,
// in which the button is created
addChild (button);
button.addEventListener (MouseEvent.CLICK, btnClick);
}
private function btnClick (event:MouseEvent):void {
var x:uint, y:uint, color:uint;
for (y=0; y<30; y++) {
for (x=0; x<40; x++) {
color=Math.round(Math.random()*16777215);
bg.graphics.beginFill (color);
bg.graphics.drawRect (x*10, y*10, 10, 10);
bg.graphics.endFill ();
}
}
}
}
}
The code is so short, because I have removed many void lines. I have left only the important ones.
What is wrong with this code? Please help me.
Thanks in advance.
clear your graphics before the loop
var x:uint, y:uint, color:uint;
bg.graphics.clear();
for (y=0; y<30; y++) {//etc