Can anyone help with Flash?

Coders forum. Discuss techniques, swap code snippets, ask for help etc. relating to all forms of software development.
Post Reply
User avatar
hyphz
Baaaaaa!
Baaaaaa!
Posts: 2856
Joined: Tue Aug 13, 2002 4:24 pm 0
Yahoo Messenger: hyphz
Location: Reading, which is deep and dark apparantly
Contact:

Can anyone help with Flash?

Post by hyphz »

Just in case anyone here happens to know or can help...

I'm writing a simple turret defense-type game just to learn. Here's my turret .as file:

Code: Select all

package {
	
	import flash.display.MovieClip;
	import flash.events.Event;
	
	public class Turret extends MovieClip {
		public function Turret() {
			super();
		}
		
		
		public function aimAt(target:BadGuy) {
			var xDif:Number = x - target.x;
			var yDif:Number = y - target.y;
			var rot:Number = Math.atan(xDif/yDif);
			rotation = 360 - (rot * 90.00);
		}
	}
	
}
BadGuys are just plain ol' MovieClips, and here's the Stage they're all on:

Code: Select all

ackage {

	import flash.display.MovieClip;
    import flash.events.MouseEvent;
	import flash.events.Event;
    import Turret;

	
	public class MainStage extends MovieClip {
		
		var turrets:Array = [];
		var badguys:Array = [];
		
		public function MainStage() {
			super();
			trace("Here");
			stage.addEventListener(MouseEvent.MOUSE_DOWN,clicked);
			stage.addEventListener(Event.ENTER_FRAME,inFrame);
		}
		
		
		public function inFrame(evt:Event):void {
		     var dist:int;
			 dist = 99999;
			 for each (var turret in turrets) {
				 var nearest:BadGuy;
				 for each (var badguy in badguys) {
					 var thisDist:int;
					 thisDist = Math.abs(turret.x - badguy.x) + Math.abs(turret.y - badguy.y);
					 if (thisDist < dist) {
						 nearest = badguy;
						 dist = thisDist;
					 }
				 }
				 if (nearest != null) {
				     turret.aimAt(nearest);
				 }
			 }
			 for each (var badguy in badguys) {
				 badguy.x++;
			 }
			 
		}
		
		public function clicked(evt:MouseEvent):void {
			 
			 var newTurret:Turret;
			 var newBadguy:BadGuy;
			 trace ("mouse at " + evt.localX + " " + evt.localY);
			 if (evt.shiftKey) {
				 newBadguy = new BadGuy();
				 newBadguy.x = evt.localX;
				 newBadguy.y = evt.localY;
				 badguys = badguys.concat(newBadguy);
				 addChild(newBadguy);
			 } else {
			 	newTurret = new Turret();
			 	newTurret.x = evt.localX;
			 	newTurret.y = evt.localY;
			 	turrets = turrets.concat(newTurret);
			 	addChild(newTurret);
			 }
		}

	}
}
Two questions:

1) Is there any more efficent way of doing this?

2) At a certain distance away, the turrets tend to _miss_. Usually they're pointing off in the anti-clockwise direction by quite a way. Can anyone see what's causing this?
User avatar
handcircus
Baaa!
Baaa!
Posts: 129
Joined: Tue Jul 20, 2004 4:36 pm 0

Post by handcircus »

For your angle problem, just use Math.atan2(dy,dx). This should hopefully sort out that issue (tho you might need to append Math.PI/2 to get the result you are looking for)

hth
simon
http://www.handcircus.com - game and interaction design
http://handcircus.blogspot.com - blog
User avatar
KlaxonCow
Baaaaaaa!
Baaaaaaa!
Posts: 8446
Joined: Fri Dec 13, 2002 3:46 am 0
Location: A large grassy field.

Post by KlaxonCow »

With atan, you should be dividing the Y by the X, not the X by the Y.


Yeah, this is easily done, especially because, "by convention", we're all so used to the idea of putting X first then Y following all the time.

Although, this is only a convention - there's nothing magical about that order - and it, of course, completely doesn't apply here because we're dividing one by the other according to geometry, not simply listing them out as parameters.

So, really, this is a silly mistake to make but, yeah, when I first started using the atan function in my code, I constantly got it the wrong way around too.

It's easily done because it's some kind of psychological thing - a mental discipline, a "bad habit of the brain" - to think "X then Y (then Z)" all the time and to fall into that pattern automatically.

Even, indeed, when this actually has nothing to do with anything (mathematically speaking), as is the case here.

So, just remember that "atan is the wrong way around".


(No, in a mathematical sense, that statement is complete nonsense, as there is no such thing as "the right way around" in this context anyway.

But it's just a "corrective meme" whose purpose is just to make you pause and think about the order, so it doesn't have to be precise or accurate.

In fact, its vagueness is potentially confusing and that's actually useful because it'll probably force you to look it up, trying to remember what the hell you even meant by remembering such a confusing phrase.

Well, it works for me. But then I do have a strange mind.)


But, anyway, returning to reality from my little digression there, yes, Simon's suggestion to use "atan2" is a good idea.

