Jump to content
This forum will be closing down. Please move to the respective dedicated project forums.

Sprite groups: Animations.add and random movement during Update() not working.


Nebulocity
 Share

Recommended Posts

Would someone be kind enough to help me understand why this isn't working?

I am trying to create 10 enemies, randomly placed in my game world.  If I comment out the broken code inside my Update() function, it works, and displays 5 enemies in a row.  However, there are two problems that I do not understand how to fix:

 

  1. In my Create() function, I do not understand why I am unable to use this.sprite.animations.add when creating a new sprite within the group.  If I un-comment this code (line 30), it no longer creates the 5 enemies on the screen, just 1.  I'm not sure why that happens, either.  Considering the fact that the .create method is called and places the enemy before the animations get added, it would logically follow that the enemies would display, but without moving.
     
  2. In my Update() function, I do not understand why I keep getting the error:

     

      1.  
      2. Uncaught TypeError: Cannot read property 'y' of undefined enemies.js:48
        1. (anonymous function)enemies.js:48
        2. d.Group.forEachphaser.min.js:5
        3. Enemy.updateenemies.js:42
        4. d.StateManager.updatephaser.min.js:4
        5. d.Game.updatephaser.min.js:5
        6. d.RequestAnimationFrame.updateRAFphaser.min.js:8
        7. window.requestAnimationFrame._onLoop



    My code is below.  Any help would be appreciated.
     
