In the following Test in line 133 onwards i am testing for collision between targets and the bullets. I am wondering why the target_hit_list is allways only one Target object? Is it because target_hit_list gets updated and new assigned in each loop, so it is allways empty as the next collision takes place?
Here is the link to the code.
Yes. Also the bullet only collides with one target. Also you should separate the code out, so you have a main loop that goes like this, with each of these a function on their own:
check_events()
update_player_position()
collision_check()
draw_all()
Rather than have everything mushed together in the same area.
something like this:
running = True
while running:
check_events()
update_player_position()
collision_check()
draw_all()
def check_events():
for e in pygame.event.get():
if e.type==pygame.QUIT or (e.type==pygame.KEYDOWN and e.key==pygame.K_ESCAPE):
runs=0
player.shoot()
def update():
#logics
for ahsm in all_have_same_method:
ahsm.hanging()
all_have_same_method.update()
def collision_check():
for b in bullet_group:
target_hit_list=pygame.sprite.spritecollide(b,target_group,0)
for thl in target_hit_list:
score+=1
print target_hit_list #why is in the target_hit_list allways only one Target object?
def draw():
#drawings
#draw score
draw_score=font.render(str(score),True,RED)
screen.fill(BLACK,(0,0,50,20))
screen.set_colorkey(BLACK)
screen.blit(draw_score,(0,0))
all_have_same_method.draw(screen)
pygame has another feature which checks for collisions between all sprites at once. (collidelistall) Try that...
Related
I'm programming a game in pygame in which you place soldiers and they fight. After they are done fighting, I want the screen to return to where it was before the battle started. I want to copy a the pygame.sprite.Group object containing the soldiers using copy.deepcopy() like so:
oldRUnits = copy.deepcopy(RedUnits)
oldBUnits = copy.deepcopy(BlueUnits)
However, I found out that pygame.sprite.Groups don't like to be deepcopied. It just raises pygame.error. I tried deepcopying each pygame.sprite.Sprite object in the group individually like so:
oldRUnits = []
oldBUnits = []
for i in RedUnits:
oldRUnits.append(copy.deepcopy(i))
for i in BlueUnits:
oldBUnits.append(copy.deepcopy(i))
However, they don't like to be deepcopied either so I'm stuck. I want to know if there is a way to copy this and if there is a better way to achieve my goal. Thanks!
I think I have a solution to my problem. Instead of
oldRUnits = []
oldBUnits = []
for i in RedUnits:
oldRUnits.append(copy.deepcopy(i))
for i in BlueUnits:
oldBUnits.append(copy.deepcopy(i))
I could write
oldRUnits = []
oldBUnits = []
for i in RedUnits:
oldRUnits.append(type(i)(*i.get_init_args()))
for i in BlueUnits:
oldBUnits.append(type(i)(*i.get_init_args()))
SKAction has waiting for duration abilities, for a period of time on a node. And seems to perform actions on nodes. Like moveTo, etc.
If I don't want that, rather I'd prefer to call functions within GameScene after a period of time, how do I do that with SpriteKit in the GameScene, not on a Sprite or other Node?
Are SKActions the way to do this? The only way to do this?
Yes. This question IS that ridiculously simple. I lack the heuristics and terminology to find an answer. Just keep looping around on how SKAction waits are calls on SKSprites for things like scale, rotation, etc, after time. Which isn't want I want/need.
Update:
Desired outcome, inside GameScene
doSetupStuff() // does some stuff...
waitForAWhile() // somehow wait, perhaps do somethings in here, while waiting
doSomethingElse() // does this after the waitForAWhile has waited
UPDATE 2:
What I think happens, again, inside didMove(to view...)
func wait(){
let timeToPause = SKAction.wait(forDuration: 3)
run(timeToPause)
}
let wontwait = SKAction.wait(forDuration: 3)
run(wontwait)
thisFunction(willnot: WAIT"it starts immediately")
wait()
thisFunction(forcedToWait: "for wait()'s nested action to complete")
UPDATE 3:
Found a way to get the delay without using SKActions. It's a little crude and brutal, but makes more sense to me than SKActions, so far:
DispatchQueue.main.asyncAfter(deadline: .now() + 10.0) {
print("I waited ten seconds before printing this!")
}
An option, as you cited, is to manage this externally. The way I typically manage this sort of thing is to have an externally run update cycle. One that
To drive this updater, you could use either CADisplayLink (which is what I use right now with my OpenGL renderer) or a dispatch source timer (which I have used with my SpriteKit engine). When you use an updated, you want to calculate the delta time. The tick handler could look something like:
func tickHandler() {
let currTime = NSDate().timeIntervalSince1970
let dt = lastTime - currTime // lastTime is a data member of the class
// Call all updaters here, pretend "updater" is a known updater class
updater.update(dt)
}
And updater's update method would look something like:
func update(deltaTime:NSTimeInterval) {
// Do your magic
}
I typically have a main overall updater running independent of what people are calling scenes. Example usage would be something like having an attract mode like in old school arcade games. There they show title screen, sample game play, high scores, rinse and repeat. Scenes would be title, game play, high score. Here you can your main updater manage the time and coordinate the construction/destruction/switching of the scenes. Note this implies having an overall scene manager (which is actually quite handy to have).
For your case, you could use this updater to drive the GameScene updater. It's updater could look something like:
func update(deltaTime:NSTimeInterval) {
switch state {
case .SetupState:
// noop?
println("I'm in setup") // Shown just so you can see there is a setup state
case .WaitState:
waitTime += deltaTime
if waitTime >= kWaitTime {
// Do whats you gots to do
doSomethingElse()
state = .NextState
}
case .NextState:
// blah blah blah blah
}
}
So the flow to do this call path from your driver (CADisplayLink or dispatch source) would be something like:
tickHandler -> master updater -> game scene updater
Some will def find this is perhaps a little heavy handed. I, on the other hand, find this very helpful. While there is obviously some time management and the loss of being able to fire and forget, it can help provide more control for orchestrating pieces, as well as arbitrarily changing state without having to worry about killing already queued actions. There is also nothing that says you still cannot mix SKAction. When I did use SpriteKit, I did all my updating this way along with some dispatched items. I only used SKAction to update hierarchy. Keep in mind that I used my own animation and physics system. So at least for me I had a lot less dependency on SpriteKit (it effectively was just a renderer for me).
Note you have to have your own means to handle pause and coming to foreground where your timer will need to be resynced (you only need to worry about tickHandler). Breakpoints also will cause time jumps.
You can use below function
#define ANIM_TIME 2
SKAction *customACtion = [SKAction customActionWithDuration: ANIM_TIME actionBlock:^(SKNode *node, CGFloat elapsedTime) {
// Do Something Here
}];
Another way to make something happen after a certain period of time is to make use of the 'current time' parm passed to update(). The following code will spawn a boss at intervals ranging from 20 to 30 seconds.
In your property definitions:
var timeOfLastBoss: CFTimeInterval = -1 //Indicate no boss yet
var timePerBoss = CFTimeInterval()
.
.
.
didMoveToView() {
...
timePerBoss = CFTimeInterval(Int.random(20...30))
'''
}
.
.
.
func update(currentTime: CFTimeInterval) {
...
spawnBossForUpdate(currentTime)
...
}
'
'
'
func spawnBossForUpdate(currentTime : CFTimeInterval) {
if ( timeOfLastBoss == -1 ) {timeOfLastBoss = currentTime}
if (currentTime - timeOfLastBoss < timePerBoss) {return}
// Rest of 'spawnBoss code
self.timePerBoss = CFTimeInterval(Int.random(20...30))
self.timeOfLastBoss = currentTime
}
One way, using SKActions, in Swift 3.0, looks like this:
DEFINE: aPatientlyWaitingFunction() at the top level of
GameScene class.
To cause a delay to happen before calling the above function, inside
didMove(to view...)
three ways I've found to do this using Actions:
All three ways seem to accomplish the exact same thing:
let timeToWait: TimeInterval = 3 // is seconds in SKAction thinking time
let waitSomeTime = SKAction.wait(forDuration: timeToWait)
// 1st way __________________________________________
// with a completion handler, the function can be called after Action
run(waitSomeTime) {self.aPatientlyWaitingFunction()}
// 2nd way __________________________________________
// as a completion to be done after action, in the run invocation:
run(waitSomeTime, completion: aPatientlyWaitingFunction)
// 3rd way __________________________________________
// alternatively, as part of a sequence of actions...
// Create a sequence, by making a run action from waitSomeTime and...
let thenDoThis = SKAction.run(aPatientlyWaitingFunction)
// then activate sequence, which does one action, then the next
run(SKAction.sequence([waitSomeTime, thenDoThis]))
// OR... for something different ____________________
////////////////////////////////////////////////////////
DispatchQueue.main.asyncAfter(deadline: .now() + timeToWait) {
self.aPatientlyWaitingFunction()
print("DispatchQueue waited for 3 seconds")
}
Hi i have a program that when a button is pressed it should move to the next stacked widget replace some text in some labels and then execute some functions but this is not working and moves to the next page when the functions completes
The code is :
QtCore.QObject.connect(self.StartBtn, QtCore.SIGNAL(_fromUtf8("clicked()")), self.start) #Start
def nextPage(self):
current_page = self.stackedWidget.currentIndex()
i = int(current_page) + 1
self.stackedWidget.setCurrentIndex(i)
def start(self):
self.nextPage()
self.animation()
self.runFunctions()
def runFunctions(self):
try:
self.DbLabel.setText(_translate("MainWindow", "Checking Database", None))
if checkDb == True:
self.DbLabel.setText(_translate("MainWindow", "Checking Database ", None))
self.checkDbFun()
self.DbLabel.setText(_translate("MainWindow", "Database checked", None))
else:
self.checkedDbImg.setPixmap(QtGui.QPixmap(_fromUtf8("Files\\x.png")))
self.DbLabel.setText(_translate("MainWindow", "Database not checked", None))
except Exception as e:
self.AlertMessage(e)
def animation(self):
self.LoadingGif = QtGui.QLabel(MainWindow)
movie = QtGui.QMovie("Files\\loading.png")
self.LoadingGif.setMovie(movie)
self.LoadingGif.setAlignment(QtCore.Qt.AlignCenter)
self.gridLayout_2.addWidget(self.LoadingGif, 4, 1, 1, 1)
movie.start()
So what i want is to press StartBtn then move to next stacked widget page load the animation image and then run the functions
You probably need to let Qt process events in order for the tab change to take effect. You could do that two ways:
insert a qApp.processEvents() between the animation() and runFunctions() (qApp is in PyQt5.QtWidgets)
call runFunctions() via a single-shot timer: QTimer.singleShot(0, runFunctions), which will schuedule runFunctions via the event loop, so any pending events will first be processed (because runFunctions() is the latest added), then runFunctions() will get called. If you actually have params for runFunctions(), use a lambda.
I favor the first approach because I find it more clearly indicates what is happening (events need to be processed), but I recommend also adding a comment on that line that "so stack tab can change".
BTW you should be use the new-style notation for signals-slot connections, much cleaner, of the form "signal.connect(slot)":
self.StartBtn.clicked.connect(self.start)
So for approach #1 your code would look like this:
from PyQt5.QtWidgets import qApp
...
self.StartBtn.clicked.connect(self.start)
...
def start(self):
self.nextPage()
self.animation()
qApp.processEvents()
self.runFunctions()
...
i know this might be simple but i have been searching everywhere for a fix but i just cannot find it!
i want to make something like a health #, so when you press whatever button the dynamic text # will go up or down. on my test project i have two layers, the first with the following code
var hp:Number = 100;
health.text = String hp;
hp being the variable, and health being the dynamic text. then i have the next layer with the button with:
function button(e:MouseEvent):void
{
hp -= 10;
}
without that second chunk of code, the dynamic text will appear, but once that is added it will disappear and the button is function-less.
how do i make this work??? once again sorry if this is a dumb question, i'm just very stumped.
The accepted answer is good, but I wanted to point out that your original code was actually very close to being correct, you just needed parenthesis:
health.text = String(hp);
For most objects String(object) and object.toString() has the same effect, except that object.toString() throws an error if object is null (which could be desirable or undesirable, depending on what you expect it to do).
This is not correct:
health.text = String hp;
use:
health.text = hp.toString();
and:
function button(e:MouseEvent):void
{
hp -= 10;
health.text = hp.toString();
}
In order to condense my code I am trying to make one of my while loops into a function. I have tried numerous times and have yet to receive the same result upon compiling as I would just leaving the while loop.
Here's the while loop:
while True:
i = find_lowest_i(logs)
if i == -1:
break
print "i=", i
tpl = logs[i].pop(0)
print tpl
out.append(tpl)
print out
And here's what I have so far for my function:
def mergesort(list_of_logs):
i = find_lowest_i(logs)
out = []
while True:
if i == -1:
break
print "i=", i
tpl = logs[i].pop(0)
print tpl
out.append(tpl)
print out
return out
Thanks in advance. This place is a safe-haven for a beginner programmer.
It looks like the parameter to your function is list_of_logs and you're still using logs inside the function's body. The simplest fix is probably to rename your parameter to mergesort from list_of_logs to logs. Otherwise, looks completely correct to me.