How to sense which direction my player object was hit from in Game Maker Studio 2 - game-maker-language

I'm making a 2D Platformer game in GMS 2 and I need to make my player face the direction that he was hit from when he dies. How do I sense which side he was hit from? I only need to sense right and left collision. Currently my code looks like this:
if (hp = 0) {
with (instance_create_layer(x, y, layer, obj_player_1_dead)) {
if (obj_laser_2.x < obj_player_1.x) {
image_xscale = 0.6
} else if (obj_laser_2.x > obj_player_1.x) {
image_xscale = -0.6
}
}
instance_destroy()
}
hp is my hit points variable.
I have instance_destroy(); at the bottom because I am destroying the object and creating a player_dead object.
Everything else works exactly how I want it to. This is the last thing before the game is done. Any help is appreciated. Thanks in advance!

Related

Animation for a canvas object

I'm trying to use an animation for a sudoku app. I want for everytime i insert a wrong number, that number would change color and it's scale.
My code is:
override fun onDraw(canvas: Canvas?) {
canvas ?: return
drawBoard(canvas)
drawNumberProblem(canvas)
}
private fun drawNumberProblem(canvas: Canvas){
paint.color=darkcolor
paint.textSize = cellSide*3/4
SudokuGame.numbersproblem.forEach { e->
canvas.drawText("${e.number}", originX + e.col * cellSide+cellSide/5, originX + (e.row+1) * cellSide-cellSide/10, paint)
}
}
And i tried:
private fun initAnimation() {
var animation = RotateAnimation(0f, 360f, 150f, 150f)
animation.setRepeatCount(Animation.INFINITE)
animation.setRepeatMode(Animation.RESTART)
animation.setDuration(7500L)
animation.interpolator = LinearInterpolator()
startAnimation(animation)
}
override fun onDraw(canvas: Canvas?) {
canvas ?: return
if(animation==null)
initAnimation()
drawBoard(canvas)
drawNumberProblem(canvas)
}
private fun drawNumberProblem(canvas: Canvas){
paint.color=darkcolor
paint.textSize = cellSide*3/4
SudokuGame.numbersproblem.forEach { e->
canvas.drawText("${e.number}", originX + e.col * cellSide+cellSide/5, originX + (e.row+1) * cellSide-cellSide/10, paint)
}
}
The animation, the board and the numbers are all good. The animation is only an example, i tried to rotate it to see if it's working. But the only problem is that the animation is working for the whole board, i want to have animation only over numbers.
Is there any way to create a initAnimation with a parameter like initAnimation(drawNumberProblem())?
I am new to kotlin animation, so i don't really care about the best way to do it, i want to find a simple way to understand it.
Thanks
If each cell is its own View (say a TextView) you can animate it the way you're trying to, and the animation framework will take care of the timing, the rotation and scaling, etc. Because each view is separate, they can all be animated independently, using Android's view animation libraries, and a lot of the work is taken care of for you - it's pretty easy to use!
If it's all one view, and you're drawing a bunch of elements which can all be animated, you have to keep track of those elements, any animations that should be happening to each one, and how each animation's state affects the element when it comes time to draw it. Instead of each view having its own state and being drawn separately, you have to draw the whole thing at once, because it's a single view. So you need to keep track of those individual element states yourself, so you can refer to them when drawing the current overall state.
So for example, say you've got an animation where an element needs to scale to 2x the size and then back to normal, and it runs for 1 second total (1000ms). When you come to draw that element, you need to know how far along that animation you are at that moment, so you can scale it appropriately, and draw it at the correct size.
There are lots of ways to do this, probably some smarter ones, but this is the most basic hands-on example I think. I'm not testing this, but hopefully it gives you the idea:
// for brevity, so we can just say "now" instead of writing out the whole function call
val now: Long get() = System.currentTimeMillis()
// store a start time for each grid cell (or null if there's no anim running)
val animStartTimes = Array(CELL_COUNT)<Long?>
val animLength = 1000 // millis
// Basic function to start an animation - you could adapt this to prevent restarts
// while an anim is already running, etc
fun startAnim(cellIndex: Int) {
animStartTimes[cellIndex] = now
// tell the view it needs to redraw (since we're animating something now)
invalidate()
}
// Get the current progress of an animation in a cell, from 0% to 100% (0.0 to 1.0)
// I'm treating a finished item as "reset" to its original state
fun getAnimProgress(cellIndex: Int): Float {
val start = animStartTimes[cellIndex]
if (start == null) return 0f
val progress = (now - start) / animLength
if (progress > 1f) {
// animation has ended (past 100% of its runtime) so let's clear it
animStartTimes[cellIndex] = null
return 0f // like I said, I'm treating finished animations as "reset" to 0%
} else return progress
}
override fun onDraw(canvas: Canvas) {
// this flag can be set to true if we find an element that's still animating,
// so we can decide whether to call invalidate() again (forcing a redraw next frame)
var animating = false
items.forEachIndexed { i, item ->
val animProgress = getAnimProgress(i)
if (animProgress > 0f) animating = true // set that flag
// now you need to use that 0.0-1.0 value to calculate your animation state,
// e.g. adjusting the text size by some factor - 0.0 should produce your "default" state
}
// finally, force a redraw next frame if necessary - only do this when your view
// contents might need to change, otherwise you're wasting resources
if (animating) invalidate()
}
I hope that makes sense - obviously I haven't shown how to actually draw the states of your animation, that depends on exactly what you're doing - but that's the basics of it. It's a lot more work than using view animation, but it's not too bad when you get the idea.
The drawing part is a little more complex, and you'll probably want to get familiar with manipulating the Canvas - e.g. to draw a rotated character, you turn the canvas, draw the character as normal, then undo the canvas rotation so it's the right way up again, and the character is tilted. I don't have time to look for any tutorials about it, but this article covers the matrix operations that scale/rotate/etc the canvas
So yeah, it's a bit involved - and depending on what you want to do, a grid of TextViews might be a better shout

