Smoothly rotating a canvas element on setInterval() - html

I am trying to replicate this effect: http://codepen.io/kenjiSpecial/pen/enrbq
I have a Segment class:
function Segment (x, y, length) {
this.x = x;
this.y = y;
this.length = length;
this.rotation = 0;
this.color = '#fff';
}
I use it to fill the screen with vertical lines (made out of segments) and then rotate each of them by 45deg clockwise using this function and a setInterval:
function drawSegments(segment) {
segment.rotation = angle;
segment.draw(ctx);
}
setInterval(function(){
angle += 45 * Math.PI / 180;
}, 800);
It works (i.e. the lines are rotated on each 800ms) but there is no animation between the transitions.. I tried somethig like this, but unfortunately it doesn't work...
for (var i = 0; i < 360; i++) {
angle += i * Math.PI / 180;
}
So, the problem is - how to animate each rotation of the segments?
Here is the link to the live demo: http://codepen.io/gbnikolov/pen/KEGzJ

Related

Actionscript 3.0 Mouse trail snake game logic

I am developing a game in actionscript 3.0 (adobe flash) similar to this https://www.tvokids.com/preschool/games/caterpillar-count. I have the code for dragging the head of the snake in the direction of the mouse. However, I do not know how do I add the body of the snake and make it follow the path of the head. Following is my code to drag movieclip in the direction of the mouse :
var _isActive = true;
var _moveSpeedMax:Number = 1000;
var _rotateSpeedMax:Number = 15;
var _decay:Number = .98;
var _destinationX:int = 150;
var _destinationY:int = 150;
var _dx:Number = 0;
var _dy:Number = 0;
var _vx:Number = 0;
var _vy:Number = 0;
var _trueRotation:Number = 0;
var _player;
var i;
createPlayer();
stage.addEventListener(MouseEvent.MOUSE_DOWN, onDown);
function createPlayer():void{
_player = new head();
_player.x = stage.stageWidth / 2;
_player.y = stage.stageHeight / 2;
stage.addChild(_player);
}
function onDown(e:MouseEvent):void{
_isActive = true;
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
}
function onMove(e:MouseEvent):void{
updatePosition(_player);
updateRotation(_player);
}
function onUp(e:MouseEvent):void{
_isActive = false;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
}
function updatePosition(mc):void
{
// check if mouse is down
if (_isActive)
{
// update destination
_destinationX = stage.mouseX;
_destinationY = stage.mouseY;
// update velocity
_vx += (_destinationX - mc.x) / _moveSpeedMax;
_vy += (_destinationY - mc.y) / _moveSpeedMax;
}
else
{
// when mouse is not down, update velocity half of normal speed
_vx += (_destinationX - mc.x) / _moveSpeedMax * .25;
_vy += (_destinationY - mc.y) / _moveSpeedMax * .25;
}
// apply decay (drag)
_vx *= _decay;
_vy *= _decay;
// if close to target, slow down turn speed
if (getDistance(_dx, _dy) < 50)
{
_trueRotation *= .5;
}
// update position
mc.x += _vx;
mc.y += _vy;
}
function updateRotation(mc):void
{
// calculate rotation
_dx = mc.x - _destinationX;
_dy = mc.y - _destinationY;
// which way to rotate
var rotateTo:Number = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (rotateTo > mc.rotation + 180) rotateTo -= 360;
if (rotateTo < mc.rotation - 180) rotateTo += 360;
// ease rotation
_trueRotation = (rotateTo - mc.rotation) / _rotateSpeedMax;
// update rotation
mc.rotation += _trueRotation;
}
function getDistance(delta_x:Number, delta_y:Number):Number
{
return Math.sqrt((delta_x*delta_x)+(delta_y*delta_y));
}
function getRadians(delta_x:Number, delta_y:Number):Number
{
var r:Number = Math.atan2(delta_y, delta_x);
if (delta_y < 0)
{
r += (2 * Math.PI);
}
return r;
}
function getDegrees(radians:Number):Number
{
return Math.floor(radians/(Math.PI/180));
}
The script below will not miraculously work on its own, however it has all the logic you need, well-explained. It makes a chain of any length follow its head by certain rules. I used the same principle here many years ago: http://delimiter.ru/games/25-lines/alone.html
// This one will represent the Mouse position.
var Rat:Sprite = new Sprite;
// The ordered list of chain elements.
// It all starts with the Mouse.
var Snake:Array = [Rat];
// Call this one each time you want to
// extend the snake with the piece of tail.
function addTail(aPiece:DisplayObject):void
{
// Get the last snake element.
var lastPiece:DisplayObject = Snake[Snake.length - 1];
// Sync the tail coordinates.
aPiece.x = lastPiece.x;
aPiece.y = lastPiece.y;
// Add the new piece to the snake.
Snake.push(aPiece);
}
// Add the pre-defined head as the first element.
addTail(SnakeHead);
// Now start following the Mouse.
addEventListener(Event.ENTER_FRAME, onFrame);
// Fires every frame and adjusts the whole snake, if needed.
function onFrame(e:Event):void
{
// Sync the attractor point with the Mouse.
Rat.x = mouseX;
Rat.y = mouseY;
// Now lets make each piece follow the previous piece,
// one by one, starting from the head, down to the tail.
for (var i:int = 1; i < Snake.length; i++)
{
followOne(Snake[i - 1], Snake[i]);
}
}
function followOne(A:DisplayObject, B:DisplayObject):void
{
// Think of these values as of vector
// pointing from B position to A position.
var dx:Number = A.x - B.x;
var dy:Number = A.y - B.y;
// Figure out the distance between the given pieces.
var aDist:Number = Math.sqrt(dx * dx + dy * dy);
// Do nothing if pieces are closer than 20 px apart.
// You can change this value to make snake shorter or longer.
if (aDist < 20)
{
return;
}
// This literally means "eat one tenth of the distance
// between me and the previous piece". If you want pieces
// to follow each other with more vigor, reduce this value,
// if you want the whole snake to slither smoothly, increase it.
B.x += dx / 10;
B.y += dy / 10;
// Rotate the B piece so it would look right into A's direction.
// Well, unless your pieces are round and look all the same.
B.rotation = Math.atan2(dy, dx) * 180 / Math.PI;
}

