I have an SKEmitterNode on my scene, when I increase the particles on update, the amount of particles being shown are not increasing. I am not sure what step I am missing.
The code is really simple:
Create any kind of default particle from Xcode.
Set birthrate to 1, max to 0
Everything else doesn't really matter.
On GameScene update:
func update(currentTime: NSTimeInterval) {
//whatever it takes to get the particle from the scene
let particles = childNodeWithName("particles") as? SKEmitter
particles!.particleBirthRate = particles!.particleBirthRate + 1;
}
Note: When doing a print, the birth rate does increase, so I know it is not using a copy
Related
I am making my first 3d fps in Godot and I don't understand how to spawn enemies in a general area. If someone could show me a tutorial or something that would be great.
Make a scene with only your enemy character, Give it control scripts as needed (movement, etc), and save it as a scene (Ex: myEnemy.tscn).
In your main script (or wherever you're calling it from), load the enemy scene and store it as a variable by writing:
onready var loadedEnemy = preload("res://myEnemy.tscn")
Then in your _process() or _ready() function (depending on what you need it for):
Instance the enemy by writing
var enemy = loadedEnemy.instance()
Add the instance to the scene with
add_child(enemy)
3.Specify the location of the enemy placement. For a random placement somewhere in a 10 x 10 area on the ground level (Y=0) by writing
enemy.transform.origin = Vector3( rand_range(0,10), 0, rand_range(0,10) )
You can also specify rotation with
enemy.transform.basis = Vector3(90deg, 0, 0) (example)
You can add more enemies by repeating these steps beginning from var enemy = loadedEnemy.instance() (Ex: The next enemy would be var enemy2 = loadedEnemy.instance())
If you need them to appear at different times, add them in the on_timer_timeout() function of a different Timer nodes.
Good Luck
I'm making a little game using swift, a Snake Game. I've already tried to do this game using python and it worked! To run the game I used a while loop. In this way, I could always change the player position and check if he had hit the margins. Now I have to do this again, but I don't know how to tell to my program to check all the time if the snake has hit the margins or himself.
I should do something like that
if player.position.x <= 0 || player.position.x >= self.size.width || player.position.y <= 0 || player.position >= self.size.height{
death()
}
So, if the player position on x or y axis is major than the screen size or minor than 0, call the function "death()".
If I had to do this with python, I'd have just put all this code inside the "main while loop". But with swift there's not a big while I can use... any suggestions?
Use SpriteKit. You can select this when creating a new project, choose Game, and then select SpriteKit. It's Apple's framework to make games. It has what you will need, and is also faster - don't make games in UIKit.
Within SpriteKit, you have the update() method, as part of SKScene. Do NOT use a while loop. These are highly unreliable, and the speed of the snake will vary between devices.
Here is a small piece of code to help you get started on the SKScene:
import SpriteKit
class Scene: SKScene {
let timeDifference: TimeInterval = 0.5 // The snake will move 2 times per second (1 / timeDifference)
var lastTime: TimeInterval = 0
let snakeNode = SKSpriteNode(color: .green, size: CGSize(width: 20, height: 20))
override func update(_ currentTime: TimeInterval) {
if currentTime > lastTime + timeDifference {
lastTime = currentTime
// Move snake node (use an SKSpriteNode or SKShapeNode)
}
}
}
After doing all this, you can finally check if the snake is over some margins or whatever within this update() loop. Try to reduce the code within the update() loop as much as possible, as it gets run usually at 60 times per second.
If I understood you correctly: You are looking for a loop in Swift that does all the calculation and drawing for your game. Here you have some tutorials about loops in Swift. In fact there are while loops that you could use in order to answer your question. I hope I could help.
I'm getting values for zRotation less/greater than -/+pi with Swift3 (e.g. 7.41137313842773, in radians at about 0,5Pi). It happens when rotating a node using the approach described below.
Code is
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
newLocation = touch.location(in: self)
turnAngle = atan2(newLocation.y - lastLocation.y - mySprite.position.y, newLocation.x - lastLocation.x - mySprite.position.x)
mySprite.run(SKAction.rotate(byAngle: turnAngle, duration: 0.1))
lastLocation = newLocation
print("mySprite zRotation: \(mySprite.zRotation)")
}
}
I also notice a jittery jump in the sprite at the point when the sprite is rotated to pi/2 (absolute). If this is normal behaviour, is there a way to recalculate zRotation between -/+Pi or 0-2Pi?
I believe in your code there are two point to analyze:
SKAction and zRotation.
The first (SKAction) should be considered in general (not about this issue). If you want to launch an SKAction like 'rotate' inside a cycle, because it have a duration you should check if this action is finished before to launch another. An example:
extension SKNode
{
func actionForKeyIsRunning(key: String) -> Bool {
return self.action(forKey: key) != nil ? true : false
}
}
if !self.mySprite.actionForKeyIsRunning(key: "rotation") {
self.mySprite.run(SKAction.rotate(byAngle: turnAngle, duration: 0.1),withKey:"rotation")
}
Speaking about zRotation and your issue the reason you have a wrong zRotation value is because you are using an action. zRotation is a node property: properties of nodes undergoing animation are not updated at each step in the simulation. You can set zRotation to rotate your node:
self.mySprite.zRotation = turnAngle
or create a physics body and set the angular velocity.
For more details about SKAction and node properties look the official Apple doc where there is this note:
When You Shouldn’t Use Actions
Although actions are efficient, there is a cost to creating and
executing them. If you are making changes to a node’s properties in
every frame of animation and those changes need to be recomputed in
each frame, you are better off making the changes to the node directly
and not using actions to do so. For more information on where you
might do this in your game, see Advanced Scene Processing.
As #PietroPepe has pointed out, you are stacking actions one on top of the other. Let's break down your code:
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
for touch in touches {
This tells us that your touch calls will be done multiple times throughout the life cycle of your touch. Even with a quick touch down and up action, it is very possible to go through at least 2 calls on this method.
newLocation = touch.location(in: self)
turnAngle = atan2(newLocation.y - lastLocation.y - mySprite.position.y, newLocation.x - lastLocation.x - mySprite.position.x)
The point of this code is to have the sprite move at the change of the touch from last position to current position
mySprite.run(SKAction.rotate(byAngle: turnAngle, duration: 0.1))
lastLocation = newLocation
print("mySprite zRotation: \(mySprite.zRotation)")
}
}
Finally this point of the code says do it in 1/10th of a second.
Now let's run through a scenario. We touch the screen, move it, and let go.
The amount of time it took to perform it was 4 frames, this means 1 touchBegan, 2 touchMoved, and 1 touchEnded.
in our toucheMoved events, we calculate a change of 60degrees, each time.
Now a frame is 1/60th of a second keep in mind.
Our rotation event will take 1/10th of a second to go from 0 to 60, so 6/60th seconds, 6 frames.
This means every frame we are moving 10 degrees.
Now we come to the second frame of the rotateBy.
The same logic as the first frame above will apply, so we will now have another series of rotations that will be moving by 10 degrees.
This mean we now have 2 events rotating our sprite at 6 degrees each.
So the timeline is as followed:
Frames: 0 1 2 3 4 5 6 7
+10 +10 +10 +10 +10 +10
+10 +10 +10 +10 +10 +10
Notice the inconsistent behaviors between the end and the beginning of your rotation? This is why things look all screwy.
Now, I am not sure of the desired effect you are looking for, but if I were to be doing this, I would be setting zRotation instead of using actions.
If you are looking for a delayed effect, then use the withKey parameter on the run function so that you only have 1 action running, and use SKAction.rotateTo to have the sprite always rotating to the last possible touch location. This of course means you need to keep track of when touch first began, not when last touched.
This also gets a little tricky depending on desired effect, because you may need to keep track of the time that has elapsed between the number of touchesMoved events called and apply the time difference to your duration, so basically duration:.01 - timeSinceTouchBegan,
I am making a game with SpriteKit where I have nodes spawning at the top of the screen and falling. However, I want these nodes to spawn at a random time interval between 0.1 and 3 seconds. For example, the first node spawns in 1.3 seconds, the next in 1.8, then 2.5, then 0.8, and so forth forever. I'm not sure how to utilize the waitForDuration function to do this. The code that I currently have is:
let wait = SKAction.waitForDuration(3, withRange: 2)
let spawn = SKAction.runBlock { addTears()
}
let sequence = SKAction.sequence([wait, spawn])
self.runAction(SKAction.repeatActionForever(spawn))
This code freezes my game when I try to run it. I removed the addTears() and put a log, and there was an infinite loop on the log. I need to know how to get rid of this.
The code for my addTears() func is:
func addTears() {
let Tears = SKSpriteNode (imageNamed: "Tear")
Tears.position = CGPointMake(Drake1.position.x, Drake1.position.y - 2)
Tears.zPosition = 3
addChild(Tears)
//gravity
Tears.physicsBody = SKPhysicsBody (circleOfRadius: 150)
Tears.physicsBody?.affectedByGravity = true
//contact
Tears.physicsBody = SKPhysicsBody (circleOfRadius: Tears.size.width/150)
Tears.physicsBody!.categoryBitMask = contactType.Tear.rawValue
Tears.physicsBody!.contactTestBitMask = contactType.Bucket.rawValue
}
If I remember well, the waitForDuration:withRange: method works like so :
if you put a duration of 3 (seconds) and a range of 1 seconds the random value that you get will be between 2 and 4 seconds. That said, you should use those value for what you described : let wait = SKAction.waitForDuration(1.55, withRange: 1.45)
For the freeze problem, if you pasted your code correctly here the problem come with this line self.runAction(SKAction.repeatActionForever(spawn)) where you should instead be calling your sequence like this : self.runAction(SKAction.repeatActionForever(sequence)).
PS : At a certain point you still might want to control the amount of tears on screen at the same time.
Let me know if it helped.
Alright I'm offically stumped. I've been able to figure out my problems myself in the past but I'm lost on this one.
I'm trying to flip a child sprite's xscale. I want the flip to occur when the child's x position is negative. With the code below, the sprite does flip, every time the sprite reaches negative position, it loops back and forth flipping until reaching positive again.
I've tried numerous variations, but this is the code in it's simplest form. Any help or alternatives would be appreciative.
override func update(currentTime: CFTimeInterval) {
/* Called before each frame is rendered */
let pin = childNodeWithName(Pin1) as SKSpriteNode!
let guyPoint = guy.convertPoint(guy.position, fromNode: pin)
if guyPoint.x <= 0 {
guy.xScale = -1
}
else {
guy.xScale = 1
}
}
So if it is constantly flipping it's probably an issue of coordinate space. So check to make sure your convertPoint method is accurately returning the point you want. I would use println() to see what's going on there.
Probably what's happening is you want to flip the xScale when the child node is negative in the scene space or something (i.e. when the child is off the screen) but instead guyPoint might be the position of the child in its parent's coordinate space (so relative to the parent).
Also try with and without the else{} part to see if that changes anything.