Get the GazeProvider.GazeTarget when GaxePointer is always on

In our app we have the gaze pointer behaviour set to be AlwaysOn:
PointerUtils.SetGazePointerBehavior(PointerBehavior.AlwaysOn);
This seems to break the GazeProvider because when a hand is detected, this:
CoreServices.InputSystem.GazeProvider.GazeTarget
returns the object actually hit by the hand rays, instead of the object at which we are gazing (could be null).
This is the code I use to get the position of the hit:
if (CoreServices.InputSystem.GazeProvider.GazeTarget?.layer == 31)
{
Debug.Log(CoreServices.InputSystem.GazeProvider.HitInfo.point);
}
But it returns the position of the hand cursor and not the gaze
I also tried filtering by SourceType(Head) but the problem persists:
foreach (var source in CoreServices.InputSystem.DetectedInputSources)
{
if (source.SourceType == InputSourceType.Head && CoreServices.InputSystem.GazeProvider.GazeTarget?.layer == 31)
{
foreach (var p in source.Pointers)
{
if (p is IMixedRealityPointer)
{
Debug.Log("HIT");
}
}
}
}
So here is the question:
When the GazePointer is set to be always visible, how can we get the position of the gaze hit even if a hand is detected?
To get the raw data of eye gaze and hand gaze at the same time, you can use InputRayUtils class, which provides the TryGetRay method that can get the ray associated with the desired input source type and hand. And if you have any question about how to use it, you can find an example in the InputDataExample scene under Assets/MRTK/Examples/Demos/Input/Scenes/InputData.

First note played in AKSequencer is off

