PixiJS Parallax Scrolling Background and Static Sprites - javascript

I'm working on a parallax sidescroller game in PixiJS for a school project, and I'm running into a bit of bother with getting things to work properly. Essentially, I have three backgrounds (using a class that extends from PIXI.extras.TilingSprite) that scroll at different speeds and a player (moving in a completely different way) when the user presses either of the arrow keys. I'm also using the Pixi Viewport extension (https://github.com/davidfig/viewport), to get a nice and clean view of the game following the player. It looks great and all (despite some issues I need to fix with shaders and what not), but now I'm trying to add static sprites into the game, and that unfortunately does not work as I thought it would. Here's a GIF of how it looks in-game:
Example GIF
Please excuse the awful quality, I had to jump through a few hoops to record that footage and make it into a GIF format.
Here's the relevant classes that I've made thus far :
class Monster extends PIXI.Sprite
{
constructor(texture, x, y)
{
super(texture);
this.anchor.x = 0.5;
this.x = x;
this.y = y;
}
}
class ParallaxLayer extends PIXI.extras.TilingSprite{
constructor(texture, deltaX = 0.5){
super(PIXI.loader.resources[texture].texture, viewport.worldWidth, viewport.worldHeight);
this.vx = 0;
this.viewportX = 0;
this.deltaX = deltaX;
this.filters = [];
this.setViewportX(-680);
this.x = -680;
}
setViewportX(newViewportX){
if (newViewportX > 0)
{
let distanceTravelled = newViewportX - this.viewportX;
this.viewportX = newViewportX;
this.tilePosition.x -= (distanceTravelled * this.deltaX);
}
}
getViewportX(){
return this.viewportX;
}
}
And here's the code that's running in my game loop to move the parallax backgrounds and the player:
// changes 'x' tile position (parallax scrolling effect
for (var i = 0; i < bgTilingSprites.length; i++)
{
if (bgTilingSprites[i].vx != 0)
{
let scale = bgTilingSprites[i].tileScale.x;
let speed = deltaTime * scale * bgTilingSprites[i].vx;
bgTilingSprites[i].setViewportX(bgTilingSprites[i].viewportX + ((i+1) * speed));
//bgTilingSprites[i].tilePosition.x -= (i + 1) * speed;
// it's "fix" a tilisprite position bug
var width = bgTilingSprites[i].texture.width * scale;
if (bgTilingSprites[i].tilePosition.x >= width)
{
//bgTilingSprites[i].tilePosition.x -= width;
bgTilingSprites[i].setViewportX(width);
}
else if (bgTilingSprites[i].tilePosition.x <= -width)
{
//bgTilingSprites[i].tilePosition.x += width;
bgTilingSprites[i].setViewportX(-width);
}
}
}
// If the player's x velocity is not 0
if (player.vx != 0)
{
// Calculate player speed
let playerSpeed = deltaTime * player.vx;
// Increment player's position by their speed
if (player.x > -675)
{
player.x += playerSpeed;
// Animate the player
if (player.playing != true)
{
player.texture = playerWalkFrames[0];
player.play();
}
}
}
else
{
if (player.playing != false){
player.gotoAndStop(0);
player.texture = playerTexture;
player.footstepToPlay = 0;
player.footstepDelay = 0;
}
}
If there is any other information that would be beneficial to helping me solve this conundrum, I would be happy to provide. I'm still very new to Stack Overflow (and I'm nowhere near an expert on JavaScript), so I would greatly appreciate advice that would help me get the best help possible for this.

How do you want it to look?
Right now I see the background layers are moving past the monster, so it looks like the monster is actually moving to the right, correct?
Well, all the parallax backgrounds are actually moving to the left, so the whole "world" is moving to the left.
Now, the monster is not moving at all (just the viewport extension camera is moving, that’s why the monster moves on the screen)
But since everything is moving to the left, makes sense that a static sprite will seem to be moving to the right.
You move the backgrounds relative to the players movement.
perhaps you should do the same to the monster, make it move like the backgrounds at a speed somewhere between the 1st and 2nd layer.

Related

How to do pixel-perfect collision detection of a player and the walls (JavaScript Game)

