AS3 Custom Cursor On Click - actionscript-3

I'm working on a painting game, that once you click on the brushes, the mouse switches to the graphical counterpart of said brushes and will let you paint on screen. If no brush has been selected, the mouse will remain the same.
The Rectangle and the brushes are on a separate Movieclip, which allows me to layer png lines over it so you can fill in and draw.
In the actions layer in the Scene 1, this is my code for changing the mouse:
var cursor_mc:MovieClip;
if (CanvPark_mc.HugeSelected1 == true){
cursor_mc = cursor1_mc;
}else if(CanvPark_mc.MediumSelected1 == true) {
cursor_mc = cursor2_mc;
}else if(CanvPark_mc.SmallSelected1 == true) {
cursor_mc = cursor3_mc;
}
stage.addEventListener(MouseEvent.MOUSE_MOVE,moveCursor);
function moveCursor(myEvent:MouseEvent) {
if(CanvPark_mc.SmallSelected1 == false, CanvPark_mc.MediumSelected1 == false, CanvPark_mc.HugeSelected1 == false)
{ Mouse.cursor="auto";
}else{
setChildIndex(cursor_mc, this.numChildren-1);
cursor_mc.x = (mouseX);
cursor_mc.y = (mouseY);
Mouse.hide();
}
}
Each brush has a boolean variable associated to it: Small, Medium and HugeSelected1, so that way, I can tell at all times in code which one is selected and which one isn't.
Right now, running this code, in the start, nothing happens, but if I click any of the brushes, this pops up in the output.
TypeError: Error #2007: Parameter child must be non-null.
at flash.display::DisplayObjectContainer/setChildIndex()
at visibilityToggle/moveCursor()[visibilityToggle::frame1:42]
Seems to be pointing specifically at
setChildIndex(cursor_mc, this.numChildren-1);
I honestly don't know what's causing this error. I thought it would be this straight forward to change my mouse cursor.
How can I fix this?

Regarding the error you posted in your first post - such error occurs when some object you work with is null, i.e. not initialized or already destroyed. The error usually generalized to NPE (null pointer exception). When such error occurs, you should check if all your objects exist.
The second error occurs because your cursor_mc doesn't have parent clip (i.e. it wasn't added to stage) or the parent object is not the same object you call the setChildIndex. I suggest reading this doc
To solve the second problem you can check if the parent clip actually exists. Also, keep in mind, that if you have reassigned a value of cursor_mc you need to add it to stage again and, perhaps, you want to remove the previous clip from stage (assuming that cursor1_mc, cursor2_mc, cursor3_mc are not on stage.)
Here is a rough example:
var cursor_mc:MovieClip;
if (CanvPark_mc.HugeSelected1 == true){
cursor_mc = cursor1_mc;
}else if(CanvPark_mc.MediumSelected1 == true) {
cursor_mc = cursor2_mc;
}else if(CanvPark_mc.SmallSelected1 == true) {
cursor_mc = cursor3_mc;
}
stage.addEventListener(MouseEvent.MOUSE_MOVE,moveCursor);
function moveCursor(myEvent:MouseEvent) {
if(CanvPark_mc.SmallSelected1 == false && CanvPark_mc.MediumSelected1 == false && CanvPark_mc.HugeSelected1 == false)
{
Mouse.cursor="auto";
}
else if (cursor_mc)
{
addChild(cursor_mc);
setChildIndex(cursor_mc, this.numChildren-1);
cursor_mc.x = (mouseX);
cursor_mc.y = (mouseY);
Mouse.hide();
}
}

Related

ActionScript 3.0 Objects Null on Stage

I'm creating a game where the user bakes a cake. If the user drags something (for example a jug of water) onto the next object (e.g saucepan) it should disappear from stage. The section of code in question is:
function mouseDownHandler(event:MouseEvent):void {
event.currentTarget.startDrag(true);
}
function mouseUpHandler(event:MouseEvent):void{
var obj = event.currentTarget;
var target = obj.dropTarget;
if (target != null){
test_match(target, obj);
}
obj.stopDrag();
trace(dropTarget);
}
function test_match(target, obj){
if (target == saucePan && obj == jug)
{
removeChild(obj);
}
}
The trace inside the mouseUpHandler function shows up "null" whenever I drop the jug on an object on the stage, hense why I don't think the code executes and removes the jug from stage.
obj.dropTarget vs. dropTarget
These are two different things.

Why am I getting error 1118 here?

