How to separate created group sprites into individual sprites - javascript

I'm trying to create a small game that has a soldier moving around a small area and fires bullets. I'm a new programmer who just started javascript not but a few months ago, and so I apologize if my question is poorly worded or my code is clunky.
I've tried using [group].get(i) to isolate each individual sprite that comes out of the gun, but it simply breaks and crashes the program.
Here is all of the code for my (small) program:
var soldier = createSprite(200, 200);
soldier.setAnimation("soldier_still");
var bullet = createGroup();
function draw() {
background(rgb(100, 85, 45));
move();
attack();
drawSprites();
}
function attack() {
if (mouseWentDown("leftButton")) {
for (var i = 0; i < 3; i++) {
bullet.add(createSprite(soldier.x, soldier.y));
bullet.setAnimationEach("bullet");
bullet.pointToEach(World.mouseX, World.mouseY);
bullet.setLifetimeEach(50);
bullet.setSpeedAndDirectionEach(20, World.mouseX, World.mouseY);
}
}
}
function move() {
createEdgeSprites();
World.allSprites.bounceOff(topEdge);
World.allSprites.bounceOff(bottomEdge);
World.allSprites.bounceOff(leftEdge);
World.allSprites.bounceOff(rightEdge);
soldier.pointTo (World.mouseX,World.mouseY);
if (keyDown() == false) {
soldier.setAnimation("soldier_still");
soldier.velocityX = 0;
soldier.velocityY = 0;
}
if (keyDown("up")) {
soldier.setAnimation("soldier_move");
soldier.velocityY = -5;
}
if (keyDown("down")) {
soldier.setAnimation("soldier_move");
soldier.velocityY = 5;
}
if (keyDown("left")) {
soldier.setAnimation("soldier_move");
soldier.velocityX = -5;
}
if (keyDown("right")) {
soldier.setAnimation("soldier_move");
soldier.velocityX = 5;
}
}
The program either crashes, or all bullet sprites face the mouse's position. Is there anyway I can improve my code, or a solution to making each group (bullet) sprite its own individual sprite?

Related

Webaudio panner crackling sound when position is changed

I'm working on a 3D web app where I want to use positional 3D audio.
I started noticing that a crackling noise appears on the output as the sound source changes its position.
Initially I thought it could be a programming issue or a library issue (I was using howler.js).
I made a very basic example based on plain JS and Webaudio API which is shown here
let params={
"xPosition":0,
"zPosition":-1
};
let gui=new dat.GUI( { autoPlace: true, width: 500 });
const AudioContext = window.AudioContext || window.webkitAudioContext;
let audioCtx;
let panner;
let listener;
let source;
let osc;
function initWebAudio(){
audioCtx = new AudioContext();
panner = audioCtx.createPanner();
listener = audioCtx.listener;
osc = audioCtx.createOscillator();
osc.frequency.value = 70;
osc.connect(panner);
osc.start(0);
panner.connect(audioCtx.destination);
panner.panningModel = 'HRTF';
panner.distanceModel = 'linear';
panner.maxDistance = 60;
panner.refDistance = 1;
panner.rolloffFactor = 1;
panner.coneInnerAngle = 360;
panner.coneOuterAngle = 360;
panner.coneOuterGain = 0;
panner.positionX.setValueAtTime(0,audioCtx.currentTime);
panner.positionY.setValueAtTime(1,audioCtx.currentTime);
panner.positionZ.setValueAtTime(1,audioCtx.currentTime);
if(panner.orientationX) {
panner.orientationX.value = 1;
panner.orientationY.value = 0;
panner.orientationZ.value = 0;
} else {
panner.setOrientation(1,0,0);
}
if(listener.forwardX) {
listener.forwardX.value = 0;
listener.forwardY.value = 0;
listener.forwardZ.value = -1;
listener.upX.value = 0;
listener.upY.value = 1;
listener.upZ.value = 0;
} else {
listener.setOrientation(0,0,-1,0,1,0);
}
if(listener.positionX) {
listener.positionX.value = 0;
listener.positionY.value = 0;
listener.positionZ.value = 0;
} else {
listener.setPosition(0,0,0);
}
}
function positionPanner() {
if(panner.positionX) {
panner.positionX.setValueAtTime(params.xPosition, audioCtx.currentTime);
} else {
panner.setPosition(params.xPosition,0,params.zPosition);
}
}
function tick(){
positionPanner();
}
function onClickStart(){
initWebAudio();
gui.add(osc.frequency,"value",50,220).name("frequency");
setInterval(tick,50);
}
function buildMenu(){
gui.add(params,"xPosition",-3,3).step(0.001);
gui.add(window,"onClickStart").name("start");
}
buildMenu();
https://jsfiddle.net/fedeM75/t9vpm8so/23/
Press start, then as you change the xPosition slider a crackling sound appears.
It is specially noticeable using headphones.
I searched on google and some people say that it has to do with the rate of change of the position. But I tried with different value ranges and it still happens with small changes.
By the way if the condition to use the panner is to have a very slow rate of change in the position it does not seem to be useful in real world cases.
I use a timer to update the position but the same happens using requestAnimationFrame()
Does anyone has a clue on why this happens and how to solve it?
I had this crackling audio with a simple GainNode. It could be a bug indeed since a simple implementation in the ScriptProcessor does work. Or it's the fact that I/we just don't get how the timing with audioCtx.currentTime should be handled?
For me the solution was to ditch the gain node and use a ScriptProcessor (deprecated: you could/should use an AudioWorkletNode) with my own gain applied to the audio signal directly:
let myGain = 1.0; // change this as you like without crackling noises
let whiteNoise = audioCtx.createScriptProcessor(4096, 0, 1);
whiteNoise.onaudioprocess = function(e) {
let output = e.outputBuffer.getChannelData(0);
for (let i = 0; i < output.length; i++) {
output[i] = (Math.random() * 2 - 1) * myGain;
}
}
This won't fix your problem directly since you have this problem with the 3D panner, but perhaps you can find sourcecode/examples for such a panner implementation and port it to an AudioWorkletNode? Hope this helps.