Rotating Angle Calculation AS3

I am writing a code where there are different rings on the stage, and a ball is rotating in one of these orbits. On click, the ball leaves its ring and travels normal to the ring. On its way if it hits another ring, it starts rotating in that ring from the point it hits the ring. I could successfully code the initial part of the code. but I am getting a problem when the ball hits another ring, it does not start from the location it hit. Instead it starts rotating in the ring from a different position. I hope I am clear with my doubt. It is somewhat similar to this game https://play.google.com/store/apps/details?id=com.drgames.orbit.jumper
here is my code in enter frame :
if(!isTravelling){
rad = Math.abs(angle * (Math.PI / 180)); // Converting Degrees To Radians
_ball.x = currOrbit.x + (currOrbit.width / 2) * Math.cos(rad); // Position The Orbiter Along x-axis
_ball.y = currOrbit.y + (currOrbit.width / 2) * Math.sin(rad); // Position The Orbiter Along y-axis
trace(_ball.x+" , "+_ball.y);
angle -= speed; // Object will orbit clockwise
_ball.rotation = (Math.atan2(_ball.y - currOrbit.y, _ball.x - currOrbit.x) * 180 / Math.PI) + 90;
}
for(var i = 0; i < orbits.length; i++){
if(orbits[i] != currOrbit){
if(ObjectsHit(orbits[i], _ball)){
currOrbit = orbits[i];
_ball.rotation = (Math.atan2(_ball.y - currOrbit.y, _ball.x - currOrbit.x) * 180 / Math.PI) + 90;
isTravelling = false;
stage.addEventListener(MouseEvent.CLICK, onClick);
}
}
}
if(isTravelling){
_ball.x += Math.cos(rad) * speed * 2;
_ball.y += Math.sin(rad) * speed * 2;
}
You seem to have forgotten to calculate the starting angle for the new orbit:
if(!isTravelling){
rad = Math.abs(angle * (Math.PI / 180)); // Converting Degrees To Radians
_ball.x = currOrbit.x + (currOrbit.width / 2) * Math.cos(rad); // Position The Orbiter Along x-axis
_ball.y = currOrbit.y + (currOrbit.width / 2) * Math.sin(rad); // Position The Orbiter Along y-axis
trace(_ball.x+" , "+_ball.y);
_ball.rotation = angle // no need for calculating the angle again
angle -= speed; // Object will orbit clockwise
}
for(var i = 0; i < orbits.length; i++){
if(orbits[i] != currOrbit){
if(ObjectsHit(orbits[i], _ball)){
currOrbit = orbits[i];
angle = (Math.atan2(_ball.y - currOrbit.y, _ball.x - currOrbit.x) * 180 / Math.PI) + 90; // Calculate the starting angle on the new orbit
_ball.rotation = angle // Set the balls rotation to the angle
isTravelling = false;
stage.addEventListener(MouseEvent.CLICK, onClick);
}
}
}
if(isTravelling){
_ball.x += Math.cos(rad) * speed * 2;
_ball.y += Math.sin(rad) * speed * 2;
}
This should fix it. Please note that you might have to add or subtract 90 degrees to your balls rotation (_ball.rotation = angle + 90) because im not 100% sure about that.

