Jump to content

  • Log In with Google      Sign In   
  • Create Account

FREE SOFTWARE GIVEAWAY

We have 4 x Pro Licences (valued at $59 each) for 2d modular animation software Spriter to give away in this Thursday's GDNet Direct email newsletter.


Read more in this forum topic or make sure you're signed up (from the right-hand sidebar on the homepage) and read Thursday's newsletter to get in the running!


Paragon123

Member Since 02 Oct 2013
Offline Last Active Oct 18 2014 08:11 PM

Topics I've Started

Data Struct for 2D map with barracades

04 September 2014 - 09:43 AM

So gennerally for 2d tile maps a tile is either passable or impassible...  so an actor can move to any passable adjacent tile.

 

I am looking for a good way to decouple the passablity of a cell from the traversal to/from the cell.

 

Which do you suppose is the best way?

 

1) Each tile contains a value indicating if the passage to the right and bottom tiles are valid. 

    Pro: Requires very little modification to a standard 2d array implementation

    Con: Checking for passage works on different cells depending on direction of travel... i.e to travel right or down you check your current tile, but travel up or left requires checking the destination tile.

 

2) Each tile contains a value indicating the passage to adjacent tiles

    Pro: Can still be implemented using a standard 2d array implementation

    Con: Disabling travel between two tiles requires setting a value on both the tiles (semi-redundant data... semi b/c you could  implement 1 way passages, etc).

 

 3) Use a separate array for tile data and traversal data... in the tile array the data describes the tile, in the separate array the data represents the "wall" between two cells.

    Pro: No data redundancy, consistent mapping

    Con: Requires entirely new map structure with more complex mapping, look up functions...

 

4) Awesome method that I haven't thought of... pro: It may be awesome, con: I didn't think of it yet... 


GameObject State management

07 February 2014 - 10:19 AM

I am trying to use the 2D portion of Unity3D for the first time so I am creating a breakout clone. 

My issue is that the state management is getting decentralized... and I am not 100% certain if it is because a) It has to be, or more likely b) I'm doing something "wrong".

 

I have 4 major game objects, The ball, the paddle, walls, and blocks. The blocks state is simple, it starts at State N and each time the ball collides with it it moves to state N-1, at state N=0 it gets destroyed.

 

The walls and the paddle are also simple as they have only a single state each.

 

The ball is where it is getting tricky..

The ball has three states: Setup, LockedToPaddle and Moving.

It has a public function setState(state) :It's only public so the animation event can see it. SetState only changes to the new state if the new state is a valid state to transition to (For example, attempting to setState(Moving) from setup will not do anything, nor will setState(x) from state x.

When a state is successfully changed, it will also update the state variable in the animator.

 

The animator has an integer parameter State: 1=Setup, 2=lockedToPaddle,3=Moving

Each state has it's own animation, at the start of each animation there is an animation event which calls setState(State). 

The setup state has a transition with a 3 loop exit condition, which moves to LockedToPaddleState

LockedPaddleState has a conditional transition on State=3 to transition to Moving.

Moving has a conditional transition on State=1 to Setup.

 

Further, I have an inputmanager game object with a delegate OnBallFire which triggers when the user presses the space bar. The ball gameobject has a method ball_OnBallFire() which calls setState(Moving)

 

Then In the collision2d method for the ball, if the ball collides with the "deadzone" (the area below the paddle). It calls setState(Setup).

 

As you can see... stateTransitions are made from all over the place... is this normal? Is there a way to centralize the state transition logic? Is it an issue that the animator can update the state, but the state can also update the animator? 

 

 

 


Dealing with multiple scales of player wealth

17 December 2013 - 01:19 PM

 I was thinking about a game that combines RPG with a merchant trading system... the problem I am having though is how to deal with the two completely seperate levels of wealth. On the one hand, they should have a manageable amount of wealth to purchase things such as equipment/upgrades/consumables etc... on the other hand they need large amounts of wealth to do things such as purchase new transports/hire shopkeepers/transporters/farmers/buy property/buy expensive goods/etc.

 It wouldn't make much sense to have two separate currencies, but it if they had the money to purchase expensive items all personal needs would be trivial, but if they only had enough to make personal belongings non-infinite they wouldn't have enough to purchase the expensive items.