Is it possible to create hundreds of p5 canvases?

I'm working on a neuroevolution snake game. I wanted to display all the individuals of the current generation on the screen. However it's really slowing things down. Here's the code which creates the canvas.
play_game() {
let game = this;
new p5(p => {
p.setup = function() {
p.createCanvas(game.width, game.width);
p.strokeWeight(1);
tf.setBackend('cpu');
p.frameRate(game.frameRate);
}
p.draw = function() {
p.background("#ddd");
game.snake.display(game.unit, p);
game.snack.display(game.unit, p);
let inputs = game.vision();
game.snake.think(inputs);
let dead = game.check_conditions();
if(dead) {
game.snake.brain.dispose();
game.snake = new Snake([5,5], "#000");
}
};
});
}
Here is the code calling it:
game_array = [];
for(let i = 0; i < 500; i++) {
game_array.push(new Game(100, 20, 10));
}
for(let i = 0; i < 500; i++) {
game_array[i].play_game();
}
Is there a better way to do this or is it even possible?
It is possible to create hundreds of p5 canvases. The key is to run p5 in instance mode. Here is the code to create 400 canvases.
let sketch = function (p) {
p.setup = function () {
p.createCanvas(50, 50);
p.background(p.random(255), p.random(255), p.random(255));
p.stroke(p.random(255), p.random(255), p.random(255));
};
p.draw = function () {
p.point(p.random(p.width), p.random(p.height));
};
};
for (let i = 0; i < 400; i++) {
new p5(sketch);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.0.0/p5.js"></script>
An idea for speeding up is to combine contents on 400 canvases and draw on 1 canvas.
400 separated canvases
rendering speed on my computer: 19 fps
demo: https://glitch.com/~400-canvases
combine contents on 400 canvases and draw on 1 canvas
rendering speed: 37 fps
demo: https://glitch.com/~400-canvases-faster

How to create objects on runtime and move them?

I'm trying to create objects on my game update and move them. This is my banana object:
function Banana() {
this.height = 1.96;
this.width = 3.955;
this.pos_x = CENTER - this.width/2;
this.pos_y = -475;
this.banana_image = banana_image;
};
And this is the Move method:
Banana.prototype.move = function(){
if (this.pos_y > 500) {
//this.banana_image.parentElement.removeChild(this.banana_image);
}
this.height += ZOOM_RATE;
this.width += ZOOM_RATE;
this.pos_y += 3;
this.pos_x -= SIDES_RATE;
};
This is the Game Update part:
Game.update = function() {
this.player.move();
//creating bananas
if (objs.lenght <= 0) {
this.banana = new Banana();
} else {
for (i = 0; i < 10; i++) {
objs.push(new Banana());
}
}
//moving bananas
for (i = 0; i < objs.lenght; i++) {
this.objs[0].move();
}
};
Game Draw:
function Game.draw = function() {
this.context.drawImage(road, 0,0, rw, rh);
this.context.drawImage(
this.player.player_image,
this.player.pos_x, this.player.pos_y,
this.player.width, this.player.height);
this.context.drawImage(
this.banana.banana_image,
this.banana.pos_x, this.banana.pos_y,
this.banana.width, this.banana.height);
};
I tried to ask this to multiple people, but I can't find an answer for it.
Let's say you want to move the objects 10 times and then stop.
First you need to add a line to the start of Game.draw, so that it clears the canvas making you always start drawing from scratch:
this.context.clearRect(0,0,500,500); // clear canvas, adjust box size if needed
Then make a function to call both update and draw, and queue that function to be called again:
var count = 10;
function updateAndDraw() {
Game.update();
Game.draw();
count--;
if (count) requestAnimationFrame(updateAndDraw);
}
// start moving:
requestAnimationFrame(updateAndDraw);
The movement may go too fast to your liking, so then adjust the move method to make smaller changes, or use setTimeout instead of requestAnimationFrame (but that will make the animation less fluent).
Note that you have a few errors in your code, which you will need to fix first:
lenght should be length
function Game.draw = function() {: remove function before Game.draw.
... check the error messages you get in console.

Smooth element translate on device orientation change

I'm trying to achieve this sort of effect, but by using JS and on device orientation change (with gyroscope). So I wrote this code:
var sky, flag, objects, maxPositiveTranslateFar = 30, maxPositiveTranslateNear = 20, maxNegativeTranslateFar=-30, maxNegativeTranslateNear=-20;
document.addEventListener("DOMContentLoaded",onload);
function onload(){
sky = document.getElementById('sky');
flag = document.getElementById('flag');
objects = [{objectName : sky}, {objectName : flag}];
if (window.DeviceOrientationEvent) {
window.addEventListener('deviceorientation', function(eventData){
var tiltLR = eventData.gamma;
var tiltD = eventData.beta;
deviceOrientationHandler(tiltLR, tiltD);
}, false);
} else {
// Do something
}
}
function deviceOrientationHandler(tiltLR, tiltD) {
for(var i = 0; i <= objects.length - 1; i++){
if(objects[i].objectName == flag){
if(tiltLR > maxPositiveTranslateNear){
tiltLR = maxPositiveTranslateNear;
} else if(tiltLR < maxNegativeTranslateNear) {
tiltLR = maxNegativeTranslateNear;
}
flag.style.webkitTransform = "translateX("+tiltLR+"px)";
} else {
if(tiltLR*1.7 > maxPositiveTranslateFar){
tiltLR = maxPositiveTranslateFar;
} else if(tiltLR*1.7 < maxNegativeTranslateFar) {
tiltLR = maxNegativeTranslateFar;
}
if(tiltD > maxPositiveTranslateNear){
tiltD = maxPositiveTranslateNear;
} else if(tiltD < maxNegativeTranslateNear) {
tiltD = maxNegativeTranslateNear;
}
sky.style.webkitTransform = "translateX("+(tiltLR*1.7)+"px) translateY("+tiltD+"px)";
}
}
}
It works, the sky and flag elements are moving correspondingly, however the movement isn't smooth as in the example above. I guess it's because the values are constantly changing when the device is rotated, thus the deviceorientationevent keeps firing. I tried to add transition to these elements' CSS:
-webkit-transition: -webkit-transform 1s ease-out;
But it just made things worse - the transform became really jumpy.
Does anybody have a solution how to make this transformation smooth? I have to do it with plain JS/CSS only, no external JS libraries (or by using a library, but it must very light-weight, 40-50 kb. is the max).

Canvas game only starts drawing when the window is inactive

I noticed something weird in my canvas code: Im making a game with little flying ghosts. The class for the ghost is below. When I just draw 1 or 2 of em by manually adding the code and having em fly to the right by updating the x every frame for example everything runs smoothly and fine.
Now I ran another test and added a ghost every 100 frames to an array, update its x by 100 and then draw that ghost to the frame. (code is below the first block, the draw function).
Now the problem is that they are actually added and drawn, but I dont see em on the board until I make the window inactive by clicking on the taskbar for example.
Any1 got a clue what is going wrong here?
/*
* Class for little ghosts
*/
function Ghost (name) {
this.name = name;
this.ghost = new Image();
this.ghost.src = "img/ghost.png";
this.ghostWidth = 150;
this.ghostHeight = 100;
this.ghostSpriteOffsetX = 0;
this.ghostSpriteOffsetY = 0;
this.ghostX = 0;
this.ghostY = 0;
}
Ghost.prototype.drawGhost = function() {
context2D.drawImage(this.ghost, this.ghostSpriteOffsetX, this.ghostSpriteOffsetY, this.ghostWidth, this.ghostHeight, this.ghostX, this.ghostY, this.ghostWidth, this.ghostHeight);
};
Ghost.prototype.goToX = function(x) {
this.ghostX = x;
};
Ghost.prototype.goToY = function(y) {
this.ghostY = y;
};
Ghost.prototype.turnPink = function() {
this.ghostSpriteOffsetX = 0;
};
Ghost.prototype.turnBlue = function() {
this.ghostSpriteOffsetX = 150;
};
Ghost.prototype.turnPurple = function() {
this.ghostSpriteOffsetX = 300;
};
-
function draw()
{
// clear board
context2D.clearRect(0, 0, canvas.width, canvas.height);
if(frame%100==0){
ghosts[ghostId] = new Ghost("g-"+frame);
ghosts[ghostId].goToX(frame-100);
ghostId++;
}
// Draw ghost
for (i=0; i<ghosts.length; i++)
{
ghosts[i].drawGhost();
}
frame++;
}

Categories

Resources