Is it possible to apply Phaser physics to TileSprite's scroll position? - javascript

I'm trying to make a game with top-down perspective where the player sprite is fixed in the center of screen and the background is moving (scrolling) in the direction opposite to the player's direction, so it results in effect of the player's movement.
I started with these examples: Invaders (for background scrolling) and Asteroids Movement (for sprite movement). The former uses TileSprite and its tilePosition property to make vertical scrolling of the background. This works good for linear scrolling in fixed direction (vertical or horizontal). But in my case I need implement scrolling (i.e. movement) in any direction. Furthermore I need such physics features as acceleration and drag, like in the Asteroids example. So I would like to apply Arcade Physics to TileSprite. But it seems that Arcade Physics doesn't work with TileSprite. Or, to be more precise, it doesn't work as I expected.
I've tried to enable Arcade Physics for TileSprite as it used with Sprites. Here is the code:
function preload() {
game.load.baseURL = 'http://examples.phaser.io/assets/';
game.load.crossOrigin = 'anonymous';
game.load.image('ship', 'games/invaders/player.png');
game.load.image('starfield', 'games/invaders/starfield.png');
}
var player;
var cursors;
var starfield;
var playerAngle = 0; // angle of the player's movement, in degrees
var playerSpeed = 5; // the player's speed, px per frame
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
// The scrolling starfield background
starfield = game.add.tileSprite(0, 0, 800, 600, 'starfield');
game.physics.enable(starfield, Phaser.Physics.ARCADE);
starfield.body.velocity.set(200);
// The player sprite
player = game.add.sprite(400, 300, 'ship');
player.anchor.setTo(0.5, 0.5);
// Gameplay controls
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
// Scroll the background
var delta = 0;
if (cursors.left.isDown)
delta = -1;
else if (cursors.right.isDown)
delta = 1;
if (delta)
player.angle = playerAngle = (playerAngle + delta + 360) % 360;
var a = (playerAngle + 90) / 360 * 2 * Math.PI; // angle of the background movement/scrolling, in radians
// move the background by playerSpeed along the a angle
game.physics.arcade.velocityFromRotation(a, 200, starfield.body.velocity);
}
Try at Phaser sandbox
Unfortunately this code doesn't work as I expected.
As far as I understood and as written in the docs, Arcade Physics is only intended for work with Sprite, not TileSprite nor any other game object. If so, this means that I have to manually reproduce all the Physics stuff such as acceleration and drag myself with respect to TileSprite. I've written simple TileSprite movement with constant velocity (no acceleration, drag and other stuff). Here is the code:
function preload() {
game.load.baseURL = 'http://examples.phaser.io/assets/';
game.load.crossOrigin = 'anonymous';
game.load.image('ship', 'games/invaders/player.png');
game.load.image('starfield', 'games/invaders/starfield.png');
}
var player;
var cursors;
var starfield;
var playerAngle = 0; // angle of the player's movement, in degrees
var playerSpeed = 5; // the player's speed, px per frame
function create() {
game.physics.startSystem(Phaser.Physics.ARCADE);
// The scrolling starfield background
starfield = game.add.tileSprite(0, 0, 800, 600, 'starfield');
// The player sprite
player = game.add.sprite(400, 300, 'ship');
player.anchor.setTo(0.5, 0.5);
// Gameplay controls
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
// Scroll the background
var delta = 0;
if (cursors.left.isDown)
delta = -1;
else if (cursors.right.isDown)
delta = 1;
if (delta)
player.angle = playerAngle = (playerAngle + delta + 360) % 360;
var a = (playerAngle + 90) / 360 * 2 * Math.PI; // angle of the background movement/scrolling, in radians
// move the background by playerSpeed along the a angle
starfield.tilePosition.x += playerSpeed * Math.cos(a);
starfield.tilePosition.y += playerSpeed * Math.sin(a);
}
Try at Phaser sandbox
Sure it works, however even such simple thing as linear motion require some math knowledge. Other things will require much more knowledge of math and physics. I would not like to implement such things manually.
So is there any way to use Phaser Physics in conjunction with tilePosition?