ECS - Renderable, Animation, Physics

21 October 2013 - 12:53 PM

I am running into some road blocks attempting to effectively implement ECS methodology. I have a heavy background in OOP, and I think that is really tainting my perspective.

 

According to a lot of the information I have gathered regarding ECS, one of the primary benefits is that each system is supposed to work independently, and also, using components should help avoid memory cache issues since components should be stored in contiguous Memory.

 

 The problem that I am experiencing is the following.

 Given a particular element for which Rendering, Animation and Physics need all be applied there is a particular sub set of information which must be available and synchronized to all systems, while an overlapping subset of information may not require availability and synchronization.

 

 For the rendering system to work it requires a component containing a Sprite, a position and a rotation.

 For the physics system to work it requires a component containing a position, a force and a rotation.

 

The animation system is slightly more complex, as there are three types of animation

  1) Tile: No animation, requires only a sprite

  2) Simple Animation: Loops through a single animation, requires a set of sprites

  3) State Animation: Infers sprite from a state and a TimeInState, requires a State and a set of sets of sprites.

 

So it seems that there is the following portions of data required for the ECS as a whole (not partitioned into components):

   Sprite - Current sprite representative of entities animation

               Rendering system Read

               Animation system Write

 

   Sprites - Complete set of sprites available to entity

                  Animation system Read

 

   State   - Current state of entity

                <Some System> Write

                Animation System Read

 

   TimeInState - How long entity has been in a particular state, to enable mapping to a specific frame of a specific animation

                  <SomeSystem> Write

                  AnimationSystem Read

 

   Position - Both physics position and drawing position (while in an idealized situation they would be equal in actuality they are only tightly coupled through some mapping function i.e drawing Y often equals -physics Y, and physics often work of Center of gravity while rendering works on either top left corner, or center of sprite)

                  Physics system Read/Write

                  Rendering System Read

 

   Rotation - Both physics position and drawing position (similar issues to position, but possible to avoid)

                 Physics system Read/Write

                 Rendering System Read

 

   Force - Physics

                <some system> Write

               Physics system Read

  -----------------------------------------------

As you can see, it becomes a rats nest of inter connectivity destroying the System Independence principle. Also, since each system uses multiple components it also destroys the Contiguous memory access principal as well. Some sources concede that complete system independence is not always possible but the breakage is acceptable as long as the more performance enhancing principal of contiguous memory access is preserved, this is seems would require Data duplication, something that I find great difficulty in accepting as good practice (this may be due to OOP and Database bias). 

 

The animation Components present a new challenge entirely... namely, how to efficiently store jagged arrays in contiguous memory. 

In my particular case it turns out to be a jagged array of jagged arrays. I plan to use a image packing software to create image atlases, the image packing software produces a string->box mapping file so a particular sprite can be located by providing the sprites String formatted Name/Id. Also, since various states may have more or less frames than other states, and since some entities may have more or less states than others you can see that the first jagged array is entity to states, followed by states to frames and finally frames to strings.

 

I suppose the gist of this post is.... ARRRRGGGG, WTF?!?! HELP PLZ!!


Renderer too slow

15 October 2013 - 11:46 PM

I have a renderer which, with no game logic, no shaders, just blitting only lets me draw 1200 sprites per frame and retain 60 FPS, is this too slow?

How can I improve it?

The main idea stems from a previous thread about renderers and decoupling the rendering logic from the game logic. To that end, I created a renderInfo struct to contain the important sprite drawing information. 

Each game loop, every object that wants to get drawn adds a renderInfo (or set of renderInfos if it is composed of multiple sprites) to the renderList.

 

