How to collide a player with walls? - javascript

I'm trying to create a top down shooter game and I am using Tiled to create my map. I've made my map and exported it as a .json file. I was finally able to make the map appear in my game, but I am having a hard time making the collision work.
I've been going through tutorials for hours and seem to have tried everything under the sun with no luck. I have an object layer in Tiled with the walls marked with the insert rectangle tool. I have every wall tile also marked with insert rectangle in the edit tileset menu. But I still cant get it to work. Walls are Tile Layer 1, ground is Tile Layer 2, object layer is called collision and the tile set name is tiles 48x48. Here's all my relevant code:
var game = new Phaser.Game(1440, 960, Phaser.man, 'phaser-example', { preload: preload, create: create, update: update, render: render });
var sprite
//sounds
var music
//movement
var controls
var cursors
//shooting
var fireRate = 200;
var nextFire = 0;
var Bullets
//map
var map
var walls
var ground
//var collision
function preload() {
game.load.audio('groove', ['sewer groove.mp3']);
game.load.audio('gunshot', 'pistol.mp3');
game.load.image('player', 'player lite.png');
game.load.image('bullet', 'bullet.png');
game.load.tilemap('map', 'sewermap.json', null, Phaser.Tilemap.TILED_JSON);
game.load.image('tiles 48x48','tiles 48x48.png')
}
function create() {
map = game.add.tilemap('map');
map.addTilesetImage('tiles 48x48');
//var tileset = map.addTilesetImage('map','tiles 48x48');
//map.physics.arcade.enable(sprite, Phaser.Physics.ARCADE);
ground = map.createLayer('Tile Layer 2');
walls = map.createLayer('Tile Layer 1');
//collision = map.createLayer('Object Layer 1')
map.setCollisionBetween(0, 65, true, 'Tile Layer 1');
//sprite.body.collideWorldbounds = true;
//layer.resizeWorld();
music = game.add.audio('groove',1,true);
music.play();
game.physics.startSystem(Phaser.Physics.ARCADE);
//game.physics.startSystem(Phaser.Physics.P2JS)
game.stage.backgroundColor = '#313131';
bullets = game.add.group();
bullets.enableBody = true;
bullets.physicsBodyType = Phaser.Physics.ARCADE;
bullets.createMultiple(50, 'bullet');
bullets.setAll('checkWorldBounds', true);
bullets.setAll('outOfBoundsKill', true);
sprite = game.add.sprite(620, 920, 'player');
sprite.anchor.set(0.5, 0.5);
//game.physics.p2.enable(sprite)
game.physics.arcade.enable(sprite, Phaser.Physics.ARCADE);
sprite.body.allowRotation = true;
cursors = game.input.keyboard.createCursorKeys();
}
function update() {
game.physics.arcade.collider(sprite, walls);
//console.log(sprite.rotation);
sprite.rotation = game.physics.arcade.angleToPointer(sprite);
if (game.input.activePointer.isDown)
{
fire();
}
//sprite.body.setZeroVelocity();
if (game.input.keyboard.isDown(Phaser.Keyboard.LEFT))
{
sprite.x -= 4;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.RIGHT))
{
sprite.x += 4;
}
if (game.input.keyboard.isDown(Phaser.Keyboard.UP))
{
sprite.y -= 4;
}
else if (game.input.keyboard.isDown(Phaser.Keyboard.DOWN))
{
sprite.y += 4;
}
}
function fire() {
if (game.time.now > nextFire && bullets.countDead() > 0)
{
nextFire = game.time.now + fireRate;
var bullet = bullets.getFirstDead();
bullet.reset(sprite.x - 8, sprite.y - 8);
game.physics.arcade.moveToPointer(bullet, 300);
}
}
function render() {
game.debug.text('Active Bullets: ' + bullets.countLiving() + ' / ' + bullets.total, 32, 32);
game.debug.spriteInfo(sprite, 32, 450);
//game.debug.spriteBounds(sprite);
//game.debug.spriteBounds(bullets);
//game.debug.body(sprite);
}