I'm making a 2D game in JavaScript. For it, I need to be able to "perfectly" check collision between my players(the game has two players, open the picture please) and the walls! I mean, I have a function that actually works, but when I make them jump against the walls they pass through the walls and keep moving until they reach another area or even leave the canvas!
Also, if they are falling down and I make them collide with a wall, they just stop there wich is also pretty bad!
I really need help with that!! It's a university project and I have to finnish it really soon!
My game looks like this
The collision detection function I have is here:
function blockRectangle (objA, objB) {
var distX = (objA.x + objA.width / 2) - (objB.x + objB.width / 2);
var distY = (objA.y + objA.height / 2) - (objB.y + objB.height / 2);
var sumWidth = (objA.width + objB.width) / 2;
var sumHeight = (objA.height + objB.height) / 2;
if (Math.abs(distX) < sumWidth && Math.abs(distY) < sumHeight) {
var overlapX = sumWidth - Math.abs(distX);
var overlapY = sumHeight - Math.abs(distY);
if (overlapX > overlapY) {
objA.y = distY > 0 ? objA.y + overlapY : objA.y - overlapY;
}
else {
objA.x = distX > 0 ? objA.x + overlapX : objA.x - overlapX;
}
}
}
I did the walls with a maze and I'm using a for cycle to check the collisions with all of the walls I have saved in an array!
As you can see here:
for (var i in walls) {
var wall = walls[i];
if ((player.x < (wall.x + wall.width)) && ((player.x + player.width) > wall.x) && (player.y < (wall.y + wall.height)) && ((player.height + player.y) > wall.y)) {
player.falling = false;
}
blockRectangle(player, wall);
}
Please help me!!! Thank you all!
In your case I doubt a pixel perfect collision is required.
You can maintain a boolean matrix to store the position of solid objects. Solid objects like walls or players. Then in every frame you can check if your player is trying to move to a position where there is a solid object, if it is then stop it. You don't have to create grid of width x height in pixels, but rather choose a largest block (single element in the grid) in which each solid object reasonably occupies most of the block.
For example you can choose block size to be player_width / 2 x player_height /2.
See following image with grid
Another simple way could be to just check the background pixel color. Since your game is simple, background and object colors are different. So you just have to check if the player is trying to move somewhere where pixel color is not of background, thus there is a solid object and player should stop. You don't have to test for a lot of pixels, just 1 pixel in the direction the player is trying to move. (1 for horizontal and 1 for vertical). This however can not be used if you don't have a clear background color. Background color here is kind of the boolean grid for us in the previous suggestion.

Determine hit on vertical or horizontal wall on a rectangle

