I am currently working on a simple game in Sprite Kit. In the game, you are a square that moves around and can shoot at enemies. You shoot "Projectiles" which are just a custom class that inherits from SKSpriteNode. The game works great at first but slowly as you continue shooting the FPS rate slowly deteriorates to extremely low. As the projectiles leave the screen however the Node count goes back down to what it was originally before the projectile was fired.
The first thing I tried to fix it was somehow release the projectiles from the scene when they hit the edge. Here is the code where I attempt to do so but it has not worked at all.
-(void)didBeginContact:(SKPhysicsContact *)contact {
if (contact.bodyA.categoryBitMask == projectileCategory) {
if (contact.bodyB.categoryBitMask == edgeCategory) {
[contact.bodyA.node removeFromParent];
}
} else if (contact.bodyA.categoryBitMask == edgeCategory) {
if (contact.bodyB.categoryBitMask == projectileCategory) {
[contact.bodyB.node removeFromParent];
}
}
}
To improve performance, you can remove the projectiles when they are out of the screen inside the update function.
override func update(currentTime: CFTimeInterval) {
for node in self.children as [SKNode] {
if node.name == "projectile" {
if !CGRectContainsPoint(self.frame, node.position)
{
println("removed")
node.removeFromParent()
}
}
}
}
Related
I'm developing camera app right now.
I finished most of important features but the most important feature left.
I want my app auto exposure mode.
Here is my sample.
do {
try camera.lockForConfiguration()
camera.focusMode = .continuousAutoFocus
camera.exposureMode = .continuousAutoExposure
camera.unlockForConfiguration()
} catch {
return
}
I made this setting between lockForConfiguration and unlockForConfiguration.
This lead to autoexposure, however it is different from native camera app.
Also, shutter speed does not go below 1/40.
It is always 1/40 whenever it is in dark environment.(where native camera app adjust shutter speed to 1/2 or even 1)
I found the answer here (https://developer.apple.com/forums/thread/26227)
But I don't understand this answer and even how to do that...
session.beginConfiguration()
defer {
session.commitConfiguration()
}
device = AVCaptureDevice.default(.builtInDualWideCamera, for: .video, position: .back)
guard let camera = device else {
set(error: .cameraUnavailable)
status = .failed
return
}
I set AVCapturedevice in this code. Also there is a session.
The answer says don't touch sessionpreset, so I did do anything by sessionPreset.
But how can I set the avcapturedevice by activeformat..?
This is very hard to understand.
Just to check if this is work, I added this codes just below above codes.
'''
var bestFormat: AVCaptureDevice.Format?
bestFormat = device!.formats[2]
print(self.device?.formats)
do {
try camera.lockForConfiguration()
camera.focusMode = .continuousAutoFocus
camera.exposureMode = .continuousAutoExposure
camera.activeFormat = bestFormat!
// camera.setExposureModeCustom(duration: CMTime(value: 1, timescale: 500), iso: 2000)
camera.unlockForConfiguration()
} catch {
return
}
'''
I believe this does not work because camera-resolution doesn't change.
even if device!.formats[2] is low resolution for me (I checked it)
My son and I are trying to implement one of the fun-science.org microbit tutorials - building a "tug of war" game. Essentially, 10 presses on button A moves the sprite closer to that button and the same applies on button B. When you hit the edge of the screen, music plays and a message is scrolled on the screen before the game restarts.
We've got it fully working, but once the game has been won, it doesn't seem to reset properly. It works fine on the simulator, but not on the physical device (a microbit 2).
Once the game is won, the behaviour is erratic. It usually puts the sprite back in the middle, sometimes not, but frequently, one button doesn't work in the next game. Occasionally both stop working. In every situation, a restart fixes things.
Is there something wrong with the code? I've wondered whether the music / message is corrupting something and I need to put a wait in for it to complete. I've re-downloaded the hex file and re-flashed the microbit several times, so I think I've eliminated a corrupt code file.
Javascript version of code shown below, but it was actually built in blockly using the Microsoft MakeCode tool.
input.onButtonPressed(Button.A, function () {
sprite.change(LedSpriteProperty.X, -0.1)
})
input.onButtonPressed(Button.B, function () {
sprite.change(LedSpriteProperty.X, 0.1)
})
let sprite: game.LedSprite = null
sprite = game.createSprite(2, 3)
basic.forever(function () {
if (sprite.get(LedSpriteProperty.X) == 0) {
music.startMelody(music.builtInMelody(Melodies.Birthday), MelodyOptions.Once)
basic.showString("liverpool wins")
sprite.set(LedSpriteProperty.X, 2)
} else if (sprite.get(LedSpriteProperty.X) == 4) {
music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once)
basic.showString("rb leipzig wins")
sprite.set(LedSpriteProperty.X, 2)
}
})
I found it was more reliable if I did game.pause() and game.resume() while scrolling the text and playing the music at the end of the game:
input.onButtonPressed(Button.A, function () {
sprite.change(LedSpriteProperty.X, -0.1)
})
input.onButtonPressed(Button.B, function () {
sprite.change(LedSpriteProperty.X, 0.1)
})
let sprite: game.LedSprite = null
sprite = game.createSprite(2, 3)
basic.forever(function () {
if (sprite.get(LedSpriteProperty.X) == 0) {
game.pause()
music.startMelody(music.builtInMelody(Melodies.Birthday), MelodyOptions.Once)
basic.showString("liverpool wins")
game.resume()
sprite.set(LedSpriteProperty.X, 2)
} else if (sprite.get(LedSpriteProperty.X) == 4) {
game.pause()
music.startMelody(music.builtInMelody(Melodies.Entertainer), MelodyOptions.Once)
basic.showString("rb leipzig wins")
game.resume()
sprite.set(LedSpriteProperty.X, 2)
}
})
You can also take a look at the following version of the game that does not use the game rendering engine https://makecode.microbit.org/projects/tug-of-led to see if that makes a difference.
I am designing a app to receive data from BLE device.
and there is a textView to show what the data the app received.
Everything is okay, but when I press the button on the corner left to second scene and then back to the first scene, the data doesn`t show on the textView anymore. But from debug area I could see the app is receiving data
here`s the part of code on showing data on TextView
func peripheral(peripheral: CBPeripheral, didUpdateValueForCharacteristic characteristic: CBCharacteristic, error: NSError?) {
print("did update")
if let error = error {
print("Error discovering services: \(error.localizedDescription)")
return
}
if let stringFromData = String(data: characteristic.value!, encoding: NSUTF8StringEncoding) {
if stringFromData.rangeOfString("tem:") != nil {
print("tem")
print("Received: \(stringFromData)")
textView.text = stringFromData
} else if stringFromData.rangeOfString("gas:") != nil{
print("gas reveived")
print("Received: \(stringFromData)")
textView.text = stringFromData
} else {
print("format wrong")
}
}
}
here`s the shot images of the app
before re-enter application image
after re-enter application image
hope to get the answer, thank you
I found a possible solution to fix this problem.
I add an action to the button,
#IBAction func onSettingButton(sender: UIButton) {
centralManager.cancelPeripheralConnection(discoveredPeripheral!)
}
when I press button on the first scene, it will cancel BLE Connection, and when I back to the first scene, viewDidLoad() will initial bluetooth setting. therefore and the problem is solved.
But I still want to know why this case happen?
Hopefully this is a fairly simple question. I create an instance variable named tutorialBox1 from my main game scene Grid.m. Inside my class TutorialBox.m, I create a sprite named textBox1, and as I tap on the main game scene, I want the position of that sprite, textBox1 to be updated. I've been trying to figure out for hours why the position of the sprite will not update after adding the child once. Here is my attempt, and all the necessary code.
Grid.m
# implementation Grid {
TutorialBox *tutorialBox1;
}
-(void)checkTutorials {
//This method is called upon loading of the scene
tutorialBox1 = (TutorialBox*)[CCBReader load:#"TutorialBox"] //creates instance of variable using Spritebuilder (don't worry if you don't use SB, this part works)
[tutorialBox1 updateBoxDisplay:1] //used to add text box child to textBox1
[self addChild:tutorialBox1];
}
-(void)gridTapped {
//When game scene is tapped, this is called to update position of textBox1 in tutorialBox1
[tutorialBox1 updateBoxDisplay:2]; //updates position of textBox1 in tutorialBox1
}
TutorialBox.m
# implementation Grid {
CCSprite9Slice *textBox1;
}
-(void)didLoadFromCCB {
//Called upon initialization of tutorialBox1
textBox1 = [CCSprite9Slice spriteWithImageNamed:#"RetroSprites/tutorialtextBox1.png"];
}
-(void)updateBoxDisplay:(int)newTutorialLevelNumber {
if (newTutorialLevelNumber == 1) {
textBox1.position = ccp(0,0);
[self addChild:textBox1];
}
else if (newTutorialLevelNumber == 2) {
textBox1.position = ccp(100,100)
}
}
TutorialBox.h
#interface TutorialBox : CCNode
- (void)updateBoxDisplay:(int)newTutorialLevelNumber
#end
I have checked to make sure everything is running properly with print statements, so it isn't an issue with anything else. It is simply being called, but the position in my main game scene, Grid.m is not being updated.
Thanks for the help!
I am not sure about this, but I guess its issue with the threading. Give a try with this code:
-(void)updateBoxDisplay:(int)newTutorialLevelNumber {
dispatch_async(dispatch_get_main_queue(), ^{
if (newTutorialLevelNumber == 1) {
textBox1.position = ccp(0,0);
[self addChild:textBox1];
}
else if (newTutorialLevelNumber == 2) {
textBox1.position = ccp(100,100)
}
});
}
I would like to load a few images to the Image object in QML. I want to do it one after another in a loop I think with some delay, because it should pretend to look like an animation. Im new in Qt and QML, so can anybody help me how to begin or somethin'? :)
The simplest solution, that works in QML 1.x and 2.0, is to use a Repeater and a Timer :
import QtQuick 2.0
Rectangle {
id: base;
width: 800;
height: 600;
property variant images : [
"image1.jpg",
"image2.jpg",
"image3.jpg",
"image4.jpg",
"image5.jpg"
];
property int currentImage : 0;
Repeater {
id: repeaterImg;
model: images;
delegate: Image {
source: modelData;
asynchronous: true;
visible: (model.index === currentImage);
}
}
Timer {
id: timerAnimImg:
interval: 500; // here is the delay between 2 images in msecs
running: false; // stopped by default, use start() or running=true to launch
repeat: true;
onTriggered: {
if (currentImage < images.length -1) {
currentImage++; // show next image
}
else {
currentImage = 0; // go back to the first image at the end
}
}
}
}
Should do it, and if you don't want the animation to restart when the last image is reached, just replace currentImage = 0; with stop(); in the timer's onTriggered.
Also, you should possibly have to tweak a little the Image delegate in the Repeater to give it the look you want (size, fill mode, position etc...).
If you are using QtQuick 2 then AnimatedSprite is the best way to do this: http://qt-project.org/doc/qt-5.0/qtquick/qtquick-effects-sprites.html
Otherwise, you could use a Timer or NumberAnimation to trigger changing the image source, but there could be unpredictable delays as images load for the first time (caching should solve this after the first loop). If you only have a few images, you could have three Images and cycle their visibility.