As renderInfos are added they are sorted first by layer, then by yposition... (originally i also sorted by spriteSheet to draw all sprites from a particular spritesheet at the same time, but that could endup with a sprite from a lower y pos being drawn before one above b/c it shares a spritesheet with something even higher, although i suppose I could sort by spriteSheet after sorting by y, but I don't know how useful that would be)

 

The weird thing is that, if I scale down the sprite (original or at runtime), or if i change the size of the display... i still get the exact same performance.

 

Out of curiosity, approximatly how many sprites are generally drawn onto a screen? I realize that simpler games may have less, but what about say, a bullet hell game?

#pragma once
#include "allegro5\allegro.h"
#include "allegro5\allegro_primitives.h"
#include "boost\property_map\vector_property_map.hpp"
#include "boost\foreach.hpp"
#include <vector>
#include <map>
#include <cstdlib>
#include "AssocVector.h"

struct BOX
{
	float X1;
	float Y1;
	float X2(){return X1+W;}
	float Y2(){return Y1+H;}
	float W;
	float H;
};

struct renderInfo
{
	ALLEGRO_BITMAP* SpriteSheet;
	BOX SpriteBox;
	BOX DrawBox;
	ALLEGRO_COLOR Tint;
	float Rotation;
	int Layer;
};

class Renderer
{
private:
	std::vector<renderInfo> renderList;

	renderInfo ri;
	ALLEGRO_COLOR bgClearClr;
public:
	ALLEGRO_DISPLAY* display;
	Renderer::Renderer(void){
		display=al_get_current_display();
		al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);
		al_init_primitives_addon();
		bgClearClr=al_map_rgb(0,0,0);
	}

	Renderer::~Renderer(void){}

	void Renderer::Add(ALLEGRO_BITMAP* spriteSheet, BOX spriteBox, BOX drawBox, float rot, ALLEGRO_COLOR tint, int Layer)
	{
		renderInfo r;
		r.SpriteSheet=spriteSheet;
		r.SpriteBox=spriteBox;
		r.DrawBox=drawBox;
		r.Rotation=rot;
		r.Tint=tint;
		r.Layer=Layer;
		binaryInsert(r,0,renderList.size());
	}

	bool renderInfoCompare(renderInfo ri1,renderInfo ri2)
	{
		if (ri1.Layer!=ri2.Layer) return ri1.Layer<ri2.Layer;
		//if((int)(ri1.SpriteSheet)!=(int)(ri2.SpriteSheet)) return (int)(ri1.SpriteSheet)<(int)(ri2.SpriteSheet);
		if(ri1.DrawBox.Y1!=ri2.DrawBox.Y1) return ri1.DrawBox.Y1<ri2.DrawBox.Y1;
		return false;
	}

	void binaryInsert(renderInfo ri,int low, int hi)
	{
		if (low==hi)
		{
			renderList.insert(renderList.begin()+low,ri);
			return;
		}
		int indx=floor((low+hi)/2.0);
		if (renderInfoCompare(ri,renderList[indx]))
			return binaryInsert(ri,low,indx);
		return binaryInsert(ri,indx+1,hi);
	}

	void Render()
	{
		al_clear_to_color(bgClearClr);
		int dCount=0;
		al_hold_bitmap_drawing(true);
		for(std::vector<renderInfo>::iterator ri=renderList.begin();ri!=renderList.end();ri++)
		{
			dCount++;
			renderInfo r= *ri;
			al_draw_tinted_scaled_rotated_bitmap_region(r.SpriteSheet,
								r.SpriteBox.X1,r.SpriteBox.Y1,r.SpriteBox.W,r.SpriteBox.H,
			                    r.Tint,
								r.SpriteBox.X1+r.SpriteBox.W/2.0,r.SpriteBox.Y1+r.SpriteBox.H/2.0,
								r.DrawBox.X1,r.DrawBox.Y1,
								r.DrawBox.W/r.SpriteBox.W, r.DrawBox.H/r.SpriteBox.H,
								r.Rotation,0);
		}
		al_hold_bitmap_drawing(false);
		renderList.clear();
		printf("Draws: %i",dCount);
		/*
		for(int j=1;j<al_get_display_height(display);j+=10)
		{
			al_draw_line(0,j,al_get_display_width(display),j,al_map_rgb(255,0,0),1);
		}
		for(int i=1;i<al_get_display_width(display);i+=10)
		{
			al_draw_line(i,0,i,al_get_display_height(display),al_map_rgb(255,0,0),1);
		}
		*/
		al_flip_display();
	}

};


PARTNERS