Alright, I've had the chance to take a look at this, the issue should solely lie in how you're moving the main player:
sprite.x -= 4;
Collisions only fire if the body has a velocity, the following table by samme should sum it up
You can apply acceleration, for the sake of example, to move the character towards the direction you're pointing at:
if (game.input.keyboard.isDown(Phaser.Keyboard.UP) || game.input.keyboard.isDown(Phaser.Keyboard.W)) {
game.physics.arcade.accelerationFromRotation(sprite.rotation, 200, sprite.body.acceleration);
}
In the image I'm also applying a certain drag and reducing acceleration when nothing is pressed but that's your call:
sprite.body.drag.x = 200;
sprite.body.drag.y = 200;
If you wanted to strafe an idea could be at dealing with multiple presses and applying a different accelerationFromRotation accordingly (with a variety of degrees converted with Phaser.Math.degToRad)
For debug's sake, if needed, you might want to use some of the following:
[...]
walls = map.createLayer("Tile Layer 1");
walls.debug = true;
[...]
function collisionHandler(obj1, obj2) {
console.log("Colliding!", obj1, obj2)
}
game.physics.arcade.collide(sprite, walls, collisionHandler, null, this);
game.debug.body(sprite);

Related

How can I clip a drawn canvas, rotate and draw to another canvas?