In the code below I have several MovieClips that are all TheBeetle(). They are in another MovieClip called gamelevel and also pushed in an array called bArray. previously I have indexed them in the gamelevel but after the event listener is called I cannot index them anymore and receive the error "1118: Implicit coercion of a value with static type Object to a possibly unrelated type flash.display:DisplayObject.". As the user clicks them, they die (and change the frame) and the dead body goes under other alive bodies, thats the reason I need to index them to 1 as they die. I understand what the error says but how can i do what i need to do?
The code works just fine but it wouldn't in the two lines i've mentioned in it, so take a look please:
public function clicked (event:MouseEvent)
{
if (event.target is TheBeetle && event.target.currentFrame <= 2)
{
var mc:Object = event.target
// TheBeetle is actually a MovieClip but i cannot write: var mc:MovieClip = event.target, if i do i receive 1118
if (mc.currentFrame == 1)
{
mc.gotoAndStop (Math.floor(Math.random() * 3 + 4));
}
else
{
mc.gotoAndStop (3);
}
mc.filters = null;
// Here i need to index the TheBeetle as i did before like gamelevel.setChildIndex(mc,1) but i'd receive 1118!
bArray.splice (bArray.indexOf(mc),1);
if (bArray.length == 0)
{
removeEventListener (Event.ENTER_FRAME,frameHandler);
waveTimer.removeEventListener (TimerEvent.TIMER_COMPLETE, changeLocation);
}
}
}
You need to explicitly cast target to the MovieClip Class:
var mc:MovieClip = MovieClip(event.target);
You may need to do this BEFORE the line that checks target's currentFrame, as 'Object' doesn't have a currentFrame method.
I would recommend to use soft casting when you work with events and targets. By soft casting, if you have catched wrong target, you will not have problems - cast process simply returns null.
public function clicked (e:MouseEvent){
var beetle: TheBeetle = e.target as TheBeetle;
if(beetle != null && beetle.currentFrame <= 2){
//Work with beetle as you want
}
}

What code in as-3 to use to allow seekbar to be moved by user?

I'm creating a simple music player which will play just one song. Stage timeline has got just one frame. There is main graphic for player which is movieClip_1 (it has 4 frames in it's own timeline) and that works ok. I've got button (button_2) which starts and pauses the song and the movieClip_1 (works ok). And i also have got a graphic (it's called tube - i have changed it to movie clip, it has got one frame inside it's timeline) as a seekbar component which I just want it to move correspondingly to channel.position of this song on the x axis which it does but gives me triple error of:
TypeError: Error #1009: Cannot access a property or method of a null object reference.
Debug points at this line:
tube.x = (chan.position/song.length) * 83;
I would really appreciate a tip regarding error and also what method to use in order for user to be able to navigate (with mouse) through song by moving tube on x axis and going to different part of song. I read about .startDrag and .stopDrag would that be good idea with my present code?
My code so far:
movieClip_1.stop();
var itsstoped:Boolean;
var youpausedit:Boolean;
var counter:Timer = new Timer(100);
var chan:SoundChannel;
var song:Sound = new Sound();
song.load(new URLRequest("wmc2.mp3"));
song.addEventListener(Event.COMPLETE, soundloaded);
function soundloaded(event:Event)
{
trace("Song has been loaded.");
}
counter.addEventListener(TimerEvent.TIMER,countcounter);
itsstoped = true;
youpausedit = false;
button_2.addEventListener(MouseEvent.CLICK, presser);
function presser(event:MouseEvent):void
{
if(itsstoped == true && youpausedit == true)
{
movieClip_1.gotoAndPlay(1);
chan = song.play(chan.position);
itsstoped = false;
}
else if(itsstoped == false)
{
movieClip_1.gotoAndStop(1);
chan.stop();
itsstoped = true;
youpausedit = true;
}
else if(itsstoped == true && youpausedit == false)
{
movieClip_1.gotoAndPlay(1);
chan = song.play();
counter.start();
itsstoped = false;
}
}
function countcounter(e:TimerEvent):void
{
trace(chan.position/song.length);
var percentage:uint = 100 * (chan.position / song.length);
trace(percentage);
if(percentage == 100)
{
movieClip_1.gotoAndStop(1);
itsstoped = true;
youpausedit = false;
counter.stop();
}
}
tube.buttonMode = true;
tube.useHandCursor = true;
addEventListener(Event.ENTER_FRAME, movewhenplay);
function movewhenplay(e:Event):void
{
tube.x = (chan.position/song.length) * 83;
}
Regarding the error, you're accessing an object that has yet to be instantiated, i.e. there is no data to fetch as it does not exist.
As for the searchbar, I'm guessing you're using some kind of mask for the search bar, as you're using its x position to display the song position. I would suggest you instead use its width parameter, and set the center point to the far left.
To be able to then search through the song, you can add a copy of this searchbar, place it on top of the first one. Set its alpha to 0, to make it invisible, but still clickable. Add mouseEvent listeners to that, and when the user clicks it, you can set the song to play from the position which you can calculate using mouseX relevant to the invisible search bar.
I.e. if you want the clicked position in percents
percent = (mouseX - invisiSearchBar.x) / invisiSearchbar.width