My suggestion is to rethink the whole thing. Main idea is to not make the player sprite fixed, but to make it "dynamic" with physics enabled. To have your desired effect, just make the camera follow the player sprite (with no deadzone). That way, the player remains in the center, and manage the tilesprite classically.

Related

EaselJS hitTest on moving bitmaps

I am trying to implement a game where there are moving objects(Bitmaps) and I need to detect collision. I used the following code to make objects move(transform) and check hitTest with mouse hover.
However, the alpha is not changed with the correct mouse position, instead, it detects the left upper corner of the canvas.
rock = new createjs.Bitmap(loader.getResult("rock"));
rock.setTransform(800, 270, 0.5, 0.5);
stage.addChild(rock);
// .....
createjs.Ticker.timingMode = createjs.Ticker.RAF;
createjs.Ticker.addEventListener("tick", tick);
// .....
function tick(event) {
rock.alpha = 0.7;
if (rock.hitTest(stage.mouseX, stage.mouseY)) {//if hit, change alpha
rock.alpha = 1;
}
var deltaS = event.delta / 1000;
rock.x = (rock.x - deltaS * groundSpeed);//to gradually shift the rock
if (rock.x + rock.image.width * rock.scaleX <= 0) {//to re-position the rock
rock.x = w + Math.random() * 1000;
}
stage.update(event);
}
I found the answer when reading the answer to this question.
Rather than directly getting stage.mouseX or stage.mouseY, the correct position can be obtained using globalToLocal as on this.
var p = rock.globalToLocal(stage.mouseX, stage.mouseY);
if (rock.hitTest(p.x, p.y)) {
rock.alpha = 1;
}

Javascript canvas animation. Moving, growing and fading object

Working on a project and cannot seem to get my animation right. I will not be showing the code because it simply doesn't work but it would be cool if someone were to give me a few pointers on how to animate a cloud of smoke moving upwards while slowly fading and increasing in size.
This effect should technically repeat once the y value reaches 0 i.o.w. the cloud reaches the top of the canvas.
What I need to know is how do I animate this, and which methods do I use. This is a kind of a self learning assignment.
Thanks in advance.
Here is a Plunker example of sprites growing in size and fading in transparency.
It is done using Pixi.js which actually renders in webgl with a canvas fallback. It should be possible to take the algorithm and apply it to raw canvas (although it would take some work).
var insertAfter = function(newNode, referenceNode) {
referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
}
var range = function(aCount) {
return new Array(aCount)
}
function main() {
var el_main = document.getElementById("animation_main");
var el_div = document.createElement('div');
el_div.setAttribute('id', 'main_stage');
insertAfter(el_div, el_main);
renderer = PIXI.autoDetectRenderer(300, 300, {
transparent: true,
antialias: true
});
el_div.appendChild(renderer.view);
window.stage = new PIXI.Container();
window.stage.x = 0;
window.stage.y = 0;
renderer.render(window.stage);
var s = [];
for (x of range(400)) {
tCircle = new PIXI.Graphics();
tCircle.beginFill(0x000000, 1);
tCircle.s = (Math.random() * 2) + 1;
tCircle.drawCircle(0, 0, 5 - tCircle.s);
tCircle.x = Math.random() * 300
tCircle.y = (Math.random() * 50) + 20
tCircle.endFill();
s.push(tCircle);
window.stage.addChild(tCircle)
}
window.t = 0
animate = function(t) {
d = t - window.t
window.t = t
//Animation Start
for (n in s){
s[n].x += ((s[n].s / 25) * d)
s[n].alpha = 1 - s[n].x / 300
s[n].scale.x = 1 - s[n].alpha
s[n].scale.y = 1 - s[n].alpha
if (s[n].x > 300) {
s[n].x = 0
s[n].y = (Math.random() * 50) + 20
}
}
renderer.render(window.stage)
//Animation End
requestAnimationFrame(animate);
}
requestAnimationFrame(animate)
}
document.addEventListener("DOMContentLoaded", function(e){
main();
});
At the moment all of the tweening is linear ... it might look more realistic with a logarithmic or exponential tween ... but for simplicity i just left it as linear.
Jakob Jenkov has done a really nice on-line book about canvas here:
http://tutorials.jenkov.com/html5-canvas/index.html
Since yours is a learning experience, I would just point you towards:
The basic workflow of html5 Canvas: Anything drawn on the canvas cannot be altered, so all canvas animation requires repeatedly doing these things in an animation loop: (1) clearing the canvas, (2) calculating a new position for your objects, and (3) redrawing the objects in their new positions.
Animations: requestAnimationFrame as a timing loop: http://blog.teamtreehouse.com/efficient-animations-with-requestanimationframe
Transformations: Canvas gives you the ability to scale, rotate and move the origin of its drawing surface.
Styling: Canvas provides all the essential styling tools for drawing--including globalAlpha which sets opacity.

