Tile-based movement with Lance game engine? - lance

I'm using Lance for a game where the gameplay area is a tiled map. When a player presses the left-arrow key, their character should move one tile to the left, etc. I tried two approaches, see below, but got neither to work.
Could either approach be modified to work with tile-based movement? Or is a third approach needed? Or is Lance not suited to this kind of game?
Approach 1: Adjust the player's position directly when a key is pressed. From my GameEngine class:
if (inputData.input == 'left') {
player.position.x -= 32;
player.angle = 180;
}
While this works well for a single player, it doesn't in multiplayer. When player A moves, their position is not updated on player B's screen.
Approach 2: Set the player's state when a key is pressed:
if (inputData.input == 'left') {
player.state = 'walkLeft';
}
Then add a postStep handler in the common GameEngine class. (Adding it to Player didn't work). This code turns the player (over many steps) to face 180 degrees and then accelerates the player in that direction:
onPostStep(event) {
let players = this.world.queryObjects({instanceType: Player});
players.forEach(player => {
if (player.state == 'walkLeft') {
if (Math.abs(player.angle - 180) > 2)
player.turnLeft(2);
}
else {
player.accelerate(1);
player.state = '';
}
}
})
}
With this approach, if a player presses the left arrow key, their angle changes as expected at first, but the acceleration and movement is erratic. Also, Player A's position appears different on their screen vs the screen of Player B.
The Spaaace demo is the base for my project, so my project uses the same bending, physics engine, etc.

The first approach is better. The Brawler game in the sample collection does exactly what you describe. You can look at the BrawlerGameEngine.js code in https://github.com/lance-gg/tinygames/tree/master/brawler
Make sure that the action is processed in the method
GameEngine::processInput(inputData, playerId)

Related

How do I find out which direction a user is panning with UIPanGestureRecognizer?