I have a canvas for the game world and a canvas for the display screen. I also have a polygon with nodes V(x,y) to serve as a viewport that follows the player and his rotation. I would like to know how to clip from the game world along the polygon, rotate and draw to the smaller canvas.`
//main looping function
var requestAnimFrame = (function(){
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback){
window.setTimeout(callback, 1000 / 60);
};
})();
//joystick setup
var leftManager = null;
var rightManager = null;
//precalculated math
var twoPi = Math.PI*2;
var halfPi = Math.PI/2;
var thirdOfCircleInRadians = twoPi/3;
//game canvas setup
var gameCvs = document.getElementById('gameCanvas');
gameCvs.width = 480;
gameCvs.height = 320;
//gameCvs.width - 960;
//gameCvs.height = 640;
var gameCtx = gameCvs.getContext("2d");
//game loop
var lastTime = 0;
function main() {
var now = Date.now();
var dt = lastTime==0? 0.016 : (now - lastTime) / 1000.0;
update(dt);
render(dt);
lastTime = now;
requestAnimFrame(main);
}
//collision class shorthand
var V = SAT.Vector;
var C = SAT.Circle;
var P = SAT.Polygon;
var R = new SAT.Response();
P.prototype.draw = function (ctx,type) {
ctx.save();
switch(type){
case 'van': ctx.fillStyle = "rgba(66, 66, 66, 0.5)"; break;
case 'col': ctx.fillStyle = "rgba(0, 0, 0, 1.0)"; break;
default: ctx.fillStyle = "rgba(0, 0, 0, 1.0)"; break;
}
ctx.translate(this.pos.x, this.pos.y);
ctx.beginPath();
var points = this.calcPoints;
ctx.moveTo(points[0].x, points[0].y);
var i = points.length;
while (i--) ctx.lineTo(points[i].x, points[i].y);
ctx.closePath();
//stroke to see through camera, when camera is not drawn use fill
ctx.stroke();
//ctx.fill();
ctx.restore();
};
//first for collisions, second for vanity. first is black, second is grey
var O = function(colPolygon,vanPolygon){
this.colPolygon = colPolygon;
this.vanPolygon = vanPolygon;
this.visible = false;
};
var objectVendor = function(type,position){
switch(type){
case 'tree':
return new O(new P(position,[
new V(10.5,19.5),
new V(20.5,9.5),
new V(23,-4),
new V(15,-16.5),
new V(-4,-19.5),
new V(-18,-14.5),
new V(-23,-0.5),
new V(-18.5,14.5),
new V(-8,20)
]),new P(position,[
new V(21,39),
new V(41,19),
new V(46,-8),
new V(30,-33),
new V(-8,-39),
new V(-36,-29),
new V(-46,-1),
new V(-37,29),
new V(-16,40)]));
break;
default: return false; break;
}
return false;
}
//Camera and Player Polygons
var cameraPoly = new P(new V(0,0),[
new V(-240,-160),
new V(240,-160),
new V(240,160),
new V(-240,160)
]);
var player = new P(new V(0,0),[
new V(5,2.5),
new V(7.5,2),
new V(7.5,-2),
new V(5,-2.5),
new V(-5,-2.5),
new V(-7.5,-2),
new V(-7.5,2),
new V(-5,2.5)
]);
//players start position on the screen, and starting angle, init velocity
player.pos = new V(240,160);
player.setAngle(1);
//players velocity for movement
player.vel = new V(0,0);
var world = {
objects: [],
visibleObjects: [],
worldCvs: null,
worldCtx: null,
init: function(){
//set up world canvas
this.worldCvs = document.createElement('canvas');
this.worldCvs.width = 480;
this.worldCvs.height = 480;
this.worldCtx = this.worldCvs.getContext("2d");
//populate world with stuff
this.objects.push(objectVendor('tree',new V(100,100)));
this.objects.push(objectVendor('tree',new V(150,200)));
this.objects.push(objectVendor('tree',new V(75,300)));
},
update: function(dt){
this.visibleObjects = [];
cameraPoly.setAngle(player.angle);
//cameraPoly.pos = player.pos;
cameraPoly.pos = new V(player.pos.x+(110*Math.cos(player.angle+halfPi)),player.pos.y+(110*Math.sin(player.angle+halfPi)));
//update objects to mark if they are in view
var i = this.objects.length;
while(i--){
if(SAT.testPolygonPolygon(this.objects[i].vanPolygon, cameraPoly, R)){
this.visibleObjects.push(this.objects[i]);
}
}
//}
},
draw: function(dt){
this.worldCtx.setTransform(1,0,0,1,0,0);
this.worldCtx.clearRect(0,0,this.worldCvs.width,this.worldCvs.height);
player.draw(this.worldCtx);
var i = this.visibleObjects.length;
while(i--){
this.visibleObjects[i].colPolygon.draw(this.worldCtx,'col');
this.visibleObjects[i].vanPolygon.draw(this.worldCtx,'van');
}
//for testing
cameraPoly.draw(this.worldCtx);
/*
this.worldCtx.save();
this.worldCtx.beginPath();
var i = cameraPoly.calcPoints.length;
this.worldCtx.moveTo(cameraPoly.calcPoints[0].x,cameraPoly.calcPoints[0].y);
while(i--){
this.worldCtx.lineTo(cameraPoly.calcPoints[i].x,cameraPoly.calcPoints[i].y);
}
this.worldCtx.clip();
this.worldCtx.restore();
*/
}
}
function render(dt){
gameCtx.setTransform(1,0,0,1,0,0);
gameCtx.clearRect(0,0,gameCvs.width,gameCvs.height);
world.draw();
//gameCtx.save();
//gameCtx.translate(cameraPoly.pos.x,cameraPoly.pos.y);
//gameCtx.translate(gameCtx.width/2,gameCtx.height/2);
//gameCtx.rotate(-player.angle+halfPi);
//gameCtx.translate(-world.worldCvs.width/2,-world.worldCvs.height/2);
gameCtx.drawImage(world.worldCvs,0,0);
//gameCtx.restore();
}
function update(dt){
world.update();
}
function init(){
//joystick setup
leftManager = nipplejs.create({
zone:document.getElementById("leftJoystick"),
color:"black",
size:75,
threshold:1.0,
position:{
top:"50%",
left:"50%"
},
mode:"static",
restOpacity:0.75,
});
rightManager = nipplejs.create({
zone:document.getElementById("rightJoystick"),
color:"black",
size:75,
threshold:1.0,
position:{
top:"50%",
right:"50%"
},
mode:"static",
restOpacity:0.75,
});
//joystick event setup
leftManager.get().on('move end', function(evt,data){
//console.log(evt);
//console.log(data);
});
rightManager.get().on('move end', function(evt,data){
//console.log(evt);
//console.log(data);
});
world.init();
main();
}
init();
`
I'm using libraries SAT.js and nipplejs.js currently.
Typically this is done in a little different of a way than you seem to be thinking of it. Instead of thinking about the viewport existing somewhere in the world, you should think about the viewport being fixed and the world being transformed behind it; you don't copy part of the world to the viewport, you draw the world offset and rotated by a certain amount, and only draw the parts that are inside the viewport. Matrices are an easy and common way to represent this transformation. You may want to read more about them here.
In practice, this would just amount to changing your existing call to worldCtx.setTransform() at the beginning of each draw frame. That link has information about how to calculate a good transform matrix, and you can find similar resources all over the place since it's pretty standard math.
In particular, you'll want to multiply a rotation and a translation matrix. Translation matrices are only possible if you use a matrix with higher-order than your coordinate space; for 2D, a 3x3 matrix, and for 3D, a 4x4 matrix. You could instead choose to just add some offset to your coordinates as you draw them, but worldCtx.setTransform already takes a matrix with a 3rd column for putting flat offsets into.
Changing the render function to the following will solve the problem, just rushing myself and didn't think things through very well.
`
function render(dt){
gameCtx.setTransform(1,0,0,1,0,0);
gameCtx.clearRect(0,0,gameCvs.width,gameCvs.height);
world.draw();
gameCtx.translate(gameCvs.width/2,gameCvs.height/2);
gameCtx.rotate(-player.angle+Math.PI);
gameCtx.translate(-cameraPoly.pos.x,-cameraPoly.pos.y);
gameCtx.drawImage(world.worldCvs,0,0);
}`
What this is doing is resetting any transformations on the context, clearing it for a new redrawing, creating the world canvas, translating to display center, rotating by the proper amount for reference point, translating to reference center point on negative axis to move game canvas proper amount so that drawing at 0,0 is in the correct location. Thank you for the reference material!