Disable a function temporarily as3

On my screen are tiles generated from an array. I have a mouse roll over function called rollover, that adds a movieclip that highlights the edge of the tiles that I am currently on. I want it so that once I click a tile, the roll over function doesn't work until another button is clicked. I tried putting removeEventListener for the roll over function in the click function, doesn't seem to work. How would I go about this if possible?
I will post more information if needed.
function rollover(event:MouseEvent)
{
var tileHover = true;
if (tileHover == true){
(event.currentTarget as Tile).outline.gotoAndStop("hover");
}
if(tileHover == false){
(event.currentTarget as Tile).outline.gotoAndStop("blank");
}
}
Below is the mouseclick function
function mouseclick(event:MouseEvent)
{
tileHover = false;
if (tileHover == false){
tile_MC.removeEventListener(MouseEvent.ROLL_OVER, rollover)
}
}
See below. You set a property and immediately check what the value of that property is. It will always be true because you just set it as true.
var tileHover = true;
if (tileHover == true){
(event.currentTarget as Tile).outline.gotoAndStop("hover");
}
Also, don't forget your data types.
I think you need to have (event.currentTarget as Tile).outline.gotoAndStop("blank"); in mouseclick.
Also, I assume tilehover is some global variable used for tracking the hover state. Explicitly setting it true/false in the handler is just for debugging purposes!!

Drag and Drop error 1010 part of the time?

I have a working drag and drop game, but it's not perfect. All my movieclips drag and drop to their targets when you are exactly lined up with the target.
However, if you let go of the mouse up when dragging the mc outside of the target zones, it will sometimes, but not always, throw the 1010 term undefined error and will not snap the mc back to its original start x/y coordinates (it just leaves the mc in the spot it was during mouse up). I ran the debugger and it deals with this line in my drop function:
if (event.currentTarget.dropTarget != null && MovieClip(event.currentTarget.dropTarget.parent).allowed.indexOf(event.currentTarget) >= 0){
FYI, allowed is a set of target arrays since I wanted "zones" for targets and not specific targets for some of the movieclips.
Any ideas?
Updated Code Below:
if (event.currentTarget.dropTarget != null) {
var mc:MovieClip=event.currentTarget.dropTarget as MovieClip;
if (mc==null) { // typecast fails. Say there's a Sprite below
reply_txt.textColor = 0xEE1212
reply_txt.text = "Oops! Try Again!";
event.currentTarget.alpha = 1;
event.currentTarget.x = startX;
event.currentTarget.y = startY;
return; // nothing to do here
}
mc=mc.parent;
if (mc && mc.allowed) {
// this MC has "allowed" property not "undefined" - we're in the grid
// so now we can check indexOf() safely
if (mc.allowed.indexOf(event.currentTarget)>=0){
reply_txt.textColor = 0x33BC10
reply_txt.text = "Good Job!";
event.currentTarget.alpha = 1;
event.currentTarget.removeEventListener(MouseEvent.MOUSE_DOWN, pickUp);
event.currentTarget.removeEventListener(MouseEvent.MOUSE_UP, dropIt);
event.currentTarget.buttonMode = false;
event.currentTarget.x = MovieClip(event.currentTarget.dropTarget.parent).x;
event.currentTarget.y = MovieClip(event.currentTarget.dropTarget.parent).y;
stored.push(event.currentTarget);
startXarray.push(startX);
startYarray.push(startY);
counter++;
}
}
}
Yes, when you stopDrag an object, it checks what kind of a DisplayObject is below the cursor, and that one is returned as dropTarget property in your event. So, if your object is dropped onto another MC that does not have allowed property, your 1010 error is thrown. You need to check this situation in a nested if statement like this:
if (event.currentTarget.dropTarget != null) {
var mc:MovieClip=event.currentTarget.dropTarget as MovieClip;
if (mc==null) { // typecast fails. Say there's a Sprite below
returnThisBack();
return; // nothing to do here
}
mc=mc.parent;
if (mc && mc.allowed) {
// this MC has "allowed" property not "undefined" - we're in the grid
// so now we can check indexOf() safely
if (mc.allowed.indexOf(event.currentTarget)>=0) snapThisToGrid();
} else returnThisBack();
} else returnThisBack();