So I am using UIPanGestureRecognizer in my project which I added to a view. I would like to know when a user either goes up, down,left or right. I am using the left and right feature to scrub through video. The up and down gesture is still to be determined. I have used the following code but I can't seem to figure it out. Thanks for the help!
#IBAction func panVideo(_ recognizer: UIPanGestureRecognizer) {
let vel = recognizer.velocity(in: self.videoView)
if vel.x > 0 {
// user dragged towards the right
print("right")
}
else {
// user dragged towards the left
print("left")
}
}
EDIT: Using Slider
if let duration = avPlayer?.currentItem?.duration {
let totalSeconds = CMTimeGetSeconds(duration)
let value = Float64(scrubberSlider.value) * totalSeconds
let seekTime = CMTime(value: Int64(value), timescale: 1)
avPlayer?.seek(to: seekTime, completionHandler: { (completedSeek) in
//perhaps do something later here
})
}
Joe's answer is close, but it won't take into account direct vertical or horizontal pans. (I'd comment on his answer except the formatting won't take.) Try this:
let vel = recognizer.velocity(in: self.videoView)
if vel.x > 0 {
// user dragged towards the right
print("right")
}
else if vel.x < 0 {
// user dragged towards the left
print("left")
}
if vel.y > 0 {
// user dragged towards the down
print("down")
}
else vel.y < 0 {
// user dragged towards the up
print("up")
In essence, you are getting the CGPoint of the gesture (x,y) and determining the velocity of the movement. You have an alternative to this - taking the starting and ending point:
var startingPoint = CGPoint.zero
#IBAction func panVideo(_ recognizer: UIPanGestureRecognizer) {
if recognizer.state == .began {
startingPoint = recognizer.location(in: self.videoView)
}
if recognizer.state == .ended {
let endingPoint = recognizer.location(in: self.videoView)
[ do the same comparing as above]
}
}
The advantage of the second option is you aren't doing unnecessary calculations during the pan. The disadvantage is that there are certain scenarios (like animating view movements) that are not conducive to it.
EDIT: I'm adding a bit more verbiage after reading your comment. It sounds to me that you may not be fully understanding what a pan gesture really is.
Like most (all?) gestures, it has a beginning, an in-between, and and end.
It is a two-dimensional drag with two components, both x and y.
There are actually SEVEN possible states, but FOUR of them (cancelled, failed, possible, recognized) do not happen with a pan gesture, leaving THREE states (began, changed, ended) that trigger.
I threw out one example - moving a view with a pan gesture - earlier. Now I'll try a second one - tracing an outline of, say, the Statue of Liberty in an image.
Here you want all THREE states, in order to know when to being tracing, when the path changes, and when it ends. And restricting this to the change state, I think you can see where both the X and the Y coordinate changes.
So yes, a logging of "left, up, left, up, left" is quite possible.I would think that if you traced a completely vertical line across the entire screen you might expect all "up" or "down" values in your log, but the odds of any human being panning that perfect is unlikely, so sure, a few "left" or "rights" may happen.
My tweak to Joe's code was to eliminate those moments of perfection. If vel.x == 0 you would have "left", and where bel.y == 0 you would have "down".
Again, if you simply want to know what the "result" of the pan is, use .began and .ended and ignore .changed - do not use recognizer.velocity but recognizer.state.
The "if" statements both of us gave you are really frameworks. If you understand both state and the two-dimensional nature of things, and you need to use .changed, then adapt those "if" statements - maybe compare the velocity of X to Y and take the greater, or eliminate those changes where the change in X or Y was under a threshold.
Try this code: tested in Swift 3.
Updated Answer: Below code will give you a starting and end location of your view when touch began.
if recognizer.state == .began {
let vel = recognizer.velocity(in: view) // view is your UIView
if vel.x > 0 {
print("right")
} else {
print("left")
}
}
if recognizer.state == .ended {
let vel = recognizer.velocity(in: view)
if vel.y > 0 {
print("down")
} else {
print("up")
}
}
Note : Your answer actually hidden in your code ?
#IBAction func panVideo(_ recognizer: UIPanGestureRecognizer) {
let vel = recognizer.velocity(in: self.videoView)
if vel.x > 0 {
// user dragged towards the right
print("right")
}
else {
// user dragged towards the left
print("left")
}
if vel.y > 0 {
// user dragged towards the down
print("down")
}
else {
// user dragged towards the up
print("up")
}
}
hope this helps...
Okay, now I'm getting the correct mental picture. You want scrub control. This is something very different, and I would recommend a UISlider over working with gestures - highly recommend it. For starters, they have the pan gesture already built in! Here's what I think apps like YouTube, QuickTime, etc. do.
(1) Let's take a specific example of having a video that is 1:53:22 in length, or (1*60*60)+(53*60)+22 = 6802 seconds in length.
(2) Add a "scrubber" subview to your main screen. You'll probably want a UISlider, two UILabels (one to each side of the slider), and anything else you think for a polished look.
(3) The UISLider will have a minimumValue of 0 seconds and a maximumValue of 6802 seconds. Of course, you'll want that max value to be calculated on each change of source.
(4) A question you'll want to answer for your app is whether to go the route of iTunes (where this scrubber view is always visible) or YouTube (where it is overly visible when the user or mouse cursor hovers over an area). For the former, you just need to position this scrub view in a position on the screen. For the latter though, you may wish to use a pan gesture - but only for visibility. Hold that thought.
(5a) You need two, maybe three more things on you UISlider. First is an automatic value update. Again it will depend on the visibility of the entire scrub view. You want to update, once a second, both the left hand UILabel and the UISLider value if it's always visible. For a disappearing one you probably can get away with only updating it once a second when it's visible.
(5b) The second thing you need to do with the UISlider is track changes the user makes to it (the "scrubbing") while it's visible. The event you are looking for is UIControl.valueChanged(). It will trigger anytime the user works with the slider, giving you the new seconds value to "scrub" the video to.
(5c) The third thing you might want to do with the UISlider is customize it a few ways - change the thumb image and the slider itself. My app changes the thumb image. These can only be done in code, there are no IB properties available.
Back to #4. All of the above doesn't need a pan gesture, unless you want the scrub view to appear only when needed.
If you have a mental picture of what I've described above, all you want to know is if a pan gesture has happened. No regards for direction. You might wish to have some regards for screen area - do want this scrub view to appear when a user pans over an area where the scrub view will not appear?
Wire up a CALayer (or the entire video view) with the pan gesture. Then code for a state of UIGestureRecognizer.began. Make the scrub view visible by changing it's alpha state from 0 to 1, or "sliding" it into view by changing it's origin or height. Add a UIView.animate(withDuration:) to it for a good effect.
Now, all that's left is setting the scrub view back to it's natural state. You'll need to code the reverse of whatever you did, and attach it to a timer set for however many seconds you want it visible.
TL;DR;
My app uses 4 UISliders that change various things (height, width, saturation, grill thickness) of of a photo effect that uses CoreImage. Performance is very tight, about 5/100 of a second to grab the new values of all 4 sliders and update the image.
These sliders are always visible today, but my next update (about 2 weeks away) will feature a "sliding control board" - think a keyboard with sliders and other controls on it. (There's limitations on the alpha value for a custom keyboard that forced me to write my own, but that's a separate discussion.)
So I know a "sliding scrub view" is possible. What I don't know for you is if you set the alpha value to a view to zero, will it detect pan gestures? I don't know, thus a CALayer may be needed.

