I'm using SpriteKit, and I'm having trouble getting one of my objects to shoot out another object, without colliding with it at the moment that it shoots it. However, as soon as they are no longer within range of contact each-other, I want them to be able to contact with each-other for the rest of the game.
Here is what I have tried-
var allCategory: UInt32 = 1;
var nillCategory: UInt32 = 2;
var bufferNode: SKNode?
bufferNode = self.childNodeWithName("player")
bufferNode!.physicsBody!.collisionBitMask = nillCategory;
bufferNode!.physicsBody!.categoryBitMask = nillCategory;
shootNewPlayer(touchLocation)
runAction(SKAction.sequence([SKAction.waitForDuration(1),SKAction.runBlock(removeBuffer)]))
}
func removeBuffer(){
bufferNode!.physicsBody!.collisionBitMask = allCategory;
bufferNode!.physicsBody!.categoryBitMask = allCategory;
}
By default, all my objects in the scene have a collisionBitMask and categoryBitMask of "allCategory." My solution was to temporarily change its categories to nill. This had absolutely no affect. I also want to avoid this solution since for 1 second the player would no longer interact with objects, which could cause bugs (With the code above it still interacts).
Any ideas on how I can get the object to shoot a new player without it flying off in a bazaar direction? Thanks!
Turn off object2 collision by default. (Do this with collisionBitMask = 0)
Enable object contactBitMask with the flag for object1.
On the didEndContact Method, enable the collision object2 for object1 when the condition of object1 contacting object2 is met.
This will allow you to avoid things like timers and checking the update loop constantly.
In English, you are saying: When object 2 no longer is touching object 1, object 2 is now able to collide with object 1.
Depending on circumstance, you may want to remove the contact test after you enable collision
Related
I'm new to Lua. I'm trying to create a game using Cocos2d-x v3.1rc0.
I'm running into an issue where it appears that one of the objects, created by the Cocos2d-x lib, is being garbage collected before it should be.
Here is a class to keep track of "prey" on the screen. Each prey references frames/animations that will be displayed depending on the state of the prey.
Prey = {
sprite = false -- Main prey sprite.
-- Frames used for movement, getting hit, knocked out, etc.
, frame = {
idle = false -- idle frames
, move = false -- move frames
, rest = false -- resting frames
}
, state = false -- The current state of the Prey.
}
Here is the constructor:
function Prey:new()
local o = {}
setmetatable(o, self)
self.__index = self
return o
end
Here is where the frames are associated to the prey:
function Prey:setFrames(frames)
--[[ Moving ]]--
self.frame.move = cc.Animation:createWithSpriteFrames({frames[1], frames[2], frames[3]}, 1.0)
cclog("move frames: " .. #self.frame.move:getFrames())
--[[ Resting ]]--
self.frame.rest = cc.Animation:createWithSpriteFrames({frames[4], frames[5]}, 2.0)
cclog("rest frames: " .. #self.frame.rest:getFrames())
end
The above will print the following:
cocos2d: [LUA-print] move frames: 3
cocos2d: [LUA-print] rest frames: 2
However, when I attempt to call the following method, the frame.move and frame.rest variables appear to be garbage collected because an error is raised when I attempt to access them. Please note that this method is called every tick:
function Prey:tick()
cclog("state: " .. self.state)
local animation = false
-- Moving
if (self.state == PreyState.MOVING)
then
cclog("moving: " .. #self.frame.move:getFrames())
animation = self.frame.move
elseif (self.state == PreyState.RESTING)
then
cclog("resting: " .. #self.frame.rest:getFrames())
-- Resting
animation = self.frame.rest
end
end
When the cclog calls are being made for either of the two conditions the following error is displayed. Please note that I know that this specific instance of Prey has not been garbage collected because self.state was set to idle before I made the call to the tick method. It also retains self.state on subsequent calls to this method.
cocos2d: [LUA-print] state: 2
cocos2d: [LUA-print] ----------------------------------------
cocos2d: [LUA-print] LUA ERROR: [string "Prey.lua"]:189: invalid 'cobj' in function 'lua_cocos2dx_Animation_getFrames'
After looking at many articles describing how objects are retained, it appears that it's possible that my Animation object is being garbage collected. But I have no idea why! The reference to the Cocos2d-x object should be strong, right?
Here are some articles I've read regarding the subject:
http://www.tutorialspoint.com/lua/lua_object_oriented.htm
http://lua-users.org/wiki/WeakTablesTutorial
http://www.lua.org/pil/17.html
http://phrogz.net/lua/LearningLua_ValuesAndMetatables.html
http://lua-users.org/wiki/GarbageCollectionTutorial
UPDATE 1
The following code is what causes the issue:
-- Create the instance of our prey object here...
prey = new Prey:new()
local function tick()
prey:tick()
end
scheduleID = cc.Director:getInstance():getScheduler():scheduleScriptFunc(tick, 0, false)
However, when I attempt to simply call prey:tick() outside of the scheduler I get NO errors. I need this code to be ran every tick... what am I missing? In this particular scenario I have made the prey a global variable so that the tick method could access the only instance of Prey. I did this to simplify this particular test. However, I'd like to make prey local and make the scheduler run the tick function for every instance of Prey.
The objects are being garbage collected. I have ran several more tests and came to the conclusion that you can not associate any Cocos2d objects to a variable without them later being garbage collected on the next cycle. Instead, you have to use Cocos2d-x's libs to cache your textures and then query for those textures at the time you need them.
It's difficult to illustrate, but what the end result was to call cc.Director:getInstance():getTextureCache():getTextureForKey("texture.png") at the time I needed the texture and re-create the frames needed for each animation when the state changed for the object. I'm going to look for a way to cache sprites so I don't have to re-create them. However, this resolved my issue. So the lesson is that Cococ2d objects get garbage collected on the next cycle. The only objects that are retained are those that are cached internally by Cocos2d. I could be wrong about this, but this is what I have observed.
So my process is to first add the image to the texture cache at load time:
local texture = cc.Director:getInstance():getTextureCache():addImage("texture.png")
And then calling the following later on:
local texture = cc.Director:getInstance():getTextureCache():getTextureForKey("texture.png")
I would really appreciate any insight into this. How are you guys handling this? Is this the right process? Are there any articles related to caching sprites, textures, etc for later use? Thank you!
UPDATE 1
Yes. The objects are being released from within the Cocos2d-x library. You can get around this by caching the sprite frames. This is the code I used, in Lua, to cache the sprite frames. After they are cached, any reference you hold to the SpriteFrame, from within your Lua code, will continue to point to an active instance of the frame.
cc.SpriteFrameCache:getInstance():addSpriteFrame(frame, name)
And to get the SpriteFrame back out of the cache:
local frame = cc.SpriteFrameCache:getInstance():getSpriteFrame(name)
I'm creating a bukkit plugin and it requires lighting to be added and I want to be able to accomplish this server side only so that users don't need special plugins to see the lighting. Could this be done? If I'm not mistaken rendering lighting has been server side before? I would also like this lighting to be colored and lighting sources to be invisible (lighting from coordinates is acceptable since the map will be set)
My fear, can it be done?
You could do this using:
p.sendBlockChange(Location, Material, Byte);
Location is the location of the block
Material is the material that you want the player to see
the Byte is the data, so in the block 43:8, you would use 8. If there is none, just use 0.
So, you could do this to send the block update to all players:
Location[] invisibleBlocks; //all Invisible locations
for(Player p : Bukkit.getOnlinePlayers()){ //get all online players
for(Location l : invisibleBlocks){ //get all invisible blocks
p.sendBlockChange(l, Material.AIR, 0); //send block change of AIR to the player
}
}
The only problem is that block changes get reset when a player unloads/loads the chunk that the change is in. So, to fix this, you could schedule a timer:
Location[] invisibleBlocks; //set this to the locations of all of the blocks you want to make invisible
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable(){
public void run(){
for(Player p : Bukkit.getOnlinePlayers()){ //get all online players
for(Location l : invisibleBlocks){ //get all invisible blocks
p.sendBlockChange(l, Material.AIR, 0); //send block change of AIR to the player
}
}
}
},100);//delay time is 5 seconds (5 seconds * 20 ticks per second)
Then all you need to do is put glowstone in the the invisibleBlocks locations, and it will appear as air, but (should) still emit light.
One problem with this is that if a player tries to walk into the block, they will walk in half way, then get teleported back out. This is because the client thinks there isn't a block there, yet the server knows that there is, and when the player walks into the block, the server teleports them back out, making a jerky kind of motion.
If you put this somewhere where players can't walk into it, you should be good!
Have been working on a Tower Defense game for iOS for some time now. I am using Cocos2d (v0.99.5 not to sure). Recently started to get into some problems when I started remove sprites.
Have profiles using instruments and Zombies and here's what I get:
The code for updating the sprites (and also delete them) is located in update:
-(void) update:(ccTime)deltaTime {
if (paused)
return;
CCArray *childs = [textureAtlas children];
//Update all objects
for (GameSprite *tempChar in childs) {
if ([tempChar respondsToSelector:#selector(updateStateWithDeltaTime:andListOfGameObjects:andAtlas:)]) {
[(GameSprite*)tempChar updateStateWithDeltaTime:deltaTime andListOfGameObjects:[textureAtlas children] andAtlas:textureAtlas];
}
}
//Remove dead projectiles
for (GameSprite *tempChar in childs) {
if ([tempChar isKindOfClass:Projectile.class]) { //(**)
if (![tempChar alive]) {
[tempChar remove];
}
}
}
//Remove dead towers
for (GameSprite *tempChar in childs) {
if ([tempChar isKindOfClass:Tower.class]) {
if (![tempChar alive]) {
[tempChar remove];
}
}
}
//Remove dead creeps
for (GameSprite *tempChar in childs) {
if ([tempChar isKindOfClass:Creep.class]) {
if (![tempChar alive]) {
[tempChar remove];
}
}
}
}
The remove method in GameSprite.m :
-(void)remove {
CCLOG(#"remove");
[self removeFromParentAndCleanup:YES];
}
The first block updates the sprites in the SpriteBatchNode/textureAtlas. The three remaining blocks checks the different objects if the should be deleted. (their alive-variable set to NO?). The reason I have three blocks of different types is due to the fact that projectiles have (weak) reference to creep they are shooting at and needs to be deleted before the creep.
So my problem is that it randomly crashes when a projectile hits a creep and the projetile (and all other projectiles shooting at that creep) are to be removed). The creeps reference count gets down to 0 but seems to still be in the childs array. Cause the error I get is:
*** -[NormalProjectile isKindOfClass:]: message sent to deallocated instance 0xff33e30
on the row I marked with (**)
Either the problem is with me understanding Cocos2d's removeFromParentAndCleanUP: or that my "solution" for handling the projectile-creep-relationship is bad from a memory point of view. Any ideas on how to solve this or debug it further?
Your fast enumeration techniques for going through the array are casting all your sprites in that array as a custom subclass of CCSprite, then checking to see if they are instead a different custom subclass, like Tower, etc. I don't see this as healthy programming practice, since methods in one class may not be in the other, yet you are casting them nonetheless.
That may or may not be contributing to your issue, but a wiser approach is to keep an assign iVar CCArray for children of a specific class. i.e. put all your projectiles into one array at the time they are created and added to the batch node then you can iterate through all projectiles, towers, etc by going through those individual arrays, where you know what kind of class they already are. Then remove them from the array as well as from the parent when necessary. I would think this is quite a bit safer than going through all the game's sprites in their entirety that are in your batchnode, which may include spites not being used, perhaps, and casting them and testing them as different classes.
I'm new to Corona. I'm not sure how to solve this.
In main I am creating 2 local objects, player and enemy.
Player has a function called takeDamage.
When I try to call player.takeDamage from within enemy, it can't see the function.
I presume it's because main owns both objects and they don't know about each other.
How can I have Enemy call that function so that it can deal damage to Player?
main.lua contains:
-- Create player character
local player = require("player");
player = player.new();
-- Create enemy character
local enemy = require("enemy");
enemy = enemy.new();
I think I could make player global, but from what I know, that would not be a best practice.
Any help would be greatly appreciated.
If it is safe to assume that there will be only one "player" instance, you can make it global. Otherwise, you would have to do something along these lines:
-- main.lua
local player = require 'player'.new()
local enemy = require 'enemy'.new()
enemy:setPlayer(player)
-- enemy.lua
...
function enemy:setPlayer(player)
self.player = player
end
And later use self.player in the enemy code to reference the player. Note that this will consume memory, because the player reference will be copied to every enemy instance.
One side note, I do not consider it good to call a module and an instance the same, i.e. player. It will become unclear later if you mean the module, or the instance. A safe way would be to call the modules as Player and Enemy, and the code will look like this:
Player = require 'Player'
local player = Player.new()
Ideally, you don't want the player referencing the enemy directly or the enemy referencing the player. Instead, you could poll each participant in a game loop and update the game state based on the result.
local player = make_player()
local enemy = make_enemy()
--game loop - in a real game this isn't a busy while
while true do
local move = player.move()
local result = validate_move(move)
if result.is_valid then
update_position(player, result)
end
move = enemy.move()
result = validate_move(move)
if result.is_valid then
update_position(enemy, result)
end
local attack = player.attack()
local attack_result = validate_attack(attack)
if attack_result.hit then
update_health(enemy, attack_result)
end
-- more game logic here
render(player)
render(enemy)
end
In a real game, state change would be driven by events - touch events, drawing events, etc. My busy loop (while true do) illustrates the general idea.
You'll also have to use your imagination for missing implementation.
There are many ways to model a game. I'm not suggesting this is the best. It does, however, show one way of decoupling interacting elements.
Okay, here's the rub. I'm making a little maze game. In this maze game, I have walls. They link to a class called Wall.as. In order to collision detect with the player, I do this:
MovieClip(parent).checkCollisonWithPlayer(this);
Where (parent) is a manager logic class. The parent does this
public function checkCollisonWithPlayer(wall:MovieClip)
{
if(player != null)
{
Collision.block(player,wall);
}
}
Now here's my problem. I have a class of Bullet.as that does much the same thing:
private function onEnterFrame(event:Event):void
{
x+= _vx;
//Check for collisions with walls and enemies
MovieClip(parent).checkCollisionWithEnemies(this);
//Remove if it leads off the stage
if (x > stage.stageWidth)
{
parent.removeChild(this);
}
}
What if I wanted to check for a collision between one of these bullets() and one of these walls()? How can I do that? They're never in the same function at the same time and there's almost certainly more than one of each in play at any time. I'm new to AS and this feels like a common issue, but I couldn;t dig up any material that made sense.
Here;s what I need:
public function checkCollisonWithWall(wall:MovieClip,bullet:MovieClip)
{
if(bullet.hitTestObject(wall))
Collision.block(bullet,wall);
}
}
But of course that doesn't work. What are my options?
On a simple level:
1) separate out physics from everything else: it makes things easier and more reusable.
2) have each physics object register itself with, say, a physics manager. things that you need to keep track of are if the object is static or dynamic (moving) and maybe even a shape flag (if you only wanted to collide certain objects with other objects). a shape flag is simply an int that tells you what type it is
3) have one onEnterFrame event, not an enter frame for each object. this will make your life easier
4) on this single onEnterFrame event, call on your physics manager to update the objects and see if any are colliding. You can to check collisions between static and dynamic objects, and (possibly) dynamic objects against other dynamic objects. You can use shape flags to cull out unnecessary tests. If you find a collision, you can dispatch an event/notify your objects/remove them from the game whatever.
something like
private function _init():void
{
// create 4 walls
for( var i:int = 0; i < 4, i++ )
{
var w:Wall = new Wall;
// position and add to stage etc
// add it to the physics manager (they don't need an update)
this._physicsManager.addStatic( w, ShapeFlags.WALL );
}
// create 10 bullets
for( i = 0; i < 10; i++ )
{
var b:Bullet = new Bullet;
// position and add to stage etc
// add it to the update and physics manager
this._updateManager.add( b );
this._physicsManager.addDynamic( b, ShapeFlags.BULLET ); // ShapeFlags is a static class of different types of objects
}
}
private function _onEnterFrame( e:Event ):void
{
// if you're moving your objects based on time, then
// dt is "delta time", i.e., the amount of time that
// has passed since the last update
// you can have an update manager that will move your
// different objects according to their speed.
this._updateManager.update( dt );
// now your objects have moved to their new position,
// get the physics manager (though in fairness, if it's
// only doing collisions, then it should just be a
// collisions manager) to check for collisions
this._physicsManager.update();
// do whatever else
}
This is a very simple example. Here, we're moving objects, then checking for collisions. You could possible run into problems with objects that are moving too fast and passing through each other, so no collision is registered. Something like this:
// frame one: object a is heading towards object b
// and object b is heading towards object a
(a)-> <-(b)
// frame two: because of their speed, they pass through
// each other, and you don't see a collision
<-(b) (a)->
This system is the easiest and simplest way to do this and is probably fine for a lot of games. If you want more complicated (as in checking for collisions between frames), then it's a bit more complicated, but you can still build on this.
Collision detection/response is a big topic, and you can find hundreds of code examples around the net. A good code structure can make the world of difference however.
It looks like the parent manager class has permanent references to the player and the enemies that it uses for collision detection. So also give it references to the walls and bullets.