I am using AKSequencer to create a sequence of notes that are played by an AKMidiSampler. My problem is, at higher tempos the first note always plays with a little delay, no matter what i do.
I tried prerolling the sequence but it won't help. Substituting the AKMidiSampler with an AKSampler or a AKSamplePlayer (and using a callback track to play them) hasn't helped either, though it made me think that the problem probably resides in the sequencer or in the way I create the notes.
Here's an example of what I'm doing (I tried to make it as simple as I could):
import UIKit
import AudioKit
class ViewController: UIViewController {
let sequencer = AKSequencer()
let sampler = AKMIDISampler()
let callbackInst = AKCallbackInstrument()
var metronomeTrack : AKMusicTrack?
var callbackTrack : AKMusicTrack?
let numberOfBeats = 8
let tempo = 280.0
var startTime : TimeInterval = 0
override func viewDidLoad() {
super.viewDidLoad()
print("Begin setup.")
// Load .wav sample in AKMidiSampler
do {
try sampler.loadWav("tick")
} catch {
print("sampler.loadWav() failed")
}
// Create tracks for the sequencer and set midi outputs
metronomeTrack = sequencer.newTrack("metronomeTrack")
callbackTrack = sequencer.newTrack("callbackTrack")
metronomeTrack?.setMIDIOutput(sampler.midiIn)
callbackTrack?.setMIDIOutput(callbackInst.midiIn)
// Setup and start AudioKit
AudioKit.output = sampler
do {
try AudioKit.start()
} catch {
print("AudioKit.start() failed")
}
// Set sequencer tempo
sequencer.setTempo(tempo)
// Create the notes
var midiSequenceIndex = 0
for i in 0 ..< numberOfBeats {
// Add notes to tracks
metronomeTrack?.add(noteNumber: 60, velocity: 100, position: AKDuration(beats: Double(midiSequenceIndex)), duration: AKDuration(beats: 0.5))
callbackTrack?.add(noteNumber: MIDINoteNumber(midiSequenceIndex), velocity: 100, position: AKDuration(beats: Double(midiSequenceIndex)), duration: AKDuration(beats: 0.5))
print("Adding beat number \(i+1) at position: \(midiSequenceIndex)")
midiSequenceIndex += 1
}
// Set the callback
callbackInst.callback = {status, noteNumber, velocity in
if status == .noteOn {
let currentTime = Date().timeIntervalSinceReferenceDate
let noteDelay = currentTime - ( self.startTime + ( 60.0 / self.tempo ) * Double(noteNumber) )
print("Beat number: \(noteNumber) delay: \(noteDelay)")
} else if ( noteNumber == midiSequenceIndex - 1 ) && ( status == .noteOff) {
print("Sequence ended.\n")
self.toggleMetronomePlayback()
} else {return}
}
// Preroll the sequencer
sequencer.preroll()
print("Setup ended.\n")
}
#IBAction func playButtonPressed(_ sender: UIButton) {
toggleMetronomePlayback()
}
func toggleMetronomePlayback() {
if sequencer.isPlaying == false {
print("Playback started.")
startTime = Date().timeIntervalSinceReferenceDate
sequencer.play()
} else {
sequencer.stop()
sequencer.rewind()
}
}
}
Could anyone help? Thank you.
As Aure commented, the start up latency is a known problem. Even with preroll, there is still noticeable latency, especially at higher tempos.
But if you are using a looping sequence, I found that you can sometimes mitigate how noticeable the latency is by setting the 'starting point' of the sequence to a position after the final MIDI event, but within the loop length. If you can find a good position, you can get the latency effects out of the way before it loops back to your content.
Make sure to call setTime() before you need it (e.g., after stopping the sequence, not when you are ready to play) because the setTime()call itself can introduce about 200ms of wonkiness.
Edit:
As an afterthought, you could do the same thing on a non-looping sequence by enabling looping and using an arbitrarily long sequence length. If you needed playback to stop at the end of the MIDI content, you could do this with an AKCallbackInstrument triggered by an MIDI event placed just after the final note.
After a bit of testing I actually found out that it is not the first note that plays off but the subsequent notes that play in advance. Moreover, the amount of notes that play exactly on time when starting the sequencer depends on the set tempo.
The funny thing is that if the tempo is < 400 there will be one note played on time and the others in advance, if it is 400 <= bpm < 800 there will be two notes played correctly and the others in advance and so on, for every 400 bpm increment you get one more note played correctly.
So... since the notes are played in advance and not late, the solution that solved it for me is:
1) Use a sampler that is not connected directly to a track's midi output but has its .play() method called inside a callback.
2) Keep track of when the sequencer gets started
3) At every callback calculate when the note should play in relation to the start time and store what time it actually is, so you can then calculate the offset.
4) use the computed offset to dispatch_async after the offset your .play() method.
And that's it, I tested this on multiple devices and now all the notes play perfectly on time.
I had the same issue, preroll didn't help, but I have managed to solve it with a dedicated sampler for the first notes.
I used a delay on the other sampler, about 0.06 of a second, works like a charm.
Kind of a silly solution but it did the job and I could go on with the project :)
//This is for fixing AK bug that plays the first playback not in delay
let fixDelay = AKDelay()
fixDelay.dryWetMix = 1
fixDelay.feedback = 0
fixDelay.lowPassCutoff = 22000
fixDelay.time = 0.06
fixDelay.start()
let preDelayMixer = AKMixer()
let preFirstMixer = AKMixer()
[playbackSampler,vocalSampler] >>> preDelayMixer >>> fixDelay
[firstNoteVocalSampler, firstRoundPlaybackSampler] >>> preFirstMixer
[fixDelay,preFirstMixer] >>> endMixer