Cocos2D - Simulating infinite scrolling

I have a BIG problem!! I want to make something like old space shooter games like “Asteroids”, where the ship, when going out of the screen, is reappearing at the other side. For example, when the ship go out at the top of the screen, it come back at the bottom. But in my game, there’s a camera following the player, showing only a quarter of the world, and I want to simulate an infinite world this way! Here’s a picture showing what I mean :
What I thought doing was simulate the scroll by only moving game objects, stored in an array, but not the player, and calculating at every frame if the objects are out of the world boundary and re-adding them at the other end of the world (i.e going out at the left would add it back at the right).
But I don’t really like that way of doing… I’d like something more… intuitive..?
Do you guys have any idea of how doing it? Like, any tutorial on the web or just the right words to explain what I mean so I could do a bright research on google (I’m french, so I had a really hard time writing that question)!
Thank you in advance!
Knowing the players position, x,y check to see if the player is within the bounds of the area. If the player has left those bounds, set the player's position to the opposite bounds, possibly adding width/height. I'll do it here for the Y coordinate only:
const float minWarpAreaY( 0 );
const float maxWarpAreaY( 400 );
//if (player.y < minWarpAreaY) { player.y = maxWarpAreaY - player.height; }
//if (player.y > maxWarpAreaY) { player.y = minWarpAreaY + player.height; }
if (player.y < minWarpAreaY) { WarpPlayer(0.0f, (maxWarpAreaY - minWarpAreaY)); }
if (player.y > maxWarpAreaY) { WarpPlayer(0.0f, -(maxWarpAreaY - minWarpAreaY)); }
void WarpPlayer(float amountX, float amountY)
{
player.x += amountX;
player.y += amountY;
for (eachObject in World)
{
eachObject.x += amountX;
eachObject.y += amountY;
}
}
Something along those lines should help.

I'm unable to make my sprites "Flip"

