This is what happens in my Tetris game right now: The hitbox for the J block is 60x40, and even though there is in reality nothing there in the actual image editor, it is taken as a hitbox. Meaning, the two invisible squares at the top right of the J block count in the hitbox, and I want to exclude it.
This is the spritesheet seen in the photo editor -- GIMP.
I tried to copy and paste the code from this example, but python immediately bugged out and said, "No module named math". I'm using python 2.7 & pygame 1.9.1.
I have pastebins for all of the code... mcve is the main one to run.
`https://pastebin.com/Zze42KmZ`
`https://pastebin.com/q5rEpk3e`
`https://pastebin.com/ChGvrMu8`
`https://pastebin.com/ppb3cREL`
How can I exclude the squares in the hitbox? Thank you and I apologize for sucking.
I'd have to argue that using one 'hitbox' for J element is not possible. That is why you have pygame detecting hit with two boxes that are not there.
Why is that?
Because 'hitbox' is one rectangle. That rectangle has its height and width and it matches the J's element height and width. Everything inside that rectangle is part of same 'hitbox'. It really doesn't matter if image that represents that element has transparent part or not.
Hitbox is not based on image and its transparent parts, it's based on rectangle that surrounds image.
That is why you have to have at least 2 rectangles that will cover both parts of J element i.e. 3 vertical squares and 2 horizontal ones. That kind of complicates the whole thing a bit. But you should be able to use child subsurfaces and use collision detection on both of them.
I'd also argue that it is not good to use pygame's collision detecting at all for this purpose. Better approach would be that you do it by using 2D matrix where you store 'O' for empty square and 'X' for occupied one. In each step you have your element at X,Y coordinate and you test if lowering it by 1 step you encounter occupied space in matrix. This is just a suggestion though.
Example of clear 5 rows x 4 columns matrix:
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
0 0 0 0
Example of J element at (1, 1) coordinate:
0 0 0 0
0 0 J 0
0 0 J 0
0 J J 0
0 0 0 0
Pay attention that pygame's coordinate system has (0,0) coordinate in top left corner of the screen. That matches with coordinates of 2D matrix generated.
Related
How is a transformation matrix defined?
I have the values defining scale, skew, and translation. I would like to find the transformation matrix they represent.
Scale x/y can be any number.
Translation x/y can be any number.
Skew x/y is in degrees between -180 and 180.
How can I find the transformation matrix for these values?
I am working with values from Flash, and would like the matrix to be formatted like this, so that I can export this matrix and apply the same transformation in another language :
| a c u |
| b d v |
| 0 0 1 |
I need to be able to go from the parameters to the matrix outside of AS3/JSFL/Flash.
(Specifically I want to use C#, but I want an answer that doesn't depend on a given language.)
This link talks about how matrices work in Flash, and I understand most of it. However from what I can tell, it does not describe how to go from position/scale/skew values to a matrix.
http://www.senocular.com/flash/tutorials/transformmatrix/
I know there is a .matrix property of flash display objects, but I am working with the given values outside of flash, and need to find a solution without using that.
Actionscript's skew is misbehaving
Given the usual definitions of tranformations in Cimbali's answer, I'm still having problems with building a matrix from its skew parameter.
Here is an example set of data:
A) Object Properties (logged directly from Flash using JSFL, element.x, element.skewX, etc...)
x: 0
y: 0
scaleX: 1
scaleY: 1.0000152587890625
skewX: 19.9998779296875
skewY: 0
B) Transform Matrix (logged directly from Flash using JSFL, element.matrix)
1 | 0 | 0
-0.342 | 0.94 | 0
0 | 0 | 1
Here is what I tried:
sx = tan(19.9998779296875 * PI / 180) = tan(0.34906372) = 0.36396782164
Scale Matrix Skew X Matrix Result Matrix
1 | 0 | 0 1 | 0 | 0 1 | 0 | 0
0 | 1 | 0 x 0.36 | 1 | 0 = 0.36 | 1 | 0
0 | 0 | 1 0 | 0 | 0 0 | 0 | 1
SkewY is 0, so there's no reason to multiply again using a Skew Y Matrix.
So why is my Result Matrix so much different than the matrix posted by Flash?
In this example my graphic is originally 200 x 100 px. It does not inherit transformations from any parent (the parent is definitely not transformed in any way). However, when I place the graphic on the stage and ONLY change the skew X value to 20°, the Height in the properties panel changes from100 to 94px, but Scale Y stays at 100%.
In case you're not familiar with Flash IDE, when you adjust ONLY the skew X value, it does not simply push the corners of the graphic left/right. It actually makes the corners move on an arc, as you increase skew X, the parallelogram comes shorter vertically.
(I realize I have rounded some numbers, but that is only for ease of displaying them here.)
Applying successive transformations is, for some strange reason, called "concatenating matrices" in actionscript 3, which as your link explains, and is done by multiplying matrices : read section "Matrix Multiplication" completely : it starts by defining matrix multiplications and ends litteraly by A*B -> B.concat(A);.
Note that the order in which transformations are applied is important : B*A is not A*B. In both A*B and B.concat(A);, B is applied before A. You can think of it as A*(B*(x,y,1)) thanks to the associativity of the matrix product. This is also explained in the section "Concatenated Matrices" of your link, where a child element is transformed by its matrix, and then by its parent matrix, which is shown to be equivalent to a single transformation by child_matrix.concat(parent_matrix);
However the missing piece of the puzzle is that for each operation you describe, there is a corresponding transformation matrix. They are all illustrated and explained in adobe's reference on Matrices. There is however a small mistake on the illustration of skew matrices, you should refer to this stackoverflow question instead.
Here is the illustration from the wikipedia page on the topic, which is just as clear :
Note that all reflections can be expressed by scaling with W and/or H having -1 value. For shear expressed as angles, just use A = tan(a) in the images above.
However, it seems that flash disagrees on the meaning of "skew", and instead of preserving one coordinate while skewing the other, it preserves the lengths that were originally along that coordinate. Or, as you describe it, if you skew along X a rectangle, (some of) its vertices aren't pushed left or right, but move on an arc.
As it seems, they skew one coordinate, then correct the elongation of the figure by scaling the other coordinate. Luckily the factor by which this happens is easily predictable since we know trigonometry : it is the cosine of the angle.
So whenever you have a skewX by an angle a in flash, you have to use the following product of matrices (expressed using definitions from the image above) : matrix(scale with W=1 and H=cos(a)) * matrix(skew along x with A=-tan(a))
It would only be logical that defining a skewY in flash would yield in a reasonable programming language matrix(scale with W=cos(a) and H=1) * matrix(skew along y with B=-tan(a))
I have a rectangular image which gets transformed applying
image.setLayoutMatrix3D(matrix3D).
I need to calculate the actual dimensions and position (in pixels) of the image after the transformation.
In this scenario there are no rotations to the image applied. The matrix3D has the following structure:
1 0 0 0
0 1 0 0
0 0 1 0
value1 value2 value3 1
Provided that the original position and size of image are originalWidth, originalHeight, originalX and originalY how can I calculate the new dimension and position?
Thanks!
Admittedly, I've never done this with a matrix applied, but, I believe you can use: image.getLayoutBoundsWidth(), image.getLayoutBoundsHeight(), image.getLayoutBoundsX(), and image.getLayoutBoundsY() to get these values.
These methods from the ILayoutElement interface have a default boolean argument, postLayoutTransform (defaults to to true). When postLayoutTransform is true, the functions return values with the transformation applied.
Like the title, anyone know how to draw a circuit diagram to check a 4 bits number odd or even ??
You don't really need a circuit for this - bit 0 of the input determines whether the number is odd or even, so you can ignore bits 1 - 3 and just use bit 0 as an odd/even output (it will be 1 for odd, 0 for even). So the circuit, such as it is, would look like this:
INPUT OUTPUT
bit 3 o------------- N/C
bit 2 o------------- N/C
bit 1 o------------- N/C
bit 0 o------------------------------------o odd/even
In Flash, pixels are calculated using twips, or twentieth of a pixel. Consequently, every position is always in multiples of 0.05. I haven't seen this mentioned in the HTML Canvas spec and am unable to trace the cursor position on Canvas. Does anyone know the accuracy of its pixel calculations?
Edit for clarification:
I'm referring more to Zeno's paradox which says in order to move something from point A to point B, it must first move to a point halfway between the two. And then halfway again, ad infinitum.
So if I want to move on the x axis from point 0 to 100 at 0.5:
At frame 1: 50
Frame 2: 75
Frame 3: 87.5
Then: 93.75, 96.875, 98.4375... etc.
So at what step does the Canvas actually round-up to the next pixel?
I'm unsure what you mean by accuracy of slicing.
Pixels on the Canvas can be drawn to a little less than 0.10, after which they make barely any visible impact.
Of course, if you scale, you can draw things that are 0.00125 pixels, and so on. But they won't be visible if you unscale.
http://jsfiddle.net/GvVD9/
(That first square block on the top-left is a pixel)
Accuracy of the mouse is an entirely different thing, in no way related to the canvas spec.
EDIT:
Well, we can sorta demonstrate that. We can draw a bunch of pixels with y values approaching 100 and see how they compare to a red pixel drawn with the y value 100.
http://jsfiddle.net/GvVD9/46/
Every single horizontally separated piece is just a single 1 by 1 pixel rect using the drawRect command.
50
75
87.5
93.75 // first black pixel you see in image
96.875
98.4375
99.21875
99.609375
99.8046875
99.90234375
99.951171875
99.9755859375
99.98779296875
99.993896484375
99.9969482421875 // last black pixel you see in image
I'm drawing rectangles at random positions on the stage, and I don't want them to overlap.
So for each rectangle, I need to find a blank area to place it.
I've thought about trying a random position, verify if it is free with
private function containsRect(r:Rectangle):Boolean {
var free:Boolean = true;
for (var i:int = 0; i < numChildren; i++)
free &&= getChildAt(i).getBounds(this).containsRect(r);
return free;
}
and in case it returns false, to try with another random position.
The problem is that if there is no free space, I'll be stuck trying random positions forever.
There is an elegant solution to this?
Let S be the area of the stage. Let A be the area of the smallest rectangle we want to draw. Let N = S/A
One possible deterministic approach:
When you draw a rectangle on an empty stage, this divides the stage into at most 4 regions that can fit your next rectangle. When you draw your next rectangle, one or two regions are split into at most 4 sub-regions (each) that can fit a rectangle, etc. You will never create more than N regions, where S is the area of your stage, and A is the area of your smallest rectangle. Keep a list of regions (unsorted is fine), each represented by its four corner points, and each labeled with its area, and use weighted-by-area reservoir sampling with a reservoir size of 1 to select a region with probability proportional to its area in at most one pass through the list. Then place a rectangle at a random location in that region. (Select a random point from bottom left portion of the region that allows you to draw a rectangle with that point as its bottom left corner without hitting the top or right wall.)
If you are not starting from a blank stage then just build your list of available regions in O(N) (by re-drawing all the existing rectangles on a blank stage in any order, for example) before searching for your first point to draw a new rectangle.
Note: You can change your reservoir size to k to select the next k rectangles all in one step.
Note 2: You could alternatively store available regions in a tree with each edge weight equaling the sum of areas of the regions in the sub-tree over the area of the stage. Then to select a region in O(logN) we recursively select the root with probability area of root region / S, or each subtree with probability edge weight / S. Updating weights when re-balancing the tree will be annoying, though.
Runtime: O(N)
Space: O(N)
One possible randomized approach:
Select a point at random on the stage. If you can draw one or more rectangles that contain the point (not just one that has the point as its bottom left corner), then return a randomly positioned rectangle that contains the point. It is possible to position the rectangle without bias with some subtleties, but I will leave this to you.
At worst there is one space exactly big enough for our rectangle and the rest of the stage is filled. So this approach succeeds with probability > 1/N, or fails with probability < 1-1/N. Repeat N times. We now fail with probability < (1-1/N)^N < 1/e. By fail we mean that there is a space for our rectangle, but we did not find it. By succeed we mean we found a space if one existed. To achieve a reasonable probability of success we repeat either Nlog(N) times for 1/N probability of failure, or N² times for 1/e^N probability of failure.
Summary: Try random points until we find a space, stopping after NlogN (or N²) tries, in which case we can be confident that no space exists.
Runtime: O(NlogN) for high probability of success, O(N²) for very high probability of success
Space: O(1)
You can simplify things with a transformation. If you're looking for a valid place to put your LxH rectangle, you can instead grow all of the previous rectangles L units to the right, and H units down, and then search for a single point that doesn't intersect any of those. This point will be the lower-right corner of a valid place to put your new rectangle.
Next apply a scan-line sweep algorithm to find areas not covered by any rectangle. If you want a uniform distribution, you should choose a random y-coordinate (assuming you sweep down) weighted by free area distribution. Then choose a random x-coordinate uniformly from the open segments in the scan line you've selected.
I'm not sure how elegant this would be, but you could set up a maximum number of attempts. Maybe 100?
Sure you might still have some space available, but you could trigger the "finish" event anyway. It would be like when tween libraries snap an object to the destination point just because it's "close enough".
HTH
One possible check you could make to determine if there was enough space, would be to check how much area the current set of rectangels are taking up. If the amount of area left over is less than the area of the new rectangle then you can immediately give up and bail out. I don't know what information you have available to you, or whether the rectangles are being laid down in a regular pattern but if so you may be able to vary the check to see if there is obviously not enough space available.
This may not be the most appropriate method for you, but it was the first thing that popped into my head!
Assuming you define the dimensions of the rectangle before trying to draw it, I think something like this might work:
Establish a grid of possible centre points across the stage for the candidate rectangle. So for a 6x4 rectangle your first point would be at (3, 2), then (3 + 6 * x, 2 + 4 * y). If you can draw a rectangle between the four adjacent points then a possible space exists.
for (x = 0, x < stage.size / rect.width - 1, x++)
for (y = 0, y < stage.size / rect.height - 1, y++)
if can_draw_rectangle_at([x,y], [x+rect.width, y+rect.height])
return true;
This doesn't tell you where you can draw it (although it should be possible to build a list of the possible drawing areas), just that you can.
I think that the only efficient way to do this with what you have is to maintain a 2D boolean array of open locations. Have the array of sufficient size such that the drawing positions still appear random.
When you draw a new rectangle, zero out the corresponding rectangular piece of the array. Then checking for a free area is constant^H^H^H^H^H^H^H time. Oops, that means a lookup is O(nm) time, where n is the length, m is the width. There must be a range based solution, argh.
Edit2: Apparently the answer is here but in my opinion this might be a bit much to implement on Actionscript, especially if you are not keen on the geometry.
Here's the algorithm I'd use
Put down N number of random points, where N is the number of rectangles you want
iteratively increase the dimensions of rectangles created at each point N until they touch another rectangle.
You can constrain the way that the initial points are put down if you want to have a minimum allowable rectangle size.
If you want all the space covered with rectangles, you can then incrementally add random points to the remaining "free" space until there is no area left uncovered.