(I'm very new to programming, so layman-friendly answers are certainly appreciated)
I'm working on a game played with two teams. I have a button that does a check for which team is up and then updates that team's score. The code runs with no errors but the score doesn't update when the button is pressed.
In my model file I declare
var teamOneScore = 0
var teamTwoScore = 0
var teamCounter = 2
In the view controller I have
#IBAction func buttonPressed(sender: AnyObject) {
if timer.valid && teamCounter % 2 == 0 {
++teamOneScore
} else if timer.valid && teamCounter % 2 != 0 {
++teamTwoScore
}
}
In viewDidLoad
if teamCounter % 2 == 0 {
scoreLabel.text = "Score: \(teamOneScore)"
} else {
scoreLabel.text = "Score: \(teamTwoScore)"
}
When the view loads, scoreLabel correctly displays 0, but when I press the button, the displayed score doesn't go up. The timer and teamCounter checks are working fine everywhere else in the code and I have another button that increments teamCounter (which is also stored as an int in the model) with no problems. So all the separate components of buttonPressed seem to be working fine and I don't have any errors to go on. I'm stumped.
You have to move the text setting in an extra method. Right now the text only gets set in viewDidLoad - that function will not be triggered more than once however.
change your viewDidLoad to something like
updateUI()
add a new function
func updateUI() {
if teamCounter % 2 == 0 {
scoreLabel.text = "Score: \(teamOneScore)"
} else {
scoreLabel.text = "Score: \(teamTwoScore)"
}
}
and call that method as the last thing in the button action:
#IBAction func buttonPressed(sender: AnyObject) {
if timer.valid && teamCounter % 2 == 0 {
++teamOneScore
} else if timer.valid && teamCounter % 2 != 0 {
++teamTwoScore
}
updateUI()
}
When you create the scoreLabel in viewDidLoad, you assign it a text value of "Score: \(teamOneScore)" which is great. However, when you increment the teamOneScore variable, the actual UILabel does not know to change its text. It assumes you wanted to display Score: 0. Even if a variable changed its value, that label has already been created and will continue to display whatever text was initialized.
What you need to do in your buttonPressed function is add
scoreLabel.text = "Score: \(teamOneScore)" or
scoreLabel.text = "Score: \(teamOneScore)" if it was team 2 that scored.
after you increment the score. This is what allows the label's text to actually change.
Related
I wrote a code to create a Button which should change the value of a label/textfield.
I wanted to make a push-up App and every time you touch the button on the screen, the label '' Your Score: 0'' increase the score with 1, I have tried it as textfield too. But it's not working, nothing is happening!
Can someone help me?
Label Code:
func setupHelloWorld() {
helloworld.textAlignment = .center
helloworld.text = "Your Score: \(score)"
helloworld.textColor = .gray
helloworld.font = .boldSystemFont(ofSize: 30)
self.view.addSubview(helloworld)
...
Button code:
func setUpNetButton() {
nextButton.backgroundColor = .blue
nextButton.setTitleColor(.white, for: .normal)
nextButton.setTitle("Tap!", for: .normal)
nextButton.addTarget(self, action: #selector(nextButtonTapped), for: .touchUpInside)
view.addSubview(nextButton)
setUpNextButtonConstraints()
}
#objc func nextButtonTapped() {
score += 1
}
You have to manually update the text property of the label. Just because you initially set its text using the score variable, it will not automatically react to any changes of the variable's value afterward unless you explicitly set the new label text.
Change your code to something like this and it will work:
func setupHelloWorld() {
helloworld.textAlignment = .center
helloworld.textColor = .gray
helloworld.font = .boldSystemFont(ofSize: 30)
updateButtonText()
self.view.addSubview(helloworld)
}
...
#objc func nextButtonTapped() {
score += 1
updateButtonText()
}
func updateButtonText() {
helloworld.text = "Your Score: \(score)"
}
Alternatively, instead of calling the updateButtonText from the nextButtonTapped() method, you can add a didSet observer to your score property and change the label text each time it gets assigned a new value. However, you'll still need to update the label's text when you view has loaded because didSet won't be called during the initialization of the class. Something like this:
private var score: Int = 0 {
didSet {
updateButtonText()
}
}
override func viewDidLoad() {
...
updateButtonText()
...
It is because you are not changing the value of helloworld assign the value to
helloworld.text in #objc function nextButtonTapped() after the score is updated
using latest swift in SpriteKit.
I would like to update the text within a defined label in SKLabelNode.
Take a look below. It does not show errors to run, but it does not change the text node. Any help?
func lookforThings() {
if player.position.x > -240 {
let label0 = SKLabelNode()
addChild(label0)
label0.text = "Start searching the forest for your friends..."
label0.position.x = 12
label0.position.y = 112
label0.zPosition = 0.5
label0.fontSize = 12
label0.fontColor = SKColor.green
if player.position.x > 100 {
label0.text = ""
}
}
Label0 is initialized above, then set at a value, using the .text attribute.
Following that, label0 is changed to be "" or empty in other words. As a way to remove the SKLabelNode from the scene at this case. Is there another way of doing this? Why did it not change the text. It stayed say "Start searching the forest for your friends..." even after the next if case was taken.
This is somewhat guessing since you haven't shown enough to be sure, but every time you call lookForThings you're creating a new label and adding it to the scene. Any previous labels added aren't being affected, so likely you're building up a stack of labels, most of which are showing the "Start searching" message. They're all at the same place so you're not noticing them as distinct.
Probably you want one label that should appear when the player is in the relevant region and be removed when not. Something like this:
class GameScene: SKScene {
var searchingLabel: SKLabelNode?
func lookForThings() {
if player.position.x > -240 && player.position.x <= 100 {
// Show the searching message
guard searchingLabel == nil else { return } // Already shown
let label = SKLabelNode()
addChild(label)
label.text = ... // Set up the label as desired
searchingLabel = label
} else {
// Don't show the message
guard let label = searchingLabel else { return } // Already removed
label.removeFromParent()
searchingLabel = nil
}
}
}
You can remove the child node this way, later on in the code, or with a time variable duration.
label.run(SKAction.sequence([ SKAction.wait(forDuration: 14), SKAction.removeFromParent()]))
I've been playing around with a basic betting app and I can't seem to figure out this problem.
The slider is a percentage of the bank unless it's moved at which point it will update the value based on the value. If it isn't moved and kept at the previous value it also uses the previous value.
For example:
My bank is 1000. I move the slider to 10% to bet 100. I win and now my bank is 1100.
I want to bet 10% again but it doesn't update to the new value which should be 110. It will keep the same value of 100 until the slider is moved? How can I fix it so that even if it doesn't move the value of 10% of the bank is true.
#IBAction func slider(_ sender: UISlider)
{
betAmount.text = String(format: "%.0f%%",sender.value)
wager = Int(sender.value) * bank / 100
}
#IBAction func flipCoin(_ sender: UIButton)
{
let number = [1,2]
winnings = wager + ((wager * 90) / 100)
if let coin = coins.randomElement()
{
if(coin == 1 && wager <= bank && wager > 0)
{
youBet.text = ("$\(wager)")
bank += winnings
bankLabel.text = ("$\(bank)")
}
else if(coin == 2 && wager <= bank && wager > 0)
{
youBet.text = ("$\(wager)")
bank -= wager
bankLabel.text = ("$\(bank)")
}
}
}
The easiest way is to do the following:-
If you don't already have an IBOutlet for the UISlider, create one (e.g. called sliderOutlet.
Extract the contents of the slider func to a new private function, called (e.g.) updateWager(). Reference sliderOutlet instead of sender.
Change the slider func to call your new function.
Also call this function from the end of flipCoin (i.e. after the bank has been updated).
This will make the wager calculation occur automatically when the flip is complete. You can also call the new function should any other event (now or in the future) update the bank.
I.e.:
#IBOutlet weak var sliderOutlet: UISlider! // Create this from the storyboard
func updateWager()
{
betAmount.text = String(format: "%.0f%%", sliderOutlet.value)
wager = Int(sliderOutlet.value) * bank / 100.0
}
#IBAction func slider(_ sender: UISlider)
{
updateWager()
}
#IBAction func flipCoin(_ sender: UIButton)
{
let number = [1,2]
winnings = wager + ((wager * 90) / 100)
if let coin = coins.randomElement()
{
if(coin == 1 && wager <= bank && wager > 0)
{
youBet.text = ("$\(wager)")
bank += winnings
bankLabel.text = ("$\(bank)")
}
else if(coin == 2 && wager <= bank && wager > 0)
{
youBet.text = ("$\(wager)")
bank -= wager
bankLabel.text = ("$\(bank)")
}
updateWager()
}
}
I am making a SpriteKit game in Swift. While gameState = inGame, I want the score to increase every second. How and where would I calculate and display something like this?
The other answers I have found are outdated and not very helpful. There might be one I am not aware of that already exists, so I would be greatly appreciative if you could point me in that direction. Thanks for the help.
Here is a very simple way of incrementing and displaying a score every second, as you have described it.
The "timer" here will be tied to your game's framerate because the counter is checked in the update method, which can vary based on your framerate. If you need a more accurate timer, consider the Timer class and search Stack Overflow or Google to see how to use it, as it can be more complicated than the simple one here.
To test this, create a new Game template project in Xcode and replace the contents of your GameScene.swift file with the following code.
You don't actually need the parts that use gameStateIsInGame. I just put that in there as a demonstration because of your remark about checking some gameState property in order for the timer to fire. In your own code you would integrate your own gameState property however you are handling it.
import SpriteKit
class GameScene: SKScene {
var scoreLabel: SKLabelNode!
var counter = 0
var gameStateIsInGame = true
var score = 0 {
didSet {
scoreLabel.text = "Score: \(score)"
}
}
override func didMove(to view: SKView) {
scoreLabel = SKLabelNode(fontNamed: "Chalkduster")
scoreLabel.text = "Score: 0"
scoreLabel.position = CGPoint(x: 100, y: 100)
addChild(scoreLabel)
}
override func update(_ currentTime: TimeInterval) {
if gameStateIsInGame {
if counter >= 60 {
score += 1
counter = 0
} else {
counter += 1
}
}
}
}
The following function counts down a red to green light, then counts the reaction time for the user to hit a button after the green light is displayed.
func updateCounter() {
timerInt -= 1
if timerInt == 2{
light.image = UIImage(named: "r.png")
} else if timerInt == 1 {
light.image = UIImage(named: "yellow.png")
} else if timerInt == 0 {
light.image = UIImage(named: arc4random_uniform(2) == 0 ? "no.png" : "g.png")
timer.invalidate()
startStop.isEnabled = true
scoreTimer = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(ViewController.updateScoreTime), userInfo: nil, repeats: true)
}
}
Where it states else if timerInt == 0, the user is given a random function. An image will either turn green or an "x" is displayed.
If the x is displayed, I would like the user to to have to hit a button that states game over to restart the red light sequence.
If a green light is displayed, I would like the user to have to test their reaction time.
This is how the function already runs now, except it does not change if the x is displayed. I guess I would like the function to run as follows:
if timeInt == 0 and green light is chosen
then run test reaction time
else if timeInt == 0 and x is chosen
then end reaction time and run game over button
How can I achieve this?
I am not exactly sure what you are trying to achieve, so I did my best. Try this:
func updateCounter() {
timerInt -= 1
if timerInt == 2{
light.image = UIImage(named: "r.png")
} else if timerInt == 1 {
light.image = UIImage(named: "yellow.png")
} else if timerInt == 0 {
let green = (arc4random_uniform(2) == 0)
light.image = UIImage(named: (green ? "g.png" : "no.png"))
if green {
// run test reaction time
} else {
//end reaction time and run game over button
}
// NOTE: Do you mean `scoreTimer.invalidate()`?
timer.invalidate()
startStop.isEnabled = true
// NOTE: This time interval seems WAY too small ↓↓↓↓↓↓: it is only a millisecond!
scoreTimer = Timer.scheduledTimer(timeInterval: 0.0001, target: self, selector: #selector(ViewController.updateScoreTime), userInfo: nil, repeats: true)
}
}
Replace the first two comments (aka lines beginning with //) with the appropriate code, and take note of the third and fourth comments.