Enemy = function(game) {	this.game = game;	this.sprite = null;};Enemy.prototype = {	preload: function () {		this.game.load.spritesheet('enemy', 'images/RedMage.png', 64, 64, 8);	},	create: function () 	{		var enemies;	    enemies = game.add.group();		for (var i = 0; i < 5; i++)		{			//  This creates a new Phaser.Sprite instance within the group			//  It will be randomly placed within the world and use the 'baddie' image to display			// enemies.create(360 + Math.random() * 200, 120 + Math.random() * 200, 'enemy');			enemies.create(150 + (100 * i), 50, 'enemy');		    // Player animations		    // this.sprite.animations.add('down', [0, 1], 7, true);		    // this.sprite.animations.add('left', [2, 3], 7, true);		    // this.sprite.animations.add('right', [4, 5], 7, true);		    // this.sprite.animations.add('up', [6, 7], 7, true);		    // Default animation		    // this.sprite.animations.play('down');		}	},	update: function() 	{		game.world.forEach(function(enemy) 		{	 		var direction = Math.floor(Math.random() * (4 - 1 + 1) + 1);						if (direction == 1) 			{	// Move north				enemy.sprite.y -= SPEED;			} 			else if (direction == 2) 			{	// Move east				enemy.sprite.x += SPEED;			}			else if (direction == 3) 			{	// Move south				enemy.sprite.y += SPEED;			}			else if (direction == 4) 			{	// Move west				enemy.sprite.x -= SPEED;			}									});	}}
Link to comment
Share on other sites

There are a few things wrong here, but they seem to stem from one initial mistake.

 

What you have here is a game state object called Enemy, not a object called Enemy.

 

A game state contains the preload, create and update functions.

Your enemy objects can simply be Phaser Sprites.

 

I would change these to something else:

Enemy = function(game)Enemy.prototype = //Maybe change Enemy to MyGameState

After that, you would want your state to contain a reference to the group of enemies, so I'd suggest this change:

//in the constructor:    //this.sprite = null;    this.enemies = null//in the create:    //var enemies;    this.enemies = this.game.add.group();

Also in your create function, you need to save a reference to the sprite that the group is creating so you can act on it.

In your code, this.sprite is never assigned anything.

var enemy = this.enemies.create(150 + (100 * i), 50, 'enemy')

Your animations are then added onto this enemy variable.

         // Player animations         //ALL OF THESE need to be changed to enemy.animations         // this.sprite.animations.add('down', [0, 1], 7, true);         // this.sprite.animations.add('left', [2, 3], 7, true);         // this.sprite.animations.add('right', [4, 5], 7, true);         // this.sprite.animations.add('up', [6, 7], 7, true);          // Default animation         // this.sprite.animations.play('down');

Finally, in your update function, you do not need to reference enemy.sprite, because the enemy object itself is the sprite.

You might also want to change this:

game.world.forEach(function(enemy)//to this:this.enemies.forEach(function(enemy) 

because as you start adding more things to your game world, they will also be looped over here.

Link to comment
Share on other sites

Thank you, XekeDeath, for helping me out ;-)

Making all of your recommended changes, except for changing "Enemy" (the State object) to "MyGameState", the code works and my enemies are all jitterbugging around on the map.  I haven't read about the game State object yet, beyond the initial description of it.  This was actually code that was from the tutorial on the Toastedware site about how to cleanly split code into separate files. 

My apologies for my dimwittedness on the subject, but this is what's used to manage state in the game, right?  For instance, having States like "Menu" and "Combat", etc?  I'm still a bit confused on what that code was actually doing, but since I wasn't able to understand the answers in the documentation, I decided to leave it there until later after I became more experienced.  As it turns out, I have 2 more files (player.js, levels.js) that each have the same State object at the top, although it's "Player" for player.js and "Level" for level.js. 

Assuming is needed, though, and I change this

Enemy = function(game) {    this.game = game;    this.enemies = null;};

into this

MyGameState = function(game) {    this.game = game;    this.enemies = null;};

Then I will also need to rename them here as well.  Honestly, I was a bit confused on this because on the tutorial that I read about cleaning up the code a bit (http://toastedware.com/?p=258), all it says is:"This way the class Player will preload anything related to it and we prevent to create a big mess inside the main source file."

function preload()    {        level = new Level(game);        level.preload();        player = new Player(game);        player.preload();        enemy = new Enemy(game);        enemy.preload();    }

Thanks again for your help.  If at any time my silly questions get out of hand, just let me know :rolleyes:

Link to comment
Share on other sites

I have not read any tutorials on Phaser, I took the trial by fire approach.

 

Having looked at that tutorial, I can see what the author was getting at, and it is possible my explanation may have confused the subjects a little bit.

 

As you say, game states are for having a menu state, combat state and so on.

A game state has some reserved functions that are called at specific times by the game. The most common are preload, create and update.

The tutorial you are following has duplicated these inside the game objects, to be called by the state, to separate the code and clean up the main file.

In that tutorial, and many of the examples, you will see this:

var game = new Phaser.Game(800, 600, Phaser.AUTO, '', { preload: preload, create: create, update: update });//This part is the game state object: { preload: preload, create: create, update: update 
 

I see that you are trying to extend the tutorial and add the enemies in.

If you want to keep the tutorials file structure, and have the Player object and Enemy object responsible for their own preloading, creation and upldating,

then you will need to treat Enemy as a single game object (it is called Enemy, not Enemies after all), and have it create only one sprite instead of a group of sprites.

Link to comment
Share on other sites

Haha, I'm trying my best to do it on my own, but with number of problems that I've run into, it's not exactly happening.  My goal was to try to get as much done over one weekend as possible, and then use it as a study to see what I need to learn, etc.  So the way the Toastedware poster had it is fine then, in this instance.  Honestly, I just want the code to look cleaner, because having hundreds of lines in one file is kind of bloated, and daunting when needing to make changes.  But perhaps I should have stuck to that method first, until I understood more about the framework.  Do you separate your code into different files?  And if so, how do you prefer to do it (if you don't mind me asking)?

 

Link to comment
Share on other sites

There is nothing wrong with the tutorial from Toastedware, it just doesn't fit with how I am used to doing things.

 

I use separate files only for logic, really. To me, preloading assets is logic that should be in one place, while

Toastedware's method is more about "This asset belongs to this object, so preloading it goes in that file".

Which is handy if you want to just drop that file into a different project, it handles all its own loading

 

Most of the time I can get away with just using a Phaser.Sprite for my game objects,

but something that either is not a simple sprite (example: inventory GUI), or is a data storage object (example: a players inventory, which is separate from the inventory GUI)

will get a file to itself. I generally don't need a create or update function on those, as they are there to store data that is manipulated

through the included functions.

 

All assets I list in one place for preloading, I just separate them with comments.

I put most of my assets into a single atlas, so in the end I only have one file to load, and I have most of my art assets.

I say most because tile sprites do not work with images in a texture atlas, so they have to be loaded separately

Link to comment
Share on other sites

 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...