"atan2" takes the X and Y axes (well, actually, it takes any two axes, more generally speaking, but we're talking 2D here, so no need to be overly complicated at the moment) as separate parameters and handles the potential "error case" in there automatically.

The "error case" being that when X is zero, "Y / X" is a "divide by zero" and will likely throw an exception.

You can manually code around this by checking whether X is zero and then using atan if it isn't or working it out manually when it is (this is easily done: Because X is zero when the two points are directly above or directly below each other. So you can just manually compare the Y co-ordinates - which is just a "is it positive or negative?" test - and then return the correct angle in your own code).

Or, you can avoid all this by using "atan2" where they've already coded in the "exception" case for you (and this is why you pass X and Y as separate parameters, so the function can detect and handle the "error case" for you).


There's also a further "error case" to possibly consider of when the two points are exactly on top of one another (both X and Y are the zero), where the concept of an "angle" between them doesn't even make sense any more.

This "error case", though, is usually irrelevant in most games because, typically, "collision detection" and the inability for two things to stand on top of each other in the game rules itself (e.g. the player would be dead already or is simply disallowed from moving into that position because game objects are treated as "solid" that you can't pass through or over), usually means that this never crops up anyway.

As the concept of an "angle" is immaterial in this case anyway, you can also usually just use any arbitrary angle. For example, just treat it as "directly up / down" or something (e.g. the earlier test for whether Y is positive or negative can just be made into a test whether Y is "zero or positive" or negative and just lump in "Y is zero too" case with one of the others. In practice, for most uses, this won't make a sodding bit of difference and is a standard "get out clause" for such a situation).

I do believe that this is basically what an "atan2" implementation typically does.

Never tested it explicitly, mind you, because if I'm ever in a situation where it does matter how it deals with the "on top of each other" case, I tend to use "atan" and manually code the exceptions myself, so I can catch that case and I wouldn't be using "atan2" (e.g. if it actually matters how this is dealt with, then I'd avoid using the "convenience" function anyway).

Note, though, that most "atan2" functions take the parameters in the "Y, X" order to match up with "atan" (so that changing from one to the other is a very simple case of adding / removing a "2" and changing the divide into a comma or vice versa). Rather than the "X, Y" order of convention.

Although, whether a particular implementation does that or not, is up to the particular implementation. So check it out in your case, but most of them usually do keep the "reversed order" (so to speak), as a "convenience" to those used to using "atan".

So, yeah, even with "atan2", you still usually have to remember the "atan is the wrong way around" meme thingy.


Unless you have a particular need to "do it yourself" (which, typically, in most games, you generally won't), then, as Simon suggests, just use "atan2". Much easier all round. :D
"Words ought to be a little wild - for they are assaults of thought on the unthinking."
- John Maynard Keynes
User avatar
pasquinelli
Baaaa!
Baaaa!
Posts: 812
Joined: Wed Nov 12, 2003 10:45 pm 0
Location: chicago, il, usa

Post by pasquinelli »

dude, you just posted forever about atan2. :lol:

edit:

not making fun btw, i'm sure it was helpful, but the length of the post just amused me.
[*]]
[*]]^|
User avatar
KlaxonCow
Baaaaaaa!
Baaaaaaa!
Posts: 8446
Joined: Fri Dec 13, 2002 3:46 am 0
Location: A large grassy field.

Post by KlaxonCow »

pasquinelli wrote:dude, you just posted forever about atan2. :lol:
Indeed.

Don't get me started on religion or politics or we'll be here all night. :lol:
"Words ought to be a little wild - for they are assaults of thought on the unthinking."
- John Maynard Keynes
User avatar
funkstar
Baaaaaa!
Baaaaaa!
Posts: 2069
Joined: Sun Aug 08, 2004 2:56 pm 0
Location: Copenhagen, Denmark

Post by funkstar »

Slightly non-sequitur, I know...

Any of you lot know of a good Flash reference? Preferably something to get me started with actionscript, and put something small up quick. Everything I run across seems to want to be a general programming tutorial as well, and I don't need to learn how to program a linked list, dammit!

A .pdf would be nice, as my internet connectivity is a bit wonky at the moment, but an online ref. or even a book recco would be greatly appreciated.

[Edit: Ok, so on the Adobe homepage I just grabbed a whopping 800-page .pdf called Programming ActionScript 3.0. I suspect it will do, though any reccomendations are still welcome...]
User avatar
Istar
Baaaaaa!
Baaaaaa!
Posts: 4869
Joined: Mon Apr 22, 2002 4:42 pm 0
Location: London, UK.

Post by Istar »

KlaxonCow wrote:It's easily done because it's some kind of psychological thing - a mental discipline, a "bad habit of the brain" - to think "X then Y (then Z)" all the time and to fall into that pattern automatically.
Oh come on, a 'bad habit'? One of the core learning cycles of childhood is to memorise the alphabet, which ends 'XYZ'. Then in primary/secondary school, we're taught to plot graphs using X-Y co-ordinates. Hell, men literally have XY ingrained at the very genetic level. ;)

So it's atan2 that has the bad habit, going against all other conventions. An easy mistake to make, yes - but an entirely understandable one.
User avatar
moosedude
Baaaaaaa!
Baaaaaaa!
Posts: 6209
Joined: Fri Nov 19, 2004 1:19 pm 0
Location: Craggy Island
Contact:

Post by moosedude »

Istar wrote:
KlaxonCow wrote:It's easily done because it's some kind of psychological thing - a mental discipline, a "bad habit of the brain" - to think "X then Y (then Z)" all the time and to fall into that pattern automatically.
Oh come on, a 'bad habit'? One of the core learning cycles of childhood is to memorise the alphabet, which ends 'XYZ'. Then in primary/secondary school, we're taught to plot graphs using X-Y co-ordinates. Hell, men literally have XY ingrained at the very genetic level. ;)

So it's atan2 that has the bad habit, going against all other conventions. An easy mistake to make, yes - but an entirely understandable one.
Anticipation and assumption, fairly important and natural things when trying to work out something new, and discovering/testing new things. making an assumption is just as important as discovering that assumption is incorrect.

01000101 01000100 01000111 01000101

http://www.redbubble.com/people/fotofill/ buy my photos!
Post Reply