Simulating two circles bouncing off each other

I have many particles moving around and hit detection to see when they touch. If two particles touch they should bounce off in the opposite direction.
particle.moveSelf = function() {
var radians = this.angle * Math.PI / 180;
var moveX = this.velocity * Math.sin(radians);
var moveY = this.velocity * Math.cos(radians);
for (var i = 0; i < particles.length; i++) {
var distance = this.position.getDistance(new Point(particles[i].position.x, particles[i].position.y));
//if distance < radius 1 + radius 2, bounce this circle away
if (distance < (this.radius + particles[i].radius) && this.id !== particles[i].id) {
this.velocity = -this.velocity;
}
}
this.position.x += moveX;
this.position.y += moveY;
};
When I run this code, the circles get stuck in each other moving back and forth by 1*velocity every frame.
There are lots of questions on how to work out the velocity or angle of the bounce but my problem is just that it gets stuck in an infinite oscillation.
I done this before so here are some insights:
the safest way is add list of collisions per each particle
in first pass you just detect the collisions
and clear/fill the collision lists with indexes of all particles that collide to each other
for (i=0;i<particles;i++) particle[i].collide.clear();
for (i=0;i<particles;i++)
for (j=i+1;j<particles;j++)
if (colide(particle[i],particle[j]))
{
particle[i].collide.add(j);
particle[j].collide.add(i);
}
you can also do this with one list inside for (i=0;i<...) loop instead
but that is not that precise
update position and speed of collided items only
now comes the tricky part
I add new direction vector to each particle and set it to zero
then add in each collision a reflection (unit or speed or force impulse) vector to it
for (i=0;i<particles;i++)
for (j=0;j<particle[i].collides;j++)
{
// here compute reflected direction ,speed whatever of the bounce to vector dir
particle[ i].reflect+=dir;
particle[particle[i].collide[j]].reflect+=dir;
}
when it is done then just update the positions/speed ...
but you need add the stuff needed for update for example
if you used unit vectors then normalize reflect, and set it size to new speed
the same goes for displacement so the particles do not overlap
you can also compute the combined kinetic energy vector of all bounced particles and compute the new speeds form it via mass energy distribution
for (i=0;i<particles;i++)
{
particle[i].speed=compute_speed_from(particle[i].reflect);
}
[Notes]
the best is to store driving reflection force
it is easy to implement physics simulation of bounce properly on it
and also for handling springs and other stuff
if you have permanent bonds then you can have them precomputed once in some permanent collide lists
to improve performance
bullet 2 can be used without collide list but then it is not so precise for multiple bounces at once

Simulate a physical 3d ball throw on a 2d js canvas from mouse click into the scene