Make identical objects move independently in Javascript Canvas

So I am trying to make a simple space game. You will have a ship that moves left and right, and Asteroids will be generated above the top of the canvas at random X position and size and they will move down towards the ship.
How can I create Asteroid objects in seperate positions? Like having more than one existing in the canvas at once, without creating them as totally seperate objects with seperate variables?
This sets the variables I would like the asteroid to be created on.
var asteroids = {
size: Math.floor((Math.random() * 40) + 15),
startY: 100,
startX: Math.floor((Math.random() * canvas.width-200) + 200),
speed: 1
}
This is what I used to draw the asteroid. (It makes a hexagon shape with random size at a random x coordinate)
function drawasteroid() {
this.x = asteroids.startX;
this.y = 100;
this.size = asteroids.size;
ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
ctx.moveTo(this.x,this.y-this.size*0.5);
ctx.lineTo(this.x+this.size*0.9,this.y);
ctx.lineTo(this.x+this.size*0.9,this.y+this.size*1);
ctx.lineTo(this.x,this.y+this.size*1.5);
ctx.lineTo(this.x-this.size*0.9,this.y+this.size*1);
ctx.lineTo(this.x-this.size*0.9,this.y);
ctx.fill();
}
I included ALL of my code in this snippet. Upon running it, you will see that I currently have a ship that moves and the asteroid is drawn at a random size and random x coordinate. I just need to know about how to go about making the asteroid move down while creating other new asteroids that will also move down.
Thank You for all your help! I am new to javascript.
// JavaScript Document
////// Variables //////
var canvas = {width:300, height:500, fps:30};
var score = 0;
var player = {
x:canvas.width/2,
y:canvas.height-100,
defaultSpeed: 5,
speed: 10
};
var asteroids = {
size: Math.floor((Math.random() * 40) + 15),
startY: 100,
startX: Math.floor((Math.random() * canvas.width-200) + 200),
speed: 1
}
var left = false;
var right = false;
////// Arrow keys //////
function onkeydown(e) {
if(e.keyCode === 37) {
left = true;
}
if(e.keyCode === 39) {
right = true;
}
}
function onkeyup(e) {
if (e.keyCode === 37) {
left = false;
}
if(e.keyCode === 39) {
right = false;
}
}
////// other functions //////
//function to clear canvas
function clearCanvas() {
ctx.clearRect(0,0,canvas.width,canvas.height);
}
// draw the score in the upper left corner
function drawscore(score) {
var score = 0;
ctx.fillStyle = "#FFFFFF";
ctx.fillText(score,50,50);
}
// Draw Player ship.
function ship(x,y) {
var x = player.x;
var y = player.y;
ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
ctx.moveTo(x,y);
ctx.lineTo(x+15,y+50);
ctx.lineTo(x-15,y+50);
ctx.fill();
}
// move player ship.
function moveShip() {
document.onkeydown = onkeydown;
document.onkeyup = onkeyup;
if (left === true && player.x > 50) {
player.x -= player.speed;
}
if (right === true && player.x < canvas.width - 50) {
player.x += player.speed;
}
}
// Draw Asteroid
function drawasteroid() {
this.x = asteroids.startX;
this.y = 100;
this.size = asteroids.size;
ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
ctx.moveTo(this.x,this.y-this.size*0.5);
ctx.lineTo(this.x+this.size*0.9,this.y);
ctx.lineTo(this.x+this.size*0.9,this.y+this.size*1);
ctx.lineTo(this.x,this.y+this.size*1.5);
ctx.lineTo(this.x-this.size*0.9,this.y+this.size*1);
ctx.lineTo(this.x-this.size*0.9,this.y);
ctx.fill();
}
// move Asteroid
function moveAsteroid() {
//don't know how I should go about this.
}
// update
setInterval (update, 1000/canvas.fps);
function update() {
// test collisions and key inputs
moveShip();
// redraw the next frame of the animation
clearCanvas();
drawasteroid();
drawscore();
ship();
}
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>My Game</title>
<script src="game-functions.js"></script>
<!--
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.7/angular.min.js"></script>
-->
</head>
<body>
<canvas id="ctx" width="300" height="500" style="border: thin solid black; background-color: black;"></canvas>
<br>
<script>
////// Canvas setup //////
var ctx = document.getElementById("ctx").getContext("2d");
</script>
</body>
</html>
You want to make the creation of asteroids dynamic...so why not set up a setInterval that gets called at random intervals as below. You don't need a separate declaration for each Asteroids object you create. You can just declare a temporary one in a setInterval function. This will instantiate multiple different objects with the same declaration. Of course you need to store each object somewhere which is precisely what the array is for.
You also have to make sure that asteroids get removed from the array whenever the moveAsteroid function is called if they are off of the canvas. The setInterval function below should be called on window load and exists alongside your main rendering setInterval function.
You are also going to have to change your moveAsteroid function a bit to be able to point to a specific Asteroids object from the array. You can do this by adding the Asteroids object as a parameter of the function or by making the function a property of the Asteroids class and using this. I did the latter in the example below.
var astArray = [];
var manageAsteroidFrequency = 2000;
var Asteroids {
X: //something
Y://something
speed:1
move: function() {
this.X -= speed;
}
}
var mainRenderingFunction = setInterval( function() {
for (var i = astArray.length-1 ; i > -1; i --){
if(astArray[i].Y < 0){
astArray.splice(i, 1)
}else{
astArray[i].move;
}
}
}, 40);
var manageAsteroids = setInterval( function () {
if (astArray.length < 4){
var tmpAst = new Asteroids();
astArray.push(tmpAst);
}
manageAsteroidFrequency = Math.floor(Math.random()*10000);
}, manageAsteroidFrequency);