Currently i am working on bouncing a ball of a wall, in classic 2D-geometry.
The wall can be hit on both vertical and horizontal sides, and the result of the reflection depends on which side the ball hits.
I have tried some different solutions, but they just make me more confused.
How can i determine whether the ball is hitting a vertical or horizontal side of the wall?
PseudoCode for the overview:
iterate through each wall
if (collision between ball and wall)
determine if vertical/horizontal hit
calculate new velocity for ball
I use this code for collision detection and it works like a charm:
source: Circle-Rectangle collision detection (intersection)
var isCollision = function (_projectile) {
if(direction != undefined){
var circleDistance = {};
circleDistance.x = Math.abs(_projectile.getCenter().x - centerX);
circleDistance.y = Math.abs(_projectile.getCenter().y - centerY);
if (circleDistance.x > (width/2 + _projectile.getRadius())) { return false; }
if (circleDistance.y > (height/2 + _projectile.getRadius())) { return false; }
if (circleDistance.x <= (width/2)) { return true; }
if (circleDistance.y <= (height/2)) { return true; }
var cornerDistance_sq = square(circleDistance.x - width/2) + square(circleDistance.y - height/2);
return (cornerDistance_sq <= (square(_projectile.getRadius())));
}
return false;
};
var square = function(_value){
return _value * _value;
};
Thank you!
update after question update
Asuming the ball has a direction/velocity vector dx,dy and has a radius of r (ball.x, ball.y are the ball positions of the ball center) do sth like this (have used similar in a billiard game, it is basic geometry and physics):
if (ball.x+ball.dx+r > wallV.x) ball.dx = -ball.dx // ball bounces off the
vertical wall
if ( ball.y+ball.dy+r > wallH.y ) ball.dy = -ball.dy // ball bounces off horizontal wall
do similar for opposite walls if needed, since velocity vector changes, the new ball position after bouncing (or anyway) will be ball.x += ball.dx; ball.y += ball.dy;
Bonus if you add some friction factor (meaning the magnitudes of dx dy eventually fade away to zero, the ball eventually stops after following a path)
To solve properly a collision, you can't just test on X => if collision solve and return THEN test on y => if collision solve on y.
You have to check which axe (x OR y) collides first, and there's also the case when the ball hits two walls at the same time.
So you can't just reason with space : you have to deal with time, and compute an ETA -Estimated Time Arrival- for all walls, based on the ball speed (assuming walls are still).
pseudo code :
minETA = a too big number;
colliderList = [];
for (each wall in walls) {
thisWallETA = computeETA(ball, wall);
if (thisWallETA > minETA) continue;
if (thisWallETA < minETA) {
minETA = thisWallETA;
colliderList.length = 0;
colliderList.push(wall);
continue;
}
if (thisWallETA == minETA) {
colliderList.push(wall);
continue;
}
}
Then when the colliderList has only one item => solve on corresponding axe. If it has two items => solve on both axes.
Then increase the current time by minETA, and try again until the currentTime + minETA you found is > to thisCycleTime + thisCycleDt.
If you're interested, i might clarify some things up.
Good luck !

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.

2D collision detection on html5 canvas

I'm trying to replicate a game called haxball, which is a really simple and basic 2d football game. However I am having trouble on the collision detection and I didn't want to use a engine like Box2d because it's a bit of overkill for what I want and I'm making the game just to practice, since I'm a beginner.
I can check if the collision happens, but I can't resolve it properly. I loop through all objects and check if they are colliding with the ball and then, if they are, I put the ball at the "border" of the object so that it stops being "inside" the other.
The problem comes here, because if the ball collides with a circle and a edge at the same time it will stay inside the edge or inside the circle.
This is the code of collision resolving for the circle and detection and resolving of the edge:
this.resolveCollisionCircle = function(circle) {
var nv = circle.pos.sub(this.pos);
nv = nv.setMag(circle.radius + this.radius).add(circle.pos);
this.pos = nv;
// I'll try to add later the bounce effect
}
this.edgeCollision = function() {
if(this.pos.x-this.radius < 0) {
this.pos.x = this.radius;
this.velocity = this.velocity.mult(new Vector(-1, 1));
}
else if(this.pos.x+this.radius > Width) {
this.velocity = this.velocity.mult(new Vector(-1, 1));
}
if(this.pos.y-this.radius < 0) {
this.pos.y = this.radius;
this.velocity = this.velocity.mult(new Vector(1, -1));
}
else if(this.pos.y+this.radius > Height) {
console.log('baixo')
this.velocity = this.velocity.mult(new Vector(1, -1));
}
}
The ball moves accordingly to a velocity vector, in this case it starts as (-4,0)
Demo of the bug: http://antoniomc.0fees.us/
Also! If you could point me to a good canvas tutorial that could teach me this things, I would appreciate it! I only seem to find for another languages, which helped me anyway, but it would be nice to see a canvas collision detection and resolution tutorial once in a while...
In .resolveCollisionCircle(), store the old position, change the position, and revert back to the old position and stop the ball completely if the new position is outside of the canvas.
this.resolveCollisionCircle = function(circle) {
//previous position
var prevPos = this.pos;
//set new position
var nv = circle.pos.sub(this.pos);
nv = nv.setMag(circle.radius + this.radius).add(circle.pos);
this.pos = nv;
//change back if out of canvas
if ((this.pos.x-this.radius < 0) || (this.pos.x+this.radius > Width) || (this.pos.y-this.radius < 0) || (this.pos.y+this.radius > Height)) {
this.pos = prevPos;
this.velocity = this.acceleration = new Vector(0, 0);
}
}

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