I'll start off by admitting that I am a beginner to ActionScript and I am in the process of coding my own basic arcade game (Similar to that of the old arcade game "Joust"). Whilst I have been able to code the sprite's movement I am looking to make the sprite flip to face the other way when I press the right arrow. I figured either I could try and rotate the object around its axis (Which I've tried multiple times and has proved difficult) or I could try and "Replace" the current sprite with another sprite (Which is just the sprite facing the opposite way). I've searched everywhere for a method of replacing a sprite with another sprite but to no avail. How would it be possible to give this sprite a flip effect when a certain keyCode is used?
Try this simple code below. Here 'object' is the movieclip/sprite that you want to flip
stage.addEventListener(KeyboardEvent.KEY_DOWN, OnKeyDown);
function OnKeyDown(event:KeyboardEvent):void
{
var uiKeyCode:uint = event.keyCode;
switch (uiKeyCode)
{
case Keyboard.LEFT :
object.scaleX = -1; //flip
break;
case Keyboard.RIGHT :
object.scaleX = 1; //unflip
break;
}
}
NOTE: If you want the movieclip to flip without any shift in its position then the movieclip must be horizontally center registered.
Tell me if this works for you.
Are you using as2/as3? you could flip the axis Y 180 degrees
if your using as2 you will need to either mirror the bitmap via actionScript or
add a second bitmap that is mirrored to the display list.
stage.addEventListener(KeyboardEvent.KEY_DOWN, keyPressedDown);
function keyPressedDown(event:KeyboardEvent):void
{
var key:uint = event.keyCode;
switch (key)
{
case Keyboard.LEFT :
myMovieClip.rotaionY = 180; // MC will be mirrored
break;
case Keyboard.RIGHT :
myMovieClip.rotaionY = 0;
}

Swipe Gesture for iOS in Flash CS6

I'm creating an app for iOS (mainly) in Flash CS6 and I'm having a few problems with getting a particular page to work.
The layout is as follows: I have a movie clip that is 3 times the width of the stage with my content, with the instance name of txtContent.
On a separate layer, my Action Script (v3.0) reads as follows:
import com.greensock.*;
import flash.events.MouseEvent;
//Swipe
Multitouch.inputMode = MultitouchInputMode.GESTURE;
var currentTile:Number = 1;
var totalTiles:Number = 3;
txtContent.addEventListener(TransformGestureEvent.GESTURE_SWIPE , onSwipe);
function moveLeft():void{
txtContent.x += 640;
}
function moveRight():void{
txtContent.x -= 640;
}
function onSwipe (e:TransformGestureEvent):void{
if (e.offsetX == 1) {
if(currentTile > 1){
moveLeft()
currentTile--
} else {}
}
if (e.offsetX == -1) {
if(currentTile < totalTiles){
moveRight()
currentTile++
}
}
}
stop();
When I test the movie, with a touch layer, the movie clip successfully moves left and right for each swipe, and does not continue to move too far in either direction, in effect ignoring any other swipes.
However, when I compile the IPA and test on the iPhone, only the first two "tiles" move (I can only see two thirds of the movie clip with swiping), as if I swipe to the third "tile" I cannot swipe back at all. No matter what I do, it gets stuck on that third section.
Is there a problem in my code that isn't registering properly in iOS?
FYI, I'm testing on an iPhone 3GS.
It was my own mistake - the final 'page' of the slides did not have a large background with the alpha set to 0% like the others, therefore to slide it back it would only work when holding the text (which was small). With the addition of the background, the movieclip is solid and therefore swiping the whole screen worked fine.

Jumping effect in games

I'm currently trying to make a basic platformer with XNA and I'm wondering how to create a "jumping effect." I currently have basic keyboard input which allows for sideways movement, but I would like my sprite to slowly progress into a jump rather than instantly teleporting there (right now I have something like Rectangle.Y += 40 every time I jump, making the sprite instantly appear there). Does anyone have any insight?
I'm not totally across how to implement this in XNA/C#, but in Flash games I've made I just added a vertical velocity property. I'll try write everything as C# as I can..
Example; create the velocity property:
float verticalVelocity = 0;
Vertical velocity should be constantly reduced (by gravity). Set up a gravity property somewhere accessible from your player:
float Gravity = 2.5;
And in your update() method for the player, increment the verticalVelocity by Gravity. Also increment the Y position of your player by the verticalVelocity. This will simulate falling:
verticalVelocity += Gravity;
Position.Y += verticalVelocity; // this may be -= in XNA, not sure where the y axis beings
When you hit a surface, the velocity should be reset to 0.
And finally, to jump, simply subtract a given value from verticalVelocity:
public void Jump(float height)
{
// Only jump if standing on a surface.
if(verticalVelocity == 0)
verticalVelocity -= height;
}
You'll eventually want to add gravity and possibly other forces to your game, so I highly recommend you save yourself a lot of pain and implement some kind of basic force system. This can be done using Vector2s, as you can just add them to the speed of your character. Then just apply an instantaneous force to your character to push it up.
If you really don't want to use a physics engine, you can make a Vector2 with the high point of the jump for the Y and the characters X, and then use the Vector2.Lerp method to interpolate between the characters position and the end point of the jump.
This is generally a very bad system to use, and I highly recommend you either use an existing physics engine, or make your own simple one.
use a sinusoidcode should look something like this:
float ground = 0.0f;
float angle = 330.0f;
jump(){
if(ground == 0.0f)ground = Rectangle.Y;
if(Rectangle.Y <= ground)
{
Rectangle.Y+=Math.Sin(angle/(Math.Pi*180));
angle++;
}
}
You can accurately create a gravity effect if you modify the ySpeed dynamically, as opposed to just adding 40.
You want to declare a ySpeed
ySpeed = 0;
Then you want to use an acceleration variable
acceleration = 0.25;
Okay, now that we've done that, let's add gravity, provided that our player isn't touching the floor.
if(playerLocationY + playerHeight > floorLocationY)
{
gravity = false;
}
else
{
gravity = true;
}
if(gravity)
{
ySpeed += acceleration;
}
Now that we've got that down, we want to include something that allows us to jump.
if(KeyPressed == UP)
{
ySpeed -= acceleration;
}
This will move our player in the upward direction
We now want to make sure we actually move, so let's add one last line and we're done.
playerLocationY += ySpeed;
Congratulations, you made it.

Resources