Spritebuilder sprite position changes

I have my game in spritebuilder, and I am trying to move a ball up every 0.005 seconds. I have an NSTimer doing that, but sometimes ball.position.y + 2 is different.
For instance, one time I play the game, the ball moves to the top of the screen at the speed I want it to. Then, without even closing the game, just opening the scene again, the ball moves at half of the speed, as if + 2 isn't as much at that time, or the NSTimer decides to run at half speed.
NOTE: This only happens on an actual device. I can't get it to happen in a simulator.
Does anyone know why this is happening?
Thanks.
EDIT: My code (abridged):
timer2 = NSTimer.scheduledTimerWithTimeInterval(0.005, target: self, selector: "updateTick", userInfo: nil, repeats: true)
My update function:
func updateTick() {
...
incrementBalls()
...
}
My incrementBalls() function:
for index in 0...balls.count - 1 {
balls[index].position = ccpAdd(_physicsBody.position, CGPoint(x: balls[index].position.x, y: balls[index].position.y + 2))
}
I fixed this by instead using the update method and doing some math to move the balls instead of the unreliable NSTimer.

Phaser P2 body.collideWorldBounds stops body collisions

I'm using Phaser 2.4.2 with P2 physics. I have a sort of jar shaped body containing some circular bodies (balls). I want to move the jar offscreen but the balls are colliding with the world bounds.
I tried setting collideWorldBounds on the balls like so:
ball.body.setCircle(64);
ball.body.collideWorldBounds = false;
but this stops them colliding with the jar which I want -- the result is gravity makes them drop offscreen.
You can see a demo here: https://output.jsbin.com/vuyexo
Click the red button to make the jar move.
Uncomment collideWorldBounds=false in the 'balls' section.
Why is this happening and how can I make the balls collide with the jar body but not the world bounds when the jar is moved offscreen?
You can set the P2 world bounds using setBoundsToWorld so like this
//..
game.physics.p2.gravity.y = 300;
game.physics.p2.setBoundsToWorld(false, false, true, true); // left=false, right=false, top=true, bottom=true
Alternatively you could just make the P2 world larger, so for example make the width 2000 instead of 768.
game.world.setBounds(0, 0, 2000, 1024);
By default p2 collides everything with everything else, but if you want it to do something different then you have to explicitly list which objects collide with each other by adding each body to a collision group and then calling body.collides like this:
var jarCG = this.physics.p2.createCollisionGroup();
var ballsCG = this.physics.p2.createCollisionGroup();
jar.body.setCollisionGroup(jarCG);
jar.body.collides(ballsCG);
for (var i = 0; i < 9; i++)
{
var ball = balls.create(250+(i%3)*128,300+Math.floor(i/3)*128);
ball.body.setCircle(64);
ball.body.debug = true;
ball.body.collideWorldBounds = false;
ball.body.setCollisionGroup(ballsCG);
ball.body.collides([jarCG, ballsCG]);
}
This is working for me, but using a tween to move the jar still makes the physics act weird. You can fix it by either using jar.body.velocity.x instead of tweening or by also tweening all the balls. You can also try tweening stack.x if you just want to move the sprites, but for some reason this isn't moving their bodies.

Resources