I'd like to throw a ball (with an image) into a 2d scene and check it for a collision when it reached some distance. But I can't make it "fly" correctly. It seems like this has been asked like a million times, but with the more I find, the more confused I get..
Now I followed this answer but it seems, like the ball behaves very different than I expect. In fact, its moving to the top left of my canvas and becoming too little way too fast - ofcouse I could adjust this by setting vz to 0.01 or similar, but then I dont't see a ball at all...
This is my object (simplyfied) / Link to full source who is interested. Important parts are update() and render()
var ball = function(x,y) {
this.x = x;
this.y = y;
this.z = 0;
this.r = 0;
this.src = 'img/ball.png';
this.gravity = -0.097;
this.scaleX = 1;
this.scaleY = 1;
this.vx = 0;
this.vy = 3.0;
this.vz = 5.0;
this.isLoaded = false;
// update is called inside window.requestAnimationFrame game loop
this.update = function() {
if(this.isLoaded) {
// ball should fly 'into' the scene
this.x += this.vx;
this.y += this.vy;
this.z += this.vz;
// do more stuff like removing it when hit the ground or check for collision
//this.r += ?
this.vz += this.gravity;
}
};
// render is called inside window.requestAnimationFrame game loop after this.update()
this.render = function() {
if(this.isLoaded) {
var x = this.x / this.z;
var y = this.y / this.z;
this.scaleX = this.scaleX / this.z;
this.scaleY = this.scaleY / this.z;
var width = this.img.width * this.scaleX;
var height = this.img.height * this.scaleY;
canvasContext.drawImage(this.img, x, y, width, height);
}
};
// load image
var self = this;
this.img = new Image();
this.img.onLoad = function() {
self.isLoaded = true;
// update offset to spawn the ball in the middle of the click
self.x = this.width/2;
self.y = this.height/2;
// set radius for collision detection because the ball is round
self.r = this.x;
};
this.img.src = this.src;
}
I'm also wondering, which parametes for velocity should be apropriate when rendering the canvas with ~ 60fps using requestAnimationFrame, to have a "natural" flying animation
I'd appreciate it very much, if anyone could point me to the right direction (also with pseudocode explaining the logic ofcourse).
Thanks
I think the best way is to simulate the situation first within metric system.
speed = 30; // 30 meters per second or 108 km/hour -- quite fast ...
angle = 30 * pi/180; // 30 degree angle, moved to radians.
speed_x = speed * cos(angle);
speed_y = speed * sin(angle); // now you have initial direction vector
x_coord = 0;
y_coord = 0; // assuming quadrant 1 of traditional cartesian coordinate system
time_step = 1.0/60.0; // every frame...
// at most 100 meters and while not below ground
while (y_coord > 0 && x_coord < 100) {
x_coord += speed_x * time_step;
y_coord += speed_y * time_step;
speed_y -= 9.81 * time_step; // in one second the speed has changed 9.81m/s
// Final stage: ball shape, mass and viscosity of air causes a counter force
// that is proportional to the speed of the object. This is a funny part:
// just multiply each speed component separately by a factor (< 1.0)
// (You can calculate the actual factor by noticing that there is a limit for speed
// speed == (speed - 9.81 * time_step)*0.99, called _terminal velocity_
// if you know or guesstimate that, you don't need to remember _rho_,
// projected Area or any other terms for the counter force.
speed_x *= 0.99; speed_y *=0.99;
}
Now you'll have a time / position series, which start at 0,0 (you can calculate this with Excel or OpenOffice Calc)
speed_x speed_y position_x position_y time
25,9807687475 14,9999885096 0 0 0
25,72096106 14,6881236245 0,4286826843 0,2448020604 1 / 60
25,4637514494 14,3793773883 0,8530785418 0,4844583502 2 / 60
25,2091139349 14,0737186144 1,2732304407 0,7190203271
...
5,9296028059 -9,0687933774 33,0844238036 0,0565651137 147 / 60
5,8703067779 -9,1399704437 33,1822622499 -0,0957677271 148 / 60
From that sheet one can first estimate the distance of ball hitting ground and time.
They are 33,08 meters and 2.45 seconds (or 148 frames). By continuing the simulation in excel, one also notices that the terminal velocity will be ~58 km/h, which is not much.
Deciding that terminal velocity of 60 m/s or 216 km/h is suitable, a correct decay factor would be 0,9972824054451614.
Now the only remaining task is to decide how long (in meters) the screen will be and multiply the pos_x, pos_y with correct scaling factor. If screen of 1024 pixels would be 32 meters, then each pixel would correspond to 3.125 centimeters. Depending on the application, one may wish to "improve" the reality and make the ball much larger.
EDIT: Another thing is how to project this on 3D. I suggest you make the path generated by the former algorithm (or excel) as a visible object (consisting of line segments), which you will able to rotate & translate.
The origin of the bad behaviour you're seeing is the projection that you use, centered on (0,0), and more generally too simple to look nice.
You need a more complete projection with center, scale, ...
i use that one for adding a little 3d :
projectOnScreen : function(wx,wy,wz) {
var screenX = ... real X size of your canvas here ... ;
var screenY = ... real Y size of your canvas here ... ;
var scale = ... the scale you use between world / screen coordinates ...;
var ZOffset=3000; // the bigger, the less z has effet
var k =ZOffset; // coeficient to have projected point = point for z=0
var zScale =2.0; // the bigger, the more a change in Z will have effect
var worldCenterX=screenX/(2*scale);
var worldCenterY=screenY/(2*scale);
var sizeAt = ig.system.scale*k/(ZOffset+zScale*wz);
return {
x: screenX/2 + sizeAt * (wx-worldCenterX) ,
y: screenY/2 + sizeAt * (wy-worldCenterY) ,
sizeAt : sizeAt
}
}
Obviously you can optimize depending on your game. For instance if resolution and scale don't change you can compute some parameters once, out of that function.
sizeAt is the zoom factor (canvas.scale) you will have to apply to your images.
Edit : for your update/render code, as pointed out in the post of Aki Suihkonen, you need to use a 'dt', the time in between two updates. so if you change later the frame per second (fps) OR if you have a temporary slowdown in the game, you can change the dt and everything still behaves the same.
Equation becomes x+=vx*dt / ... / vx+=gravity*dt;
you should have the speed, and gravity computed relative to screen height, to have same behaviour whatever the screen size.
i would also use a negative z to start with. to have a bigger ball first.
Also i would separate concerns :
- handle loading of the image separatly. Your game should start after all necessary assets are loaded. Some free and tiny frameworks can do a lot for you. just one example : crafty.js, but there are a lot of good ones.
- adjustment relative to the click position and the image size should be done in the render, and x,y are just the mouse coordinates.
var currWidth = this.width *scaleAt, currHeight= this.height*scaleAt;
canvasContext.drawImage(this.img, x-currWidth/2, y-currHeight/2, currWidth, currHeight);
Or you can have the canvas to do the scale. bonus is that you can easily rotate this way :
ctx.save();
ctx.translate(x,y);
ctx.scale(scaleAt, scaleAt); // or scaleAt * worldToScreenScale if you have
// a scaling factor
// ctx.rotate(someAngle); // if you want...
ctx.drawImage(this.img, x-this.width/2, x-this.height/2);
ctx.restore();

