I am trying to write an XNA game. But I am new. I want to determine the top-most object in the scene. In rectangle form, when two rectangles intersect on the screen, I want to click on the top-most one. But I don't know how I can detect the top-most object from the scene.
Can anybody help me? Is there a method for that?
It depends what method you are using to draw them.
If you're use SpriteSortMode.Deferred mode you draw them in the order the SpriteBatch.Draw is called. In this way you know which object is top-most. To achieve that you need to check every object you have in a list, an array or whatever, the first (or the last, it depends on how you've managed your structure) element's Rectangle collider that contains your click will be the top-most object. Once you've found it you need to break the cycle that is "sweeping" your list/array, in order to detect only that click.
If you're using SpriteSortMode.BackToFront or FrontToBack it's a bit harder to know.
Reference here.
UPDATE
When you draw your objects with Deferred mode, and they "collides" you know for sure that the last one that has been drawn is the top-most.
If you are using a list you have to do something like this:
for (int i = spriteList.Count - 1; i >= 0; i--)
{
if (spriteList[i].collisionRect.Contains(touch))
{
topMostSprite = spriteList[i];
break;
}
}
Related
I'm on Yosemite 10.10.5 and Xcode 7, using Swift to make a game targeting iOS 8 and above.
EDIT: More details that might be useful: This is a 2D puzzle/arcade game where the player moves stones around to match them up. There is no 3D rendering at all. Drawing is already too slow and I haven't even gotten to explosions with debris yet. There is also a level fade-in, very concerning. But this is all on the simulator so far. I don't yet have an actual iPhone to test with yet and I'm betting the actual device will be at least a little faster.
I have my own Draw2D class, which is a type of UIView, set up as in this tutorial. I have a single NSTimer which initiates the following chain of calls in Draw2D:
[setNeedsDisplay]; // which calls drawRect, which is the master draw function of Draw2D
drawRect(rect: CGRect)
{
scr_step(); // the master update function, which loops thru all objects and calls their individual update functions. I put it here so that updating and drawing are always in sync
CNT = UIGraphicsGetCurrentContext(); // get the curret drawing context
switch (Realm) // based on what realm im in, call the draw function for that realm
{
case rlm.intro: scr_draw_intro();
case rlm.mm: scr_draw_mm();
case rlm.level: scr_draw_level(); // this in particular loops thru all objects and calls their individual draw functions
default: return;
}
var i = AARR.count - 1; // loop thru my own animation objects and draw them too, note it's iterating backwards because sometimes they destroy themselves
while (i >= 0)
{
let A = AARR[i];
A.scr_draw();
i -= 1;
}
}
And all the drawing works fine, but slow.
The problem is now I want to optimize drawing. I want to draw only in the dirty rectangles that need drawing, not the whole screen, which is what setNeedsDisplay is doing.
I could not find any tutorials or good example code for this. The closest I found was apple's documentation here, but it does not explain, among other things, how to get a list of all dirty rectangles so far. It does not also explicitly state if the list of dirty rectangles is automatically cleared at the end of each call to drawRect?
It also does not explain if I have to manually clip all drawing based on the rectangles. I found conflicting info about that around the web, apparently different iOS versions do it differently. In particular, if I'm gonna hafta manually clip things then I don't see the point of apple's core function in the first place. I could just maintain my own list of rectangles and manually compare each drawing destination rectangle to the dirty rectangle to see if I should draw anything. That would be a huge pain, however, because I have a background picture in each level and I would hafta draw a piece of it behind every moving object. What I'm really hoping for is the proper way to use setNeedsDisplayInRect to let the core framework do automatic clipping for everything that gets drawn on the next draw cycle, so that it automatically draws only that piece of the background plus the moving object on top.
So I tried some experiments: First in my array of stones:
func scr_draw_stone()
{
// the following 3 lines are new, I added them to try to draw in only dirty rectangles
if (xvp != xv || yvp != yv) // if the stone's coordinates have changed from its previous coordinates
{
MyD.setNeedsDisplayInRect(CGRectMake(x, y, MyD.swc, MyD.shc)); // MyD.swc is Draw2D's current square width in points, maintained to softcode things for different screen sizes.
}
MyD.img_stone?.drawInRect(CGRectMake(x, y, MyD.swc, MyD.shc)); // draw the plain stone
img?.drawInRect(CGRectMake(x, y, MyD.swc, MyD.shc)); // draw the stone's icon
}
This did not seem to change anything. Things were drawing just as slow as before. So then I put it in brackets:
[MyD.setNeedsDisplayInRect(CGRectMake(x, y, MyD.swc, MyD.shc))];
I have no idea what the brackets do, but my original setNeedsDisplay was in brackets just like they said to do in the tutorial. So I tried it in my stone object, but it had no effect either.
So what do I need to do to make setNeedsDisplayInRect work properly?
Right now, I suspect there's some conditional check I need in my master draw function, something like:
if (ListOfDirtyRectangles.count == 0)
{
[setNeedsDisplay]; // just redraw the whole view
}
else
{
[setNeedsDisplayInRect(ListOfDirtyRecangles)];
}
However I don't know the name of the built-in list of dirty rectangles. I found this saying the method name is getRectsBeingDrawn, but that is for Mac OSX. It doesn't exist in iOS.
Can anyone help me out? Am I on the right track with this? I'm still fairly new to Macs and iOS.
You should really avoid overriding drawRect if at all possible. Existing view/technologies take advantage of any hardware capabilities to make things a lot faster than manually drawing in a graphics context could, including buffering the contents of views, using the GPU, etc. This is repeated many times in the "View Programming Guide for iOS".
If you have a background and other objects on top of that, you should probably use separate views or layers for those rather than redraw them.
You may also consider technologies such as SpriteKit, SceneKit, OpenGL ES, etc.
Beyond that, I'm not quite sure I understand your question. When you call setNeedsDisplayInRect, it will add that rect to those that need to be redrawn (possibly merging with rectangles that are already in the list). drawRect: will then be called a bit later to draw those rectangles one at a time.
The whole point of the setNeedsDisplayInRect / drawRect: separation is to make sure multiple requests to redraw a given part of the view are merged together, and drawing only happens once per redraw cycle.
You should not call your scr_step method in drawRect:, as it may be called multiple times in a cycle redraw cycle. This is clearly stated in the "View Programming Guide for iOS" (emphasis mine):
The implementation of your drawRect: method should do exactly one
thing: draw your content. This method is not the place to be updating
your application’s data structures or performing any tasks not related
to drawing. It should configure the drawing environment, draw your
content, and exit as quickly as possible. And if your drawRect: method
might be called frequently, you should do everything you can to
optimize your drawing code and draw as little as possible each time
the method is called.
Regarding clipping, the documentation of drawRect states that:
You should limit any drawing to the rectangle specified in the rect
parameter. In addition, if the opaque property of your view is set to
YES, your drawRect: method must totally fill the specified rectangle
with opaque content.
Not having any idea what your view shows, what the various method you call do, what actually takes time, it's difficult to provide much more insight into what you could do. Provide more details into your actual needs, and we may be able to help.
I have made a PNG image which will be my button background. In the preload() of my relevant state I load that image. I want a way to have this image placed in the world and be able to set text onto it (and also be clickable but I guess that's a bit unimportant here because I know how to set up event handlers).
I thought I could manage something with
Text text = new Text(x,y,foo,style);
text.texture = <something>
but trying to, for example, create a new Texture() shows a warning "undefined class Texture" in DartEditor, and anyway (as far as I can tell?) Texture doesn't seem to allow giving a source image key/URL..
So could anyone with Phaser experience tell me how I can get an in-game button as I want?
I currently seem to have achieved more or less what I wanted (may have to tweak some values here and there but generally seems alright) with code like this
class MyState
{
preload() {
//...
game.load.image('key','$assetPath/button.png');
//...
}
create() {
Sprite temp2;
temp2 = new Sprite(this.game, x, y, 'button');
BitmapData bmp = game.add.bitmapData(temp2.width, temp2.height);
bmp.draw(temp2);
//Text positioning x,y in fillText() is just my choice of course
bmp.ctx.fillText('Wait', bmp.width / 2, bmp.height / 2);
game.add.sprite(game, someX, someY, bmp);
}
}
EDIT: For what I'm doing there adding the bitmap to game cache wasn't needed; must've been something I was trying when trying to figure it out and forgot to delete.
So I needed to use the BitmapData class. My only little concern with this (although I'm not sure it really is an issue) is how when I create the Sprite temp2 I am giving it a position but of course it is not used in the game, rather the output of drawing the sprite, and then text on top, to bmp is added as a sprite to the game. Does anyone know if there are any real implications of creating that first Sprite and leaving it like so? I'm just wondering because visually it appears it is not an issue since it is not appearing in the "game world".
Also, while this method seems just fine for me at the moment I'm curious as to whether there other ways, like something else that is somehow better and/or more preferred?
I'm building a Mega Man clone for a school project and I just finished the code to make my character jump and it works perfectly. But I need it to display the actual jump sprite of Mega Man. This is the whole code in Game1:
http://pastebin.com/py7Y7mtD
The AnimatedSprites jt helps you decide the direcrtion and display the sprite. Doesn't matter right now if it's efficient. It's just for starts. When I'll get to more complex stuff I'll work on it.
MegamanJump has the jump sprite(5 or 6 sprites displayed from left to right)
MegamanJump_Flip is the same thing but to the left(again, forget about efficiency).
Basically you want to switch out the current drawable sprite with the sprite you want to draw depending on moving direction or moving direction + jump.
Since you already have a running update method, all you have to do is write another method that does this for you, a state variable to track what is happening and the actual states it can have, preferrably in an enum for clarity.
Essentially
private void swapSprite() {
if(state == CharacterState.LEFT) {
sprite = leftDrawable;
}
//etc other single ifs
if(state == CharacterState.LEFTJUMPING) {
sprite = leftJumpDrawable;
}
}
Change the states on button press combinations, call this method after checking for movement.
I hope this helped!
so as per title I am trying to figure out if there is a good way to calculate the bounds of a scene as the usual frame/bounds properties don't really work in the context.
I basically need a way to check if an object has moved out of the viewable screen based on the camera settings of xFov/yFov/zNear/zFar. So far I haven't really found a good way to do so. Have I overlooked any API methods here or does this need to be calculated manually?
I hope I have made sense here if not please tell me and I will clarify further.
SCNView conforms to SCNSceneRenderer which in turn has a method called isNodeInsideFrustum:withPointOfView: which is what you are looking for. According to the documentation, it returns:
YES if the bounding box of the tested node intersects the view frustum defined by the pointOfView node; otherwise, NO.
Using it looks something like this:
BOOL isInside = [sceneView isNodeInsideFrustum:nodeToTest
withPointOfView:sceneView.pointOfView];
if (!isInside) {
// the bounding box of nodeToTest is not in the viewport ...
}
I need the user to be able to drag and drop several pictures(sprites). However, I do not want them to overlap with each other. I plan to add something in the 'onTouchEnded' method but do not know how to do it.
The preferred way is to only change the overlapping part of the two sprites to red-tinted. However, if this is not possible, we can also change the two sprites both to red-tinted.
I tried to use sprite.color = ccRED. but it changed the whole sprite to red color instead of a tinted one.
By the way, both the two sprites are in regular sizes.
Simple way is you can check colliding of two sprite
if( CGRectIntersectsRect( [sprite1 boundingBox], [sprite2 boundingBox] ) ) {
// Handle overlap
}
You This logic in your case :
Also i got it from This Link.
Yes, it should… though it might look a little weird, depending on how exactly your sprites are shaped. You can also try testing for distance, which works better if your sprites are more circular:
// This is how close the sprites have to be for the game to think that they're colliding
// (or overlapping). Use a smaller value than 0.5 if you want them to be closer together
// in order for there to be a collision.
float distanceForCollision = (sprite1.contentSize.width * 0.5) + (sprite2.contentSize.width * 0.5);
// This is how close the sprites actually are
float actualDistance = ccpDistance( sprite1.position, sprite2.position );
// Check if they're close enough
if( actualDistance <= distanceForCollision ) {
// Handle overlap
}
Both methods work really well, but like I said… it might look a little strange, depending on the shape. Testing for collision/overlap with, say, star-shaped sprites would look a little weird using either method. Still, for menus and drag & drop, it should be enough.