PaperJS random point

I've got this code. What I want the code to do is to make the ball move and when the ball goes over a grey spot (holes) it goes back to the starting point. I've done that by creating a random place for the grey holes. I simply need to find a way to define the position of these holes even though they are randomized.
var startPoint = new Path.Circle(new Point(40, 40), 40);
startPoint.fillColor = "green";
//finishPoint
var finishPoint = new Path.Circle(new Point(1300, 600), 40);
finishPoint.fillColor = "red";
var ball = new Path.Circle(new Point(40, 40), 20);
ball.fillColor = "black";
//holes
var path = new Path(new Point(20, 20), new Point(20, 23));
path.style = {
strokeColor: 'grey',
strokeWidth: 70,
strokeCap: 'round'
};
var holes = new Symbol(path);
for (var i = 0; i < 10; i++) {
var placement = view.size * Point.random();
var placed = holes.place(placement);
}
var vector = new Point(0, 0);
function onFrame(event) {
ball.position += vector / 100;
}
var moves = new Point(100, 1);
function onKeyDown(event) {
if (event.key === "s") {
vector.y += 10;
}
if (event.key === "d") {
vector.x += 10;
}
if (event.key === "a") {
vector.x -= 10;
}
if (event.key === "w") {
vector.y -= 10;
}
var ballPlace = ball.position;
if (ballPlace.isClose(finishPoint.position, 40) == true) {
var text = new PointText(view.center);
text.content = 'Congratulations';
text.style = {
fontFamily: 'Courier New',
fontWeight: 'bold',
fontSize: 100,
fillColor: 'gold',
justification: 'center'
};
ball.remove();
}
if(ballPlace.isClose(placement.position, 40) == true) {
ball = new Point(40, 40);
}
};
and I want the ball to go back to Point(40, 40) when it goes over a grey hole (var holes) but I can't get it to work. Any idea how to fix this?
You want to test the ball's position against the holes to see if the ball goes back to the starting position. The simplest way I can think of to do this is to create a group of the holes then test the position of the ball against that group. In the following code the ball's position is simulated via the onMouseMove function and the holes are flashed red to indicate when the ball would be returned to the the starting position.
var holes = [];
var hole;
for (var i = 0; i < 10; i++) {
hole = new Path.Circle(view.size * Point.random(), 10);
hole.fillColor = 'grey';
holes.push(hole);
}
holes = new Group(holes);
onMouseMove = function(e) {
if (holes.hitTest(e.point)) {
holes.fillColor = 'red';
} else {
holes.fillColor = 'grey';
}
Here's an implementation: sketch. It should be straightforward to replaced onMouseMove with onFrame, move the ball as you currently do, and then test to see if it falls into a hole.
In order to test if the ball is over a hole you can remove on the onMouseMove function and replace it with:
onFrame = function(e) {
ball.position += vector / 100;
if (holes.hitTest(ball.position)) {
// move the ball wherever you want to move it, position text,
// etc. you might have to loop through the array to find which
// hole was hit.
}
}
#Luke Park is right about using an array.
Trial each new point, by ensuring it is a distance from all other existing points. Example below (not scaled to view.size).
p = Point.random();
while ( isTooClose(p, points) ) {
p = Point.random();
}
It's possible for this to loop infinitely, but if you're populating the area sparsely, there should be no problem.
isTooClose tests each point in array p, where distance = sqrt(dxdx + dydy). If you have many points, you can optimise by avoiding sqrt(), by testing whether the raw dx and dy values are smaller than the test radius.
You can also use a similar function on each frame, to test for collision.

Sprites not loading on canvas

I'm trying to create a game with sprite animation, but I can't seem to load both the animated sprite and the canvas at the same time. When the canvas loads, there is no error in the console but I can't see the sprite on the canvas. When I change the code around a bit (e.g. call "Sprites()" in the render function), the animated sprite shows up but the rest of the canvas is blank.
Here are the areas of code that I believe the errors are in:
app.js
/*
Sonic class creates the player's character, Sonic the Hedgehog
Parameters -
x and y are the player's initial coordinates
sprites passes in a sprite object to add animation
speed is the pace of the game based on level
*/
var Sonic = function(x, y) {
// set initial sprite/image
this.sprite = Sprites;
this.x = x;
this.y = y;
// set initial score to 0
this.score = 0;
// set initial life count to 3
this.lives = 3;
// initialize sonic as alive
this.alive === false;
};
/*
Update sonic's sprite to give the appearance of movement
Parameter - dt, the time delta between loops
*/
Sonic.prototype.update = function(dt) {
// Sprites();
};
/*
Draw the player character on the screen in canvas' context
*/
Sonic.prototype.render = function() {
// ctx.drawImage(Resources.get(this.sprite), 30, 250);
};
// create new instance of sonic
var sonic = new Sonic(30, 250);
sprites.js
var Sprites = (function(global) {
var sonicSprite,
soniceSpriteImg;
// update and render sprite at same speed as browser redraws
function gameLoop() {
window.requestAnimationFrame(gameLoop);
ctx.clearRect(0, 0, 760, 608);
sonicSprite.update();
sonicSprite.render();
}
function sprite(options) {
var obj = {},
// current frame
frameIndex = 0,
// number of updates since current frame was displayed
tickCount = 0,
// number of updates until next frame should be displayed
ticksPerFrame = options.ticksPerFrame || 0;
// number of frames in sprite sheet
numberOfFrames = options.numberOfFrames || 1;
obj.context = options.context;
obj.width = options.width;
obj.height = options.height;
obj.image = options.image;
obj.update = function() {
tickCount += 1;
// reset tickCount once it is surpasses ticks per frame
if (tickCount > ticksPerFrame) {
tickCount = 0;
// increase frameIndex if it is less than number of frames
if (frameIndex < numberOfFrames - 1) {
// go to next frame
frameIndex += 1;
} else {
// reset frameIndex to loop if out of frames
frameIndex = 0;
}
}
};
obj.render = function() {
// clear the canvas
// obj.context.clearRect(0, 0, obj.width, obj.height);
// draw animation
obj.context.drawImage(
obj.image,
frameIndex * obj.width / numberOfFrames,
0,
obj.width / numberOfFrames,
obj.height,
0,
0,
obj.width / numberOfFrames,
obj.height);
};
// obj.render();
return obj;
}
sonicSpriteImg = new Image();
sonicSprite = sprite({
context: ctx,
width: 408.8,
height: 117,
image: sonicSpriteImg,
numberOfFrames: 4,
ticksPerFrame: 3
});
// start game loop as soon as sprite sheet is loaded
sonicSpriteImg.addEventListener("load", gameLoop);
sonicSpriteImg.src = "images/sonicrunningsheet.png";
}());
The full source code for this project is here (please excuse the messy parts, this is still in progress) https://github.com/alexxisroxxanne/sonicvszombies
The live page for it is here: http://alexxisroxxanne.github.io/sonicvszombies/
Any help would be greatly appreciated! Thanks!
In the Sonic constructor you assign this.sprite to the result of the Sprites IIFE.
var Sonic = function(x, y) {
// set initial sprite/image
this.sprite = Sprites;
...
The Sprites IIFE doesn't return anything, so Sprites is always undefined.
I guess you want to return the sonicSpriteImg there.
...
sonicSpriteImg = new Image();
sonicSprite = sprite({
context: ctx,
width: 408.8,
height: 117,
image: sonicSpriteImg,
numberOfFrames: 4,
ticksPerFrame: 3
});
// start game loop as soon as sprite sheet is loaded
sonicSpriteImg.addEventListener("load", gameLoop);
sonicSpriteImg.src = "images/sonicrunningsheet.png";
return sonicSpriteImg;
}());
In the Sonic render function you get the sprite from the resources. The resources only returns undefined there. The reason is because this.sprite isn't an img url like on the other objects (Zombie, Nyancat etc.), but an img object. So you don't have to get it from resources.
Sonic.prototype.render = function() {
// ctx.drawImage(Resources.get(this.sprite), 30, 250);
ctx.drawImage(this.sprite, 30, 250);
};
My issue was fixed when I moved the variables sonicSprite and sonicSpriteImg outside of the Sprites function and into the global context, and then, in app.js, calling sonicSprite.update(); in Sonic.prototype.update() and calling sonicSprite.render(); in Sonic.prototype.render()

