Shooting bullets at cursor Flash AS3 - actionscript-3

I am making a top down shooter in flash using AS3 and I'm having some trouble firing a bullet from a ship moved by the WASD keys towards the cursor. The bullets are created fine enough but they go off in random directions rather than towards where the cursor is when you press space.
This is the code for the bullet class:
package{
import flash.display.MovieClip;
import flash.events.Event;
import flash.ui.Mouse;
import flash.events.MouseEvent;
import flash.geom.Point;
public class Bullet extends MovieClip
{
var speed:Number;
var moveX:Number;
var moveY:Number;
var shipX:Number;
var shipY:Number;
function Bullet(target:Ship)
{
speed = 20;
shipX = target.x;
shipY = target.y;
graphics.lineStyle(7,0x000000);
graphics.moveTo(-2,0);
graphics.lineTo(2,0);
graphics.lineStyle(3,0xffffff);
graphics.moveTo(-2,0);
graphics.lineTo(2,0);
addEventListener(Event.ADDED_TO_STAGE, onStage);
}
function onStage (e:Event)
{
/*addEventListener("enterFrame", enterFrame);
/*var mc =
var angleRadian = Math.atan2(mouseY - mc.y, mouseX - mc.x);
var angleDegree = angleRadian * 180 / Math.PI;
mc.rotation = angleDegree;*/
/*Ship.y += speed * Math.sin((Ship.rotation - 90) * (Math.PI / 180));
Ship.x += speed * Math.cos((Ship.rotation - 90) * (Math.PI / 180));*/
trace(stage.mouseY);
var cy:Number = stage.mouseY - shipY;
var cx:Number = stage.mouseX - shipX;
moveX = cx / cy;
moveY = (cy < 0) ? -1 : 1;
var Radians:Number = Math.atan2(cy,cx);
var Degrees:Number = Radians * 180 / Math.PI;*/
}
function enterFrame(e:Event)
{
/*this.x += speed;*/
this.x += moveX * speed;
this.y += moveY * speed;
if (this.x > 900)
{
removeEventListener("enterFrame",enterFrame);
stage.removeChild(this);
}
if (this.x < 0)
{
removeEventListener("enterFrame",enterFrame);
stage.removeChild(this);
}
if (this.y > 800)
{
removeEventListener("enterFrame",enterFrame);
stage.removeChild(this);
}
if (this.y < 0)
{
removeEventListener("enterFrame",enterFrame);
stage.removeChild(this);
}
for(var i in Enemy.list)
{
if(this.hitTestObject(Enemy.list[i]))
{
removeEventListener("enterFrame", enterFrame);
stage.removeChild(this);
Enemy.list[i].kill();
break;
}
}
}
}
}
Any help getting the bullets to fire properly would be much appreciated!