As3 Trigonometry and math

i'm trying to create a minigame with circles rotating around circles
however, i have a problem when i shoot the circle and it hits the second circle it doesnt continue the angle but "jumping" to the other side i'm sure it something with the angle var that should reset or something. can you help me im getting nervous around here... :(
check the example
This is my code for the enter frame function that deals with the circles
public function UpdateCircles(e:Event):void
{
for (var i:int = 0; i < EnemySpriteVector.length; i++)
{
EnemySpriteVector[i].rotation += EnemySpriteVector[i].enemyspeed;
}
var rad:Number = angle * (Math.PI / 180); // Converting Degrees To Radians
if (IsplayerShoot)
{
playerSprite.x += Math.cos(rad) * PlayerCircleShootSpeed;
playerSprite.y += Math.sin(rad) * PlayerCircleShootSpeed;
for (var j:int = 0; j < EnemySpriteVector.length; j++)
{
if (EnemySpriteVector[j].hitTestPoint(playerSprite.x,playerSprite.y) && (EnemySpriteVector[j].IsCircleHit == false))
{
trace("hit");
EnemySpriteVector[j].IsCircleHit = true;
removeChild(EnemySpriteVector[0]);
EnemySpriteVector.splice(0, 1);
var EnemySprite:Sprite = new EnemySpriteClass();
EnemySpriteVector.push(EnemySprite);
addChild(EnemySprite);
EnemySprite.x = Math.random() * stage.stageWidth;
EnemySprite.y = Math.random() * stage.stageHeight;
IsplayerShoot = false;
}
}
}
else
{
playerSprite.x = EnemySpriteVector[0].x + EnemySpriteVector[0].radius * Math.cos(rad); // Position The Orbiter Along x-axis
playerSprite.y = EnemySpriteVector[0].y + EnemySpriteVector[0].radius * Math.sin(rad); // Position The Orbiter Along y-axis
angle += EnemySpriteVector[0].enemyspeed; // Object will orbit clockwise
playerSprite.rotation = (Math.atan2(playerSprite.y - EnemySpriteVector[0].y, playerSprite.x - EnemySpriteVector[0].x) * 180 / Math.PI); //only rotates the player circle itself
}
}
Looks like when the pink circle hits the green one it simply continues its rotation from where it left of. A quick solution would be to add 180 degrees to the angle. Keep in mind this will only work for static objects. If you want a more dynamic environment I would recommend using vectors (linear algebra). Vector math is really easy to understand and it hides a lot of complex trigonometry. You can start here :)