Simulating movement similar to dust particles

I've tried a setInterval loop with css and animate. Both ways of movement consists of tiny movement from oldpos1 -> newpos1 with no random curve movement, easing however occured with jQuery animate but only between randomly generated 1-3 pixels, which is not what I want
.
Does the problem lies in setInterval's clock, where only linear time units flow?
Where should I start, to make below images exist in jQuery?
What I would like to do:
Dodge behaviour:
A, B - particle
AB1 - common dodge area, only certain amount
2 Movement:
Av, Bv - random circular movement
Aacc, Bacc - where the tiny random acceleration occurs (on image marked as more condenced dashed lines)
I would not rely on jQuery's animate for this as your case is rather special ... instead, use the "game loop pattern": Have a game object which keeps a collection of particles, which are moved (and collided ...) and then drawn in regular intervals.
Here's a basic structure:
function Particle(x, y) {
this.x = x;
this.y = y;
this.speed = 0; // in pixels per second
this.direction = 0; // in radians per second
}
Particle.prototype.move = function(d_time) {
this.x += Math.cos(this.direction) * this.speed;
this.y += Math.sin(this.direction) * this.speed;
}
Particle.prototype.draw = function() {
// either set the position of a DOM object belonging to this particle
// or draw to a canvas
}
function Game() {
this.particles = Array();
this.MS_PER_FRAME = 20; // in milliseconds
this.D_TIME = 1000.0 / this.MS_PER_FRAME;
}
Game.prototype.tick = function() {
$.each(this.particles, function(_, particle) {
particle.move(this.D_TIME);
particle.draw();
})
}
Game.prototype.go = function() {
setInterval(this.tick, this.MS_PER_FRAME)
})
Then you can manipulate speed and direction of particles as you like, maybe by introducing additional members d_speed (acceleration) and d_direction or so.

Categories

Resources