The x and y velocities should be the result of cos and sin of the angle (in radians) respectively.
i.e.
var angle:Number = Math.atan2(cy, cx);
moveX = Math.cos(angle);
moveY = Math.sin(angle);
You then multiply both of these by the speed (which you're already doing).
Also, you don't need to calculate the degrees unless you want to rotate the graphics:
rotation = angle * 180 / Math.PI;

Related

ActionScript3 Flash ,How in the package Correct the characters' interactions and collisions with walls?

I'm making a game.
Problem:
How should the enemies hit the wall and be reversed?
In the part of the enemy moving with the walls, how should the movements hitTestPoint?
What I've tried:
package {
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Point;
public class Enemy extends Sprite {
private var speed: int;
private var target: Point;
function Enemy() {
speed = 2 + Math.random() * 5;
trace("Make a ship");
target = new Point(Math.random() * 1280, Math.random() * 768);
addEventListener(Event.ENTER_FRAME, update);
//Movement Enemy
}
function update(e: Event) {
var dx = target.x - x;
var dy = target.y - y;
var angle = Math.atan2(dy, dx) / Math.PI * 180;
rotation = angle;
x = x + Math.cos(rotation / 180 * Math.PI) * speed;
y = y + Math.sin(rotation / 180 * Math.PI) * speed;
var hyp = Math.sqrt((dx * dx) + (dy * dy));
if (hyp < 5) {
target.x = Math.random() * 1280;
target.y = Math.random() * 768;
}
if (Enemy.hitTestObject(rect2)) {
trace("HIT!")
txt_hit.text = "HIT!";
} else {
txt_hit.text = "";
}
}
}
}
//Collision Hit Enemy to Wall
stage.addEventListener(Event.ENTER_FRAME, updatePos);
function updatePos(e: Event) {
hitTesting();
}
function hitTesting() {
for each(var enemy: Enemy in Enemies) {
if (enemy.hitTestObject(rect2)) {
// stage.addEventListener(Event.ENTER_FRAME, hitTest);
// function hitTest(event: Event): void {
// if (Enemy.hitTestObject(rect2)) {
trace("HIT!")
txt_hit.text = "HIT!";
} else {
txt_hit.text = "";
}
}
}

How to make a movieClip move independent of the stage if added on it?

In my flash-made game, if my character jump on top of an enemy movieclip it spawns 3 minions from another class by MovieClip(root).addChild(spawn1);. In my minions class I've put the code for them to fall and stop upon hitting the ground and also follow my character.
I have a VCam(virtual camera) movieClip to follow my character(who moves on the stage, not the stage around him) with this code build-in:
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.display.MovieClip;
//VCam
addEventListener(Event.ENTER_FRAME, handleEnterFrame);
function handleEnterFrame(event:Event):void {
if (parent) {
parent.scaleX = 1 / scaleX;
parent.scaleY = 1 / scaleY;
if (rotation == 0) {
parent.x = (width / 2 - x) / scaleX;
parent.y = (height / 2 - y) / scaleY;
parent.rotation = 0;
} else {
var bounds:Rectangle = getBounds(this);
var angle:Number = rotation * Math.PI / 180;
var midX:Number = -x / scaleX;
var midY:Number = -y / scaleY;
var rx:Number = -bounds.width / 2;
var ry:Number = -bounds.height / 2;
var cos:Number = Math.cos(angle);
var sin:Number = Math.sin(angle);
var rotatedX:Number = rx * cos - ry * sin;
var rotatedY:Number = ry * cos + rx * sin;
var cornerX:Number = midX - rotatedX;
var cornerY:Number = midY - rotatedY;
cos = Math.cos(-angle);
sin = Math.sin(-angle);
parent.x = cornerX * cos - cornerY * sin;
parent.y = cornerY * cos + cornerX * sin;
parent.rotation = -rotation;
}
}
}
addEventListener(Event.REMOVED, handleRemoved, false, 0, true);
function handleRemoved(event:Event):void
{
removeEventListener(Event.ENTER_FRAME, handleEnterFrame);
removeEventListener(Event.REMOVED, handleRemoved);
}
When I jump with my character it seems that the minions follow the movement of my vcam and not behaving normally, jumping with the camera and falling throu'the ground when the character falls.
If I add a child normally from the main timeline by addChild(m_clip); it does not behave like that.
Is there an easy fix? Thanks!
This is the minions class code:
package {
import flash.display.*;
import flash.events.*;
public class EnemySpawned extends MovieClip {
protected var gravitysp: Number = 1;
protected var ySpeedsp: Number = 0;
protected var Speedsp: Number = 6.5;
var charMTL:MovieClip;
public function EnemySpawned()
{
this.addEventListener(Event.ENTER_FRAME, movement);
trace('exist');
}
function movement(event:Event):void
{
var MTL:MovieClip = MovieClip(root);
charMTL = MTL.char1;
ySpeedsp += gravitysp;
if(! MTL.ground_1.hitTestPoint(this.x, this.y, true))
{
this.y += ySpeedsp;
}
if(ySpeedsp > 40)
{
ySpeedsp = 40;
}
for(var j:int = 0; j<20; j++)
{
if(MTL.ground_1.hitTestPoint(this.x, this.y, true))
{
this.y--
ySpeedsp = 0;
}
}
var Distance:Number = charMTL.x - this.x;
if(Distance < -charMTL.width/2 - this.width/2)
{
this.x -= Speedsp;
}
if(Distance > charMTL.width/2 + this.width/2)
{
this.x += Speedsp;
}
}
}
}
There is no moving of ground_1 movieClip via code.

actionscript 3.0 can't figure out why a collision fails with one line in an array of lines

can't figure out why the ball object falls right through line[2] while it bounces off all the others. I have two classes below; a main class that creates the lines along with some collision and motion code for the ball, and a class for the ball. I included a comment above the line in the main class which pertains to the line that doesn't interact. When the program runs, it bounces off of all the lines with some distance based collision code - but passes right through one of the lines- the line created in the array at line[2]
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Rectangle;
public class MultiAngleBounce extends Sprite
{
private var ball:Ball;
private var lines:Array;
private var numLines:uint = 6;
private var gravity:Number = 0.3;
private var bounce:Number = -0.6;
public function MultiAngleBounce()
{
init();
}
private function init():void
{
ball = new Ball(20);
addChild(ball);
ball.x = 100;
ball.y = 100;
//create five lines
lines = new Array();
for(var i:uint = 0; i < numLines; i++)
{
var line:Sprite = new Sprite();
line.graphics.lineStyle(1);
line.graphics.moveTo(-50, 0);
line.graphics.lineTo(50, 0);
addChild(line);
lines.push(line);
}
lines[0].x = 100;
lines[0].y = 100;
lines[0].rotation = 30;
lines[1].x = 100;
lines[1].y = 230;
lines[1].rotation = 50;
//why does this one get ignored
lines[2].x = 250;
lines[2].y = 180;
lines[2].rotation = -30;
lines[3].x = 150;
lines[3].y = 330;
lines[3].rotation = 10;
lines[4].x = 230;
lines[4].y = 250;
lines[4].rotation = -30;
lines[5].x = 300;
lines[5].y = 350;
lines[5].rotation = -20;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void
{
//normal motion code
ball.vy += gravity;
ball.x += ball.vx;
ball.y += ball.vy;
//bounce off ceiling, floor, walls
if(ball.x + ball.radius > stage.stageWidth)
{
ball.x = stage.stageWidth - ball.radius;
ball.vx *= bounce;
}
else if(ball.x - ball.radius < 0)
{
ball.x = ball.radius;
ball.vx *= bounce;
}
if(ball.y + ball.radius > stage.stageHeight)
{
ball.y = stage.stageHeight - ball.radius
ball.vy *= bounce;
}
else if(ball.y - ball.radius < 0)
{
ball.y = ball.radius;
ball.vy *= bounce;
}
//check each line
for(var i:uint = 0; i < numLines; i++)
{
checkLine(lines[i]);
}
}
private function checkLine(line:Sprite):void
{
//get the bounding box of the line
var bounds:Rectangle = line.getBounds(this);
if(ball.x > bounds.left && ball.x < bounds.right)
{
//get angle, sine and cosine
var angle:Number = line.rotation * Math.PI / 180;
var cos:Number = Math.cos(angle);
var sin:Number = Math.sin(angle);
//get position of ball, relative to line
var x1:Number = ball.x - line.x;
var y1:Number = ball.y - line.y;
//rotate coordinates
var y2:Number = cos * y1 - sin * x1;
//rotate velocity
var vy1:Number = cos * ball.vy - sin * ball.vx;
//perform bounce with rotated values
if(y2 > -ball.height / 2 && y2 < vy1)
{
//rotate coordinates
var x2:Number = cos * x1 + sin * y1;
//rotate velocity
var vx1:Number = cos * ball.vx + sin * ball.vy;
y2 = -ball.height / 2;
vy1 *= bounce;
//rotate everything back;
x1 = cos * x2 - sin * y2;
y1 = cos * y2 + sin * x2;
ball.vx = cos * vx1 - sin * vy1;
ball.vy = cos * vy1 + sin * vx1;
ball.x = line.x + x1;
ball.y = line.y + y1;
}
}
}
}
}
package
{
import flash.display.Sprite;
public class Ball extends Sprite
{
public var radius:Number;
private var color:uint;
public var internalAngle:Number;
public var internalRadius:Number;
internal var vx:Number = 0;
internal var vy:Number = 0;
public function Ball(radius:Number = 40, color:uint = 0xff0000)
{
this.radius = radius;
this.color = color;
init();
}
public function init():void {
graphics.beginFill(color);
graphics.drawCircle(0, 0, radius);
graphics.endFill();
}
}
}
You bounds check
if(ball.x > bounds.left && ball.x < bounds.right)
is failing for the second line. The ball hasn't attained enough speed by the time it reaches lines[2] that it can get completely into the bounds rect. You can use
if(line.hitTestObject(ball))
to do collision detection instead.

AS3: Click and stop at mouse click

I want to create an object that follows and stops at mouse click. I managed to make it happen with rotation but the problem is that whenever i click on the empty stage, the object will move towards it and it carries on moving. It does not stop at the mouse location. Anyone know how i can do that. Below is my code:
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.MouseEvent;
public class Guest extends MovieClip
{
var walkSpeed:Number = 5;
public function Guest()
{
stage.addEventListener(MouseEvent.CLICK, walk);
}
function walk(event:MouseEvent):void
{
var dx = parent.mouseX - x;
var dy = parent.mouseY - y;
var angle = Math.atan2(dy,dx) / Math.PI * 180;
rotation = angle;
stage.addEventListener(Event.ENTER_FRAME, loop);
}
function loop(event:Event):void
{
x = x+Math.cos(rotation/180*Math.PI)*walkSpeed;
y = y+Math.sin(rotation/180*Math.PI)*walkSpeed;
stage.removeEventListener(Event.ENTER_FRAME, loop);
}
}
}
Your code is a bit weird, here you will never move towards position for more than one frame since you remove the event listener as soon as loop is done.
Here is some code that fixes the moving and then stopping issue. However I strongly suggests that you do this with some kind of "tweening library" and I will after this show an example of doing that with Caurina Transitions.
function walk(e:MouseEvent):void {
targetX = parent.mouseX; //targetX created as a member variable
targetY = parent.mouseY; //targetY created as a member variable
var dx = parent.mouseX - x;
var dy = parent.mouseY - y;
var angle = Math.atan2(dy,dx) / Math.PI * 180;
rotation = angle;
stage.addEventListener(Event.ENTER_FRAME, loop);
}
function loop(e:Event):void {
var newX:Number = x + Math.cos(rotation / 180 * Math.PI) * walkSpeed;
var newY:Number = y + Math.sin(rotation / 180 * Math.PI) * walkSpeed;
var atTarget:Boolean = true;
if (Math.abs(targetX - newX) > walkSpeed) {
x = newX;
atTarget = false;
}
if(Math.abs(targetY - y) > walkSpeed) {
y = newY;
atTarget = false;
}
if (atTarget) {
stage.removeEventListener(Event.ENTER_FRAME, loop);
}
}
Here's the same behaviour with caurina.
package
{
import caurina.transitions.Tweener;
import flash.display.MovieClip;
import flash.events.MouseEvent;
public class TransitionExample extends MovieClip
{
private var targetX:Number;
private var targetY:Number;
var walkSpeed:Number = 5;
public function TransitionExample()
{
trace("ctor()");
stage.addEventListener(MouseEvent.CLICK, walk);
}
private function walk(e:MouseEvent):void {
targetX = parent.mouseX;
targetY = parent.mouseY;
var dx = targetX - x;
var dy = targetY - y;
var angle = Math.atan2(dy,dx) / Math.PI * 180;
rotation = angle;
var tweenDone:Function = function():void {
trace("tween is finished");
}
//modify time to be dependant on the "walkspeed" and the distance travelled etc...
Tweener.addTween(this, { x:targetX, y:targetY, time:0.458, transition:"linear", onComplete:tweenDone});
}
}
}

