I'm creating a game where if the enemy is in a certain range and is in front of the player the player can attack the enemy. I have worked out the radius distance and made it facing forward depending in which way the player faces but how can i create the angle so it makes like a cone shape from the player. I have got an image. The thin green line is the radius which I have worked out but how can i calculate the red cone.
Here is the image for more better understanding
http://tinypic.com/view.php?pic=28v63h0&s=6
This is what I done so far
package
{
import flash.display.MovieClip;
import flash.events.Event;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.ui.Keyboard;
public class Player extends MovieClip
{
var radius:Number = 60;
public function Player()
{
addEventListener(Event.ENTER_FRAME, Update);
}
function Update(event:Event)
{
var radiusx:Number = x+radius*Math.cos(rotation/180*Math.PI);
var radiusy:Number = y+radius*Math.sin(rotation/180*Math.PI);
// Rotate to mouse;
var dx = parent.mouseX - x;
var dy = parent.mouseY - y;
var angle = Math.atan2(dy,dx) / Math.PI * 180;
rotation = angle;
}
}
}
You can use the definition of tangent:
tan(a/2) = s/(2d)
where s is size (diamerer) of the enemy and d is the shortest distance to the enemy. Here a is the total visible angle (between two red lines).
Related
Help please write a function of the projectile bounce off the ground. How do I find the angle of the collision, and what should be the reflection angle or at least learn the point of collision?
package {
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.BlendMode;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.events.Event;
import flash.events.MouseEvent;
public class worms extends Sprite {
public var terrain_bmpd=new BitmapData(550,200,true,0xFF00FF00);//This is the Bitmap of the terrain
public var terrain_bmp=new Bitmap(terrain_bmpd);//and this the BitmapData
public var character=new Sprite();//The character will work as a worm
public var hole=new Sprite();//That's the hole we need
public var hole_matrix:Matrix;//The hole_matrix is used to set the position of the hole
public var left_foot:Point;
public var right_foot:Point;//These are the feet of the character. We will use it to check collisions
public function worms() {
draw_objects();//This function draws the character, the terrain and the hole.
stage.addEventListener(Event.ENTER_FRAME,fall);
}
public function fall(e:Event) {
/*This function will move down the character if there isn't a collision
between the terrain and the "feet" of the character*/
for (var i:int=0; i<10; i++) {//We want to check every pixel if there's acollision, so we won't move the character 10 pixels all at once
left_foot=new Point(character.x-5,character.y+10);
right_foot=new Point(character.x+5,character.y+10);
if (!(terrain_bmpd.hitTest(new
Point(terrain_bmp.x,terrain_bmp.y),0x01,left_foot))&&!(terrain_bmpd.hitTest(new Point(terrain_bmp.x,terrain_bmp.y),0x01,right_foot))) {
character.y++;//If there aren't any collisions, make the character fall one pixel
}
}
}
public function draw_objects() {
terrain_bmp.y=200;//The terrain shouldn't be at the top of the stage!
stage.addChild(terrain_bmp);//We can make the terrain visible
character.graphics.beginFill(0x0000FF);//Let's draw the character. It will be a blue rectangle.
character.graphics.drawRect(-5,-10,10,20);
character.x=250;
stage.addChild(character);
hole.graphics.beginFill(0x000000);//Now we draw the hole. It doesn't matter the colour.
hole.graphics.drawCircle(0,0,30);
}
}
}
There's several parts to this, and it seems you don't really know where to begin.
Like the others have mentioned, your object (projectile, character, etc) movement should be represented by a vector, ie x and y velocity. (A Point can represent a vector.)
Next, to detect angle of collision on pixel-based terrain like you have, you can do a series of point (pixel) hit tests in a radius around the object. This will give you a collection of hit points, which you define as vectors from the center of the object. Average the vectors and you have your collision angle.
Here's a function I've used to do this:
/**
* Test for a hit against a shape based on a point and radius,
* returns the angle of the hit or NaN if no hit.
* Like hitTestPoint, xPos and yPos must be in stage coordinates.
*/
function hitTestAngle(shape:Sprite, xPos:Number, yPos:Number, radius:Number, samples:uint = 90):Number {
const PI2:Number = Math.PI * 2, SAMPLE:Number = 1 / samples;
var dx:Number, dy:Number, a:Number, tx:Number = 0, ty:Number = 0, hits:int = 0;
var i:int = samples;
while(i--){
a = PI2 * (i * SAMPLE);
dx = radius * Math.cos(a);
dy = radius * Math.sin(a);
if(shape.hitTestPoint(xPos + dx, yPos + dy, true)){
hits++;
tx += dx;
ty += dy;
}
}
if(!hits)
return NaN;
return Math.atan2(ty, tx) * (180 / Math.PI);
}
This uses hitTestPoint() but since your terrain is BitmapData you could just use getPixel32() and check the alpha value.
You could also use Collision Detection Kit, which uses a similar approach under the hood, with a bunch of extra features.
Once you have the angle of collision, you can define a perpendicular vector as the collision surface to reflect the projectile's vector.
That should get you started.
Flat, horizontal ground:
//Check next movementstep
if((vel_y + pos_y) > terrainBottom) {
vel_y = -vel_y*DampingFactor;
}
for the general case you need to transform vel_x, vel_y into the case shown above using trigonometric functions.
As in the previous answer, use vel_x and vel_y to represent the motion of your character in vector form. Use these values to increase your x and y co-ordinates at each iteration. In your example you are using vel_x = 0, vel_y = 1, because you are increasing the y-coordinate by 1 each time.
If a surface has an an angle A measured counter-clockwise from the horizontal then x_vel and y_vel after bouncing (relfecting) on the surface will be
x_vel.cos2A + y_vel.sin2A and x_vel.sin2A - y_vel.cos2A respectively. To see how this is derived see planetmath
This is for a perfectly elastic collision, ie no loss of speed on impact.
So I'm currently attempting to make a prototype for a Bullet Hell game and I've run into a bit of a dead end.
So far I can move my player perfectly, the boss moves back and forth as he is supposed to, however the projectiles have some funny behaviour. Basically, when the boss moves left/right, so do the projectiles as if they are stuck to him. They move on the y as they are supposed to, except they stop just short of the player and move no further, so I'm hoping anyone can take a look at my code and give me a hand with what's going on.
Note: Ignore the rotation stuff, that's for later implementation, I was just laying the ground work.
Projectile.as
package
{
import flash.display.Stage;
import flash.display.MovieClip;
import flash.events.Event;
public class Projectile extends MovieClip
{
private var stageRef:Stage;
private var _xVel:Number = 0;
private var _yVel:Number = 0;
private var rotationInRadians = 0;
private const SPEED:Number = 10;
public function Projectile(stageRef:Stage, x:Number, y:Number, rotationInDegrees:Number)
{
this.stageRef = stageRef;
this.x = x;
this.y = y;
this.rotation = rotationInDegrees;
this.rotationInRadians = rotationInDegrees * Math.PI / 180;
}
public function update():void
{
this.y += SPEED;;
if(x > stageRef.stageWidth || x < 0 || y > stageRef.stageHeight || y < 0)
{
//this.removeChild(this); <- Causing a crash, will fix later
}
}
}
}
Boss.as
package
{
import flash.display.MovieClip;
import flash.display.Stage;
import flash.events.Event;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class Boss extends MovieClip
{
private var stageRef:Stage;
private var _vx:Number = 3;
private var _vy:Number = 3;
private var fireTimer:Timer;
private var canFire:Boolean = true;
private var projectile:Projectile;
public var projectileList:Array = [];
public function Boss(stageRef:Stage, X:int, Y:int)
{
this.stageRef = stageRef;
this.x = X;
this.y = Y;
fireTimer = new Timer(300, 1);
fireTimer.addEventListener(TimerEvent.TIMER, fireTimerHandler, false, 0, true);
}
public function update():void
{
this.x += _vx;
if(this.x <= 100 || this.x >= 700)
{
_vx *= -1;
}
fireProjectile();
projectile.update();
}
public function fireProjectile():void
{
if(canFire)
{
projectile = new Projectile(stageRef, this.x / 200 + this._vx, this.y, 90);
addChild(projectile);
canFire = false;
fireTimer.start();
}
}
private function fireTimerHandler(event:TimerEvent) : void
{
canFire = true;
}
}
}
Edit: Current suggestions have been to do the following:
stage.addChild(projectile); and this.parent.addChild(projectile); both which have the projectile firing from the top left corner (0, 0) and not constantly firing from the current center of the Boss.
The other issue, which has been untouched, is the fast that the projectile stops moving after a certain point and remains on the screen.
Another Edit:
After commenting out the code with the timer I have found that the projectile stops moving entirely. The reason why it was stopping after a certain amount of time was due to the timer, when the timer elapsed the projectile stopped and another would fire.
So now I need the projectile to constantly fire and move until it hits the edge of the screen, any ideas?
The problem is you are 'addChild'ing your projectiles to your Boss as opposed the stage (or the same display level as your Boss). When your Boss moves, your projectiles will move relative to him (ie, when he moves sideways, so will they).
When your boss fires a projectile, use a custom event to trigger a fireProjectile method in the Class that is your Boss' display parent. Instantiate your projectiles there and addChild them to the same object to which you addChild your Boss (possibly the stage?).
Alternatively, if you don't want to use a custom event, in your current fireProjectile method change the addChild line to:
this.parent.addChild(projectile);
This will add projectiles to the parent object of your Boss. Although that line seems, slightly, like cheating to me.
I have a ball that will be kicked by the player, it is a movieclip and I want it to get smaller little by little as it gets away from the original spot, a AS3 tween perhaps? This is the code moving the ball:
speed=10;
var ease:int = 100;
var gravity:Number = 0.5;
function moveBall()
{
var targetX:Number = mouseX;
var targetY:Number = mouseY;
var angle = Math.atan2(targetY,targetX);
bola.x = mouseX + Math.cos(angle);
bola.y = mouseY + Math.sin(angle) ;
ballRotation = true;
stage.removeEventListener(MouseEvent.CLICK, kick);
Thanks a lot for your patience and help!
If you have tweenlite/tweenmax, you can get a pretty realistic ball getting kicked with this code:
import com.greensock.*;
import com.greensock.plugins.*;
import flash.events.MouseEvent;
TweenPlugin.activate([BezierPlugin]);
ball.addEventListener(MouseEvent.CLICK, kickBall);
function kickBall(e:MouseEvent):void
{
TweenMax.to(ball,2,{scaleX:0,scaleY:0,bezier:[{x:400, y:-250}, {x:315, y:200}]});
}
Obviously you can tweak those values as you please.
example: http://ronnieswietek.com/_random/ball.swf
I don't know what to do next.
Right now when I click, it adds the bullet and rotates it to the correct angle, but I don't know how to make it fire. I want to have the bullet shoot to where the mouse is pointing. Thanks!
PS: Sorry if the code is messy.
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.events.KeyboardEvent;
import flash.utils.Timer;
import flash.text.Font;
import flash.events.MouseEvent;
import flash.text.TextDisplayMode;
import flash.text.TextExtent;
import flash.text.TextField;
import flash.text.TextFormat;
import fl.motion.easing.Back;
import flash.display.DisplayObject;
public class GameEnter extends MovieClip
{
public var _bullet:bullet;
public function GameEnter()
{
stage.addEventListener(MouseEvent.MOUSE_DOWN, shootBullet);
stage.addEventListener(MouseEvent.MOUSE_UP, removeBullet);
}
public function init()
{
_bullet = new bullet();
addChild(_bullet);
_bullet.x = stage.stageWidth / 2;
_bullet.y = stage.stageHeight / 2;
addEventListener(Event.ENTER_FRAME, onEnter);
}
public function onEnter(event:Event)
{
var dx:Number = mouseX - _bullet.x;
var dy:Number = mouseY - _bullet.y;
var angle:Number = Math.atan2(dy,dx) * 180 / Math.PI;
_bullet.rotation = angle;
}
public function shootBullet(event:MouseEvent)
{
init();
}
public function removeBullet(event:MouseEvent)
{
removeChild(_bullet);
}
}
}
To move an object in a direction based on rotation, you'll need cos and sin.
Math.cos() and Math.sin() only accept radians, so you'll need to convert rotation to radians like you have for Math.atan2() in your example.
Sample:
// Note: Utilising the property 'angle' from your code.
_bullet.x += Math.cos(angle);
_bullet.y += Math.sin(angle);
And then obviously multiply these values by a value that will represent how fast you want the bullet to go, eg:
var velocity:Number = 10.5;
_bullet.x += Math.cos(angle) * velocity;
_bullet.y += Math.sin(angle) * velocity;
I'm writing a game and it has enemies and bullets. When a bullet hits an enemy, I want to destroy the enemy and the bullet. I'm using the hitTestPoint() method to test if a bullet has hit an enemy. Here's the code in my game loop:
for each(var bullet:Bullet in this.bullets) {
for each(var enemy:Enemy in this.enemies) {
if(enemy.hitTestPoint(bullet.x, bullet.y)) {
trace("hit");
}
}
bullet.update();
}
this.bullets and this.enemies are both arrays containing objects for bullets and enemies. Here's those two classes:
package com {
import flash.display.MovieClip;
import flash.display.Stage;
public class Bullet extends MovieClip {
private var stageRef:Stage;
public var speed:Number = 10;
public function Bullet(stage:Stage) {
this.stageRef = stage;
}
public function update() {
this.x += Math.sin((Math.PI / 180) * (360 - this.rotation)) * this.speed;
this.y += Math.cos((Math.PI / 180) * (360 - this.rotation)) * this.speed;
}
}
}
--
package com {
import flash.display.MovieClip;
import flash.display.Stage;
public class Enemy extends MovieClip {
public var speed:Number = 4;
private var stageRef:Stage;
public function Enemy(stage:Stage) {
this.stageRef = stage;
this.x = this.stageRef.stageWidth / 3;
this.y = this.stageRef.stageHeight / 2;
}
public function update() {
}
}
}
The problem is, hitTestPoint only returns true if both the x and y values of bullet and enemy are the same, rather than if the two movie clips overlap. This leads to bullets going right through enemies but it not registering as a hit. Perhaps I'm missing a bounding box?
Is there a way I can make hitTestPoint return true if the bullet hits the enemy at all rather than only if the bullet and enemy co-ordinates are the same?
Thank you!
You want hitTestObject(), not hitTestPoint()
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/DisplayObject.html#hitTestObject%28%29
Yes, if yours movieclips are too small the frame x will be just right to the object and the next frame it will be pass it, you may want to make a "hitbox" bigger, like doing the movieclip bigger with alpha rectangles.