I have 2 problems with PolygonSpriteBatch on libGDX.
1) I try to render a simple polygon (in this case a rectangle) and I only see a triangle when drawn.
Picture:
http://i.snag.gy/kHV3N.jpg
texture=new TextureRegion(new Texture("texture.png"));
texture.getTexture().setWrap(Texture.TextureWrap.Repeat, Texture.TextureWrap.Repeat);
polygonRegion=new PolygonRegion(texture,createVertices(),createIndices(createVertices()));
The polygon that i want to draw is this one
private float[] createVertices() {
float[] verts = new float[5 * 2];
int i = 0;
verts[i++] = 2;
verts[i++] = 2;
verts[i++] = 2;
verts[i++] = 3;
verts[i++] = 3;
verts[i++] = 3;
verts[i++] = 3;
verts[i++] = 2;
verts[i++] = verts[0];
verts[i++] = verts[1];
return verts;
}
private short[] createIndices(float[] vertices){
short[] indices=new short[vertices.length/2];
for(short i=0; i<vertices.length/2; i++){
indices[i]=i;
}
return indices;
}
And when I draw it
shapeRenderer.setProjectionMatrix(camera.combined);
shapeRenderer.begin(ShapeRenderer.ShapeType.Line);
shapeRenderer.polygon(createVertices());
shapeRenderer.end();
polygonSpriteBatch.setProjectionMatrix(camera.combined);
polygonSpriteBatch.begin();
polygonSpriteBatch.draw(polygonRegion, 0, 0);
polygonSpriteBatch.end();
I also draw the plain texture to see how it looks like
batch.setProjectionMatrix(camera.combined);
batch.begin();
batch.draw(texture, 4f, 2.4f, 1f, 1f);
batch.end();
As you can see, the polygon is drawn with the shaperenderer correctly, but not well textured with the polygonspritebatch.
The second problem:
Instead of the problem above, polygonspritebatch works perfectly when using a normal camera size, like 800x480.
When I use a camera that is 8 x 4.8 (for box2d world) the texture is zoomed a lot ..like in the picture out there.
Any solutions?
For the first issue, the problem is the createIndices() function. The third argument to PolygonRegion needs to contain a number of indices that is a multiple of three (the first three vertices form a triangle, etc).
So you should return { 0, 1, 2, 1, 2, 3 }. Also, why do you have 5 vertices? It seems four are enough.
For the second issue, you should clarify your question. From the screenshot, everything seems fine.
Related
I know that there are many questions related to this, but none are relevant to my problem.
So, I have a TiledMap which has 2 layers for boxes in my game - one for the box graphics and one for the box objects. Now, I want to get the textures of all the boxes because I want to be able to draw them anywhere freely. So I wrote some code to find out which tiles a given rectangle (attained from the object layer of the boxes) is covering (this code works fine). Then, from the graphics layer (TileMapTileLayer), I am accessing the textures in those tiles and drawing them to a single texture using Pixmaps. Finally, I store this texture. However, when I render these textures, they are black. Heres the code -
TiledMapTileLayer boxLayer = (TiledMapTileLayer) (map.getLayers().get(2)); // this is the graphics layer
ArrayList<Vector2> cells;
Texture tex;
Pixmap pmap, pmapScld;
int numCols, numRows, cellNum;
int boxInd = 0;
FileTextureData texData;
StaticTiledMapTile tile;
for(RectangleMapObject boxBody : map.getLayers().get(3).getObjects().getByType(RectangleMapObject.class)) { //object layer
bounds = boxBody.getRectangle();
cells = getOccupiedCells(bounds);
numCols = (int) cells.get(0).x; //I have stored the width and height of the texture
numRows = (int) cells.get(0).y; //in tiles in the first Vector2 of the Array
tex = new Texture(numCols * tileWidthOrg, numRows * tileHeightOrg, Format.RGBA8888);
cellNum = 1;
System.out.println(cells);
for(int i = 0 ; i < numCols ; i++) {
for(int j = 0 ; j < numRows ; j++) {
tile = (StaticTiledMapTile) (boxLayer.getCell((int) cells.get(cellNum).x, (int) cells.get(cellNum).y).getTile());
texData = (FileTextureData) tile.getTextureRegion().getTexture().getTextureData();
texData.prepare();
pmap = texData.consumePixmap();
//pmapScld = new Pixmap(tileWidthScld, tileHeightScld, pmap.getFormat());
//pmapScld.drawPixmap(pmap, 0, pmap.getHeight(), pmap.getWidth(), pmap.getHeight(),
//0, pmapScld.getHeight(), pmapScld.getWidth(), pmapScld.getHeight());
tex.draw(pmap, i * tileWidthOrg, j * tileHeightOrg);
pmap.dispose();
texData.disposePixmap();
//pmapScld.dispose();
cellNum++;
}
}
contactListener.addBox(new GBox(world, tex, bounds, boxInd));
tex.dispose();
boxInd++;
}
The code for rendering these boxes -
for(GBox box : contactListener.boxes) {
box.render(sb);
}
public void render(SpriteBatch sb) {
sb.draw(tex, body.getPosition().x - width / 2, body.getPosition().y - height / 2, width, height);
//System.out.println("rendering box " + index + " at position " + body.getPosition());
}
I am making a game in which i am making arcs using ShapeRenderer, As i needed to rotate those arcs around the center so i wrote that code only begin and end in render method, I am initializing them in create method,
But as the number of arcs increases the game gets slower and slower. I have maximum of 13 arcs and minimum 2 arcs.
It running fine till few say 8 arcs and after that it gets slower.
Please any one out there if he/she can help, please help...
thanks in advance.
Render Method is having 5 loops, I don't have any choice to get rid of them.
this is in create:
for (int i = 0; i < 13; i++) {
random = randomGenerator.nextInt(5);
a[i] = new Arc(arcColors[random]);
arcs_visible[i] = 1;
pointercolor[i] = a[i].getArcColor();
a[i].begin(ShapeRenderer.ShapeType.Line);
}
this is in render:
private void draw_one_arc(int i, double radius, float startangle, float sweep) {
if (arcs_visible[i] == 1 && collides[i] == false) {
a[i].arc(pointerorigin.x + pointer.getWidth() / 2, pointerorigin.y + pointer.getWidth() / 2, (float) radius, startangle, sweep, 100);
}
}
`
HTML5 canvas: I'm looking for a way to draw a single stroke around a combined path.
For example if I have two overlapping circles I don't want to have two overlapping circle strokes, but one single stroke around the combined region of both circles..
Any chance for that?
It can be done by using globalCompositeOperation. There are various ways you can draw the shapes them selves but here is one approach that results in this (for the two rectangle circles in the demo):
Step 1: setup the normal canvas
Step 2: setup an off-screen canvas
Update Not sure how I could miss the obvious, but you can of course just stroke the circles first, then punch a whole with composite mode and a fill - much faster (I guess I had images on my mind when I came up with the offset redraw).
The reason for off-screen canvas is if you have something in the background already on the main canvas. This will be deleted otherwise where we punch the hole. If nothing is there there is no problem drawing this to a single canvas - updated code:
/// some regions
var rect = [ [20, 20, 200, 200], [100, 100, 200,200] ],
/// ox = off-screen context
ox.strokeStyle = '#fff';
ox.lineWidth = 3 * 2; /// x2 as half will be gone when we punch hole
/// stroke outlines
for(; r = rect[i]; i++) {
o = r[2] * 0.5;
ox.beginPath();
ox.arc(r[0] + o, r[1] + o, o, 0, 2 * Math.PI);
ox.stroke();
}
/// punch hole with composite mode and fill
ox.globalCompositeOperation = 'destination-out';
for(i = 0; r = rect[i]; i++) {
o = r[2] * 0.5;
ox.beginPath();
ox.arc(r[0] + o, r[1] + o, o, 0, 2 * Math.PI);
ox.fill();
}
/// draw result to main canvas
/// ctx = main context, ocanvas = off-screen canvas
ctx.drawImage(ocanvas, 0, 0);
(Animated) online demo using this optimized version
I'll leave the old code as it can be used for images that can't be stroked -
Now draw the shapes filled to the off-screen canvas. Draw in the color you want the outline to be in.
/// some regions
var rect = [ [20, 20, 200, 200], [100, 100, 200,200] ],
/// ox = off-screen canvas
ox.fillStyle = '#fff';
/// draw the array with circes
for(; r = rect[i]; i++) {
var o = r[2] * 0.5;
ox.beginPath(); //use this here - arcs are currently buggy
ox.arc(r[0] + o, r[1] + o, o, 0, 2 * Math.PI);
ox.fill(); //.. and here
}
Now draw the cached image of the shapes back to main canvas. the shapes must be drawn with a slight offset in each direction - this step will create the outline:
/// ctx = main context, ocanvas = off-screen canvas
ctx.drawImage(ocanvas, -1, -1);
ctx.drawImage(ocanvas, 1, -1);
ctx.drawImage(ocanvas, 1, -1);
ctx.drawImage(ocanvas, 1, 1);
ctx.drawImage(ocanvas, -1, 1);
ctx.drawImage(ocanvas, 1, 1);
ctx.drawImage(ocanvas, -1, -1);
ctx.drawImage(ocanvas, -1, 1);
And finally we punch a "hole" in the filled shape to make it transparent with an outline using globalCompositeOperation + a final draw in 0 offset position :
ctx.globalCompositeOperation = 'destination-out';
ctx.drawImage(ocanvas, 0, 0);
ONLINE DEMO
To make the border thicker just increase the offset when you draw back the shapes to main canvas.
That's my current solution. Doesn't need a second canvas and is easier to achieve. It still uses the Ken's idea to use globalCompositeOperation:
context.lineWidth = 2;
context.stroke();
var prev = context.globalCompositeOperation;
context.globalCompositeOperation = "destination-out";
context.fill();
context.globalCompositeOperation = prev;
I'm use Perlin Noise for world generator in 2D (how in Terraria). I found an implementation that suits me. I need to generate parts of the world, but this realization can only generate once the whole world.
Realization - http://sirisian.com/javascriptgame/tests/valuenoise2.html
I rewrote it to AS3, slightly modifying (+ main code) - http://codepad.org/crMEQ2DD
Please help to modify the code so that it was possible to generate a noise part:
PerlinNoise.randomize(65735);
...
var noises:Vector.<Number> = PerlinNoise.getNoise(0, 0, 100, 100, 6, 6, 1.0, 20);
...
var noises:Vector.<Number> = PerlinNoise.getNoise(100 /*<--x offset*/, 0, 100, 100, 6, 6, 1.0, 20);
I tried several options, but the different noise parts are not docked.
And if you have an implementation of Perlin Noise, which is suitable for the world generator, you can give it to me.
Thanks!
Flash already contains an implementation of Perlin noise, through the BitmapData.perlinNoise() method. What you can do if you need to get the noise as a vector of numbers (as opposed to a renderable bitmap) is to then use the BitmapData.getVector() method which returns all the pixels as a vector of 32 bit integers, where the four bytes represent alpha, red, green and blue channels respectively.
I've employed this very pattern in a project myself, to great success. Below is the very function I wrote and used.
public static function initNoiseVector(output : Vector.<Number>, baseX : Number, numOctaves : Number, scale : Number, blur : uint = 0) : void
{
var i : uint;
var len : uint;
var sum : uint;
var avg : uint;
var perlin : BitmapData;
var noise : Vector.<uint>;
len = output.length;
perlin = new BitmapData(len, 1);
perlin.perlinNoise(baseX, 1, numOctaves, 0, true, false, 7, true);
if (blur > 0)
perlin.applyFilter(perlin, perlin.rect, new Point(), new BlurFilter(blur, 1, 3));
noise = perlin.getVector(perlin.rect);
// Calculate average
sum = 0;
for (i=0; i<len; i++) {
// Mask out blue channel
sum += noise[i]&0xff;
}
avg = sum/len;
for (i=0; i<len; i++) {
var speed : Number;
// Convert perlin noise color to value between -1 and 1
speed = ((noise[i]&0xff) - avg) / avg;
output[i] = speed * scale;
}
}
This function basically just creates a 1px high bitmap (width defined as the length of the vector), initiates grayscale Perlin noise in that bitmap, optionally applies a blur and then scales the values according to the scale function argument.
The scaling is done by first calculating the average value (using just the blue channel, since all channels will be identical due to the noise being grayscale.) The values are then normalized between -1 and 1, where the average will be 0, and scaled by the supplied scale factor.
The function can then be used in the following way, to retrieve 1000 values:
_noise = new Vector.<Number>(1000, true);
PerlinNoiseUtil.initNoiseVector(_noise, 300, 10, randomDev * periodTime, 10);
Hope this helps!
I'd like some help with a little project of mine.
Background:
i have a little hierarchy of Sprite derived classes (5 levels starting from the one, that is the root application class in Flex Builder). Width and Height properties are overriden so that my class always remembers it's requested size (not just bounding size around content) and also those properties explicitly set scaleX and scaleY to 1, so that no scaling would ever be involved. After storing those values, draw() method is called to redraw content.
Drawing:
Drawing is very straight forward. Only the deepest object (at 1-indexed level 5) draws something into this.graphics object like this:
var gr:Graphics = this.graphics;
gr.clear();
gr.lineStyle(0, this.borderColor, 1, true, LineScaleMode.NONE);
gr.beginFill(0x0000CC);
gr.drawRoundRectComplex(0, 0, this.width, this.height, 10, 10, 0, 0);
gr.endFill();
Further on:
There is also MouseEvent.MOUSE_WHEEL event attached to the parent of the object that draws. What handler does is simply resizes that drawing object.
Problem:
Screenshot
When resizing sometimes that hairline border line with LineScaleMode.NONE set gains thickness (quite often even >10 px) + it quite often leaves a trail of itself (as seen in the picture above and below blue box (notice that box itself has one px black border)). When i set lineStile thickness to NaN or alpha to 0, that trail is no more happening.
I've been coming back to this problem and dropping it for some other stuff for over a week now.
Any ideas anyone?
P.S. Grey background is that of Flash Player itself, not my own choise.. :D
As requested, a bit more:
Application is supposed to be a calendar-timeline with a zooming "feature" (project for a course at university). Thus i have these functions that have something to do with resizing:
public function performZoom():void
{
// Calculate new width:
var newDayWidth:Number = view.width / 7 * this.calModel.zoom;
if (newDayWidth < 1)
{
newDayWidth = 1;
}
var newWidth:int = int(newDayWidth * timeline.totalDays);
// Calculate day element Height/Width ratio:
var headerHeight:Number = this.timeline.headerAllDay;
var proportion:Number = 0;
if (this.view.width != 0 && this.view.height != 0)
{
proportion = 1 / (this.view.width / 7) * (this.view.height - this.timeline.headerAllDay);
}
// Calculate new height:
var newHeight:int = int(newDayWidth * proportion + this.timeline.headerAllDay);
// Calculate mouse position scale on X axis:
var xScale:Number = 0;
if (this.timeline.width != 0)
{
xScale = newWidth / this.timeline.width;
}
// Calculate mouse position scale on Y axis:
var yScale:Number = 0;
if (this.timeline.height - this.timeline.headerAllDay != 0)
{
yScale = (newHeight - this.timeline.headerAllDay) / (this.timeline.height - this.timeline.headerAllDay);
}
this.timeline.beginUpdate();
// Resize the timeline
this.timeline.resizeElement(newWidth, newHeight);
this.timeline.endUpdate();
// Move timeline:
this.centerElement(xScale, yScale);
// Reset timeline local mouse position:
this.centerMouse();
}
public function resizeElement(widthValue:Number, heightValue:Number):void
{
var prevWidth:Number = this.myWidth;
var prevHeight:Number = this.myHeight;
if (widthValue != prevWidth || heightValue != prevHeight)
{
super.width = widthValue;
super.height = heightValue;
this.scaleX = 1.0;
this.scaleY = 1.0;
this.myHeight = heightValue;
this.myWidth = widthValue;
if (!this.docking)
{
this.origHeight = heightValue;
this.origWidth = widthValue;
}
this.updateAnchorMargins();
onResizeInternal(prevWidth, prevHeight, widthValue, heightValue);
}
}
Yes. I know.. a lot of core, and a lot of properties, but in fact most of the stuff has been disabled at the end and the situation is as described at the top.
this didn't work:
gr.lineStyle(); // Reset line style
Can we see your resizing code?
Also try clearing your line style as well as your fill:
gr.lineStyle(0, this.borderColor, 1, true, LineScaleMode.NONE);
gr.beginFill(0x0000CC);
gr.drawRoundRectComplex(0, 0, this.width, this.height, 10, 10, 0, 0);
gr.endFill();
gr.lineStyle();//<---- add this line
I don't know whether it's flash bug or what it is, but i finally found the solution.
The thing is that in my case when resizing in a nutshell you get like this:
this.width = this.stage.stageWidth / 7 * 365;
When i switch to maximized window this.width gains value 86k+. When i added this piece of code to draw horizontal line, it fixed itself:
var recWidth:Number = this.width;
var i:int;
var newEnd:Number = 0;
for (i = 1; newEnd < recWidth; i++)
{
newEnd = 100 * i;
if (newEnd > recWidth)
{
newEnd = recWidth;
}
gr.lineTo(newEnd, 0);
}
I don't know what is going on.. This is inconvenient...