Collision-based springing

I have placed one large ball, "centerBall", in the center of the stage. Then I added in a
bunch of smaller ones, giving them random sizes and velocities. These will move with basic motion code and bounce off the walls. On each frame, did a distance-based collision check between each moving ball and the center ball. If I got a collision, I've calculated an offset spring target based on the angle between the two balls and the minimum distance.
There is still one problem: some of the smaller balls bypass "centerBall" boundaries and then bounce off. You can see that in the attached image. Why is happening this?
Here is the code:
import flash.display.Sprite;
import flash.events.Event;
public class Bubbles extends Sprite
{
private var balls:Array;
private var numBalls:Number = 10;
private var centerBall:Ball;
private var bounce:Number = -1;
private var spring:Number = 0.2;
public function Bubbles()
{
init();
}
private function init():void
{
balls = new Array();
centerBall = new Ball(100, 0xcccccc);
addChild(centerBall);
centerBall.x = stage.stageWidth / 2;
centerBall.y = stage.stageHeight / 2;
for(var i:uint = 0; i < numBalls; i++)
{
var ball:Ball = new Ball(Math.random() * 40 + 5, Math.random() * 0xffffff);
ball.x = Math.random() * stage.stageWidth;
ball.y = Math.random() * stage.stageHeight;
ball.vx = Math.random() * 6 - 3;
ball.vy = Math.random() * 6 - 3;
addChild(ball);
balls.push(ball);
}
addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(event:Event):void
{
for(var i:uint = 0; i < numBalls; i++)
{
var ball:Ball = balls[i];
move(ball);
var dx:Number = ball.x - centerBall.x;
var dy:Number = ball.y - centerBall.y;
var dist:Number = Math.sqrt(dx * dx + dy * dy);
var minDist:Number = ball.radius + centerBall.radius;
if(dist < minDist)
{
var angle:Number = Math.atan2(dy, dx);
var targetX:Number = centerBall.x + Math.cos(angle) * minDist;
var targetY:Number = centerBall.y + Math.sin(angle) * minDist;
ball.vx += (targetX - ball.x) * spring;
ball.vy += (targetY - ball.y) * spring;
}
}
}
private function move(ball:Ball):void
{
ball.x += ball.vx;
ball.y += ball.vy;
if(ball.x + ball.radius > stage.stageWidth)
{
ball.x = stage.stageWidth - ball.radius;
ball.vx *= bounce;
}
else if(ball.x - ball.radius < 0)
{
ball.x = ball.radius;
ball.vx *= bounce;
}
if(ball.y + ball.radius > stage.stageHeight)
{
ball.y = stage.stageHeight - ball.radius;
ball.vy *= bounce;
}
else if(ball.y - ball.radius < 0)
{
ball.y = ball.radius;
ball.vy *= bounce;
}
}
}
Click here to see the pic
The problem you have is that you are doing collision detection based on them frames and not the positions.
You need to check where it is now and where it was last frame so you can keep track of its movements. This is why it goes through your center ball because you check in the current frame for a collision.
Here is a link to a time based collision detection of circles.
Timed based collision
Hope this helps ; )