Trouble animating spritesheet in EaselJS

I'm trying to animate a spritesheet using EaselJS, but I keep getting an uncaught type error: undefined is not a function on this line - bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
Here is my code so far:
// JavaScript Document
window.onload = function(){
//Creating a new Stage instance, passing in our canvas element's ID.
var stage = new createjs.Stage("canvas"),
imgMonsterARun = new Image();
imgMonsterARun.src = "img/MonsterARun.png";
var spriteSheet = new createjs.SpriteSheet({
// image to use
images: [imgMonsterARun],
// width, height & registration point of each sprite
frames: {width: 64, height: 64, regX: 32, regY: 32},
animations: {
walk: [0, 9, "walk"]
}
});
// create a BitmapAnimation instance to display and play back the sprite sheet:
bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
// start playing the first sequence:
bmpAnimation.gotoAndPlay("walk"); //animate
// set up a shadow. Note that shadows are ridiculously expensive. You could display hundreds
// of animated rats if you disabled the shadow.
bmpAnimation.shadow = new createjs.Shadow("#454", 0, 5, 4);
bmpAnimation.name = "monster1";
bmpAnimation.direction = 90;
bmpAnimation.vX = 4;
bmpAnimation.x = 16;
bmpAnimation.y = 32;
// have each monster start at a specific frame
bmpAnimation.currentFrame = 0;
stage.addChild(bmpAnimation);
createjs.Ticker.setFPS(60);
createjs.Ticker.useRAF = true;
createjs.Ticker.addListener(window);
function tick()
{
// Hit testing the screen width, otherwise our sprite would disappear
if (bmpAnimation.x >= screen_width - 16) {
// We've reached the right side of our screen
// We need to walk left now to go back to our initial position
bmpAnimation.direction = -90;
}
if (bmpAnimation.x < 16) {
// We've reached the left side of our screen
// We need to walk right now
bmpAnimation.direction = 90;
}
// Moving the sprite based on the direction & the speed
if (bmpAnimation.direction == 90) {
bmpAnimation.x += bmpAnimation.vX;
}
else {
bmpAnimation.x -= bmpAnimation.vX;
}
// update the stage:
stage.update();
}
tick();
};
Any help would be appreciated.
In 0.8.0 you can use the normal SpriteSheet to create an animated SpriteSheet. Checkout the Demo on http://createjs.com/Demos/EaselJS/SpriteSheet (make sure to check the code under "live-edit" ;-))
Try using "Sprite" instead of "BitmapAnimation".
That is
bmpAnimation = new createjs.BitmapAnimation(spriteSheet);
becomes
bmpAnimation = new createjs.Sprite(spriteSheet);
Worked for me.

Categories