Converting complicated trigonometry from AS2 to AS3

I'm trying to make a game, following this tutorial.
The issue comes from the fact that I am using ActionScript 3.0 whereas the tutorial was written using ActionScript 2.0.
Regarding the sight of the enemy, I have turned this code:
onClipEvent (enterFrame) {
dist_x = _root.hero._x-_x;
dist_y = _root.hero._y-_y;
dist = Math.sqrt(dist_x*dist_x+dist_y*dist_y);
angle = Math.atan(dist_y/dist_x)/(Math.PI/180);
if (dist_x<0) {
angle += 180;
}
if (dist_x>=0 && dist_y<0) {
angle += 360;
}
wall_collision = 0;
for (x=1; x<=dist; x++) {
point_x = _x+x*Math.cos(angle*Math.PI/180);
point_y = _y+x*Math.sin(angle*Math.PI/180);
if (_root.wall.hitTest(point_x, point_y, true)) {
wall_collision = 100;
break;
}
}
_root.line._x = _x;
_root.line._y = _y;
_root.line._rotation = angle;
_root.line._alpha = 100-wall_collision;
}
Into that:
// calculate rotation based on target
_dx = this.x - _root.hero.x;
_dy = this.y - _root.hero.y;
// which way to rotate
_rotateTo = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (_rotateTo > barrel.rotation + 90) _rotateTo -= 360;
if (_rotateTo < barrel.rotation - 90) _rotateTo += 360;
// ease rotation
_trueRotation = (_rotateTo - barrel.rotation) / _rotateSpeedMax;
// update rotation
barrel.rotation += _trueRotation;
wall_collision = 0;
OuterLoop: for (var xi=1; xi<=_dx; xi++)
{
var point_x:Number = this.x + xi*Math.cos(_rotateTo);
var point_y:Number = this.y + xi*Math.sin(_rotateTo);
if(_root.wall.hitTestPoint(point_x, point_y, true))
{
trace("HIT");
wall_collision = 100;
break OuterLoop;
}
}
_root.sight.x = this.x;
_root.sight.y = this.y;
_root.sight.rotation += _trueRotation;
_root.sight.alpha = 100 - wall_collision;
But the it does not work.
The rotation do work fine, but the whole "alpha = 0 if player is behind a wall" does not work.
Please help me resolving the issue.
Try the following:
// calculate rotation based on target
_dx = _root.hero.x-this.x;
_dy = _root.hero.y-this.y;
// The full distance is missing from your AS3 code
_dist = Math.sqrt(_dx*_dx+_dy*_dy);
// Return the old good approach for finding angle
angle = Math.atan(_dy/_dx)/(Math.PI/180);
if (_dx<0) {
_angle += 180;
}
if (_dx>=0 && _dy<0) {
_angle += 360;
}
wall_collision = 0;
OuterLoop: for (var xi=1; xi<=_dist; xi++)
{
var point_x:Number = this.x + xi*Math.cos(_angle*Math.PI/180);
var point_y:Number = this.y + xi*Math.sin(_angle*Math.PI/180);
if(_root.wall.hitTestPoint(point_x, point_y, true))
{
trace("HIT");
wall_collision = 100;
break OuterLoop;
}
}
_root.sight.x = this.x;
_root.sight.y = this.y;
_root.sight.rotation = _angle;
// Alpha changed from [0, 100] scale to [0, 1] scale.
_root.sight.alpha = (100 - wall_collision) * 0.01;
Information on alpha in ActionScript 3.0.
As per AS3 reference, alpha is from 0 to 1, not 0 to 100. That would suggest
`_root.sight.alpha = (100 - wall_collision)/100.0ยด
might work.
Can You try the following code. I have no prev exp with flash, but seems like You missed something.
The iterator xi should take values in range of distance, not only by one axis dx.
// calculate rotation based on target
_dx = this.x - _root.hero.x;
_dy = this.y - _root.hero.y;
// the iteration is by distance in original article mentioned so
// keep dist
//=================================
_dist = Math.sqrt(_dx*_dx+_dy*_dy);
// which way to rotate
_rotateTo = getDegrees(getRadians(_dx, _dy));
// keep rotation positive, between 0 and 360 degrees
if (_rotateTo > barrel.rotation + 90) _rotateTo -= 360;
if (_rotateTo < barrel.rotation - 90) _rotateTo += 360;
// ease rotation
_trueRotation = (_rotateTo - barrel.rotation) / _rotateSpeedMax;
// update rotation
barrel.rotation += _trueRotation;
wall_collision = 0;
// xi iterations are to a distance
//== =======
OuterLoop: for (var xi=1; xi<=_dist; xi++)
{
var point_x:Number = this.x + xi*Math.cos(_rotateTo);
var point_y:Number = this.y + xi*Math.sin(_rotateTo);
if(_root.wall.hitTestPoint(point_x, point_y, true))
{
trace("HIT");
wall_collision = 100;
break OuterLoop;
}
}
_root.sight.x = this.x;
_root.sight.y = this.y;
_root.sight.rotation += _trueRotation;
// EDITED AFTER OTHERS SOLVED
// was
//_root.sight.alpha = 100 - wall_collision;
// should be:
// Alpha changed from [0, 100] scale to [0, 1] scale.
_root.sight.alpha = (100 - wall_collision) * 0.01;
// END OF SOLUTION
There is only slight modification to Your original code, marked by preceding //=====
EDIT:
And the winner is transparency range. Still, I do recommend to iterate to a distance, not to _dx.

How to make an object move relative to the mouse pointer using actionscript 3? [duplicate]

This question already has answers here:
How to make my character move relative to the mouse position with actionscript 3?
(2 answers)
Closed 9 years ago.
I am making a game where I want my character to move towards the mouse pointer when pressing forward and for it to strafe left and right with the respecting arrow keys.
Here is my current code:
import flash.events.MouseEvent;
//Event Listners
stage.addChild(crosshair_mc);
crosshair_mc.mouseEnabled = false;
crosshair_mc.addEventListener(Event.ENTER_FRAME, fl_CustomMouseCursor);
function fl_CustomMouseCursor(event:Event)
{
crosshair_mc.x = stage.mouseX;
crosshair_mc.y = stage.mouseY;
}
Mouse.hide();
stage.addEventListener(MouseEvent.MOUSE_MOVE,facecursor);
stage.addEventListener(KeyboardEvent.KEY_DOWN, fl_KeyboardDownHandler);
//Functions
function facecursor(event):void
{
character_mc.rotation = (180 * Math.atan2(mouseY - character_mc.y,mouseX - character_mc.x))/Math.PI + 90;
}
function fl_KeyboardDownHandler(event:KeyboardEvent):void
{
trace("Key Code Pressed: " + event.keyCode);
if (event.keyCode == 38)
{
character_mc.y = character_mc.y - 5;
}
if (event.keyCode == 40)
{
character_mc.y = character_mc.y + 5;
}
if (event.keyCode == 39)
{
character_mc.x = character_mc.x + 5;
}
if (event.keyCode == 37)
{
character_mc.x = character_mc.x - 5;
}
}
You have the rotation part right, now all you need is to incorporate that with cos and sin for the x and y axis respectively. Example:
var speed:Number = 8;
var angle:Number = Math.atan2(mouseY - character_mc.y, mouseX - character_mc.x);
character_mc.rotation = angle * 180 / Math.PI;
character_mc.x += Math.cos( angle ) * speed;
character_mc.y += Math.sin( angle ) * speed;
To avoid confusion, I would stop adding 90 degrees onto the rotation and instead rotate your graphics to face right / east.
The strafing thing uses the same logic, you just want to add a quarter of a circle to the rotation in whichever direction you want to strafe. FYI, a quater of a circle in radians is PI / 2. There are 2 PI radians in one circle:
// Augment angle for strafing.
angle += Math.PI / 2;