Newbie here! :P
I'm trying to create a game in Corona where animals falls from the top of the screen and keep bouncing. When you touch an animal it disappears.
I've drawn all the animals like circles, then, I added a circular physics body to it. The images are PNG with transparency.
The problem is, some details of the animals, such as ears and paws, they are outside of the physics body (what I want, because it seems a better collision this way). Moreover, when I touch outside the animal image sometimes it is pressed on the alpha region of my image and it is counted as a tap, but I have not actually tapped in the animal.
I would like to it disappear when i click only on its physical body region.
Anyone knows how to handle this? Is there a way to add a touch handler for the physics body? (The collision works pretty fine, it's just the touch that is related to the image instead of the physics body).
local rect = display.newImage("img/Animals/cow_a1.png");
rect.x = 60 + math.random( 160 )
rect.y = -100
physics.addBody( rect, { density=9, friction=0.3, bounce=0.3,radius=27} )
function rect:touch(e)
-- Remove the animals from screen and memory
removeAnimal(self);
end
-- Add event listener to the cow
rect:addEventListener("touch", rect);
This is because of the rectangular image space. try using MASK on your animal objet with HIT TEST option on (true):
try this link for masking images
here is an example:
local displayGroupTmp = display.newGroup( )
displayGroupTmp.id = id + 1
-- creating a slice
local circleSize = Constants.screenX*3.8/4 - 20
local background = display.newImageRect( displayGroupTmp, "images/slice.png", circleSize/2, circleSize*1.5/2 )
background.anchorX = 0
background.anchorY = 0.66
background.x = Constants.screenX/2 + deltaX
background.y = Constants.screenY/2 + deltaY
background:setFillColor( color[1], color[2], color[3] )
-- setting mask of an object to identify the true bounding of the background
local mask = graphics.newMask( "images/sliceMask.png" )
-- mask.anchorX = 0
background.maskX = background.x
background.maskY = background.y
background:setMask( mask )
background.maskScaleX, background.maskScaleY = 0.38,0.38
background.isHitTestMasked = true
Related
I have a moving animation called "instance1" which has 8 frames in my corona sdk game. Unfortunately the dynamic physics body I try to add picks up the transparent space in the rest of the animation and when instance1 jumps on to a platform it just goes off of the screen because of the transparent space. Is there a way to set a physics body to the current frame's opaque colour only?
Here is the code:
local sheet1 = graphics.newImageSheet( "runningcat.png", { width=496, height=206.5, numFrames=8 } )
local instance1 = display.newSprite( sheet1, { name="cat", start=1, count=8, time=1000 } )
instance1.x = display.contentWidth / 4 + 10
instance1.y = baseline - 100
instance1.xScale = .3
instance1.yScale = .3
instance1:play()
physics.addBody( instance1, { density=3.0, friction=0.5, bounce=0.3 } )
Any help appreciated.
Mitra0000
If you don't define, the body will create with a square equals to you image.
Try to set body vertices to make it work exactly what you want
local pentagonShape = { 0,-37, 37,-10, 23,34, -23,34, -37,-10 }
physics.addBody( pentagon, { density=3.0, friction=0.8, bounce=0.3, shape=pentagonShape } )
I want objects to be able to pass through the bottom and top of the screen but not be able to leave the right and left side. I have this code but when my objects go to the left or right it doesn't act as a wall and lets it go right through it. I used the contactTestBitMask to make sure there was contact but there is no collision. This is the code for the wall on the left:
func wall() {
let leftWall = SKNode()
leftWall.physicsBody = SKPhysicsBody(edgeLoopFromRect:CGRectMake(1.0,
1.0, 1.0, CGRectGetHeight(self.frame)));
leftWall.physicsBody?.categoryBitMask = OutsideCategory
leftWall.physicsBody?.contactTestBitMask = HeroCategory
leftWall.physicsBody?.collisionBitMask = 0
leftWall.physicsBody?.mass = 5
leftWall.physicsBody?.friction = 1.0
leftWall.physicsBody?.restitution = 1
leftWall.physicsBody?.usesPreciseCollisionDetection = true
leftWall.physicsBody?.dynamic = false
leftWall.physicsBody?.affectedByGravity = false
leftWall.position = CGPointMake(0, self.size.height / 40)
leftWall.setScale(1.0)
self.addChild(leftWall)
As long as the category bit mask is set on your wall, and your walls do in fact exist where you expect them to exist (you can set a flag on the scene to draw physics bodies which will display your wall), and the collisionBitMask of the nodes that should collide with the walls are set to the categoryBitMask of the wall (and you have created world physics body on the scene), you should be good to go.
Example:
self.physicsBody = [SKPhysicsBody bodyWithEdgeLoopFromRect:self.frame];
self.physicsWorld.contactDelegate = self;
self.physicsBody.categoryBitMask = CNPhysicsCategoryEdge;
_catNode.physicsBody.collisionBitMask = CNPhysicsCategoryBlock | CNPhysicsCategoryEdge | CNPhysicsCategorySpring;
_catNode.physicsBody.contactTestBitMask = CNPhysicsCategoryBed | CNPhysicsCategoryEdge;
The cat sprite node in this example will collide with the world physics body now.
Your collisionBitMask cannot be set to 0. It must match an enum value that coinsides with the categoryBitMask of the other objects. Per apple's documentation:
collisionBitMask Property A mask that defines which categories of
physics bodies can collide with this physics body.
Declaration
SWIFT var collisionBitMask: UInt32 OBJECTIVE-C
#property(nonatomic, assign) uint32_t collisionBitMask
Discussion When
two physics bodies contact each other, a collision may occur. This
body’s collision mask is compared to the other body’s category mask by
performing a logical AND operation. If the result is a nonzero value,
this body is affected by the collision. Each body independently
chooses whether it wants to be affected by the other body. For
example, you might use this to avoid collision calculations that would
make negligible changes to a body’s velocity.
The default value is 0xFFFFFFFF (all bits set).
Example:
CGRect bodyRect = CGRectInset(frame, 2, 2);
self.physicsBody = [SKPhysicsBody bodyWithRectangleOfSize:bodyRect.size];
self.physicsBody.categoryBitMask = CNPhysicsCategoryBlock;
self.physicsBody.collisionBitMask = CNPhysicsCategoryBlock | CNPhysicsCategoryCat | CNPhysicsCategoryEdge;
I am currently working on a school project and missed a class where the instructor explained how to do this without a massive amount of code.
Here is the assignment:
Create an XNA application shows 50 animated sprites accelerating downward. When a sprite hits the bottom of the window, make it bounce. Spawn each sprite in a random location such that the sprite is always completely in the window. Limit the Y component of the random location to be between 0 and 300. Lastly, make it so the sprites reset to their original location upon a press of the space bar.
This is a link to an example image, rep isn't high enough for inserting images
http://hypergrade.com/grader/file_download.php?id=132
I have a single sprite drawn and animated, I just need some guidance on randomly generating locations for the same Texture2D.
you should use Random class.
// Make one instance of random, the seed is the milliseconds, other way random always returns the same sequence of random numbers.
static readonly Random rnd = new Random(DateTime.Nom.Milliseconds);
List<Sprite> Sprites = new List<Sprite>(50);
public void Update()
{
//Add new sprites with a 90% or probability
if (Sprites.Count<50 && rnd.Next(100) > 90)
{
Sprite sprite = new Sprite();
// This X calculation makes the sprite not to get out of the screen at both sides
sprite.Pos.X = (float) ( (0.1f + 0.8f * rnd.NextDouble()) * GraphicsDevice.Viewport.Width);
sprite.Pos.Y = (float) ( rnd.NextDouble() * 300 );
Sprites.Add(Sprite);
}
}
Of course de Sprite class depends on you.. :)
I've written a home-brew view_port class for a 2D strategy game. The panning (with arrow keys) and zooming (with mouse wheel) work fine, but I'd like the view to also home towards wherever the cursor is placed, as in Google Maps or Supreme Commander
I'll spare you the specifics of how the zoom is implemented and even what language I'm using: this is all irrelevant. What's important is the zoom function, which modifies the rectangle structure (x,y,w,h) that represents the view. So far the code looks like this:
void zoom(float delta, float mouse_x, float mouse_y)
{
zoom += delta;
view.w = window.w/zoom;
view.h = window.h/zoom;
// view.x = ???
// view.y = ???
}
Before somebody suggests it, the following will not work:
view.x = mouse_x - view.w/2;
view.y = mouse_y - view.h/2;
This picture illustrates why, as I attempt to zoom towards the smiley face:
As you can see when the object underneath the mouse is placed in the centre of the screen it stops being under the mouse, so we stop zooming towards it!
If you've got a head for maths (you'll need one) any help on this would be most appreciated!
I managed to figure out the solution, thanks to a lot of head-scratching a lot of little picture: I'll post the algorithm here in case anybody else needs it.
Vect2f mouse_true(mouse_position.x/zoom + view.x, mouse_position.y/zoom + view.y);
Vect2f mouse_relative(window_size.x/mouse_pos.x, window_size.y/mouse_pos.y);
view.x = mouse_true.x - view.w/mouse_relative.x;
view.y = mouse_true.y - view.h/mouse_relative.y;
This ensures that objects placed under the mouse stay under the mouse. You can check out the code over on github, and I also made a showcase demo for youtube.
In my concept there is a camera and a screen.
The camera is the moving part. The screen is the scalable part.
I made an example script including a live demo.
The problem is reduced to only one dimension in order to keep it simple.
https://www.khanacademy.org/cs/cam-positioning/4772921545326592
var a = (mouse.x + camera.x) / zoom;
// now increase the zoom e.g.: like that:
zoom = zoom + 1;
var newPosition = a * zoom - mouse.x;
camera.setX(newPosition);
screen.setWidth(originalWidth * zoom);
For a 2D example you can simply add the same code for the height and y positions.
Corona has a method for creating images that will be displayed dynamically based on device resolution:
img = display.newImageRect("image.png", 100, 100)
Great, but what if all your images are in a sprite sheet, which is recommended for performance? Then you have to do something like this to display the image:
local data = require("sheet1")
local tileSheet = sprite.newSpriteSheetFromData("sheet1.png", data.getSpriteSheetData())
local tileSet = sprite.newSpriteSet(tileSheet, 1, 3)
local img = sprite.newSprite(tileSet)
img.currentFrame = 1
How do you create dynamically sized images from sprite sheets?
use display.contentScaleX http://developer.anscamobile.com/reference/index/displaycontentscalex
here's how http://developer.anscamobile.com/forum/2010/12/08/dynamic-retina-spritesheets-heres-how
Here's how I resized my background animation. It consisted of 2 frames, each 794 x 446. It needed to be full-screen, landscape mode. Refer to step 6 below.
--> Initialize background animations
-- 1. Data = define size and frames
local bgData = { width=794, height=446, numFrames=2, sheetContentWidth=1588, sheetContentHeight=446 }
-- 2. Sheet = define the sprite sheet
local bgSheet = graphics.newImageSheet( "hkc.png", bgData )
-- 3. Animation = define animation characteristics
local bgAnim = {
{ name = "bgAnimation", start = 1, count = 2, time = 800, loopCount = 0, -- repeat forever
loopDirection = "forward"
}
}
-- 4. Display the sprite (can't set size here unlike display.newImageRect)
local bg = display.newSprite( bgSheet, bgAnim )
-- 5. Center the animation
bg:setReferencePoint( display.CenterReferencePoint )
bg.x = display.contentCenterX
bg.y = display.contentCenterY
-- 6. Resize to match screen size based on a ratio with the actual background pixel dimensions
bg:scale( display.contentWidth / 794, display.contentHeight / 446 )
-- 7. Play the animation
bg:play()